Pārlūkot izejas kodu

Add a registry package with registry v1/v2 code

This extract what was in registry_test.go and
registry_mock_test.go. This also move `RegistryHosting`
requirement to `registry.Hosting`

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
Vincent Demeester 8 gadi atpakaļ
vecāks
revīzija
4300e5e881

+ 12 - 11
integration-cli/check_test.go

@@ -16,6 +16,7 @@ import (
 	cliconfig "github.com/docker/docker/cli/config"
 	"github.com/docker/docker/integration-cli/daemon"
 	"github.com/docker/docker/integration-cli/environment"
+	"github.com/docker/docker/integration-cli/registry"
 	"github.com/docker/docker/pkg/reexec"
 	"github.com/go-check/check"
 )
@@ -172,7 +173,7 @@ func init() {
 
 type DockerRegistrySuite struct {
 	ds  *DockerSuite
-	reg *testRegistryV2
+	reg *registry.V2
 	d   *daemon.Daemon
 }
 
@@ -181,7 +182,7 @@ func (s *DockerRegistrySuite) OnTimeout(c *check.C) {
 }
 
 func (s *DockerRegistrySuite) SetUpTest(c *check.C) {
-	testRequires(c, DaemonIsLinux, RegistryHosting)
+	testRequires(c, DaemonIsLinux, registry.Hosting)
 	s.reg = setupRegistry(c, false, "", "")
 	s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
 		Experimental: experimentalDaemon,
@@ -206,7 +207,7 @@ func init() {
 
 type DockerSchema1RegistrySuite struct {
 	ds  *DockerSuite
-	reg *testRegistryV2
+	reg *registry.V2
 	d   *daemon.Daemon
 }
 
@@ -215,7 +216,7 @@ func (s *DockerSchema1RegistrySuite) OnTimeout(c *check.C) {
 }
 
 func (s *DockerSchema1RegistrySuite) SetUpTest(c *check.C) {
-	testRequires(c, DaemonIsLinux, RegistryHosting, NotArm64)
+	testRequires(c, DaemonIsLinux, registry.Hosting, NotArm64)
 	s.reg = setupRegistry(c, true, "", "")
 	s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
 		Experimental: experimentalDaemon,
@@ -240,7 +241,7 @@ func init() {
 
 type DockerRegistryAuthHtpasswdSuite struct {
 	ds  *DockerSuite
-	reg *testRegistryV2
+	reg *registry.V2
 	d   *daemon.Daemon
 }
 
@@ -249,7 +250,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) OnTimeout(c *check.C) {
 }
 
 func (s *DockerRegistryAuthHtpasswdSuite) SetUpTest(c *check.C) {
-	testRequires(c, DaemonIsLinux, RegistryHosting)
+	testRequires(c, DaemonIsLinux, registry.Hosting)
 	s.reg = setupRegistry(c, false, "htpasswd", "")
 	s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
 		Experimental: experimentalDaemon,
@@ -276,7 +277,7 @@ func init() {
 
 type DockerRegistryAuthTokenSuite struct {
 	ds  *DockerSuite
-	reg *testRegistryV2
+	reg *registry.V2
 	d   *daemon.Daemon
 }
 
@@ -285,7 +286,7 @@ func (s *DockerRegistryAuthTokenSuite) OnTimeout(c *check.C) {
 }
 
 func (s *DockerRegistryAuthTokenSuite) SetUpTest(c *check.C) {
-	testRequires(c, DaemonIsLinux, RegistryHosting)
+	testRequires(c, DaemonIsLinux, registry.Hosting)
 	s.d = daemon.New(c, dockerBinary, dockerdBinary, daemon.Config{
 		Experimental: experimentalDaemon,
 	})
@@ -449,12 +450,12 @@ func init() {
 
 type DockerTrustSuite struct {
 	ds  *DockerSuite
-	reg *testRegistryV2
+	reg *registry.V2
 	not *testNotary
 }
 
 func (s *DockerTrustSuite) SetUpTest(c *check.C) {
-	testRequires(c, RegistryHosting, NotaryServerHosting)
+	testRequires(c, registry.Hosting, NotaryServerHosting)
 	s.reg = setupRegistry(c, false, "", "")
 	s.not = setupNotary(c)
 }
@@ -487,7 +488,7 @@ func init() {
 type DockerTrustedSwarmSuite struct {
 	swarmSuite DockerSwarmSuite
 	trustSuite DockerTrustSuite
-	reg        *testRegistryV2
+	reg        *registry.V2
 	not        *testNotary
 }
 

+ 2 - 2
integration-cli/docker_cli_build_test.go

@@ -6580,7 +6580,7 @@ func (s *DockerSuite) TestBuildLabelOverwrite(c *check.C) {
 }
 
 func (s *DockerRegistryAuthHtpasswdSuite) TestBuildFromAuthenticatedRegistry(c *check.C) {
-	dockerCmd(c, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL)
+	dockerCmd(c, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL)
 
 	baseImage := privateRegistryURL + "/baseimage"
 
@@ -6625,7 +6625,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestBuildWithExternalAuth(c *check.C)
 	err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644)
 	c.Assert(err, checker.IsNil)
 
-	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL)
+	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL)
 
 	b, err := ioutil.ReadFile(configPath)
 	c.Assert(err, checker.IsNil)

+ 12 - 12
integration-cli/docker_cli_by_digest_test.go

@@ -533,7 +533,7 @@ func (s *DockerRegistrySuite) TestPullFailsWithAlteredManifest(c *check.C) {
 	c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
 
 	// Load the target manifest blob.
-	manifestBlob := s.reg.readBlobContents(c, manifestDigest)
+	manifestBlob := s.reg.ReadBlobContents(c, manifestDigest)
 
 	var imgManifest schema2.Manifest
 	err = json.Unmarshal(manifestBlob, &imgManifest)
@@ -544,13 +544,13 @@ func (s *DockerRegistrySuite) TestPullFailsWithAlteredManifest(c *check.C) {
 
 	// Move the existing data file aside, so that we can replace it with a
 	// malicious blob of data. NOTE: we defer the returned undo func.
-	undo := s.reg.tempMoveBlobData(c, manifestDigest)
+	undo := s.reg.TempMoveBlobData(c, manifestDigest)
 	defer undo()
 
 	alteredManifestBlob, err := json.MarshalIndent(imgManifest, "", "   ")
 	c.Assert(err, checker.IsNil, check.Commentf("unable to encode altered image manifest to JSON"))
 
-	s.reg.writeBlobContents(c, manifestDigest, alteredManifestBlob)
+	s.reg.WriteBlobContents(c, manifestDigest, alteredManifestBlob)
 
 	// Now try pulling that image by digest. We should get an error about
 	// digest verification for the manifest digest.
@@ -573,7 +573,7 @@ func (s *DockerSchema1RegistrySuite) TestPullFailsWithAlteredManifest(c *check.C
 	c.Assert(err, checker.IsNil, check.Commentf("error setting up image"))
 
 	// Load the target manifest blob.
-	manifestBlob := s.reg.readBlobContents(c, manifestDigest)
+	manifestBlob := s.reg.ReadBlobContents(c, manifestDigest)
 
 	var imgManifest schema1.Manifest
 	err = json.Unmarshal(manifestBlob, &imgManifest)
@@ -586,13 +586,13 @@ func (s *DockerSchema1RegistrySuite) TestPullFailsWithAlteredManifest(c *check.C
 
 	// Move the existing data file aside, so that we can replace it with a
 	// malicious blob of data. NOTE: we defer the returned undo func.
-	undo := s.reg.tempMoveBlobData(c, manifestDigest)
+	undo := s.reg.TempMoveBlobData(c, manifestDigest)
 	defer undo()
 
 	alteredManifestBlob, err := json.MarshalIndent(imgManifest, "", "   ")
 	c.Assert(err, checker.IsNil, check.Commentf("unable to encode altered image manifest to JSON"))
 
-	s.reg.writeBlobContents(c, manifestDigest, alteredManifestBlob)
+	s.reg.WriteBlobContents(c, manifestDigest, alteredManifestBlob)
 
 	// Now try pulling that image by digest. We should get an error about
 	// digest verification for the manifest digest.
@@ -615,7 +615,7 @@ func (s *DockerRegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) {
 	c.Assert(err, checker.IsNil)
 
 	// Load the target manifest blob.
-	manifestBlob := s.reg.readBlobContents(c, manifestDigest)
+	manifestBlob := s.reg.ReadBlobContents(c, manifestDigest)
 
 	var imgManifest schema2.Manifest
 	err = json.Unmarshal(manifestBlob, &imgManifest)
@@ -626,11 +626,11 @@ func (s *DockerRegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) {
 
 	// Move the existing data file aside, so that we can replace it with a
 	// malicious blob of data. NOTE: we defer the returned undo func.
-	undo := s.reg.tempMoveBlobData(c, targetLayerDigest)
+	undo := s.reg.TempMoveBlobData(c, targetLayerDigest)
 	defer undo()
 
 	// Now make a fake data blob in this directory.
-	s.reg.writeBlobContents(c, targetLayerDigest, []byte("This is not the data you are looking for."))
+	s.reg.WriteBlobContents(c, targetLayerDigest, []byte("This is not the data you are looking for."))
 
 	// Now try pulling that image by digest. We should get an error about
 	// digest verification for the target layer digest.
@@ -658,7 +658,7 @@ func (s *DockerSchema1RegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) {
 	c.Assert(err, checker.IsNil)
 
 	// Load the target manifest blob.
-	manifestBlob := s.reg.readBlobContents(c, manifestDigest)
+	manifestBlob := s.reg.ReadBlobContents(c, manifestDigest)
 
 	var imgManifest schema1.Manifest
 	err = json.Unmarshal(manifestBlob, &imgManifest)
@@ -669,11 +669,11 @@ func (s *DockerSchema1RegistrySuite) TestPullFailsWithAlteredLayer(c *check.C) {
 
 	// Move the existing data file aside, so that we can replace it with a
 	// malicious blob of data. NOTE: we defer the returned undo func.
-	undo := s.reg.tempMoveBlobData(c, targetLayerDigest)
+	undo := s.reg.TempMoveBlobData(c, targetLayerDigest)
 	defer undo()
 
 	// Now make a fake data blob in this directory.
-	s.reg.writeBlobContents(c, targetLayerDigest, []byte("This is not the data you are looking for."))
+	s.reg.WriteBlobContents(c, targetLayerDigest, []byte("This is not the data you are looking for."))
 
 	// Now try pulling that image by digest. We should get an error about
 	// digest verification for the target layer digest.

+ 2 - 2
integration-cli/docker_cli_login_test.go

@@ -21,10 +21,10 @@ func (s *DockerSuite) TestLoginWithoutTTY(c *check.C) {
 
 func (s *DockerRegistryAuthHtpasswdSuite) TestLoginToPrivateRegistry(c *check.C) {
 	// wrong credentials
-	out, _, err := dockerCmdWithError("login", "-u", s.reg.username, "-p", "WRONGPASSWORD", privateRegistryURL)
+	out, _, err := dockerCmdWithError("login", "-u", s.reg.Username(), "-p", "WRONGPASSWORD", privateRegistryURL)
 	c.Assert(err, checker.NotNil, check.Commentf(out))
 	c.Assert(out, checker.Contains, "401 Unauthorized")
 
 	// now it's fine
-	dockerCmd(c, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL)
+	dockerCmd(c, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL)
 }

+ 3 - 3
integration-cli/docker_cli_logout_test.go

@@ -35,7 +35,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestLogoutWithExternalAuth(c *check.C)
 	err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644)
 	c.Assert(err, checker.IsNil)
 
-	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL)
+	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL)
 
 	b, err := ioutil.ReadFile(configPath)
 	c.Assert(err, checker.IsNil)
@@ -71,7 +71,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestLogoutWithWrongHostnamesStored(c *
 	os.Setenv("PATH", testPath)
 
 	cmd := exec.Command("docker-credential-shell-test", "store")
-	stdin := bytes.NewReader([]byte(fmt.Sprintf(`{"ServerURL": "https://%s", "Username": "%s", "Secret": "%s"}`, privateRegistryURL, s.reg.username, s.reg.password)))
+	stdin := bytes.NewReader([]byte(fmt.Sprintf(`{"ServerURL": "https://%s", "Username": "%s", "Secret": "%s"}`, privateRegistryURL, s.reg.Username(), s.reg.Password())))
 	cmd.Stdin = stdin
 	c.Assert(cmd.Run(), checker.IsNil)
 
@@ -84,7 +84,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestLogoutWithWrongHostnamesStored(c *
 	err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644)
 	c.Assert(err, checker.IsNil)
 
-	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL)
+	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL)
 
 	b, err := ioutil.ReadFile(configPath)
 	c.Assert(err, checker.IsNil)

+ 4 - 4
integration-cli/docker_cli_pull_local_test.go

@@ -347,7 +347,7 @@ func (s *DockerRegistrySuite) TestPullManifestList(c *check.C) {
 	manifestListDigest := digest.FromBytes(manifestListJSON)
 	hexDigest := manifestListDigest.Hex()
 
-	registryV2Path := filepath.Join(s.reg.dir, "docker", "registry", "v2")
+	registryV2Path := s.reg.Path()
 
 	// Write manifest list to blob store
 	blobDir := filepath.Join(registryV2Path, "blobs", "sha256", hexDigest[:2], hexDigest)
@@ -411,7 +411,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestPullWithExternalAuthLoginWithSchem
 	err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644)
 	c.Assert(err, checker.IsNil)
 
-	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL)
+	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL)
 
 	b, err := ioutil.ReadFile(configPath)
 	c.Assert(err, checker.IsNil)
@@ -421,7 +421,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestPullWithExternalAuthLoginWithSchem
 	dockerCmd(c, "--config", tmp, "push", repoName)
 
 	dockerCmd(c, "--config", tmp, "logout", privateRegistryURL)
-	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, "https://"+privateRegistryURL)
+	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), "https://"+privateRegistryURL)
 	dockerCmd(c, "--config", tmp, "pull", repoName)
 
 	// likewise push should work
@@ -456,7 +456,7 @@ func (s *DockerRegistryAuthHtpasswdSuite) TestPullWithExternalAuth(c *check.C) {
 	err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644)
 	c.Assert(err, checker.IsNil)
 
-	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL)
+	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL)
 
 	b, err := ioutil.ReadFile(configPath)
 	c.Assert(err, checker.IsNil)

+ 15 - 14
integration-cli/docker_cli_registry_user_agent_test.go

@@ -5,6 +5,7 @@ import (
 	"net/http"
 	"regexp"
 
+	"github.com/docker/docker/integration-cli/registry"
 	"github.com/go-check/check"
 )
 
@@ -46,8 +47,8 @@ func regexpCheckUA(c *check.C, ua string) {
 	c.Assert(bMatchUpstreamUA, check.Equals, true, check.Commentf("(Upstream) Docker Client User-Agent malformed"))
 }
 
-func registerUserAgentHandler(reg *testRegistry, result *string) {
-	reg.registerHandler("/v2/", func(w http.ResponseWriter, r *http.Request) {
+func registerUserAgentHandler(reg *registry.Mock, result *string) {
+	reg.RegisterHandler("/v2/", func(w http.ResponseWriter, r *http.Request) {
 		w.WriteHeader(404)
 		var ua string
 		for k, v := range r.Header {
@@ -70,30 +71,30 @@ func (s *DockerRegistrySuite) TestUserAgentPassThrough(c *check.C) {
 		loginUA string
 	)
 
-	buildReg, err := newTestRegistry(c)
+	buildReg, err := registry.NewMock(c)
 	c.Assert(err, check.IsNil)
 	registerUserAgentHandler(buildReg, &buildUA)
-	buildRepoName := fmt.Sprintf("%s/busybox", buildReg.hostport)
+	buildRepoName := fmt.Sprintf("%s/busybox", buildReg.URL())
 
-	pullReg, err := newTestRegistry(c)
+	pullReg, err := registry.NewMock(c)
 	c.Assert(err, check.IsNil)
 	registerUserAgentHandler(pullReg, &pullUA)
-	pullRepoName := fmt.Sprintf("%s/busybox", pullReg.hostport)
+	pullRepoName := fmt.Sprintf("%s/busybox", pullReg.URL())
 
-	pushReg, err := newTestRegistry(c)
+	pushReg, err := registry.NewMock(c)
 	c.Assert(err, check.IsNil)
 	registerUserAgentHandler(pushReg, &pushUA)
-	pushRepoName := fmt.Sprintf("%s/busybox", pushReg.hostport)
+	pushRepoName := fmt.Sprintf("%s/busybox", pushReg.URL())
 
-	loginReg, err := newTestRegistry(c)
+	loginReg, err := registry.NewMock(c)
 	c.Assert(err, check.IsNil)
 	registerUserAgentHandler(loginReg, &loginUA)
 
 	s.d.Start(c,
-		"--insecure-registry", buildReg.hostport,
-		"--insecure-registry", pullReg.hostport,
-		"--insecure-registry", pushReg.hostport,
-		"--insecure-registry", loginReg.hostport,
+		"--insecure-registry", buildReg.URL(),
+		"--insecure-registry", pullReg.URL(),
+		"--insecure-registry", pushReg.URL(),
+		"--insecure-registry", loginReg.URL(),
 		"--disable-legacy-registry=true")
 
 	dockerfileName, cleanup1, err := makefile(fmt.Sprintf("FROM %s", buildRepoName))
@@ -102,7 +103,7 @@ func (s *DockerRegistrySuite) TestUserAgentPassThrough(c *check.C) {
 	s.d.Cmd("build", "--file", dockerfileName, ".")
 	regexpCheckUA(c, buildUA)
 
-	s.d.Cmd("login", "-u", "richard", "-p", "testtest", loginReg.hostport)
+	s.d.Cmd("login", "-u", "richard", "-p", "testtest", loginReg.URL())
 	regexpCheckUA(c, loginUA)
 
 	s.d.Cmd("pull", pullRepoName)

+ 18 - 17
integration-cli/docker_cli_v2_only_test.go

@@ -6,6 +6,7 @@ import (
 	"net/http"
 	"os"
 
+	"github.com/docker/docker/integration-cli/registry"
 	"github.com/go-check/check"
 )
 
@@ -36,29 +37,29 @@ func makefile(contents string) (string, func(), error) {
 // TestV2Only ensures that a daemon in v2-only mode does not
 // attempt to contact any v1 registry endpoints.
 func (s *DockerRegistrySuite) TestV2Only(c *check.C) {
-	reg, err := newTestRegistry(c)
+	reg, err := registry.NewMock(c)
 	c.Assert(err, check.IsNil)
 
-	reg.registerHandler("/v2/", func(w http.ResponseWriter, r *http.Request) {
+	reg.RegisterHandler("/v2/", func(w http.ResponseWriter, r *http.Request) {
 		w.WriteHeader(404)
 	})
 
-	reg.registerHandler("/v1/.*", func(w http.ResponseWriter, r *http.Request) {
+	reg.RegisterHandler("/v1/.*", func(w http.ResponseWriter, r *http.Request) {
 		c.Fatal("V1 registry contacted")
 	})
 
-	repoName := fmt.Sprintf("%s/busybox", reg.hostport)
+	repoName := fmt.Sprintf("%s/busybox", reg.URL())
 
-	s.d.Start(c, "--insecure-registry", reg.hostport, "--disable-legacy-registry=true")
+	s.d.Start(c, "--insecure-registry", reg.URL(), "--disable-legacy-registry=true")
 
-	dockerfileName, cleanup, err := makefile(fmt.Sprintf("FROM %s/busybox", reg.hostport))
+	dockerfileName, cleanup, err := makefile(fmt.Sprintf("FROM %s/busybox", reg.URL()))
 	c.Assert(err, check.IsNil, check.Commentf("Unable to create test dockerfile"))
 	defer cleanup()
 
 	s.d.Cmd("build", "--file", dockerfileName, ".")
 
 	s.d.Cmd("run", repoName)
-	s.d.Cmd("login", "-u", "richard", "-p", "testtest", "-e", "testuser@testdomain.com", reg.hostport)
+	s.d.Cmd("login", "-u", "richard", "-p", "testtest", "-e", "testuser@testdomain.com", reg.URL())
 	s.d.Cmd("tag", "busybox", repoName)
 	s.d.Cmd("push", repoName)
 	s.d.Cmd("pull", repoName)
@@ -68,49 +69,49 @@ func (s *DockerRegistrySuite) TestV2Only(c *check.C) {
 // and ensure v1 endpoints are hit for the following operations:
 // login, push, pull, build & run
 func (s *DockerRegistrySuite) TestV1(c *check.C) {
-	reg, err := newTestRegistry(c)
+	reg, err := registry.NewMock(c)
 	c.Assert(err, check.IsNil)
 
 	v2Pings := 0
-	reg.registerHandler("/v2/", func(w http.ResponseWriter, r *http.Request) {
+	reg.RegisterHandler("/v2/", func(w http.ResponseWriter, r *http.Request) {
 		v2Pings++
 		// V2 ping 404 causes fallback to v1
 		w.WriteHeader(404)
 	})
 
 	v1Pings := 0
-	reg.registerHandler("/v1/_ping", func(w http.ResponseWriter, r *http.Request) {
+	reg.RegisterHandler("/v1/_ping", func(w http.ResponseWriter, r *http.Request) {
 		v1Pings++
 	})
 
 	v1Logins := 0
-	reg.registerHandler("/v1/users/", func(w http.ResponseWriter, r *http.Request) {
+	reg.RegisterHandler("/v1/users/", func(w http.ResponseWriter, r *http.Request) {
 		v1Logins++
 	})
 
 	v1Repo := 0
-	reg.registerHandler("/v1/repositories/busybox/", func(w http.ResponseWriter, r *http.Request) {
+	reg.RegisterHandler("/v1/repositories/busybox/", func(w http.ResponseWriter, r *http.Request) {
 		v1Repo++
 	})
 
-	reg.registerHandler("/v1/repositories/busybox/images", func(w http.ResponseWriter, r *http.Request) {
+	reg.RegisterHandler("/v1/repositories/busybox/images", func(w http.ResponseWriter, r *http.Request) {
 		v1Repo++
 	})
 
-	s.d.Start(c, "--insecure-registry", reg.hostport, "--disable-legacy-registry=false")
+	s.d.Start(c, "--insecure-registry", reg.URL(), "--disable-legacy-registry=false")
 
-	dockerfileName, cleanup, err := makefile(fmt.Sprintf("FROM %s/busybox", reg.hostport))
+	dockerfileName, cleanup, err := makefile(fmt.Sprintf("FROM %s/busybox", reg.URL()))
 	c.Assert(err, check.IsNil, check.Commentf("Unable to create test dockerfile"))
 	defer cleanup()
 
 	s.d.Cmd("build", "--file", dockerfileName, ".")
 	c.Assert(v1Repo, check.Equals, 1, check.Commentf("Expected v1 repository access after build"))
 
-	repoName := fmt.Sprintf("%s/busybox", reg.hostport)
+	repoName := fmt.Sprintf("%s/busybox", reg.URL())
 	s.d.Cmd("run", repoName)
 	c.Assert(v1Repo, check.Equals, 2, check.Commentf("Expected v1 repository access after run"))
 
-	s.d.Cmd("login", "-u", "richard", "-p", "testtest", reg.hostport)
+	s.d.Cmd("login", "-u", "richard", "-p", "testtest", reg.URL())
 	c.Assert(v1Logins, check.Equals, 1, check.Commentf("Expected v1 login attempt"))
 
 	s.d.Cmd("tag", "busybox", repoName)

+ 3 - 2
integration-cli/docker_utils_test.go

@@ -24,6 +24,7 @@ import (
 	"github.com/docker/docker/api/types"
 	volumetypes "github.com/docker/docker/api/types/volume"
 	"github.com/docker/docker/integration-cli/daemon"
+	"github.com/docker/docker/integration-cli/registry"
 	"github.com/docker/docker/opts"
 	"github.com/docker/docker/pkg/integration"
 	"github.com/docker/docker/pkg/integration/checker"
@@ -1083,8 +1084,8 @@ 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) *testRegistryV2 {
-	reg, err := newTestRegistryV2(c, schema1, auth, tokenURL)
+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.

+ 70 - 39
integration-cli/registry_test.go → integration-cli/registry/registry.go

@@ -1,4 +1,4 @@
-package main
+package registry
 
 import (
 	"fmt"
@@ -9,7 +9,6 @@ import (
 	"path/filepath"
 
 	"github.com/docker/distribution/digest"
-	"github.com/go-check/check"
 )
 
 const (
@@ -17,16 +16,29 @@ const (
 	v2binarySchema1 = "registry-v2-schema1"
 )
 
-type testRegistryV2 struct {
-	cmd      *exec.Cmd
-	dir      string
-	auth     string
-	username string
-	password string
-	email    string
+type testingT interface {
+	logT
+	Fatal(...interface{})
+	Fatalf(string, ...interface{})
 }
 
-func newTestRegistryV2(c *check.C, schema1 bool, auth, tokenURL string) (*testRegistryV2, error) {
+type logT interface {
+	Logf(string, ...interface{})
+}
+
+// V2 represent a registry version 2
+type V2 struct {
+	cmd         *exec.Cmd
+	registryURL string
+	dir         string
+	auth        string
+	username    string
+	password    string
+	email       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
@@ -78,7 +90,7 @@ http:
 	}
 	defer config.Close()
 
-	if _, err := fmt.Fprintf(config, template, tmp, privateRegistryURL, authTemplate); err != nil {
+	if _, err := fmt.Fprintf(config, template, tmp, registryURL, authTemplate); err != nil {
 		os.RemoveAll(tmp)
 		return nil, err
 	}
@@ -90,31 +102,30 @@ http:
 	cmd := exec.Command(binary, confPath)
 	if err := cmd.Start(); err != nil {
 		os.RemoveAll(tmp)
-		if os.IsNotExist(err) {
-			c.Skip(err.Error())
-		}
 		return nil, err
 	}
-	return &testRegistryV2{
-		cmd:      cmd,
-		dir:      tmp,
-		auth:     auth,
-		username: username,
-		password: password,
-		email:    email,
+	return &V2{
+		cmd:         cmd,
+		dir:         tmp,
+		auth:        auth,
+		username:    username,
+		password:    password,
+		email:       email,
+		registryURL: registryURL,
 	}, nil
 }
 
-func (t *testRegistryV2) Ping() error {
+// Ping sends an http request to the current registry, and fail if it doesn't respond correctly
+func (r *V2) Ping() error {
 	// We always ping through HTTP for our test registry.
-	resp, err := http.Get(fmt.Sprintf("http://%s/v2/", privateRegistryURL))
+	resp, err := http.Get(fmt.Sprintf("http://%s/v2/", r.registryURL))
 	if err != nil {
 		return err
 	}
 	resp.Body.Close()
 
 	fail := resp.StatusCode != http.StatusOK
-	if t.auth != "" {
+	if r.auth != "" {
 		// unauthorized is a _good_ status when pinging v2/ and it needs auth
 		fail = fail && resp.StatusCode != http.StatusUnauthorized
 	}
@@ -124,50 +135,55 @@ func (t *testRegistryV2) Ping() error {
 	return nil
 }
 
-func (t *testRegistryV2) Close() {
-	t.cmd.Process.Kill()
-	os.RemoveAll(t.dir)
+// Close kills the registry server
+func (r *V2) Close() {
+	r.cmd.Process.Kill()
+	os.RemoveAll(r.dir)
 }
 
-func (t *testRegistryV2) getBlobFilename(blobDigest digest.Digest) string {
+func (r *V2) getBlobFilename(blobDigest digest.Digest) string {
 	// Split the digest into its algorithm and hex components.
 	dgstAlg, dgstHex := blobDigest.Algorithm(), blobDigest.Hex()
 
 	// The path to the target blob data looks something like:
 	//   baseDir + "docker/registry/v2/blobs/sha256/a3/a3ed...46d4/data"
-	return fmt.Sprintf("%s/docker/registry/v2/blobs/%s/%s/%s/data", t.dir, dgstAlg, dgstHex[:2], dgstHex)
+	return fmt.Sprintf("%s/docker/registry/v2/blobs/%s/%s/%s/data", r.dir, dgstAlg, dgstHex[:2], dgstHex)
 }
 
-func (t *testRegistryV2) readBlobContents(c *check.C, blobDigest digest.Digest) []byte {
+// ReadBlobContents read the file corresponding to the specified digest
+func (r *V2) ReadBlobContents(t testingT, blobDigest digest.Digest) []byte {
 	// Load the target manifest blob.
-	manifestBlob, err := ioutil.ReadFile(t.getBlobFilename(blobDigest))
+	manifestBlob, err := ioutil.ReadFile(r.getBlobFilename(blobDigest))
 	if err != nil {
-		c.Fatalf("unable to read blob: %s", err)
+		t.Fatalf("unable to read blob: %s", err)
 	}
 
 	return manifestBlob
 }
 
-func (t *testRegistryV2) writeBlobContents(c *check.C, blobDigest digest.Digest, data []byte) {
-	if err := ioutil.WriteFile(t.getBlobFilename(blobDigest), data, os.FileMode(0644)); err != nil {
-		c.Fatalf("unable to write malicious data blob: %s", err)
+// 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 (t *testRegistryV2) tempMoveBlobData(c *check.C, blobDigest digest.Digest) (undo func()) {
+// 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 {
-		c.Fatalf("unable to get temporary blob file: %s", err)
+		t.Fatalf("unable to get temporary blob file: %s", err)
 	}
 	tempFile.Close()
 
-	blobFilename := t.getBlobFilename(blobDigest)
+	blobFilename := r.getBlobFilename(blobDigest)
 
 	// 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 {
 		os.Remove(tempFile.Name())
-		c.Fatalf("unable to move data blob: %s", err)
+		t.Fatalf("unable to move data blob: %s", err)
 	}
 
 	return func() {
@@ -175,3 +191,18 @@ func (t *testRegistryV2) tempMoveBlobData(c *check.C, blobDigest digest.Digest)
 		os.Remove(tempFile.Name())
 	}
 }
+
+// Username returns the configured user name of the server
+func (r *V2) Username() string {
+	return r.username
+}
+
+// Password returns the configured password of the server
+func (r *V2) Password() string {
+	return r.password
+}
+
+// Path returns the path where the registry write data
+func (r *V2) Path() string {
+	return filepath.Join(r.dir, "docker", "registry", "v2")
+}

+ 15 - 9
integration-cli/registry_mock_test.go → integration-cli/registry/registry_mock.go

@@ -1,4 +1,4 @@
-package main
+package registry
 
 import (
 	"net/http"
@@ -6,27 +6,28 @@ import (
 	"regexp"
 	"strings"
 	"sync"
-
-	"github.com/go-check/check"
 )
 
 type handlerFunc func(w http.ResponseWriter, r *http.Request)
 
-type testRegistry struct {
+// Mock represent a registry mock
+type Mock struct {
 	server   *httptest.Server
 	hostport string
 	handlers map[string]handlerFunc
 	mu       sync.Mutex
 }
 
-func (tr *testRegistry) registerHandler(path string, h handlerFunc) {
+// RegisterHandler register the specified handler for the registry mock
+func (tr *Mock) RegisterHandler(path string, h handlerFunc) {
 	tr.mu.Lock()
 	defer tr.mu.Unlock()
 	tr.handlers[path] = h
 }
 
-func newTestRegistry(c *check.C) (*testRegistry, error) {
-	testReg := &testRegistry{handlers: make(map[string]handlerFunc)}
+// NewMock creates a registry mock
+func NewMock(t testingT) (*Mock, error) {
+	testReg := &Mock{handlers: make(map[string]handlerFunc)}
 
 	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		url := r.URL.String()
@@ -36,7 +37,7 @@ func newTestRegistry(c *check.C) (*testRegistry, error) {
 		for re, function := range testReg.handlers {
 			matched, err = regexp.MatchString(re, url)
 			if err != nil {
-				c.Fatal("Error with handler regexp")
+				t.Fatal("Error with handler regexp")
 			}
 			if matched {
 				function(w, r)
@@ -45,7 +46,7 @@ func newTestRegistry(c *check.C) (*testRegistry, error) {
 		}
 
 		if !matched {
-			c.Fatalf("Unable to match %s with regexp", url)
+			t.Fatalf("Unable to match %s with regexp", url)
 		}
 	}))
 
@@ -53,3 +54,8 @@ func newTestRegistry(c *check.C) (*testRegistry, error) {
 	testReg.hostport = strings.Replace(ts.URL, "http://", "", 1)
 	return testReg, nil
 }
+
+// URL returns the url of the registry
+func (tr *Mock) URL() string {
+	return tr.hostport
+}

+ 12 - 0
integration-cli/registry/requirement.go

@@ -0,0 +1,12 @@
+package 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
+}

+ 0 - 8
integration-cli/requirements_test.go

@@ -105,14 +105,6 @@ func Apparmor() bool {
 	return err == nil && len(buf) > 1 && buf[0] == 'Y'
 }
 
-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(v2binary)
-	return err == nil
-}
-
 func NotaryHosting() bool {
 	// for now notary binary is built only if we're running inside
 	// container through `make test`. Figure that out by testing if