10 "github.com/edwarnicke/exechelper"
11 "github.com/stretchr/testify/assert"
12 "github.com/stretchr/testify/suite"
17 defaultNetworkNumber int = 1
20 var IsPersistent = flag.Bool("persist", false, "persists topology config")
21 var IsVerbose = flag.Bool("verbose", false, "verbose test output")
23 type HstSuite struct {
25 containers map[string]*Container
27 netConfigs []NetConfig
28 netInterfaces map[string]*NetInterface
30 testIds map[string]string
33 func (s *HstSuite) TearDownSuite() {
34 s.unconfigureNetworkTopology()
37 func (s *HstSuite) TearDownTest() {
45 func (s *HstSuite) SetupTest() {
50 func (s *HstSuite) SetupVolumes() {
51 for _, volume := range s.volumes {
52 cmd := "docker volume create --name=" + volume
58 func (s *HstSuite) SetupContainers() {
59 for _, container := range s.containers {
60 if container.isOptional == false {
66 func (s *HstSuite) hstFail() {
70 func (s *HstSuite) assertNil(object interface{}, msgAndArgs ...interface{}) {
71 if !assert.Nil(s.T(), object, msgAndArgs...) {
76 func (s *HstSuite) assertNotNil(object interface{}, msgAndArgs ...interface{}) {
77 if !assert.NotNil(s.T(), object, msgAndArgs...) {
82 func (s *HstSuite) assertEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
83 if !assert.Equal(s.T(), expected, actual, msgAndArgs...) {
88 func (s *HstSuite) assertNotEqual(expected, actual interface{}, msgAndArgs ...interface{}) {
89 if !assert.NotEqual(s.T(), expected, actual, msgAndArgs...) {
94 func (s *HstSuite) assertContains(testString, contains interface{}, msgAndArgs ...interface{}) {
95 if !assert.Contains(s.T(), testString, contains, msgAndArgs...) {
100 func (s *HstSuite) assertNotContains(testString, contains interface{}, msgAndArgs ...interface{}) {
101 if !assert.NotContains(s.T(), testString, contains, msgAndArgs...) {
106 func (s *HstSuite) assertNotEmpty(object interface{}, msgAndArgs ...interface{}) {
107 if !assert.NotEmpty(s.T(), object, msgAndArgs...) {
112 func (s *HstSuite) log(args ...any) {
119 func (s *HstSuite) skip(args ...any) {
124 func (s *HstSuite) ResetContainers() {
125 for _, container := range s.containers {
130 func (s *HstSuite) RemoveVolumes() {
131 for _, volumeName := range s.volumes {
132 cmd := "docker volume rm " + volumeName
134 os.RemoveAll(volumeName)
138 func (s *HstSuite) getContainerByName(name string) *Container {
139 return s.containers[name]
143 * Create a copy and return its address, so that individial tests which call this
144 * are not able to modify the original container and affect other tests by doing that
146 func (s *HstSuite) getTransientContainerByName(name string) *Container {
147 containerCopy := *s.containers[name]
148 return &containerCopy
151 func (s *HstSuite) loadContainerTopology(topologyName string) {
152 data, err := ioutil.ReadFile(ContainerTopologyDir + topologyName + ".yaml")
154 s.T().Fatalf("read error: %v", err)
156 var yamlTopo YamlTopology
157 err = yaml.Unmarshal(data, &yamlTopo)
159 s.T().Fatalf("unmarshal error: %v", err)
162 for _, elem := range yamlTopo.Volumes {
163 volumeMap := elem["volume"].(VolumeConfig)
164 hostDir := volumeMap["host-dir"].(string)
165 s.volumes = append(s.volumes, hostDir)
168 s.containers = make(map[string]*Container)
169 for _, elem := range yamlTopo.Containers {
170 newContainer, err := NewContainer(elem)
171 newContainer.suite = s
173 s.T().Fatalf("container config error: %v", err)
175 s.containers[newContainer.name] = newContainer
179 func (s *HstSuite) loadNetworkTopology(topologyName string) {
180 data, err := ioutil.ReadFile(NetworkTopologyDir + topologyName + ".yaml")
182 s.T().Fatalf("read error: %v", err)
184 var yamlTopo YamlTopology
185 err = yaml.Unmarshal(data, &yamlTopo)
187 s.T().Fatalf("unmarshal error: %v", err)
190 s.addresser = NewAddresser(s)
191 s.netInterfaces = make(map[string]*NetInterface)
192 for _, elem := range yamlTopo.Devices {
193 switch elem["type"].(string) {
196 if namespace, err := NewNetNamespace(elem); err == nil {
197 s.netConfigs = append(s.netConfigs, &namespace)
199 s.T().Fatalf("network config error: %v", err)
204 if netIf, err := NewNetworkInterface(elem, s.addresser); err == nil {
205 s.netConfigs = append(s.netConfigs, netIf)
206 s.netInterfaces[netIf.Name()] = netIf
208 s.T().Fatalf("network config error: %v", err)
213 if bridge, err := NewBridge(elem); err == nil {
214 s.netConfigs = append(s.netConfigs, &bridge)
216 s.T().Fatalf("network config error: %v", err)
223 func (s *HstSuite) configureNetworkTopology(topologyName string) {
224 s.loadNetworkTopology(topologyName)
226 for _, nc := range s.netConfigs {
227 if err := nc.Configure(); err != nil {
228 s.T().Fatalf("network config error: %v", err)
233 func (s *HstSuite) unconfigureNetworkTopology() {
237 for _, nc := range s.netConfigs {
242 func (s *HstSuite) getTestId() string {
243 testName := s.T().Name()
245 if s.testIds == nil {
246 s.testIds = map[string]string{}
249 if _, ok := s.testIds[testName]; !ok {
250 s.testIds[testName] = time.Now().Format(time.RFC3339)
253 return s.testIds[testName]
256 type AddressCounter = int
258 type Addresser struct {
259 networks map[int]AddressCounter
263 func (a *Addresser) AddNetwork(networkNumber int) {
264 a.networks[networkNumber] = 1
267 func (a *Addresser) NewIp4Address(inputNetworkNumber ...int) (string, error) {
268 var networkNumber int = 0
269 if len(inputNetworkNumber) > 0 {
270 networkNumber = inputNetworkNumber[0]
273 if _, ok := a.networks[networkNumber]; !ok {
274 a.AddNetwork(networkNumber)
277 numberOfAddresses := a.networks[networkNumber]
279 if numberOfAddresses == 254 {
280 return "", fmt.Errorf("no available IPv4 addresses")
283 address := fmt.Sprintf("10.10.%v.%v/24", networkNumber, numberOfAddresses)
284 a.networks[networkNumber] = numberOfAddresses + 1
289 func NewAddresser(suite *HstSuite) *Addresser {
290 var addresser = new(Addresser)
291 addresser.suite = suite
292 addresser.networks = make(map[int]AddressCounter)
293 addresser.AddNetwork(0)