8 "github.com/edwarnicke/exechelper"
9 "github.com/stretchr/testify/assert"
10 "github.com/stretchr/testify/suite"
11 "go.fd.io/govpp/binapi/ip_types"
15 func IsPersistent() bool {
16 return os.Getenv("HST_PERSIST") == "1"
19 func IsVerbose() bool {
20 return os.Getenv("HST_VERBOSE") == "1"
23 type HstSuite struct {
26 containers map[string]*Container
28 networkNamespaces map[string]*NetworkNamespace
29 veths map[string]*NetworkInterfaceVeth
30 taps map[string]*NetworkInterfaceTap
31 bridges map[string]*NetworkBridge
35 func (s *HstSuite) TearDownSuite() {
36 if s.teardownSuite != nil {
37 s.teardownSuite() // TODO remove this after config moved to SetupTest() for each suite
40 s.unconfigureNetworkTopology()
43 func (s *HstSuite) TearDownTest() {
51 func (s *HstSuite) SetupTest() {
56 func (s *HstSuite) SetupVolumes() {
57 for _, volume := range s.volumes {
58 cmd := "docker volume create --name=" + volume
64 func (s *HstSuite) SetupContainers() {
65 for _, container := range s.containers {
66 if container.isOptional == false {
72 func (s *HstSuite) hstFail() {
76 func (s *HstSuite) assertNil(object interface{}, msgAndArgs ...interface{}) {
77 if !assert.Nil(s.T(), object, msgAndArgs...) {
82 func (s *HstSuite) assertNotNil(object interface{}, msgAndArgs ...interface{}) {
83 if !assert.NotNil(s.T(), object, msgAndArgs...) {
88 func (s *HstSuite) assertEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
89 if !assert.Equal(s.T(), expected, actual, msgAndArgs...) {
94 func (s *HstSuite) assertNotEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
95 if !assert.NotEqual(s.T(), expected, actual, msgAndArgs...) {
100 func (s *HstSuite) assertContains(testString, contains interface{}, msgAndArgs ...interface{}) {
101 if !assert.Contains(s.T(), testString, contains, msgAndArgs...) {
106 func (s *HstSuite) assertNotContains(testString, contains interface{}, msgAndArgs ...interface{}) {
107 if !assert.NotContains(s.T(), testString, contains, msgAndArgs...) {
112 func (s *HstSuite) log(args ...any) {
118 func (s *HstSuite) skip(args ...any) {
123 func (s *HstSuite) ResetContainers() {
124 for _, container := range s.containers {
129 func (s *HstSuite) RemoveVolumes() {
130 for _, volumeName := range s.volumes {
131 cmd := "docker volume rm " + volumeName
133 os.RemoveAll(volumeName)
137 func (s *HstSuite) getContainerByName(name string) *Container {
138 return s.containers[name]
141 func (s *HstSuite) getContainerCopyByName(name string) *Container {
142 // Create a copy and return its address, so that individial tests which call this
143 // are not able to modify the original container and affect other tests by doing that
144 containerCopy := *s.containers[name]
145 return &containerCopy
148 func (s *HstSuite) loadContainerTopology(topologyName string) {
149 data, err := ioutil.ReadFile(ContainerTopologyDir + topologyName + ".yaml")
151 s.T().Fatalf("read error: %v", err)
153 var yamlTopo YamlTopology
154 err = yaml.Unmarshal(data, &yamlTopo)
156 s.T().Fatalf("unmarshal error: %v", err)
159 for _, elem := range yamlTopo.Volumes {
160 volumeMap := elem["volume"].(VolumeConfig)
161 hostDir := volumeMap["host-dir"].(string)
162 s.volumes = append(s.volumes, hostDir)
165 s.containers = make(map[string]*Container)
166 for _, elem := range yamlTopo.Containers {
167 newContainer, err := NewContainer(elem)
168 newContainer.suite = s
170 s.T().Fatalf("container config error: %v", err)
172 s.log(newContainer.getRunCommand())
173 s.containers[newContainer.name] = newContainer
177 func (s *HstSuite) loadNetworkTopology(topologyName string) {
178 data, err := ioutil.ReadFile(NetworkTopologyDir + topologyName + ".yaml")
180 s.T().Fatalf("read error: %v", err)
182 var yamlTopo YamlTopology
183 err = yaml.Unmarshal(data, &yamlTopo)
185 s.T().Fatalf("unmarshal error: %v", err)
188 s.networkNamespaces = make(map[string]*NetworkNamespace)
189 s.veths = make(map[string]*NetworkInterfaceVeth)
190 s.taps = make(map[string]*NetworkInterfaceTap)
191 s.bridges = make(map[string]*NetworkBridge)
192 for _, elem := range yamlTopo.Devices {
193 switch elem["type"].(string) {
196 if namespace, err := NewNetNamespace(elem); err == nil {
197 s.networkNamespaces[namespace.Name()] = &namespace
199 s.T().Fatalf("network config error: %v", err)
204 if veth, err := NewVeth(elem); err == nil {
205 s.veths[veth.Name()] = &veth
207 s.T().Fatalf("network config error: %v", err)
212 if tap, err := NewTap(elem); err == nil {
213 s.taps[tap.Name()] = &tap
215 s.T().Fatalf("network config error: %v", err)
220 if bridge, err := NewBridge(elem); err == nil {
221 s.bridges[bridge.Name()] = &bridge
223 s.T().Fatalf("network config error: %v", err)
230 func (s *HstSuite) configureNetworkTopology(topologyName string) {
231 s.loadNetworkTopology(topologyName)
233 for _, ns := range s.networkNamespaces {
234 if err := ns.Configure(); err != nil {
235 s.T().Fatalf("network config error: %v", err)
238 for _, veth := range s.veths {
239 if err := veth.Configure(); err != nil {
240 s.T().Fatalf("network config error: %v", err)
243 for _, tap := range s.taps {
244 if err := tap.Configure(); err != nil {
245 s.T().Fatalf("network config error: %v", err)
248 for _, bridge := range s.bridges {
249 if err := bridge.Configure(); err != nil {
250 s.T().Fatalf("network config error: %v", err)
255 func (s *HstSuite) unconfigureNetworkTopology() {
259 for _, ns := range s.networkNamespaces {
262 for _, veth := range s.veths {
265 for _, tap := range s.taps {
268 for _, bridge := range s.bridges {
273 func (s *HstSuite) NewAddress() (AddressWithPrefix, error) {
274 var ipPrefix AddressWithPrefix
277 if s.numberOfAddresses == 255 {
278 s.T().Fatalf("no available IPv4 addresses")
281 address := fmt.Sprintf("10.10.10.%v/24", s.numberOfAddresses+1)
282 ipPrefix, err = ip_types.ParseAddressWithPrefix(address)
284 return AddressWithPrefix{}, err
286 s.numberOfAddresses++