9 "github.com/edwarnicke/exechelper"
10 "github.com/stretchr/testify/assert"
11 "github.com/stretchr/testify/suite"
16 defaultNetworkNumber int = 1
19 var IsPersistent = flag.Bool("persist", false, "persists topology config")
20 var IsVerbose = flag.Bool("verbose", false, "verbose test output")
22 type HstSuite struct {
24 containers map[string]*Container
26 netConfigs []NetConfig
27 netInterfaces map[string]NetInterface
31 func (s *HstSuite) TearDownSuite() {
32 s.unconfigureNetworkTopology()
35 func (s *HstSuite) TearDownTest() {
43 func (s *HstSuite) SetupTest() {
48 func (s *HstSuite) SetupVolumes() {
49 for _, volume := range s.volumes {
50 cmd := "docker volume create --name=" + volume
56 func (s *HstSuite) SetupContainers() {
57 for _, container := range s.containers {
58 if container.isOptional == false {
64 func (s *HstSuite) hstFail() {
68 func (s *HstSuite) assertNil(object interface{}, msgAndArgs ...interface{}) {
69 if !assert.Nil(s.T(), object, msgAndArgs...) {
74 func (s *HstSuite) assertNotNil(object interface{}, msgAndArgs ...interface{}) {
75 if !assert.NotNil(s.T(), object, msgAndArgs...) {
80 func (s *HstSuite) assertEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
81 if !assert.Equal(s.T(), expected, actual, msgAndArgs...) {
86 func (s *HstSuite) assertNotEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
87 if !assert.NotEqual(s.T(), expected, actual, msgAndArgs...) {
92 func (s *HstSuite) assertContains(testString, contains interface{}, msgAndArgs ...interface{}) {
93 if !assert.Contains(s.T(), testString, contains, msgAndArgs...) {
98 func (s *HstSuite) assertNotContains(testString, contains interface{}, msgAndArgs ...interface{}) {
99 if !assert.NotContains(s.T(), testString, contains, msgAndArgs...) {
104 func (s *HstSuite) assertNotEmpty(object interface{}, msgAndArgs ...interface{}) {
105 if !assert.NotEmpty(s.T(), object, msgAndArgs...) {
110 func (s *HstSuite) log(args ...any) {
116 func (s *HstSuite) skip(args ...any) {
121 func (s *HstSuite) ResetContainers() {
122 for _, container := range s.containers {
127 func (s *HstSuite) RemoveVolumes() {
128 for _, volumeName := range s.volumes {
129 cmd := "docker volume rm " + volumeName
131 os.RemoveAll(volumeName)
135 func (s *HstSuite) getContainerByName(name string) *Container {
136 return s.containers[name]
140 * Create a copy and return its address, so that individial tests which call this
141 * are not able to modify the original container and affect other tests by doing that
143 func (s *HstSuite) getTransientContainerByName(name string) *Container {
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.containers[newContainer.name] = newContainer
176 func (s *HstSuite) loadNetworkTopology(topologyName string) {
177 data, err := ioutil.ReadFile(NetworkTopologyDir + topologyName + ".yaml")
179 s.T().Fatalf("read error: %v", err)
181 var yamlTopo YamlTopology
182 err = yaml.Unmarshal(data, &yamlTopo)
184 s.T().Fatalf("unmarshal error: %v", err)
187 s.addresser = NewAddresser(s)
188 s.netInterfaces = make(map[string]NetInterface)
189 for _, elem := range yamlTopo.Devices {
190 switch elem["type"].(string) {
193 if namespace, err := NewNetNamespace(elem); err == nil {
194 s.netConfigs = append(s.netConfigs, &namespace)
196 s.T().Fatalf("network config error: %v", err)
201 if veth, err := NewVeth(elem, s.addresser); err == nil {
202 s.netConfigs = append(s.netConfigs, &veth)
203 s.netInterfaces[veth.Name()] = &veth
205 s.T().Fatalf("network config error: %v", err)
210 if tap, err := NewTap(elem, s.addresser); err == nil {
211 s.netConfigs = append(s.netConfigs, &tap)
212 s.netInterfaces[tap.Name()] = &tap
214 s.T().Fatalf("network config error: %v", err)
219 if bridge, err := NewBridge(elem); err == nil {
220 s.netConfigs = append(s.netConfigs, &bridge)
222 s.T().Fatalf("network config error: %v", err)
229 func (s *HstSuite) configureNetworkTopology(topologyName string) {
230 s.loadNetworkTopology(topologyName)
232 for _, nc := range s.netConfigs {
233 if err := nc.Configure(); err != nil {
234 s.T().Fatalf("network config error: %v", err)
239 func (s *HstSuite) unconfigureNetworkTopology() {
243 for _, nc := range s.netConfigs {
248 type NetworkAddresses struct {
250 numberOfAddresses int
253 type AddressCounter = int
255 type Addresser struct {
256 networks map[int]AddressCounter
260 func (a *Addresser) AddNetwork(networkNumber int) {
261 a.networks[networkNumber] = 1
264 func (a *Addresser) NewIp4Address(inputNetworkNumber ...int) (string, error) {
265 var networkNumber int = 0
266 if len(inputNetworkNumber) > 0 {
267 networkNumber = inputNetworkNumber[0]
270 if _, ok := a.networks[networkNumber]; !ok {
271 a.AddNetwork(networkNumber)
274 numberOfAddresses := a.networks[networkNumber]
276 if numberOfAddresses == 254 {
277 return "", fmt.Errorf("no available IPv4 addresses")
280 address := fmt.Sprintf("10.10.%v.%v/24", networkNumber, numberOfAddresses)
281 a.networks[networkNumber] = numberOfAddresses + 1
286 func NewAddresser(suite *HstSuite) *Addresser {
287 var addresser = new(Addresser)
288 addresser.suite = suite
289 addresser.networks = make(map[int]AddressCounter)
290 addresser.AddNetwork(0)