Browse Source

Merge pull request #1362 from dotcloud/registry_test

* Registry: Registry unit tests + mock registry
Guillaume J. Charmes 12 years ago
parent
commit
3e6e08ce00
3 changed files with 549 additions and 168 deletions
  1. 7 2
      registry/registry.go
  2. 346 0
      registry/registry_mock_test.go
  3. 196 166
      registry/registry_test.go

+ 7 - 2
registry/registry.go

@@ -161,13 +161,14 @@ func (r *Registry) GetRemoteHistory(imgID, registry string, token []string) ([]s
 
 
 // Check if an image exists in the Registry
 // Check if an image exists in the Registry
 func (r *Registry) LookupRemoteImage(imgID, registry string, token []string) bool {
 func (r *Registry) LookupRemoteImage(imgID, registry string, token []string) bool {
-	rt := &http.Transport{Proxy: http.ProxyFromEnvironment}
+
 
 
 	req, err := r.reqFactory.NewRequest("GET", registry+"images/"+imgID+"/json", nil)
 	req, err := r.reqFactory.NewRequest("GET", registry+"images/"+imgID+"/json", nil)
 	if err != nil {
 	if err != nil {
 		return false
 		return false
 	}
 	}
-	res, err := rt.RoundTrip(req)
+	req.Header.Set("Authorization", "Token "+strings.Join(token, ", "))
+	res, err := doWithCookies(r.client, req)
 	if err != nil {
 	if err != nil {
 		return false
 		return false
 	}
 	}
@@ -214,6 +215,10 @@ func (r *Registry) GetRemoteImageLayer(imgID, registry string, token []string) (
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
+	if res.StatusCode != 200 {
+		return nil, fmt.Errorf("Server error: Status %d while fetching image layer (%s)",
+			res.StatusCode, imgID)
+	}
 	return res.Body, nil
 	return res.Body, nil
 }
 }
 
 

+ 346 - 0
registry/registry_mock_test.go

@@ -0,0 +1,346 @@
+package registry
+
+import (
+	"encoding/json"
+	"fmt"
+	"github.com/dotcloud/docker/utils"
+	"github.com/gorilla/mux"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"net/http/httptest"
+	"net/url"
+	"strconv"
+	"strings"
+	"testing"
+	"time"
+)
+
+var (
+	testHttpServer *httptest.Server
+	testLayers     = map[string]map[string]string{
+		"77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20": {
+			"json": `{"id":"77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
+				"comment":"test base image","created":"2013-03-23T12:53:11.10432-07:00",
+				"container_config":{"Hostname":"","User":"","Memory":0,"MemorySwap":0,
+				"CpuShares":0,"AttachStdin":false,"AttachStdout":false,"AttachStderr":false,
+				"PortSpecs":null,"Tty":false,"OpenStdin":false,"StdinOnce":false,
+				"Env":null,"Cmd":null,"Dns":null,"Image":"","Volumes":null,
+				"VolumesFrom":"","Entrypoint":null},"Size":424242}`,
+			"checksum_simple": "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37",
+			"checksum_tarsum": "tarsum+sha256:4409a0685741ca86d38df878ed6f8cbba4c99de5dc73cd71aef04be3bb70be7c",
+			"ancestry":        `["77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20"]`,
+			"layer": string([]byte{
+				0x1f, 0x8b, 0x08, 0x08, 0x0e, 0xb0, 0xee, 0x51, 0x02, 0x03, 0x6c, 0x61, 0x79, 0x65,
+				0x72, 0x2e, 0x74, 0x61, 0x72, 0x00, 0xed, 0xd2, 0x31, 0x0e, 0xc2, 0x30, 0x0c, 0x05,
+				0x50, 0xcf, 0x9c, 0xc2, 0x27, 0x48, 0xed, 0x38, 0x4e, 0xce, 0x13, 0x44, 0x2b, 0x66,
+				0x62, 0x24, 0x8e, 0x4f, 0xa0, 0x15, 0x63, 0xb6, 0x20, 0x21, 0xfc, 0x96, 0xbf, 0x78,
+				0xb0, 0xf5, 0x1d, 0x16, 0x98, 0x8e, 0x88, 0x8a, 0x2a, 0xbe, 0x33, 0xef, 0x49, 0x31,
+				0xed, 0x79, 0x40, 0x8e, 0x5c, 0x44, 0x85, 0x88, 0x33, 0x12, 0x73, 0x2c, 0x02, 0xa8,
+				0xf0, 0x05, 0xf7, 0x66, 0xf5, 0xd6, 0x57, 0x69, 0xd7, 0x7a, 0x19, 0xcd, 0xf5, 0xb1,
+				0x6d, 0x1b, 0x1f, 0xf9, 0xba, 0xe3, 0x93, 0x3f, 0x22, 0x2c, 0xb6, 0x36, 0x0b, 0xf6,
+				0xb0, 0xa9, 0xfd, 0xe7, 0x94, 0x46, 0xfd, 0xeb, 0xd1, 0x7f, 0x2c, 0xc4, 0xd2, 0xfb,
+				0x97, 0xfe, 0x02, 0x80, 0xe4, 0xfd, 0x4f, 0x77, 0xae, 0x6d, 0x3d, 0x81, 0x73, 0xce,
+				0xb9, 0x7f, 0xf3, 0x04, 0x41, 0xc1, 0xab, 0xc6, 0x00, 0x0a, 0x00, 0x00,
+			}),
+		},
+		"42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d": {
+			"json": `{"id":"42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d",
+				"parent":"77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
+				"comment":"test base image","created":"2013-03-23T12:55:11.10432-07:00",
+				"container_config":{"Hostname":"","User":"","Memory":0,"MemorySwap":0,
+				"CpuShares":0,"AttachStdin":false,"AttachStdout":false,"AttachStderr":false,
+				"PortSpecs":null,"Tty":false,"OpenStdin":false,"StdinOnce":false,
+				"Env":null,"Cmd":null,"Dns":null,"Image":"","Volumes":null,
+				"VolumesFrom":"","Entrypoint":null},"Size":424242}`,
+			"checksum_simple": "sha256:bea7bf2e4bacd479344b737328db47b18880d09096e6674165533aa994f5e9f2",
+			"checksum_tarsum": "tarsum+sha256:68fdb56fb364f074eec2c9b3f85ca175329c4dcabc4a6a452b7272aa613a07a2",
+			"ancestry": `["42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d",
+				"77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20"]`,
+			"layer": string([]byte{
+				0x1f, 0x8b, 0x08, 0x08, 0xbd, 0xb3, 0xee, 0x51, 0x02, 0x03, 0x6c, 0x61, 0x79, 0x65,
+				0x72, 0x2e, 0x74, 0x61, 0x72, 0x00, 0xed, 0xd1, 0x31, 0x0e, 0xc2, 0x30, 0x0c, 0x05,
+				0x50, 0xcf, 0x9c, 0xc2, 0x27, 0x48, 0x9d, 0x38, 0x8e, 0xcf, 0x53, 0x51, 0xaa, 0x56,
+				0xea, 0x44, 0x82, 0xc4, 0xf1, 0x09, 0xb4, 0xea, 0x98, 0x2d, 0x48, 0x08, 0xbf, 0xe5,
+				0x2f, 0x1e, 0xfc, 0xf5, 0xdd, 0x00, 0xdd, 0x11, 0x91, 0x8a, 0xe0, 0x27, 0xd3, 0x9e,
+				0x14, 0xe2, 0x9e, 0x07, 0xf4, 0xc1, 0x2b, 0x0b, 0xfb, 0xa4, 0x82, 0xe4, 0x3d, 0x93,
+				0x02, 0x0a, 0x7c, 0xc1, 0x23, 0x97, 0xf1, 0x5e, 0x5f, 0xc9, 0xcb, 0x38, 0xb5, 0xee,
+				0xea, 0xd9, 0x3c, 0xb7, 0x4b, 0xbe, 0x7b, 0x9c, 0xf9, 0x23, 0xdc, 0x50, 0x6e, 0xb9,
+				0xb8, 0xf2, 0x2c, 0x5d, 0xf7, 0x4f, 0x31, 0xb6, 0xf6, 0x4f, 0xc7, 0xfe, 0x41, 0x55,
+				0x63, 0xdd, 0x9f, 0x89, 0x09, 0x90, 0x6c, 0xff, 0xee, 0xae, 0xcb, 0xba, 0x4d, 0x17,
+				0x30, 0xc6, 0x18, 0xf3, 0x67, 0x5e, 0xc1, 0xed, 0x21, 0x5d, 0x00, 0x0a, 0x00, 0x00,
+			}),
+		},
+	}
+	testRepositories = map[string]map[string]string{
+		"foo42/bar": {
+			"latest": "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d",
+		},
+	}
+)
+
+func init() {
+	r := mux.NewRouter()
+	r.HandleFunc("/v1/_ping", handlerGetPing).Methods("GET")
+	r.HandleFunc("/v1/images/{image_id:[^/]+}/{action:json|layer|ancestry}", handlerGetImage).Methods("GET")
+	r.HandleFunc("/v1/images/{image_id:[^/]+}/{action:json|layer|checksum}", handlerPutImage).Methods("PUT")
+	r.HandleFunc("/v1/repositories/{repository:.+}/tags", handlerGetDeleteTags).Methods("GET", "DELETE")
+	r.HandleFunc("/v1/repositories/{repository:.+}/tags/{tag:.+}", handlerGetTag).Methods("GET")
+	r.HandleFunc("/v1/repositories/{repository:.+}/tags/{tag:.+}", handlerPutTag).Methods("PUT")
+	r.HandleFunc("/v1/users{null:.*}", handlerUsers).Methods("GET", "POST", "PUT")
+	r.HandleFunc("/v1/repositories/{repository:.+}{action:/images|/}", handlerImages).Methods("GET", "PUT", "DELETE")
+	r.HandleFunc("/v1/repositories/{repository:.+}/auth", handlerAuth).Methods("PUT")
+	r.HandleFunc("/v1/search", handlerSearch).Methods("GET")
+	testHttpServer = httptest.NewServer(handlerAccessLog(r))
+}
+
+func handlerAccessLog(handler http.Handler) http.Handler {
+	logHandler := func(w http.ResponseWriter, r *http.Request) {
+		utils.Debugf("%s \"%s %s\"", r.RemoteAddr, r.Method, r.URL)
+		handler.ServeHTTP(w, r)
+	}
+	return http.HandlerFunc(logHandler)
+}
+
+func makeURL(req string) string {
+	return testHttpServer.URL + req
+}
+
+func writeHeaders(w http.ResponseWriter) {
+	h := w.Header()
+	h.Add("Server", "docker-tests/mock")
+	h.Add("Expires", "-1")
+	h.Add("Content-Type", "application/json")
+	h.Add("Pragma", "no-cache")
+	h.Add("Cache-Control", "no-cache")
+	h.Add("X-Docker-Registry-Version", "0.0.0")
+	h.Add("X-Docker-Registry-Config", "mock")
+}
+
+func writeResponse(w http.ResponseWriter, message interface{}, code int) {
+	writeHeaders(w)
+	w.WriteHeader(code)
+	body, err := json.Marshal(message)
+	if err != nil {
+		io.WriteString(w, err.Error())
+		return
+	}
+	w.Write(body)
+}
+
+func readJSON(r *http.Request, dest interface{}) error {
+	body, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		return err
+	}
+	return json.Unmarshal(body, dest)
+}
+
+func apiError(w http.ResponseWriter, message string, code int) {
+	body := map[string]string{
+		"error": message,
+	}
+	writeResponse(w, body, code)
+}
+
+func assertEqual(t *testing.T, a interface{}, b interface{}, message string) {
+	if a == b {
+		return
+	}
+	if len(message) == 0 {
+		message = fmt.Sprintf("%v != %v", a, b)
+	}
+	t.Fatal(message)
+}
+
+func requiresAuth(w http.ResponseWriter, r *http.Request) bool {
+	writeCookie := func() {
+		value := fmt.Sprintf("FAKE-SESSION-%d", time.Now().UnixNano())
+		cookie := &http.Cookie{Name: "session", Value: value, MaxAge: 3600}
+		http.SetCookie(w, cookie)
+		//FIXME(sam): this should be sent only on Index routes
+		value = fmt.Sprintf("FAKE-TOKEN-%d", time.Now().UnixNano())
+		w.Header().Add("X-Docker-Token", value)
+	}
+	if len(r.Cookies()) > 0 {
+		writeCookie()
+		return true
+	}
+	if len(r.Header.Get("Authorization")) > 0 {
+		writeCookie()
+		return true
+	}
+	w.Header().Add("WWW-Authenticate", "token")
+	apiError(w, "Wrong auth", 401)
+	return false
+}
+
+func handlerGetPing(w http.ResponseWriter, r *http.Request) {
+	writeResponse(w, true, 200)
+}
+
+func handlerGetImage(w http.ResponseWriter, r *http.Request) {
+	if !requiresAuth(w, r) {
+		return
+	}
+	vars := mux.Vars(r)
+	layer, exists := testLayers[vars["image_id"]]
+	if !exists {
+		http.NotFound(w, r)
+		return
+	}
+	writeHeaders(w)
+	layer_size := len(layer["layer"])
+	w.Header().Add("X-Docker-Size", strconv.Itoa(layer_size))
+	io.WriteString(w, layer[vars["action"]])
+}
+
+func handlerPutImage(w http.ResponseWriter, r *http.Request) {
+	if !requiresAuth(w, r) {
+		return
+	}
+	vars := mux.Vars(r)
+	image_id := vars["image_id"]
+	action := vars["action"]
+	layer, exists := testLayers[image_id]
+	if !exists {
+		if action != "json" {
+			http.NotFound(w, r)
+			return
+		}
+		layer = make(map[string]string)
+		testLayers[image_id] = layer
+	}
+	if checksum := r.Header.Get("X-Docker-Checksum"); checksum != "" {
+		if checksum != layer["checksum_simple"] && checksum != layer["checksum_tarsum"] {
+			apiError(w, "Wrong checksum", 400)
+			return
+		}
+	}
+	body, err := ioutil.ReadAll(r.Body)
+	if err != nil {
+		apiError(w, fmt.Sprintf("Error: %s", err), 500)
+		return
+	}
+	layer[action] = string(body)
+	writeResponse(w, true, 200)
+}
+
+func handlerGetDeleteTags(w http.ResponseWriter, r *http.Request) {
+	if !requiresAuth(w, r) {
+		return
+	}
+	repositoryName := mux.Vars(r)["repository"]
+	tags, exists := testRepositories[repositoryName]
+	if !exists {
+		apiError(w, "Repository not found", 404)
+	}
+	if r.Method == "DELETE" {
+		delete(testRepositories, repositoryName)
+		writeResponse(w, true, 200)
+		return
+	}
+	writeResponse(w, tags, 200)
+}
+
+func handlerGetTag(w http.ResponseWriter, r *http.Request) {
+	if !requiresAuth(w, r) {
+		return
+	}
+	vars := mux.Vars(r)
+	repositoryName := vars["repository"]
+	tagName := vars["tag"]
+	tags, exists := testRepositories[repositoryName]
+	if !exists {
+		apiError(w, "Repository not found", 404)
+	}
+	tag, exists := tags[tagName]
+	if !exists {
+		apiError(w, "Tag not found", 404)
+	}
+	writeResponse(w, tag, 200)
+}
+
+func handlerPutTag(w http.ResponseWriter, r *http.Request) {
+	if !requiresAuth(w, r) {
+		return
+	}
+	vars := mux.Vars(r)
+	repositoryName := vars["repository"]
+	tagName := vars["tag"]
+	tags, exists := testRepositories[repositoryName]
+	if !exists {
+		tags := make(map[string]string)
+		testRepositories[repositoryName] = tags
+	}
+	tagValue := ""
+	readJSON(r, tagValue)
+	tags[tagName] = tagValue
+	writeResponse(w, true, 200)
+}
+
+func handlerUsers(w http.ResponseWriter, r *http.Request) {
+	code := 200
+	if r.Method == "POST" {
+		code = 201
+	} else if r.Method == "PUT" {
+		code = 204
+	}
+	writeResponse(w, "", code)
+}
+
+func handlerImages(w http.ResponseWriter, r *http.Request) {
+	u, _ := url.Parse(testHttpServer.URL)
+	w.Header().Add("X-Docker-Endpoints", u.Host)
+	w.Header().Add("X-Docker-Token", fmt.Sprintf("FAKE-SESSION-%d", time.Now().UnixNano()))
+	if r.Method == "PUT" {
+		if strings.HasSuffix(r.URL.Path, "images") {
+			writeResponse(w, "", 204)
+			return
+		}
+		writeResponse(w, "", 200)
+		return
+	}
+	if r.Method == "DELETE" {
+		writeResponse(w, "", 204)
+		return
+	}
+	images := []map[string]string{}
+	for image_id, layer := range testLayers {
+		image := make(map[string]string)
+		image["id"] = image_id
+		image["checksum"] = layer["checksum_tarsum"]
+		image["Tag"] = "latest"
+		images = append(images, image)
+	}
+	writeResponse(w, images, 200)
+}
+
+func handlerAuth(w http.ResponseWriter, r *http.Request) {
+	writeResponse(w, "OK", 200)
+}
+
+func handlerSearch(w http.ResponseWriter, r *http.Request) {
+	writeResponse(w, "{}", 200)
+}
+
+func TestPing(t *testing.T) {
+	res, err := http.Get(makeURL("/v1/_ping"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	assertEqual(t, res.StatusCode, 200, "")
+	assertEqual(t, res.Header.Get("X-Docker-Registry-Config"), "mock",
+		"This is not a Mocked Registry")
+}
+
+/* Uncomment this to test Mocked Registry locally with curl
+ * WARNING: Don't push on the repos uncommented, it'll block the tests
+ *
+func TestWait(t *testing.T) {
+	log.Println("Test HTTP server ready and waiting:", testHttpServer.URL)
+	c := make(chan int)
+	<-c
+}
+
+//*/

+ 196 - 166
registry/registry_test.go

@@ -1,168 +1,198 @@
 package registry
 package registry
 
 
-// import (
-// 	"crypto/rand"
-// 	"encoding/hex"
-// 	"github.com/dotcloud/docker"
-// 	"github.com/dotcloud/docker/auth"
-// 	"io/ioutil"
-// 	"os"
-// 	"path"
-// 	"testing"
-// )
-
-// func newTestRuntime() (*Runtime, error) {
-// 	root, err := ioutil.TempDir("", "docker-test")
-// 	if err != nil {
-// 		return nil, err
-// 	}
-// 	if err := os.Remove(root); err != nil {
-// 		return nil, err
-// 	}
-
-// 	if err := os.MkdirAll(root, 0700); err != nil && !os.IsExist(err) {
-// 		return nil, err
-// 	}
-
-// 	return runtime, nil
-// }
-
-// func TestPull(t *testing.T) {
-// 	os.Setenv("DOCKER_INDEX_URL", "")
-// 	runtime, err := newTestRuntime()
-// 	if err != nil {
-// 		t.Fatal(err)
-// 	}
-// 	defer nuke(runtime)
-
-// 	err = runtime.graph.PullRepository(ioutil.Discard, "busybox", "", runtime.repositories, nil)
-// 	if err != nil {
-// 		t.Fatal(err)
-// 	}
-// 	img, err := runtime.repositories.LookupImage("busybox")
-// 	if err != nil {
-// 		t.Fatal(err)
-// 	}
-
-// 	// Try to run something on this image to make sure the layer's been downloaded properly.
-// 	config, _, err := docker.ParseRun([]string{img.Id, "echo", "Hello World"}, runtime.capabilities)
-// 	if err != nil {
-// 		t.Fatal(err)
-// 	}
-
-// 	b := NewBuilder(runtime)
-// 	container, err := b.Create(config)
-// 	if err != nil {
-// 		t.Fatal(err)
-// 	}
-// 	if err := container.Start(); err != nil {
-// 		t.Fatal(err)
-// 	}
-
-// 	if status := container.Wait(); status != 0 {
-// 		t.Fatalf("Expected status code 0, found %d instead", status)
-// 	}
-// }
-
-// func TestPullTag(t *testing.T) {
-// 	os.Setenv("DOCKER_INDEX_URL", "")
-// 	runtime, err := newTestRuntime()
-// 	if err != nil {
-// 		t.Fatal(err)
-// 	}
-// 	defer nuke(runtime)
-
-// 	err = runtime.graph.PullRepository(ioutil.Discard, "ubuntu", "12.04", runtime.repositories, nil)
-// 	if err != nil {
-// 		t.Fatal(err)
-// 	}
-// 	_, err = runtime.repositories.LookupImage("ubuntu:12.04")
-// 	if err != nil {
-// 		t.Fatal(err)
-// 	}
-
-// 	img2, err := runtime.repositories.LookupImage("ubuntu:12.10")
-// 	if img2 != nil {
-// 		t.Fatalf("Expected nil image but found %v instead", img2.Id)
-// 	}
-// }
-
-// func login(runtime *Runtime) error {
-// 	authConfig := auth.NewAuthConfig("unittester", "surlautrerivejetattendrai", "noise+unittester@dotcloud.com", runtime.root)
-// 	runtime.authConfig = authConfig
-// 	_, err := auth.Login(authConfig)
-// 	return err
-// }
-
-// func TestPush(t *testing.T) {
-// 	os.Setenv("DOCKER_INDEX_URL", "https://indexstaging-docker.dotcloud.com")
-// 	defer os.Setenv("DOCKER_INDEX_URL", "")
-// 	runtime, err := newTestRuntime()
-// 	if err != nil {
-// 		t.Fatal(err)
-// 	}
-// 	defer nuke(runtime)
-
-// 	err = login(runtime)
-// 	if err != nil {
-// 		t.Fatal(err)
-// 	}
-
-// 	err = runtime.graph.PullRepository(ioutil.Discard, "joffrey/busybox", "", runtime.repositories, nil)
-// 	if err != nil {
-// 		t.Fatal(err)
-// 	}
-// 	tokenBuffer := make([]byte, 16)
-// 	_, err = rand.Read(tokenBuffer)
-// 	if err != nil {
-// 		t.Fatal(err)
-// 	}
-// 	token := hex.EncodeToString(tokenBuffer)[:29]
-// 	config, _, err := ParseRun([]string{"joffrey/busybox", "touch", "/" + token}, runtime.capabilities)
-// 	if err != nil {
-// 		t.Fatal(err)
-// 	}
-
-// 	b := NewBuilder(runtime)
-// 	container, err := b.Create(config)
-// 	if err != nil {
-// 		t.Fatal(err)
-// 	}
-// 	if err := container.Start(); err != nil {
-// 		t.Fatal(err)
-// 	}
-
-// 	if status := container.Wait(); status != 0 {
-// 		t.Fatalf("Expected status code 0, found %d instead", status)
-// 	}
-
-// 	img, err := b.Commit(container, "unittester/"+token, "", "", "", nil)
-// 	if err != nil {
-// 		t.Fatal(err)
-// 	}
-
-// 	repo := runtime.repositories.Repositories["unittester/"+token]
-// 	err = runtime.graph.PushRepository(ioutil.Discard, "unittester/"+token, repo, runtime.authConfig)
-// 	if err != nil {
-// 		t.Fatal(err)
-// 	}
-
-// 	// Remove image so we can pull it again
-// 	if err := runtime.graph.Delete(img.Id); err != nil {
-// 		t.Fatal(err)
-// 	}
-
-// 	err = runtime.graph.PullRepository(ioutil.Discard, "unittester/"+token, "", runtime.repositories, runtime.authConfig)
-// 	if err != nil {
-// 		t.Fatal(err)
-// 	}
-
-// 	layerPath, err := img.layer()
-// 	if err != nil {
-// 		t.Fatal(err)
-// 	}
-
-// 	if _, err := os.Stat(path.Join(layerPath, token)); err != nil {
-// 		t.Fatalf("Error while trying to retrieve token file: %v", err)
-// 	}
-// }
+import (
+	"github.com/dotcloud/docker/auth"
+	"github.com/dotcloud/docker/utils"
+	"strings"
+	"testing"
+)
+
+var (
+	IMAGE_ID = "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d"
+	TOKEN    = []string{"fake-token"}
+	REPO     = "foo42/bar"
+)
+
+func spawnTestRegistry(t *testing.T) *Registry {
+	authConfig := &auth.AuthConfig{}
+	r, err := NewRegistry("", authConfig, utils.NewHTTPRequestFactory())
+	if err != nil {
+		t.Fatal(err)
+	}
+	return r
+}
+
+func TestPingRegistryEndpoint(t *testing.T) {
+	err := pingRegistryEndpoint(makeURL("/v1/"))
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestGetRemoteHistory(t *testing.T) {
+	r := spawnTestRegistry(t)
+	hist, err := r.GetRemoteHistory(IMAGE_ID, makeURL("/v1/"), TOKEN)
+	if err != nil {
+		t.Fatal(err)
+	}
+	assertEqual(t, len(hist), 2, "Expected 2 images in history")
+	assertEqual(t, hist[0], IMAGE_ID, "Expected "+IMAGE_ID+"as first ancestry")
+	assertEqual(t, hist[1], "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
+		"Unexpected second ancestry")
+}
+
+func TestLookupRemoteImage(t *testing.T) {
+	r := spawnTestRegistry(t)
+	found := r.LookupRemoteImage(IMAGE_ID, makeURL("/v1/"), TOKEN)
+	assertEqual(t, found, true, "Expected remote lookup to succeed")
+	found = r.LookupRemoteImage("abcdef", makeURL("/v1/"), TOKEN)
+	assertEqual(t, found, false, "Expected remote lookup to fail")
+}
+
+func TestGetRemoteImageJSON(t *testing.T) {
+	r := spawnTestRegistry(t)
+	json, size, err := r.GetRemoteImageJSON(IMAGE_ID, makeURL("/v1/"), TOKEN)
+	if err != nil {
+		t.Fatal(err)
+	}
+	assertEqual(t, size, 154, "Expected size 154")
+	if len(json) <= 0 {
+		t.Fatal("Expected non-empty json")
+	}
+
+	_, _, err = r.GetRemoteImageJSON("abcdef", makeURL("/v1/"), TOKEN)
+	if err == nil {
+		t.Fatal("Expected image not found error")
+	}
+}
+
+func TestGetRemoteImageLayer(t *testing.T) {
+	r := spawnTestRegistry(t)
+	data, err := r.GetRemoteImageLayer(IMAGE_ID, makeURL("/v1/"), TOKEN)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if data == nil {
+		t.Fatal("Expected non-nil data result")
+	}
+
+	_, err = r.GetRemoteImageLayer("abcdef", makeURL("/v1/"), TOKEN)
+	if err == nil {
+		t.Fatal("Expected image not found error")
+	}
+}
+
+func TestGetRemoteTags(t *testing.T) {
+	r := spawnTestRegistry(t)
+	tags, err := r.GetRemoteTags([]string{makeURL("/v1/")}, REPO, TOKEN)
+	if err != nil {
+		t.Fatal(err)
+	}
+	assertEqual(t, len(tags), 1, "Expected one tag")
+	assertEqual(t, tags["latest"], IMAGE_ID, "Expected tag latest to map to "+IMAGE_ID)
+
+	_, err = r.GetRemoteTags([]string{makeURL("/v1/")}, "foo42/baz", TOKEN)
+	if err == nil {
+		t.Fatal("Expected error when fetching tags for bogus repo")
+	}
+}
+
+func TestGetRepositoryData(t *testing.T) {
+	r := spawnTestRegistry(t)
+	data, err := r.GetRepositoryData(makeURL("/v1/"), "foo42/bar")
+	if err != nil {
+		t.Fatal(err)
+	}
+	assertEqual(t, len(data.ImgList), 2, "Expected 2 images in ImgList")
+	assertEqual(t, len(data.Endpoints), 1, "Expected one endpoint in Endpoints")
+}
+
+func TestPushImageJSONRegistry(t *testing.T) {
+	r := spawnTestRegistry(t)
+	imgData := &ImgData{
+		ID:       "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
+		Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37",
+	}
+
+	err := r.PushImageJSONRegistry(imgData, []byte{0x42, 0xdf, 0x0}, makeURL("/v1/"), TOKEN)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestPushImageLayerRegistry(t *testing.T) {
+	r := spawnTestRegistry(t)
+	layer := strings.NewReader("")
+	_, err := r.PushImageLayerRegistry(IMAGE_ID, layer, makeURL("/v1/"), TOKEN, []byte{})
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestResolveRepositoryName(t *testing.T) {
+	_, _, err := ResolveRepositoryName("https://github.com/dotcloud/docker")
+	assertEqual(t, err, ErrInvalidRepositoryName, "Expected error invalid repo name")
+	ep, repo, err := ResolveRepositoryName("fooo/bar")
+	if err != nil {
+		t.Fatal(err)
+	}
+	assertEqual(t, ep, auth.IndexServerAddress(), "Expected endpoint to be index server address")
+	assertEqual(t, repo, "fooo/bar", "Expected resolved repo to be foo/bar")
+
+	u := makeURL("")[7:]
+	ep, repo, err = ResolveRepositoryName(u + "/private/moonbase")
+	if err != nil {
+		t.Fatal(err)
+	}
+	assertEqual(t, ep, "http://"+u+"/v1/", "Expected endpoint to be "+u)
+	assertEqual(t, repo, "private/moonbase", "Expected endpoint to be private/moonbase")
+}
+
+func TestPushRegistryTag(t *testing.T) {
+	r := spawnTestRegistry(t)
+	err := r.PushRegistryTag("foo42/bar", IMAGE_ID, "stable", makeURL("/v1/"), TOKEN)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestPushImageJSONIndex(t *testing.T) {
+	r := spawnTestRegistry(t)
+	imgData := []*ImgData{
+		&ImgData{
+			ID:       "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
+			Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37",
+		},
+		&ImgData{
+			ID:       "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d",
+			Checksum: "sha256:bea7bf2e4bacd479344b737328db47b18880d09096e6674165533aa994f5e9f2",
+		},
+	}
+	ep := makeURL("/v1/")
+	repoData, err := r.PushImageJSONIndex(ep, "foo42/bar", imgData, false, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if repoData == nil {
+		t.Fatal("Expected RepositoryData object")
+	}
+	repoData, err = r.PushImageJSONIndex(ep, "foo42/bar", imgData, true, []string{ep})
+	if err != nil {
+		t.Fatal(err)
+	}
+	if repoData == nil {
+		t.Fatal("Expected RepositoryData object")
+	}
+}
+
+func TestSearchRepositories(t *testing.T) {
+	r := spawnTestRegistry(t)
+	results, err := r.SearchRepositories("supercalifragilisticepsialidocious")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if results == nil {
+		t.Fatal("Expected non-nil SearchResults object")
+	}
+	assertEqual(t, results.NumResults, 0, "Expected 0 search results")
+}