blob: 26dcf4e5a2b235fc9b5ba417bcf197026a894e6c [file] [log] [blame]
Maros Ondrejickaffa3f602023-01-26 10:07:29 +01001package main
2
3import (
adrianvillin7c675472024-02-12 02:44:53 -05004 "bufio"
Filip Tehlar4b3598e2023-09-02 08:54:21 +02005 "errors"
Filip Tehlar671cf512023-01-31 10:34:18 +01006 "flag"
Filip Tehlar4b3598e2023-09-02 08:54:21 +02007 "fmt"
Adrian Villin637edda2024-05-06 06:55:34 -04008 "io"
9 "log"
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010010 "os"
Filip Tehlar31eaea92023-06-15 10:06:57 +020011 "os/exec"
12 "strings"
Maros Ondrejickaa2d52622023-02-24 11:26:39 +010013 "time"
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010014
15 "github.com/edwarnicke/exechelper"
Adrian Villincee15aa2024-03-14 11:42:55 -040016 . "github.com/onsi/ginkgo/v2"
17 . "github.com/onsi/gomega"
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010018 "gopkg.in/yaml.v3"
19)
20
Maros Ondrejicka2908f8c2023-02-02 08:58:04 +010021const (
Filip Tehlar608d0062023-04-28 10:29:47 +020022 DEFAULT_NETWORK_NUM int = 1
Maros Ondrejicka2908f8c2023-02-02 08:58:04 +010023)
24
Maros Ondrejickae7625d02023-02-28 16:55:01 +010025var isPersistent = flag.Bool("persist", false, "persists topology config")
26var isVerbose = flag.Bool("verbose", false, "verbose test output")
27var isUnconfiguring = flag.Bool("unconfigure", false, "remove topology")
28var isVppDebug = flag.Bool("debug", false, "attach gdb to vpp")
Filip Tehlar608d0062023-04-28 10:29:47 +020029var nConfiguredCpus = flag.Int("cpus", 1, "number of CPUs assigned to vpp")
Filip Tehlar109f3ce2023-09-05 15:36:28 +020030var vppSourceFileDir = flag.String("vppsrc", "", "vpp source file directory")
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010031
32type HstSuite struct {
Adrian Villinfd366b42024-05-31 06:46:52 -040033 containers map[string]*Container
34 startedContainers []*Container
35 volumes []string
36 netConfigs []NetConfig
37 netInterfaces map[string]*NetInterface
38 ip4AddrAllocator *Ip4AddressAllocator
39 testIds map[string]string
40 cpuAllocator *CpuAllocatorT
41 cpuContexts []*CpuContext
42 cpuPerVpp int
43 pid string
44 logger *log.Logger
45 logFile *os.File
Filip Tehlar608d0062023-04-28 10:29:47 +020046}
47
48func (s *HstSuite) SetupSuite() {
Adrian Villin637edda2024-05-06 06:55:34 -040049 s.createLogger()
50 s.log("Suite Setup")
51 RegisterFailHandler(func(message string, callerSkip ...int) {
52 s.hstFail()
53 Fail(message, callerSkip...)
54 })
Filip Tehlar608d0062023-04-28 10:29:47 +020055 var err error
adrianvillin28bd8f02024-02-13 06:00:02 -050056 s.pid = fmt.Sprint(os.Getpid())
Filip Tehlar608d0062023-04-28 10:29:47 +020057 s.cpuAllocator, err = CpuAllocator()
58 if err != nil {
Adrian Villincee15aa2024-03-14 11:42:55 -040059 Fail("failed to init cpu allocator: " + fmt.Sprint(err))
Filip Tehlar608d0062023-04-28 10:29:47 +020060 }
61 s.cpuPerVpp = *nConfiguredCpus
62}
63
64func (s *HstSuite) AllocateCpus() []int {
Adrian Villinfd366b42024-05-31 06:46:52 -040065 cpuCtx, err := s.cpuAllocator.Allocate(len(s.startedContainers), s.cpuPerVpp)
Filip Tehlar608d0062023-04-28 10:29:47 +020066 s.assertNil(err)
67 s.AddCpuContext(cpuCtx)
68 return cpuCtx.cpus
69}
70
71func (s *HstSuite) AddCpuContext(cpuCtx *CpuContext) {
72 s.cpuContexts = append(s.cpuContexts, cpuCtx)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010073}
74
75func (s *HstSuite) TearDownSuite() {
Adrian Villin637edda2024-05-06 06:55:34 -040076 defer s.logFile.Close()
77 s.log("Suite Teardown")
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010078 s.unconfigureNetworkTopology()
79}
80
81func (s *HstSuite) TearDownTest() {
Adrian Villin637edda2024-05-06 06:55:34 -040082 s.log("Test Teardown")
Maros Ondrejickae7625d02023-02-28 16:55:01 +010083 if *isPersistent {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010084 return
85 }
Maros Ondrejickae7625d02023-02-28 16:55:01 +010086 s.resetContainers()
87 s.removeVolumes()
adrianvillin28bd8f02024-02-13 06:00:02 -050088 s.ip4AddrAllocator.deleteIpAddresses()
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010089}
90
Maros Ondrejickaaf004dd2023-02-27 16:52:57 +010091func (s *HstSuite) skipIfUnconfiguring() {
Maros Ondrejickae7625d02023-02-28 16:55:01 +010092 if *isUnconfiguring {
Maros Ondrejickaaf004dd2023-02-27 16:52:57 +010093 s.skip("skipping to unconfigure")
94 }
95}
96
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010097func (s *HstSuite) SetupTest() {
Adrian Villin637edda2024-05-06 06:55:34 -040098 s.log("Test Setup")
Adrian Villinfd366b42024-05-31 06:46:52 -040099 s.startedContainers = s.startedContainers[:0]
Maros Ondrejickaaf004dd2023-02-27 16:52:57 +0100100 s.skipIfUnconfiguring()
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100101 s.setupVolumes()
102 s.setupContainers()
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100103}
104
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100105func (s *HstSuite) setupVolumes() {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100106 for _, volume := range s.volumes {
107 cmd := "docker volume create --name=" + volume
108 s.log(cmd)
109 exechelper.Run(cmd)
110 }
111}
112
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100113func (s *HstSuite) setupContainers() {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100114 for _, container := range s.containers {
Filip Tehlar608d0062023-04-28 10:29:47 +0200115 if !container.isOptional {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100116 container.run()
117 }
118 }
119}
120
Adrian Villin637edda2024-05-06 06:55:34 -0400121func (s *HstSuite) logVppInstance(container *Container, maxLines int) {
Adrian Villincee15aa2024-03-14 11:42:55 -0400122 if container.vppInstance == nil {
adrianvillin7c675472024-02-12 02:44:53 -0500123 return
124 }
125
126 logSource := container.getHostWorkDir() + defaultLogFilePath
127 file, err := os.Open(logSource)
128
Adrian Villincee15aa2024-03-14 11:42:55 -0400129 if err != nil {
adrianvillin7c675472024-02-12 02:44:53 -0500130 return
131 }
132 defer file.Close()
133
134 scanner := bufio.NewScanner(file)
135 var lines []string
136 var counter int
137
Adrian Villincee15aa2024-03-14 11:42:55 -0400138 for scanner.Scan() {
adrianvillin7c675472024-02-12 02:44:53 -0500139 lines = append(lines, scanner.Text())
140 counter++
141 if counter > maxLines {
142 lines = lines[1:]
143 counter--
144 }
145 }
146
Adrian Villin637edda2024-05-06 06:55:34 -0400147 s.log("vvvvvvvvvvvvvvv " + container.name + " [VPP instance]:")
Adrian Villincee15aa2024-03-14 11:42:55 -0400148 for _, line := range lines {
Adrian Villin637edda2024-05-06 06:55:34 -0400149 s.log(line)
adrianvillin7c675472024-02-12 02:44:53 -0500150 }
Adrian Villin637edda2024-05-06 06:55:34 -0400151 s.log("^^^^^^^^^^^^^^^\n\n")
adrianvillin7c675472024-02-12 02:44:53 -0500152}
153
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100154func (s *HstSuite) hstFail() {
Adrian Villinfd366b42024-05-31 06:46:52 -0400155 for _, container := range s.startedContainers {
adrianvillin7c675472024-02-12 02:44:53 -0500156 out, err := container.log(20)
Adrian Villincee15aa2024-03-14 11:42:55 -0400157 if err != nil {
Adrian Villin0df582e2024-05-22 09:26:47 -0400158 s.log("An error occured while obtaining '" + container.name + "' container logs: " + fmt.Sprint(err))
Adrian Villinfd366b42024-05-31 06:46:52 -0400159 s.log("The container might not be running - check logs in " + container.getLogDirPath())
Matus Fabian616201a2024-05-02 11:17:15 +0200160 continue
adrianvillin7c675472024-02-12 02:44:53 -0500161 }
Adrian Villin637edda2024-05-06 06:55:34 -0400162 s.log("\nvvvvvvvvvvvvvvv " +
Adrian Villincee15aa2024-03-14 11:42:55 -0400163 container.name + ":\n" +
164 out +
165 "^^^^^^^^^^^^^^^\n\n")
Adrian Villin637edda2024-05-06 06:55:34 -0400166 s.logVppInstance(container, 20)
adrianvillin7c675472024-02-12 02:44:53 -0500167 }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100168}
169
170func (s *HstSuite) assertNil(object interface{}, msgAndArgs ...interface{}) {
Adrian Villincee15aa2024-03-14 11:42:55 -0400171 Expect(object).To(BeNil(), msgAndArgs...)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100172}
173
174func (s *HstSuite) assertNotNil(object interface{}, msgAndArgs ...interface{}) {
Adrian Villincee15aa2024-03-14 11:42:55 -0400175 Expect(object).ToNot(BeNil(), msgAndArgs...)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100176}
177
178func (s *HstSuite) assertEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
Adrian Villincee15aa2024-03-14 11:42:55 -0400179 Expect(actual).To(Equal(expected), msgAndArgs...)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100180}
181
182func (s *HstSuite) assertNotEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
Adrian Villincee15aa2024-03-14 11:42:55 -0400183 Expect(actual).ToNot(Equal(expected), msgAndArgs...)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100184}
185
186func (s *HstSuite) assertContains(testString, contains interface{}, msgAndArgs ...interface{}) {
Adrian Villincee15aa2024-03-14 11:42:55 -0400187 Expect(testString).To(ContainSubstring(fmt.Sprint(contains)), msgAndArgs...)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100188}
189
190func (s *HstSuite) assertNotContains(testString, contains interface{}, msgAndArgs ...interface{}) {
Adrian Villincee15aa2024-03-14 11:42:55 -0400191 Expect(testString).ToNot(ContainSubstring(fmt.Sprint(contains)), msgAndArgs...)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100192}
193
Maros Ondrejicka2ddb2fd2023-02-15 17:44:46 +0100194func (s *HstSuite) assertNotEmpty(object interface{}, msgAndArgs ...interface{}) {
Adrian Villincee15aa2024-03-14 11:42:55 -0400195 Expect(object).ToNot(BeEmpty(), msgAndArgs...)
Maros Ondrejicka2ddb2fd2023-02-15 17:44:46 +0100196}
197
Adrian Villin46d66002024-05-15 04:33:41 -0400198func (s *HstSuite) createLogger() {
Adrian Villin637edda2024-05-06 06:55:34 -0400199 suiteName := CurrentSpecReport().ContainerHierarchyTexts[0]
200 var err error
201 s.logFile, err = os.Create("summary/" + suiteName + ".log")
202 if err != nil {
203 Fail("Unable to create log file.")
204 }
205 s.logger = log.New(io.Writer(s.logFile), "", log.LstdFlags)
206}
207
208// Logs to files by default, logs to stdout when VERBOSE=true with GinkgoWriter
209// to keep console tidy
Adrian Villincee15aa2024-03-14 11:42:55 -0400210func (s *HstSuite) log(arg any) {
Adrian Villin637edda2024-05-06 06:55:34 -0400211 logs := strings.Split(fmt.Sprint(arg), "\n")
212 for _, line := range logs {
213 s.logger.Println(line)
214 }
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100215 if *isVerbose {
Adrian Villin637edda2024-05-06 06:55:34 -0400216 GinkgoWriter.Println(arg)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100217 }
218}
219
Adrian Villincee15aa2024-03-14 11:42:55 -0400220func (s *HstSuite) skip(args string) {
221 Skip(args)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100222}
223
Filip Tehlar608d0062023-04-28 10:29:47 +0200224func (s *HstSuite) SkipIfMultiWorker(args ...any) {
225 if *nConfiguredCpus > 1 {
226 s.skip("test case not supported with multiple vpp workers")
227 }
228}
229
Filip Tehlar31eaea92023-06-15 10:06:57 +0200230func (s *HstSuite) SkipUnlessExtendedTestsBuilt() {
231 imageName := "hs-test/nginx-http3"
232
233 cmd := exec.Command("docker", "images", imageName)
234 byteOutput, err := cmd.CombinedOutput()
235 if err != nil {
236 s.log("error while searching for docker image")
237 return
238 }
239 if !strings.Contains(string(byteOutput), imageName) {
240 s.skip("extended tests not built")
241 }
242}
243
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100244func (s *HstSuite) resetContainers() {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100245 for _, container := range s.containers {
246 container.stop()
247 }
248}
249
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100250func (s *HstSuite) removeVolumes() {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100251 for _, volumeName := range s.volumes {
252 cmd := "docker volume rm " + volumeName
253 exechelper.Run(cmd)
254 os.RemoveAll(volumeName)
255 }
256}
257
adrianvillin28bd8f02024-02-13 06:00:02 -0500258func (s *HstSuite) getNetNamespaceByName(name string) string {
259 return name + s.pid
260}
261
262func (s *HstSuite) getInterfaceByName(name string) *NetInterface {
Adrian Villincee15aa2024-03-14 11:42:55 -0400263 return s.netInterfaces[name+s.pid]
adrianvillin28bd8f02024-02-13 06:00:02 -0500264}
265
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100266func (s *HstSuite) getContainerByName(name string) *Container {
Adrian Villincee15aa2024-03-14 11:42:55 -0400267 return s.containers[name+s.pid]
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100268}
269
Maros Ondrejicka2908f8c2023-02-02 08:58:04 +0100270/*
271 * Create a copy and return its address, so that individial tests which call this
272 * are not able to modify the original container and affect other tests by doing that
273 */
274func (s *HstSuite) getTransientContainerByName(name string) *Container {
Adrian Villincee15aa2024-03-14 11:42:55 -0400275 containerCopy := *s.containers[name+s.pid]
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100276 return &containerCopy
277}
278
279func (s *HstSuite) loadContainerTopology(topologyName string) {
adrianvillin707210c2024-01-24 01:45:59 -0500280 data, err := os.ReadFile(containerTopologyDir + topologyName + ".yaml")
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100281 if err != nil {
Adrian Villincee15aa2024-03-14 11:42:55 -0400282 Fail("read error: " + fmt.Sprint(err))
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100283 }
284 var yamlTopo YamlTopology
285 err = yaml.Unmarshal(data, &yamlTopo)
286 if err != nil {
Adrian Villincee15aa2024-03-14 11:42:55 -0400287 Fail("unmarshal error: " + fmt.Sprint(err))
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100288 }
289
290 for _, elem := range yamlTopo.Volumes {
291 volumeMap := elem["volume"].(VolumeConfig)
292 hostDir := volumeMap["host-dir"].(string)
Adrian Villin637edda2024-05-06 06:55:34 -0400293 workingVolumeDir := logDir + CurrentSpecReport().LeafNodeText + volumeDir
Filip Tehlara1bd50c2024-01-24 11:59:44 +0100294 volDirReplacer := strings.NewReplacer("$HST_VOLUME_DIR", workingVolumeDir)
295 hostDir = volDirReplacer.Replace(hostDir)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100296 s.volumes = append(s.volumes, hostDir)
297 }
298
299 s.containers = make(map[string]*Container)
300 for _, elem := range yamlTopo.Containers {
Adrian Villincee15aa2024-03-14 11:42:55 -0400301 newContainer, err := newContainer(s, elem)
adrianvillin28bd8f02024-02-13 06:00:02 -0500302 newContainer.suite = s
Adrian Villincee15aa2024-03-14 11:42:55 -0400303 newContainer.name += newContainer.suite.pid
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100304 if err != nil {
Adrian Villincee15aa2024-03-14 11:42:55 -0400305 Fail("container config error: " + fmt.Sprint(err))
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100306 }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100307 s.containers[newContainer.name] = newContainer
308 }
309}
310
311func (s *HstSuite) loadNetworkTopology(topologyName string) {
adrianvillin707210c2024-01-24 01:45:59 -0500312 data, err := os.ReadFile(networkTopologyDir + topologyName + ".yaml")
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100313 if err != nil {
Adrian Villincee15aa2024-03-14 11:42:55 -0400314 Fail("read error: " + fmt.Sprint(err))
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100315 }
316 var yamlTopo YamlTopology
317 err = yaml.Unmarshal(data, &yamlTopo)
318 if err != nil {
Adrian Villincee15aa2024-03-14 11:42:55 -0400319 Fail("unmarshal error: " + fmt.Sprint(err))
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100320 }
321
Filip Tehlar3a910ab2023-06-08 17:39:39 +0200322 s.ip4AddrAllocator = NewIp4AddressAllocator()
Maros Ondrejicka40cba402023-02-23 13:19:15 +0100323 s.netInterfaces = make(map[string]*NetInterface)
adrianvillin28bd8f02024-02-13 06:00:02 -0500324
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100325 for _, elem := range yamlTopo.Devices {
adrianvillin28bd8f02024-02-13 06:00:02 -0500326 if _, ok := elem["name"]; ok {
327 elem["name"] = elem["name"].(string) + s.pid
328 }
329
330 if peer, ok := elem["peer"].(NetDevConfig); ok {
Adrian Villincee15aa2024-03-14 11:42:55 -0400331 if peer["name"].(string) != "" {
adrianvillin28bd8f02024-02-13 06:00:02 -0500332 peer["name"] = peer["name"].(string) + s.pid
333 }
Adrian Villincee15aa2024-03-14 11:42:55 -0400334 if _, ok := peer["netns"]; ok {
adrianvillin28bd8f02024-02-13 06:00:02 -0500335 peer["netns"] = peer["netns"].(string) + s.pid
336 }
337 }
338
339 if _, ok := elem["netns"]; ok {
340 elem["netns"] = elem["netns"].(string) + s.pid
341 }
342
343 if _, ok := elem["interfaces"]; ok {
344 interfaceCount := len(elem["interfaces"].([]interface{}))
345 for i := 0; i < interfaceCount; i++ {
346 elem["interfaces"].([]interface{})[i] = elem["interfaces"].([]interface{})[i].(string) + s.pid
347 }
348 }
349
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100350 switch elem["type"].(string) {
351 case NetNs:
352 {
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100353 if namespace, err := newNetNamespace(elem); err == nil {
Maros Ondrejicka2908f8c2023-02-02 08:58:04 +0100354 s.netConfigs = append(s.netConfigs, &namespace)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100355 } else {
Adrian Villincee15aa2024-03-14 11:42:55 -0400356 Fail("network config error: " + fmt.Sprint(err))
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100357 }
358 }
Maros Ondrejicka40cba402023-02-23 13:19:15 +0100359 case Veth, Tap:
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100360 {
Filip Tehlar3a910ab2023-06-08 17:39:39 +0200361 if netIf, err := newNetworkInterface(elem, s.ip4AddrAllocator); err == nil {
Maros Ondrejicka40cba402023-02-23 13:19:15 +0100362 s.netConfigs = append(s.netConfigs, netIf)
363 s.netInterfaces[netIf.Name()] = netIf
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100364 } else {
Adrian Villincee15aa2024-03-14 11:42:55 -0400365 Fail("network config error: " + fmt.Sprint(err))
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100366 }
367 }
368 case Bridge:
369 {
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100370 if bridge, err := newBridge(elem); err == nil {
Maros Ondrejicka2908f8c2023-02-02 08:58:04 +0100371 s.netConfigs = append(s.netConfigs, &bridge)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100372 } else {
Adrian Villincee15aa2024-03-14 11:42:55 -0400373 Fail("network config error: " + fmt.Sprint(err))
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100374 }
375 }
376 }
377 }
378}
379
380func (s *HstSuite) configureNetworkTopology(topologyName string) {
381 s.loadNetworkTopology(topologyName)
382
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100383 if *isUnconfiguring {
Maros Ondrejickaaf004dd2023-02-27 16:52:57 +0100384 return
385 }
386
Maros Ondrejicka2908f8c2023-02-02 08:58:04 +0100387 for _, nc := range s.netConfigs {
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100388 if err := nc.configure(); err != nil {
Adrian Villincee15aa2024-03-14 11:42:55 -0400389 Fail("Network config error: " + fmt.Sprint(err))
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100390 }
391 }
392}
393
394func (s *HstSuite) unconfigureNetworkTopology() {
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100395 if *isPersistent {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100396 return
397 }
Maros Ondrejicka2908f8c2023-02-02 08:58:04 +0100398 for _, nc := range s.netConfigs {
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100399 nc.unconfigure()
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100400 }
401}
402
Maros Ondrejickaa2d52622023-02-24 11:26:39 +0100403func (s *HstSuite) getTestId() string {
Adrian Villincee15aa2024-03-14 11:42:55 -0400404 testName := CurrentSpecReport().LeafNodeText
Maros Ondrejickaa2d52622023-02-24 11:26:39 +0100405
406 if s.testIds == nil {
407 s.testIds = map[string]string{}
408 }
409
410 if _, ok := s.testIds[testName]; !ok {
Filip Tehlar75776f02023-03-24 13:47:45 +0100411 s.testIds[testName] = time.Now().Format("2006-01-02_15-04-05")
Maros Ondrejickaa2d52622023-02-24 11:26:39 +0100412 }
413
414 return s.testIds[testName]
415}
Filip Tehlar4b3598e2023-09-02 08:54:21 +0200416
adrianvillin28bd8f02024-02-13 06:00:02 -0500417// Returns last 4 digits of PID
418func (s *HstSuite) getPortFromPid() string {
419 port := s.pid
420 for len(port) < 4 {
421 port += "0"
422 }
423 return port[len(port)-4:]
424}
425
Filip Tehlar4b3598e2023-09-02 08:54:21 +0200426func (s *HstSuite) startServerApp(running chan error, done chan struct{}, env []string) {
adrianvillin28bd8f02024-02-13 06:00:02 -0500427 cmd := exec.Command("iperf3", "-4", "-s", "-p", s.getPortFromPid())
Filip Tehlar4b3598e2023-09-02 08:54:21 +0200428 if env != nil {
429 cmd.Env = env
430 }
431 s.log(cmd)
432 err := cmd.Start()
433 if err != nil {
434 msg := fmt.Errorf("failed to start iperf server: %v", err)
435 running <- msg
436 return
437 }
438 running <- nil
439 <-done
440 cmd.Process.Kill()
441}
442
443func (s *HstSuite) startClientApp(ipAddress string, env []string, clnCh chan error, clnRes chan string) {
444 defer func() {
445 clnCh <- nil
446 }()
447
448 nTries := 0
449
450 for {
adrianvillin28bd8f02024-02-13 06:00:02 -0500451 cmd := exec.Command("iperf3", "-c", ipAddress, "-u", "-l", "1460", "-b", "10g", "-p", s.getPortFromPid())
Filip Tehlar4b3598e2023-09-02 08:54:21 +0200452 if env != nil {
453 cmd.Env = env
454 }
455 s.log(cmd)
456 o, err := cmd.CombinedOutput()
457 if err != nil {
458 if nTries > 5 {
459 clnCh <- fmt.Errorf("failed to start client app '%s'.\n%s", err, o)
460 return
461 }
462 time.Sleep(1 * time.Second)
463 nTries++
464 continue
465 } else {
466 clnRes <- fmt.Sprintf("Client output: %s", o)
467 }
468 break
469 }
470}
471
472func (s *HstSuite) startHttpServer(running chan struct{}, done chan struct{}, addressPort, netNs string) {
adrianvillin28bd8f02024-02-13 06:00:02 -0500473 cmd := newCommand([]string{"./http_server", addressPort, s.pid}, netNs)
Filip Tehlar4b3598e2023-09-02 08:54:21 +0200474 err := cmd.Start()
475 s.log(cmd)
476 if err != nil {
Adrian Villin46d66002024-05-15 04:33:41 -0400477 s.log("Failed to start http server: " + fmt.Sprint(err))
Filip Tehlar4b3598e2023-09-02 08:54:21 +0200478 return
479 }
480 running <- struct{}{}
481 <-done
482 cmd.Process.Kill()
483}
484
485func (s *HstSuite) startWget(finished chan error, server_ip, port, query, netNs string) {
486 defer func() {
487 finished <- errors.New("wget error")
488 }()
489
490 cmd := newCommand([]string{"wget", "--timeout=10", "--no-proxy", "--tries=5", "-O", "/dev/null", server_ip + ":" + port + "/" + query},
491 netNs)
492 s.log(cmd)
493 o, err := cmd.CombinedOutput()
494 if err != nil {
495 finished <- fmt.Errorf("wget error: '%v\n\n%s'", err, o)
496 return
497 } else if !strings.Contains(string(o), "200 OK") {
498 finished <- fmt.Errorf("wget error: response not 200 OK")
499 return
500 }
501 finished <- nil
502}