From 240d5b3fa1b66f099b71c20ff8dc4ed1ecffc1d3 Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Wed, 16 Oct 2013 20:10:20 +0000 Subject: [PATCH 1/4] Hack: don't run integration tests in /var/lib/docker/unit-tests; add missing cleanups in a few tests --- api_test.go | 1 + runtime_test.go | 60 ++++++++++++++++++++++++++++++++----------------- server_test.go | 1 + z_final_test.go | 2 +- 4 files changed, 42 insertions(+), 22 deletions(-) diff --git a/api_test.go b/api_test.go index fcb3bc8593..e047aba9e5 100644 --- a/api_test.go +++ b/api_test.go @@ -112,6 +112,7 @@ func TestGetInfo(t *testing.T) { func TestGetEvents(t *testing.T) { runtime := mkRuntime(t) + defer nuke(runtime) srv := &Server{ runtime: runtime, events: make([]utils.JSONMessage, 0, 64), diff --git a/runtime_test.go b/runtime_test.go index 1abbcc51e6..75081fff1e 100644 --- a/runtime_test.go +++ b/runtime_test.go @@ -87,45 +87,63 @@ func init() { NetworkBridgeIface = unitTestNetworkBridge - // Make it our Store root - if runtime, err := NewRuntimeFromDirectory(unitTestStoreBase, false); err != nil { - log.Fatalf("Unable to create a runtime for tests:", err) - } else { - globalRuntime = runtime - } + // Setup the base runtime, which will be duplicated for each test. + // (no tests are run directly in the base) + setupBaseImage() - // Cleanup any leftover container - for _, container := range globalRuntime.List() { - if err := globalRuntime.Destroy(container); err != nil { - log.Fatalf("Error destroying leftover container: %s", err) - } + // Create the "global runtime" with a long-running daemon for integration tests + spawnGlobalDaemon() + startFds, startGoroutines = utils.GetTotalUsedFds(), runtime.NumGoroutine() +} + + +func setupBaseImage() { + runtime, err := NewRuntimeFromDirectory(unitTestStoreBase, false) + if err != nil { + log.Fatalf("Unable to create a runtime for tests:", err) } // Create the "Server" + srv := &Server{ + runtime: runtime, + enableCors: false, + pullingPool: make(map[string]struct{}), + pushingPool: make(map[string]struct{}), + } + + // If the unit test is not found, try to download it. + if img, err := runtime.repositories.LookupImage(unitTestImageName); err != nil || img.ID != unitTestImageID { + // Retrieve the Image + if err := srv.ImagePull(unitTestImageName, "", os.Stdout, utils.NewStreamFormatter(false), nil, nil, true); err != nil { + log.Fatalf("Unable to pull the test image:", err) + } + } +} + + +func spawnGlobalDaemon() { + if globalRuntime != nil { + utils.Debugf("Global runtime already exists. Skipping.") + return + } + globalRuntime = mkRuntime(log.New(os.Stderr, "", 0)) srv := &Server{ runtime: globalRuntime, enableCors: false, pullingPool: make(map[string]struct{}), pushingPool: make(map[string]struct{}), } - // If the unit test is not found, try to download it. - if img, err := globalRuntime.repositories.LookupImage(unitTestImageName); err != nil || img.ID != unitTestImageID { - // Retrieve the Image - if err := srv.ImagePull(unitTestImageName, "", os.Stdout, utils.NewStreamFormatter(false), nil, nil, true); err != nil { - log.Fatalf("Unable to pull the test image:", err) - } - } + // Spawn a Daemon go func() { + utils.Debugf("Spawning global daemon for integration tests") if err := ListenAndServe(testDaemonProto, testDaemonAddr, srv, os.Getenv("DEBUG") != ""); err != nil { log.Fatalf("Unable to spawn the test daemon:", err) } }() - // Give some time to ListenAndServer to actually start + // FIXME: use inmem transports instead of tcp time.Sleep(time.Second) - - startFds, startGoroutines = utils.GetTotalUsedFds(), runtime.NumGoroutine() } // FIXME: test that ImagePull(json=true) send correct json output diff --git a/server_test.go b/server_test.go index ee9549d7b7..c13754b5ea 100644 --- a/server_test.go +++ b/server_test.go @@ -351,6 +351,7 @@ func TestPools(t *testing.T) { func TestLogEvent(t *testing.T) { runtime := mkRuntime(t) + defer nuke(runtime) srv := &Server{ runtime: runtime, events: make([]utils.JSONMessage, 0, 64), diff --git a/z_final_test.go b/z_final_test.go index 08a180baaf..837b5d13e6 100644 --- a/z_final_test.go +++ b/z_final_test.go @@ -11,7 +11,7 @@ func displayFdGoroutines(t *testing.T) { } func TestFinal(t *testing.T) { - cleanup(globalRuntime) + nuke(globalRuntime) t.Logf("Start Fds: %d, Start Goroutines: %d", startFds, startGoroutines) displayFdGoroutines(t) } From 5c175357aaa7e011e3535eeb1ee162450f390b9e Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Wed, 16 Oct 2013 20:44:15 +0000 Subject: [PATCH 2/4] Hack: fix tests which didn't cleanup properly --- auth/auth_test.go | 5 ++++- container_test.go | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/auth/auth_test.go b/auth/auth_test.go index 01aecae3da..5dc634a719 100644 --- a/auth/auth_test.go +++ b/auth/auth_test.go @@ -76,7 +76,7 @@ func TestCreateAccount(t *testing.T) { } func setupTempConfigFile() (*ConfigFile, error) { - root, err := ioutil.TempDir("", "docker-test") + root, err := ioutil.TempDir("", "docker-test-auth") if err != nil { return nil, err } @@ -101,6 +101,7 @@ func TestSameAuthDataPostSave(t *testing.T) { if err != nil { t.Fatal(err) } + defer os.RemoveAll(configFile.rootPath) err = SaveConfig(configFile) if err != nil { @@ -127,6 +128,7 @@ func TestResolveAuthConfigIndexServer(t *testing.T) { if err != nil { t.Fatal(err) } + defer os.RemoveAll(configFile.rootPath) for _, registry := range []string{"", IndexServerAddress()} { resolved := configFile.ResolveAuthConfig(registry) @@ -141,6 +143,7 @@ func TestResolveAuthConfigFullURL(t *testing.T) { if err != nil { t.Fatal(err) } + defer os.RemoveAll(configFile.rootPath) registryAuth := AuthConfig{ Username: "foo-user", diff --git a/container_test.go b/container_test.go index e678c98898..9fdddc9044 100644 --- a/container_test.go +++ b/container_test.go @@ -1189,7 +1189,7 @@ func BenchmarkRunParallel(b *testing.B) { } func tempDir(t *testing.T) string { - tmpDir, err := ioutil.TempDir("", "docker-test") + tmpDir, err := ioutil.TempDir("", "docker-test-container") if err != nil { t.Fatal(err) } From 07d9e4353bc199db7abb52b4b4bba1c2feb75c1a Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Fri, 18 Oct 2013 06:44:30 +0000 Subject: [PATCH 3/4] Increase readbility of unit tests by using mkRuntime everywhere --- api_test.go | 5 +---- buildfile_test.go | 30 ++++++------------------------ 2 files changed, 7 insertions(+), 28 deletions(-) diff --git a/api_test.go b/api_test.go index e047aba9e5..479b9e1e57 100644 --- a/api_test.go +++ b/api_test.go @@ -472,10 +472,7 @@ func TestGetContainersChanges(t *testing.T) { func TestGetContainersTop(t *testing.T) { t.Skip("Fixme. Skipping test for now. Reported error when testing using dind: 'api_test.go:527: Expected 2 processes, found 0.'") - runtime, err := newTestRuntime() - if err != nil { - t.Fatal(err) - } + runtime := mkRuntime(t) defer nuke(runtime) srv := &Server{runtime: runtime} diff --git a/buildfile_test.go b/buildfile_test.go index c3881a214f..1af457158a 100644 --- a/buildfile_test.go +++ b/buildfile_test.go @@ -229,10 +229,7 @@ func TestBuild(t *testing.T) { func buildImage(context testContextTemplate, t *testing.T, srv *Server, useCache bool) *Image { if srv == nil { - runtime, err := newTestRuntime() - if err != nil { - t.Fatal(err) - } + runtime := mkRuntime(t) defer nuke(runtime) srv = &Server{ @@ -370,10 +367,7 @@ func TestBuildEntrypoint(t *testing.T) { // testing #1405 - config.Cmd does not get cleaned up if // utilizing cache func TestBuildEntrypointRunCleanup(t *testing.T) { - runtime, err := newTestRuntime() - if err != nil { - t.Fatal(err) - } + runtime := mkRuntime(t) defer nuke(runtime) srv := &Server{ @@ -402,10 +396,7 @@ func TestBuildEntrypointRunCleanup(t *testing.T) { } func TestBuildImageWithCache(t *testing.T) { - runtime, err := newTestRuntime() - if err != nil { - t.Fatal(err) - } + runtime := mkRuntime(t) defer nuke(runtime) srv := &Server{ @@ -433,10 +424,7 @@ func TestBuildImageWithCache(t *testing.T) { } func TestBuildImageWithoutCache(t *testing.T) { - runtime, err := newTestRuntime() - if err != nil { - t.Fatal(err) - } + runtime := mkRuntime(t) defer nuke(runtime) srv := &Server{ @@ -464,10 +452,7 @@ func TestBuildImageWithoutCache(t *testing.T) { } func TestForbiddenContextPath(t *testing.T) { - runtime, err := newTestRuntime() - if err != nil { - t.Fatal(err) - } + runtime := mkRuntime(t) defer nuke(runtime) srv := &Server{ @@ -513,10 +498,7 @@ func TestForbiddenContextPath(t *testing.T) { } func TestBuildADDFileNotFound(t *testing.T) { - runtime, err := newTestRuntime() - if err != nil { - t.Fatal(err) - } + runtime := mkRuntime(t) defer nuke(runtime) srv := &Server{ From b629810fe08dc864674a6e64a7f1b418096bc448 Mon Sep 17 00:00:00 2001 From: Solomon Hykes Date: Fri, 18 Oct 2013 06:47:08 +0000 Subject: [PATCH 4/4] hack: encode the name of the current test in temporary directories, for easier tracking Conflicts: utils_test.go --- utils_test.go | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/utils_test.go b/utils_test.go index 740a5fc1bc..3f99de570b 100644 --- a/utils_test.go +++ b/utils_test.go @@ -2,22 +2,38 @@ package docker import ( "github.com/dotcloud/docker/utils" + "fmt" "io" "io/ioutil" "os" "path" "strings" "testing" + "runtime" ) // This file contains utility functions for docker's unit test suite. // It has to be named XXX_test.go, apparently, in other to access private functions // from other XXX_test.go functions. +var globalTestID string + // Create a temporary runtime suitable for unit testing. // Call t.Fatal() at the first error. func mkRuntime(f Fataler) *Runtime { - runtime, err := newTestRuntime() + // Use the caller function name as a prefix. + // This helps trace temp directories back to their test. + pc, _, _, _ := runtime.Caller(1) + callerLongName := runtime.FuncForPC(pc).Name() + parts := strings.Split(callerLongName, ".") + callerShortName := parts[len(parts) - 1] + if globalTestID == "" { + globalTestID = GenerateID()[:4] + } + prefix := fmt.Sprintf("docker-test%s-%s-", globalTestID, callerShortName) + utils.Debugf("prefix = '%s'", prefix) + + runtime, err := newTestRuntime(prefix) if err != nil { f.Fatal(err) } @@ -30,8 +46,16 @@ type Fataler interface { Fatal(args ...interface{}) } -func newTestRuntime() (*Runtime, error) { - root, err := ioutil.TempDir("", "docker-test") +func newTestRuntime(prefix string) (runtime *Runtime, err error) { + if prefix == "" { + prefix = "docker-test-" + } + utils.Debugf("prefix = %s", prefix) + utils.Debugf("newTestRuntime start") + root, err := ioutil.TempDir("", prefix) + defer func() { + utils.Debugf("newTestRuntime: %s", root) + }() if err != nil { return nil, err } @@ -42,7 +66,7 @@ func newTestRuntime() (*Runtime, error) { return nil, err } - runtime, err := NewRuntimeFromDirectory(root, false) + runtime, err = NewRuntimeFromDirectory(root, false) if err != nil { return nil, err }