blob: d972c9d9b8ec33e7f3612b6601738191e0cbbe42 [file] [log] [blame]
Maros Ondrejickaffa3f602023-01-26 10:07:29 +01001package main
2
3import (
Filip Tehlar671cf512023-01-31 10:34:18 +01004 "flag"
Maros Ondrejickaffa3f602023-01-26 10:07:29 +01005 "io/ioutil"
6 "os"
Maros Ondrejickaa2d52622023-02-24 11:26:39 +01007 "time"
Maros Ondrejickaffa3f602023-01-26 10:07:29 +01008
9 "github.com/edwarnicke/exechelper"
10 "github.com/stretchr/testify/assert"
11 "github.com/stretchr/testify/suite"
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010012 "gopkg.in/yaml.v3"
13)
14
Maros Ondrejicka2908f8c2023-02-02 08:58:04 +010015const (
Filip Tehlar608d0062023-04-28 10:29:47 +020016 DEFAULT_NETWORK_NUM int = 1
Maros Ondrejicka2908f8c2023-02-02 08:58:04 +010017)
18
Maros Ondrejickae7625d02023-02-28 16:55:01 +010019var isPersistent = flag.Bool("persist", false, "persists topology config")
20var isVerbose = flag.Bool("verbose", false, "verbose test output")
21var isUnconfiguring = flag.Bool("unconfigure", false, "remove topology")
22var isVppDebug = flag.Bool("debug", false, "attach gdb to vpp")
Filip Tehlar608d0062023-04-28 10:29:47 +020023var nConfiguredCpus = flag.Int("cpus", 1, "number of CPUs assigned to vpp")
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010024
25type HstSuite struct {
26 suite.Suite
Filip Tehlar3a910ab2023-06-08 17:39:39 +020027 containers map[string]*Container
28 volumes []string
29 netConfigs []NetConfig
30 netInterfaces map[string]*NetInterface
31 ip4AddrAllocator *Ip4AddressAllocator
32 testIds map[string]string
33 cpuAllocator *CpuAllocatorT
34 cpuContexts []*CpuContext
35 cpuPerVpp int
Filip Tehlar608d0062023-04-28 10:29:47 +020036}
37
38func (s *HstSuite) SetupSuite() {
39 var err error
40 s.cpuAllocator, err = CpuAllocator()
41 if err != nil {
42 s.FailNow("failed to init cpu allocator: %v", err)
43 }
44 s.cpuPerVpp = *nConfiguredCpus
45}
46
47func (s *HstSuite) AllocateCpus() []int {
48 cpuCtx, err := s.cpuAllocator.Allocate(s.cpuPerVpp)
49 s.assertNil(err)
50 s.AddCpuContext(cpuCtx)
51 return cpuCtx.cpus
52}
53
54func (s *HstSuite) AddCpuContext(cpuCtx *CpuContext) {
55 s.cpuContexts = append(s.cpuContexts, cpuCtx)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010056}
57
58func (s *HstSuite) TearDownSuite() {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010059 s.unconfigureNetworkTopology()
60}
61
62func (s *HstSuite) TearDownTest() {
Maros Ondrejickae7625d02023-02-28 16:55:01 +010063 if *isPersistent {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010064 return
65 }
Filip Tehlar608d0062023-04-28 10:29:47 +020066 for _, c := range s.cpuContexts {
67 c.Release()
68 }
Maros Ondrejickae7625d02023-02-28 16:55:01 +010069 s.resetContainers()
70 s.removeVolumes()
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010071}
72
Maros Ondrejickaaf004dd2023-02-27 16:52:57 +010073func (s *HstSuite) skipIfUnconfiguring() {
Maros Ondrejickae7625d02023-02-28 16:55:01 +010074 if *isUnconfiguring {
Maros Ondrejickaaf004dd2023-02-27 16:52:57 +010075 s.skip("skipping to unconfigure")
76 }
77}
78
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010079func (s *HstSuite) SetupTest() {
Maros Ondrejickaaf004dd2023-02-27 16:52:57 +010080 s.skipIfUnconfiguring()
Maros Ondrejickae7625d02023-02-28 16:55:01 +010081 s.setupVolumes()
82 s.setupContainers()
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010083}
84
Maros Ondrejickae7625d02023-02-28 16:55:01 +010085func (s *HstSuite) setupVolumes() {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010086 for _, volume := range s.volumes {
87 cmd := "docker volume create --name=" + volume
88 s.log(cmd)
89 exechelper.Run(cmd)
90 }
91}
92
Maros Ondrejickae7625d02023-02-28 16:55:01 +010093func (s *HstSuite) setupContainers() {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010094 for _, container := range s.containers {
Filip Tehlar608d0062023-04-28 10:29:47 +020095 if !container.isOptional {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +010096 container.run()
97 }
98 }
99}
100
101func (s *HstSuite) hstFail() {
102 s.T().FailNow()
103}
104
105func (s *HstSuite) assertNil(object interface{}, msgAndArgs ...interface{}) {
106 if !assert.Nil(s.T(), object, msgAndArgs...) {
107 s.hstFail()
108 }
109}
110
111func (s *HstSuite) assertNotNil(object interface{}, msgAndArgs ...interface{}) {
112 if !assert.NotNil(s.T(), object, msgAndArgs...) {
113 s.hstFail()
114 }
115}
116
117func (s *HstSuite) assertEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
118 if !assert.Equal(s.T(), expected, actual, msgAndArgs...) {
119 s.hstFail()
120 }
121}
122
123func (s *HstSuite) assertNotEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
124 if !assert.NotEqual(s.T(), expected, actual, msgAndArgs...) {
125 s.hstFail()
126 }
127}
128
129func (s *HstSuite) assertContains(testString, contains interface{}, msgAndArgs ...interface{}) {
130 if !assert.Contains(s.T(), testString, contains, msgAndArgs...) {
131 s.hstFail()
132 }
133}
134
135func (s *HstSuite) assertNotContains(testString, contains interface{}, msgAndArgs ...interface{}) {
136 if !assert.NotContains(s.T(), testString, contains, msgAndArgs...) {
137 s.hstFail()
138 }
139}
140
Maros Ondrejicka2ddb2fd2023-02-15 17:44:46 +0100141func (s *HstSuite) assertNotEmpty(object interface{}, msgAndArgs ...interface{}) {
142 if !assert.NotEmpty(s.T(), object, msgAndArgs...) {
143 s.hstFail()
144 }
145}
146
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100147func (s *HstSuite) log(args ...any) {
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100148 if *isVerbose {
Maros Ondrejickaaf004dd2023-02-27 16:52:57 +0100149 s.T().Helper()
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100150 s.T().Log(args...)
151 }
152}
153
154func (s *HstSuite) skip(args ...any) {
155 s.log(args...)
156 s.T().SkipNow()
157}
158
Filip Tehlar608d0062023-04-28 10:29:47 +0200159func (s *HstSuite) SkipIfMultiWorker(args ...any) {
160 if *nConfiguredCpus > 1 {
161 s.skip("test case not supported with multiple vpp workers")
162 }
163}
164
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100165func (s *HstSuite) resetContainers() {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100166 for _, container := range s.containers {
167 container.stop()
168 }
169}
170
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100171func (s *HstSuite) removeVolumes() {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100172 for _, volumeName := range s.volumes {
173 cmd := "docker volume rm " + volumeName
174 exechelper.Run(cmd)
175 os.RemoveAll(volumeName)
176 }
177}
178
179func (s *HstSuite) getContainerByName(name string) *Container {
180 return s.containers[name]
181}
182
Maros Ondrejicka2908f8c2023-02-02 08:58:04 +0100183/*
184 * Create a copy and return its address, so that individial tests which call this
185 * are not able to modify the original container and affect other tests by doing that
186 */
187func (s *HstSuite) getTransientContainerByName(name string) *Container {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100188 containerCopy := *s.containers[name]
189 return &containerCopy
190}
191
192func (s *HstSuite) loadContainerTopology(topologyName string) {
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100193 data, err := ioutil.ReadFile(containerTopologyDir + topologyName + ".yaml")
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100194 if err != nil {
195 s.T().Fatalf("read error: %v", err)
196 }
197 var yamlTopo YamlTopology
198 err = yaml.Unmarshal(data, &yamlTopo)
199 if err != nil {
200 s.T().Fatalf("unmarshal error: %v", err)
201 }
202
203 for _, elem := range yamlTopo.Volumes {
204 volumeMap := elem["volume"].(VolumeConfig)
205 hostDir := volumeMap["host-dir"].(string)
206 s.volumes = append(s.volumes, hostDir)
207 }
208
209 s.containers = make(map[string]*Container)
210 for _, elem := range yamlTopo.Containers {
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100211 newContainer, err := newContainer(elem)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100212 newContainer.suite = s
213 if err != nil {
214 s.T().Fatalf("container config error: %v", err)
215 }
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100216 s.containers[newContainer.name] = newContainer
217 }
218}
219
220func (s *HstSuite) loadNetworkTopology(topologyName string) {
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100221 data, err := ioutil.ReadFile(networkTopologyDir + topologyName + ".yaml")
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100222 if err != nil {
223 s.T().Fatalf("read error: %v", err)
224 }
225 var yamlTopo YamlTopology
226 err = yaml.Unmarshal(data, &yamlTopo)
227 if err != nil {
228 s.T().Fatalf("unmarshal error: %v", err)
229 }
230
Filip Tehlar3a910ab2023-06-08 17:39:39 +0200231 s.ip4AddrAllocator = NewIp4AddressAllocator()
Maros Ondrejicka40cba402023-02-23 13:19:15 +0100232 s.netInterfaces = make(map[string]*NetInterface)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100233 for _, elem := range yamlTopo.Devices {
234 switch elem["type"].(string) {
235 case NetNs:
236 {
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100237 if namespace, err := newNetNamespace(elem); err == nil {
Maros Ondrejicka2908f8c2023-02-02 08:58:04 +0100238 s.netConfigs = append(s.netConfigs, &namespace)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100239 } else {
240 s.T().Fatalf("network config error: %v", err)
241 }
242 }
Maros Ondrejicka40cba402023-02-23 13:19:15 +0100243 case Veth, Tap:
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100244 {
Filip Tehlar3a910ab2023-06-08 17:39:39 +0200245 if netIf, err := newNetworkInterface(elem, s.ip4AddrAllocator); err == nil {
Maros Ondrejicka40cba402023-02-23 13:19:15 +0100246 s.netConfigs = append(s.netConfigs, netIf)
247 s.netInterfaces[netIf.Name()] = netIf
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100248 } else {
249 s.T().Fatalf("network config error: %v", err)
250 }
251 }
252 case Bridge:
253 {
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100254 if bridge, err := newBridge(elem); err == nil {
Maros Ondrejicka2908f8c2023-02-02 08:58:04 +0100255 s.netConfigs = append(s.netConfigs, &bridge)
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100256 } else {
257 s.T().Fatalf("network config error: %v", err)
258 }
259 }
260 }
261 }
262}
263
264func (s *HstSuite) configureNetworkTopology(topologyName string) {
265 s.loadNetworkTopology(topologyName)
266
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100267 if *isUnconfiguring {
Maros Ondrejickaaf004dd2023-02-27 16:52:57 +0100268 return
269 }
270
Maros Ondrejicka2908f8c2023-02-02 08:58:04 +0100271 for _, nc := range s.netConfigs {
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100272 if err := nc.configure(); err != nil {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100273 s.T().Fatalf("network config error: %v", err)
274 }
275 }
276}
277
278func (s *HstSuite) unconfigureNetworkTopology() {
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100279 if *isPersistent {
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100280 return
281 }
Maros Ondrejicka2908f8c2023-02-02 08:58:04 +0100282 for _, nc := range s.netConfigs {
Maros Ondrejickae7625d02023-02-28 16:55:01 +0100283 nc.unconfigure()
Maros Ondrejickaffa3f602023-01-26 10:07:29 +0100284 }
285}
286
Maros Ondrejickaa2d52622023-02-24 11:26:39 +0100287func (s *HstSuite) getTestId() string {
288 testName := s.T().Name()
289
290 if s.testIds == nil {
291 s.testIds = map[string]string{}
292 }
293
294 if _, ok := s.testIds[testName]; !ok {
Filip Tehlar75776f02023-03-24 13:47:45 +0100295 s.testIds[testName] = time.Now().Format("2006-01-02_15-04-05")
Maros Ondrejickaa2d52622023-02-24 11:26:39 +0100296 }
297
298 return s.testIds[testName]
299}