| package testing |
| |
| import ( |
| "io/ioutil" |
| "os" |
| "strconv" |
| "testing" |
| "time" |
| |
| dockertypes "github.com/docker/docker/api/types" |
| ) |
| |
| type IsReadyFunc func(Instance) bool |
| |
| type TestFunc func(*testing.T, Instance) |
| |
| type Version struct { |
| Image string |
| ENV []string |
| Cmd []string |
| } |
| |
| func ParallelTest(t *testing.T, versions []Version, readyFn IsReadyFunc, testFn TestFunc) { |
| delay, err := strconv.Atoi(os.Getenv("MIGRATE_TEST_CONTAINER_BOOT_DELAY")) |
| if err != nil { |
| delay = 0 |
| } |
| |
| for i, version := range versions { |
| version := version // capture range variable, see https://goo.gl/60w3p2 |
| |
| // Only test against one version in short mode |
| // TODO: order is random, maybe always pick first version instead? |
| if i > 0 && testing.Short() { |
| t.Logf("Skipping %v in short mode", version) |
| |
| } else { |
| t.Run(version.Image, func(t *testing.T) { |
| t.Parallel() |
| |
| // create new container |
| container, err := NewDockerContainer(t, version.Image, version.ENV, version.Cmd) |
| if err != nil { |
| t.Fatalf("%v\n%s", err, containerLogs(t, container)) |
| } |
| |
| // make sure to remove container once done |
| defer container.Remove() |
| |
| // wait until database is ready |
| tick := time.Tick(1000 * time.Millisecond) |
| timeout := time.After(time.Duration(delay + 60) * time.Second) |
| outer: |
| for { |
| select { |
| case <-tick: |
| if readyFn(container) { |
| break outer |
| } |
| |
| case <-timeout: |
| t.Fatalf("Docker: Container not ready, timeout for %v.\n%s", version, containerLogs(t, container)) |
| } |
| } |
| |
| time.Sleep(time.Duration(int64(delay)) * time.Second) |
| |
| // we can now run the tests |
| testFn(t, container) |
| }) |
| } |
| } |
| } |
| |
| func containerLogs(t *testing.T, c *DockerContainer) []byte { |
| r, err := c.Logs() |
| if err != nil { |
| t.Error("%v", err) |
| return nil |
| } |
| defer r.Close() |
| b, err := ioutil.ReadAll(r) |
| if err != nil { |
| t.Error("%v", err) |
| return nil |
| } |
| return b |
| } |
| |
| type Instance interface { |
| Host() string |
| Port() uint |
| PortFor(int) uint |
| NetworkSettings() dockertypes.NetworkSettings |
| KeepForDebugging() |
| } |