10 "github.com/edwarnicke/exechelper"
11 "github.com/stretchr/testify/assert"
12 "github.com/stretchr/testify/suite"
17 DEFAULT_NETWORK_NUM int = 1
20 var isPersistent = flag.Bool("persist", false, "persists topology config")
21 var isVerbose = flag.Bool("verbose", false, "verbose test output")
22 var isUnconfiguring = flag.Bool("unconfigure", false, "remove topology")
23 var isVppDebug = flag.Bool("debug", false, "attach gdb to vpp")
24 var nConfiguredCpus = flag.Int("cpus", 1, "number of CPUs assigned to vpp")
26 type HstSuite struct {
28 containers map[string]*Container
30 netConfigs []NetConfig
31 netInterfaces map[string]*NetInterface
33 testIds map[string]string
34 cpuAllocator *CpuAllocatorT
35 cpuContexts []*CpuContext
39 func (s *HstSuite) SetupSuite() {
41 s.cpuAllocator, err = CpuAllocator()
43 s.FailNow("failed to init cpu allocator: %v", err)
45 s.cpuPerVpp = *nConfiguredCpus
48 func (s *HstSuite) AllocateCpus() []int {
49 cpuCtx, err := s.cpuAllocator.Allocate(s.cpuPerVpp)
51 s.AddCpuContext(cpuCtx)
55 func (s *HstSuite) AddCpuContext(cpuCtx *CpuContext) {
56 s.cpuContexts = append(s.cpuContexts, cpuCtx)
59 func (s *HstSuite) TearDownSuite() {
60 s.unconfigureNetworkTopology()
63 func (s *HstSuite) TearDownTest() {
67 for _, c := range s.cpuContexts {
74 func (s *HstSuite) skipIfUnconfiguring() {
76 s.skip("skipping to unconfigure")
80 func (s *HstSuite) SetupTest() {
81 s.skipIfUnconfiguring()
86 func (s *HstSuite) setupVolumes() {
87 for _, volume := range s.volumes {
88 cmd := "docker volume create --name=" + volume
94 func (s *HstSuite) setupContainers() {
95 for _, container := range s.containers {
96 if !container.isOptional {
102 func (s *HstSuite) hstFail() {
106 func (s *HstSuite) assertNil(object interface{}, msgAndArgs ...interface{}) {
107 if !assert.Nil(s.T(), object, msgAndArgs...) {
112 func (s *HstSuite) assertNotNil(object interface{}, msgAndArgs ...interface{}) {
113 if !assert.NotNil(s.T(), object, msgAndArgs...) {
118 func (s *HstSuite) assertEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
119 if !assert.Equal(s.T(), expected, actual, msgAndArgs...) {
124 func (s *HstSuite) assertNotEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
125 if !assert.NotEqual(s.T(), expected, actual, msgAndArgs...) {
130 func (s *HstSuite) assertContains(testString, contains interface{}, msgAndArgs ...interface{}) {
131 if !assert.Contains(s.T(), testString, contains, msgAndArgs...) {
136 func (s *HstSuite) assertNotContains(testString, contains interface{}, msgAndArgs ...interface{}) {
137 if !assert.NotContains(s.T(), testString, contains, msgAndArgs...) {
142 func (s *HstSuite) assertNotEmpty(object interface{}, msgAndArgs ...interface{}) {
143 if !assert.NotEmpty(s.T(), object, msgAndArgs...) {
148 func (s *HstSuite) log(args ...any) {
155 func (s *HstSuite) skip(args ...any) {
160 func (s *HstSuite) SkipIfMultiWorker(args ...any) {
161 if *nConfiguredCpus > 1 {
162 s.skip("test case not supported with multiple vpp workers")
166 func (s *HstSuite) resetContainers() {
167 for _, container := range s.containers {
172 func (s *HstSuite) removeVolumes() {
173 for _, volumeName := range s.volumes {
174 cmd := "docker volume rm " + volumeName
176 os.RemoveAll(volumeName)
180 func (s *HstSuite) getContainerByName(name string) *Container {
181 return s.containers[name]
185 * Create a copy and return its address, so that individial tests which call this
186 * are not able to modify the original container and affect other tests by doing that
188 func (s *HstSuite) getTransientContainerByName(name string) *Container {
189 containerCopy := *s.containers[name]
190 return &containerCopy
193 func (s *HstSuite) loadContainerTopology(topologyName string) {
194 data, err := ioutil.ReadFile(containerTopologyDir + topologyName + ".yaml")
196 s.T().Fatalf("read error: %v", err)
198 var yamlTopo YamlTopology
199 err = yaml.Unmarshal(data, &yamlTopo)
201 s.T().Fatalf("unmarshal error: %v", err)
204 for _, elem := range yamlTopo.Volumes {
205 volumeMap := elem["volume"].(VolumeConfig)
206 hostDir := volumeMap["host-dir"].(string)
207 s.volumes = append(s.volumes, hostDir)
210 s.containers = make(map[string]*Container)
211 for _, elem := range yamlTopo.Containers {
212 newContainer, err := newContainer(elem)
213 newContainer.suite = s
215 s.T().Fatalf("container config error: %v", err)
217 s.containers[newContainer.name] = newContainer
221 func (s *HstSuite) loadNetworkTopology(topologyName string) {
222 data, err := ioutil.ReadFile(networkTopologyDir + topologyName + ".yaml")
224 s.T().Fatalf("read error: %v", err)
226 var yamlTopo YamlTopology
227 err = yaml.Unmarshal(data, &yamlTopo)
229 s.T().Fatalf("unmarshal error: %v", err)
232 s.addresser = newAddresser(s)
233 s.netInterfaces = make(map[string]*NetInterface)
234 for _, elem := range yamlTopo.Devices {
235 switch elem["type"].(string) {
238 if namespace, err := newNetNamespace(elem); err == nil {
239 s.netConfigs = append(s.netConfigs, &namespace)
241 s.T().Fatalf("network config error: %v", err)
246 if netIf, err := newNetworkInterface(elem, s.addresser); err == nil {
247 s.netConfigs = append(s.netConfigs, netIf)
248 s.netInterfaces[netIf.Name()] = netIf
250 s.T().Fatalf("network config error: %v", err)
255 if bridge, err := newBridge(elem); err == nil {
256 s.netConfigs = append(s.netConfigs, &bridge)
258 s.T().Fatalf("network config error: %v", err)
265 func (s *HstSuite) configureNetworkTopology(topologyName string) {
266 s.loadNetworkTopology(topologyName)
268 if *isUnconfiguring {
272 for _, nc := range s.netConfigs {
273 if err := nc.configure(); err != nil {
274 s.T().Fatalf("network config error: %v", err)
279 func (s *HstSuite) unconfigureNetworkTopology() {
283 for _, nc := range s.netConfigs {
288 func (s *HstSuite) getTestId() string {
289 testName := s.T().Name()
291 if s.testIds == nil {
292 s.testIds = map[string]string{}
295 if _, ok := s.testIds[testName]; !ok {
296 s.testIds[testName] = time.Now().Format("2006-01-02_15-04-05")
299 return s.testIds[testName]
302 type AddressCounter = int
304 type Addresser struct {
305 networks map[int]AddressCounter
309 func (a *Addresser) addNetwork(networkNumber int) {
310 a.networks[networkNumber] = 1
313 func (a *Addresser) newIp4Address(inputNetworkNumber ...int) (string, error) {
314 var networkNumber int = 0
315 if len(inputNetworkNumber) > 0 {
316 networkNumber = inputNetworkNumber[0]
319 if _, ok := a.networks[networkNumber]; !ok {
320 a.addNetwork(networkNumber)
323 numberOfAddresses := a.networks[networkNumber]
325 if numberOfAddresses == 254 {
326 return "", fmt.Errorf("no available IPv4 addresses")
329 address := fmt.Sprintf("10.10.%v.%v/24", networkNumber, numberOfAddresses)
330 a.networks[networkNumber] = numberOfAddresses + 1
335 func newAddresser(suite *HstSuite) *Addresser {
336 var addresser = new(Addresser)
337 addresser.suite = suite
338 addresser.networks = make(map[int]AddressCounter)
339 addresser.addNetwork(0)