diff --git a/integration-cli/check_test.go b/integration-cli/check_test.go index 0cae1503f8..6bab50f907 100644 --- a/integration-cli/check_test.go +++ b/integration-cli/check_test.go @@ -20,9 +20,9 @@ import ( "github.com/docker/docker/integration-cli/daemon" "github.com/docker/docker/integration-cli/environment" "github.com/docker/docker/integration-cli/fixtures/plugin" - "github.com/docker/docker/integration-cli/registry" testdaemon "github.com/docker/docker/internal/test/daemon" ienv "github.com/docker/docker/internal/test/environment" + "github.com/docker/docker/internal/test/registry" "github.com/docker/docker/pkg/reexec" "github.com/go-check/check" "golang.org/x/net/context" @@ -30,7 +30,7 @@ import ( const ( // the private registry to use for tests - privateRegistryURL = "127.0.0.1:5000" + privateRegistryURL = registry.DefaultURL // path to containerd's ctr binary ctrBinary = "docker-containerd-ctr" @@ -126,8 +126,9 @@ func (s *DockerRegistrySuite) OnTimeout(c *check.C) { } func (s *DockerRegistrySuite) SetUpTest(c *check.C) { - testRequires(c, DaemonIsLinux, registry.Hosting, SameHostDaemon) - s.reg = setupRegistry(c, false, "", "") + testRequires(c, DaemonIsLinux, RegistryHosting, SameHostDaemon) + s.reg = registry.NewV2(c) + s.reg.WaitReady(c) s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{ Experimental: testEnv.DaemonInfo.ExperimentalBuild, }) @@ -160,8 +161,9 @@ func (s *DockerSchema1RegistrySuite) OnTimeout(c *check.C) { } func (s *DockerSchema1RegistrySuite) SetUpTest(c *check.C) { - testRequires(c, DaemonIsLinux, registry.Hosting, NotArm64, SameHostDaemon) - s.reg = setupRegistry(c, true, "", "") + testRequires(c, DaemonIsLinux, RegistryHosting, NotArm64, SameHostDaemon) + s.reg = registry.NewV2(c, registry.Schema1) + s.reg.WaitReady(c) s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{ Experimental: testEnv.DaemonInfo.ExperimentalBuild, }) @@ -194,8 +196,9 @@ func (s *DockerRegistryAuthHtpasswdSuite) OnTimeout(c *check.C) { } func (s *DockerRegistryAuthHtpasswdSuite) SetUpTest(c *check.C) { - testRequires(c, DaemonIsLinux, registry.Hosting, SameHostDaemon) - s.reg = setupRegistry(c, false, "htpasswd", "") + testRequires(c, DaemonIsLinux, RegistryHosting, SameHostDaemon) + s.reg = registry.NewV2(c, registry.Htpasswd) + s.reg.WaitReady(c) s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{ Experimental: testEnv.DaemonInfo.ExperimentalBuild, }) @@ -230,7 +233,7 @@ func (s *DockerRegistryAuthTokenSuite) OnTimeout(c *check.C) { } func (s *DockerRegistryAuthTokenSuite) SetUpTest(c *check.C) { - testRequires(c, DaemonIsLinux, registry.Hosting, SameHostDaemon) + testRequires(c, DaemonIsLinux, RegistryHosting, SameHostDaemon) s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{ Experimental: testEnv.DaemonInfo.ExperimentalBuild, }) @@ -252,7 +255,8 @@ func (s *DockerRegistryAuthTokenSuite) setupRegistryWithTokenService(c *check.C, if s == nil { c.Fatal("registry suite isn't initialized") } - s.reg = setupRegistry(c, false, "token", tokenURL) + s.reg = registry.NewV2(c, registry.Token(tokenURL)) + s.reg.WaitReady(c) } func init() { @@ -405,8 +409,9 @@ func (ps *DockerPluginSuite) getPluginRepoWithTag() string { } func (ps *DockerPluginSuite) SetUpSuite(c *check.C) { - testRequires(c, DaemonIsLinux, registry.Hosting) - ps.registry = setupRegistry(c, false, "", "") + testRequires(c, DaemonIsLinux, RegistryHosting) + ps.registry = registry.NewV2(c) + ps.registry.WaitReady(c) ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() diff --git a/integration-cli/docker_api_swarm_service_test.go b/integration-cli/docker_api_swarm_service_test.go index f715265f63..e816d4f567 100644 --- a/integration-cli/docker_api_swarm_service_test.go +++ b/integration-cli/docker_api_swarm_service_test.go @@ -16,6 +16,7 @@ import ( "github.com/docker/docker/integration-cli/daemon" "github.com/docker/docker/integration-cli/fixtures/plugin" testdaemon "github.com/docker/docker/internal/test/daemon" + "github.com/docker/docker/internal/test/registry" "github.com/go-check/check" "golang.org/x/net/context" "golang.org/x/sys/unix" @@ -615,7 +616,7 @@ func (s *DockerSwarmSuite) TestAPISwarmServicesStateReporting(c *check.C) { func (s *DockerSwarmSuite) TestAPISwarmServicesPlugin(c *check.C) { testRequires(c, ExperimentalDaemon, DaemonIsLinux, IsAmd64) - reg := setupRegistry(c, false, "", "") + reg := registry.NewV2(c) defer reg.Close() repo := path.Join(privateRegistryURL, "swarm", "test:v1") diff --git a/integration-cli/docker_cli_registry_user_agent_test.go b/integration-cli/docker_cli_registry_user_agent_test.go index 6cbe6e7e66..7ee3c3d1ba 100644 --- a/integration-cli/docker_cli_registry_user_agent_test.go +++ b/integration-cli/docker_cli_registry_user_agent_test.go @@ -7,7 +7,7 @@ import ( "os" "regexp" - "github.com/docker/docker/integration-cli/registry" + "github.com/docker/docker/internal/test/registry" "github.com/go-check/check" ) diff --git a/integration-cli/docker_cli_v2_only_test.go b/integration-cli/docker_cli_v2_only_test.go index 3757341025..df0c01a517 100644 --- a/integration-cli/docker_cli_v2_only_test.go +++ b/integration-cli/docker_cli_v2_only_test.go @@ -6,7 +6,7 @@ import ( "net/http" "os" - "github.com/docker/docker/integration-cli/registry" + "github.com/docker/docker/internal/test/registry" "github.com/go-check/check" ) diff --git a/integration-cli/docker_utils_test.go b/integration-cli/docker_utils_test.go index 1475558239..a5fb437e4c 100644 --- a/integration-cli/docker_utils_test.go +++ b/integration-cli/docker_utils_test.go @@ -18,7 +18,6 @@ import ( "github.com/docker/docker/integration-cli/checker" "github.com/docker/docker/integration-cli/cli" "github.com/docker/docker/integration-cli/daemon" - "github.com/docker/docker/integration-cli/registry" "github.com/docker/docker/integration-cli/request" "github.com/go-check/check" "github.com/gotestyourself/gotestyourself/icmd" @@ -284,22 +283,6 @@ func parseEventTime(t time.Time) string { return fmt.Sprintf("%d.%09d", t.Unix(), int64(t.Nanosecond())) } -func setupRegistry(c *check.C, schema1 bool, auth, tokenURL string) *registry.V2 { - reg, err := registry.NewV2(schema1, auth, tokenURL, privateRegistryURL) - c.Assert(err, check.IsNil) - - // Wait for registry to be ready to serve requests. - for i := 0; i != 50; i++ { - if err = reg.Ping(); err == nil { - break - } - time.Sleep(100 * time.Millisecond) - } - - c.Assert(err, check.IsNil, check.Commentf("Timeout waiting for test registry to become available: %v", err)) - return reg -} - // appendBaseEnv appends the minimum set of environment variables to exec the // docker cli binary for testing with correct configuration to the given env // list. diff --git a/integration-cli/registry/requirement.go b/integration-cli/registry/requirement.go deleted file mode 100644 index 8cd428cc26..0000000000 --- a/integration-cli/registry/requirement.go +++ /dev/null @@ -1,12 +0,0 @@ -package registry // import "github.com/docker/docker/integration-cli/registry" - -import "os/exec" - -// Hosting returns wether the host can host a registry (v2) or not -func Hosting() bool { - // for now registry binary is built only if we're running inside - // container through `make test`. Figure that out by testing if - // registry binary is in PATH. - _, err := exec.LookPath(v2binary) - return err == nil -} diff --git a/integration-cli/requirements_test.go b/integration-cli/requirements_test.go index b0a95d42f8..3ae24b204c 100644 --- a/integration-cli/requirements_test.go +++ b/integration-cli/requirements_test.go @@ -14,6 +14,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/client" "github.com/docker/docker/integration-cli/requirement" + "github.com/docker/docker/internal/test/registry" ) func ArchitectureIsNot(arch string) bool { @@ -183,6 +184,15 @@ func IsolationIsProcess() bool { return IsolationIs("process") } +// RegistryHosting returns wether the host can host a registry (v2) or not +func RegistryHosting() bool { + // for now registry binary is built only if we're running inside + // container through `make test`. Figure that out by testing if + // registry binary is in PATH. + _, err := exec.LookPath(registry.V2binary) + return err == nil +} + // testRequires checks if the environment satisfies the requirements // for the test to run or skips the tests. func testRequires(c requirement.SkipT, requirements ...requirement.Test) { diff --git a/internal/test/registry/ops.go b/internal/test/registry/ops.go new file mode 100644 index 0000000000..c004f37424 --- /dev/null +++ b/internal/test/registry/ops.go @@ -0,0 +1,26 @@ +package registry + +// Schema1 sets the registry to serve v1 api +func Schema1(c *Config) { + c.schema1 = true +} + +// Htpasswd sets the auth method with htpasswd +func Htpasswd(c *Config) { + c.auth = "htpasswd" +} + +// Token sets the auth method to token, with the specified token url +func Token(tokenURL string) func(*Config) { + return func(c *Config) { + c.auth = "token" + c.tokenURL = tokenURL + } +} + +// URL sets the registry url +func URL(registryURL string) func(*Config) { + return func(c *Config) { + c.registryURL = registryURL + } +} diff --git a/integration-cli/registry/registry.go b/internal/test/registry/registry.go similarity index 67% rename from integration-cli/registry/registry.go rename to internal/test/registry/registry.go index b09887584a..a801beea29 100644 --- a/integration-cli/registry/registry.go +++ b/internal/test/registry/registry.go @@ -1,4 +1,4 @@ -package registry // import "github.com/docker/docker/integration-cli/registry" +package registry // import "github.com/docker/docker/internal/test/registry" import ( "fmt" @@ -7,16 +7,23 @@ import ( "os" "os/exec" "path/filepath" + "time" + "github.com/gotestyourself/gotestyourself/assert" "github.com/opencontainers/go-digest" ) const ( - v2binary = "registry-v2" - v2binarySchema1 = "registry-v2-schema1" + // V2binary is the name of the registry v2 binary + V2binary = "registry-v2" + // V2binarySchema1 is the name of the registry that serve schema1 + V2binarySchema1 = "registry-v2-schema1" + // DefaultURL is the default url that will be used by the registry (if not specified otherwise) + DefaultURL = "127.0.0.1:5000" ) type testingT interface { + assert.TestingT logT Fatal(...interface{}) Fatalf(string, ...interface{}) @@ -37,12 +44,24 @@ type V2 struct { email string } +// Config contains the test registry configuration +type Config struct { + schema1 bool + auth string + tokenURL string + registryURL string +} + // NewV2 creates a v2 registry server -func NewV2(schema1 bool, auth, tokenURL, registryURL string) (*V2, error) { - tmp, err := ioutil.TempDir("", "registry-test-") - if err != nil { - return nil, err +func NewV2(t testingT, ops ...func(*Config)) *V2 { + c := &Config{ + registryURL: DefaultURL, } + for _, op := range ops { + op(c) + } + tmp, err := ioutil.TempDir("", "registry-test-") + assert.NilError(t, err) template := `version: 0.1 loglevel: debug storage: @@ -57,7 +76,7 @@ http: password string email string ) - switch auth { + switch c.auth { case "htpasswd": htpasswdPath := filepath.Join(tmp, "htpasswd") // generated with: htpasswd -Bbn testuser testpassword @@ -65,9 +84,8 @@ http: username = "testuser" password = "testpassword" email = "test@test.org" - if err := ioutil.WriteFile(htpasswdPath, []byte(userpasswd), os.FileMode(0644)); err != nil { - return nil, err - } + err := ioutil.WriteFile(htpasswdPath, []byte(userpasswd), os.FileMode(0644)) + assert.NilError(t, err) authTemplate = fmt.Sprintf(`auth: htpasswd: realm: basic-realm @@ -80,39 +98,51 @@ http: service: "registry" issuer: "auth-registry" rootcertbundle: "fixtures/registry/cert.pem" -`, tokenURL) +`, c.tokenURL) } confPath := filepath.Join(tmp, "config.yaml") config, err := os.Create(confPath) - if err != nil { - return nil, err - } + assert.NilError(t, err) defer config.Close() - if _, err := fmt.Fprintf(config, template, tmp, registryURL, authTemplate); err != nil { + if _, err := fmt.Fprintf(config, template, tmp, c.registryURL, authTemplate); err != nil { + // FIXME(vdemeester) use a defer/clean func os.RemoveAll(tmp) - return nil, err + t.Fatal(err) } - binary := v2binary - if schema1 { - binary = v2binarySchema1 + binary := V2binary + if c.schema1 { + binary = V2binarySchema1 } cmd := exec.Command(binary, confPath) if err := cmd.Start(); err != nil { + // FIXME(vdemeester) use a defer/clean func os.RemoveAll(tmp) - return nil, err + t.Fatal(err) } return &V2{ cmd: cmd, dir: tmp, - auth: auth, + auth: c.auth, username: username, password: password, email: email, - registryURL: registryURL, - }, nil + registryURL: c.registryURL, + } +} + +// WaitReady waits for the registry to be ready to serve requests (or fail after a while) +func (r *V2) WaitReady(t testingT) { + var err error + for i := 0; i != 50; i++ { + if err = r.Ping(); err == nil { + return + } + time.Sleep(100 * time.Millisecond) + } + t.Fatalf("timeout waiting for test registry to become available: %v", err) } // Ping sends an http request to the current registry, and fail if it doesn't respond correctly @@ -152,30 +182,24 @@ func (r *V2) getBlobFilename(blobDigest digest.Digest) string { } // ReadBlobContents read the file corresponding to the specified digest -func (r *V2) ReadBlobContents(t testingT, blobDigest digest.Digest) []byte { +func (r *V2) ReadBlobContents(t assert.TestingT, blobDigest digest.Digest) []byte { // Load the target manifest blob. manifestBlob, err := ioutil.ReadFile(r.getBlobFilename(blobDigest)) - if err != nil { - t.Fatalf("unable to read blob: %s", err) - } - + assert.NilError(t, err, "unable to read blob") return manifestBlob } // WriteBlobContents write the file corresponding to the specified digest with the given content -func (r *V2) WriteBlobContents(t testingT, blobDigest digest.Digest, data []byte) { - if err := ioutil.WriteFile(r.getBlobFilename(blobDigest), data, os.FileMode(0644)); err != nil { - t.Fatalf("unable to write malicious data blob: %s", err) - } +func (r *V2) WriteBlobContents(t assert.TestingT, blobDigest digest.Digest, data []byte) { + err := ioutil.WriteFile(r.getBlobFilename(blobDigest), data, os.FileMode(0644)) + assert.NilError(t, err, "unable to write malicious data blob") } // TempMoveBlobData moves the existing data file aside, so that we can replace it with a // malicious blob of data for example. func (r *V2) TempMoveBlobData(t testingT, blobDigest digest.Digest) (undo func()) { tempFile, err := ioutil.TempFile("", "registry-temp-blob-") - if err != nil { - t.Fatalf("unable to get temporary blob file: %s", err) - } + assert.NilError(t, err, "unable to get temporary blob file") tempFile.Close() blobFilename := r.getBlobFilename(blobDigest) @@ -183,6 +207,7 @@ func (r *V2) TempMoveBlobData(t testingT, blobDigest digest.Digest) (undo func() // Move the existing data file aside, so that we can replace it with a // another blob of data. if err := os.Rename(blobFilename, tempFile.Name()); err != nil { + // FIXME(vdemeester) use a defer/clean func os.Remove(tempFile.Name()) t.Fatalf("unable to move data blob: %s", err) } diff --git a/integration-cli/registry/registry_mock.go b/internal/test/registry/registry_mock.go similarity index 94% rename from integration-cli/registry/registry_mock.go rename to internal/test/registry/registry_mock.go index c2b4897aad..77c4ac1bd4 100644 --- a/integration-cli/registry/registry_mock.go +++ b/internal/test/registry/registry_mock.go @@ -1,4 +1,4 @@ -package registry // import "github.com/docker/docker/integration-cli/registry" +package registry // import "github.com/docker/docker/internal/test/registry" import ( "net/http"