func testServerWithAuth(rrm testutil.RequestResponseMap, authenticate string, authCheck func(string) bool) (string, func()) { h := testutil.NewHandler(rrm) wrapper := &testAuthenticationWrapper{ headers: http.Header(map[string][]string{ "Docker-Distribution-API-Version": {"registry/2.0"}, "WWW-Authenticate": {authenticate}, }), authCheck: authCheck, next: h, } s := httptest.NewServer(wrapper) return s.URL, s.Close }
func testServer(rrm testutil.RequestResponseMap) (string, func()) { h := testutil.NewHandler(rrm) s := httptest.NewServer(h) return s.URL, s.Close }
func TestPullResume(t *testing.T) { name := "hello/world" tag := "sometag" testBlobs := []testBlob{ { digest: "tarsum.v2+sha256:12345", contents: []byte("some contents"), }, { digest: "tarsum.v2+sha256:98765", contents: []byte("some other contents"), }, } layers := make([]manifest.FSLayer, len(testBlobs)) history := make([]manifest.History, len(testBlobs)) for i, layer := range testBlobs { layers[i] = manifest.FSLayer{BlobSum: layer.digest} history[i] = manifest.History{V1Compatibility: layer.digest.String()} } m := &manifest.Manifest{ Name: name, Tag: tag, Architecture: "x86", FSLayers: layers, History: history, Versioned: manifest.Versioned{ SchemaVersion: 1, }, } manifestBytes, err := json.Marshal(m) layerRequestResponseMappings := make([]testutil.RequestResponseMapping, 2*len(testBlobs)) for i, blob := range testBlobs { layerRequestResponseMappings[2*i] = testutil.RequestResponseMapping{ Request: testutil.Request{ Method: "GET", Route: "/v2/" + name + "/blobs/" + blob.digest.String(), }, Response: testutil.Response{ StatusCode: http.StatusOK, Body: blob.contents[:len(blob.contents)/2], Headers: http.Header(map[string][]string{ "Content-Length": {fmt.Sprint(len(blob.contents))}, }), }, } layerRequestResponseMappings[2*i+1] = testutil.RequestResponseMapping{ Request: testutil.Request{ Method: "GET", Route: "/v2/" + name + "/blobs/" + blob.digest.String(), }, Response: testutil.Response{ StatusCode: http.StatusOK, Body: blob.contents[len(blob.contents)/2:], }, } } for i := 0; i < 3; i++ { layerRequestResponseMappings = append(layerRequestResponseMappings, testutil.RequestResponseMapping{ Request: testutil.Request{ Method: "GET", Route: "/v2/" + name + "/manifests/" + tag, }, Response: testutil.Response{ StatusCode: http.StatusOK, Body: manifestBytes, }, }) } handler := testutil.NewHandler(layerRequestResponseMappings) server := httptest.NewServer(handler) client, err := New(server.URL) if err != nil { t.Fatalf("error creating client: %v", err) } objectStore := &memoryObjectStore{ mutex: new(sync.Mutex), manifestStorage: make(map[string]*manifest.SignedManifest), layerStorage: make(map[digest.Digest]Layer), } for attempts := 0; attempts < 3; attempts++ { err = Pull(client, objectStore, name, tag) if err == nil { break } } if err != nil { t.Fatal(err) } sm, err := objectStore.Manifest(name, tag) if err != nil { t.Fatal(err) } mBytes, err := json.Marshal(sm) if err != nil { t.Fatal(err) } if string(mBytes) != string(manifestBytes) { t.Fatal("Incorrect manifest") } for _, blob := range testBlobs { l, err := objectStore.Layer(blob.digest) if err != nil { t.Fatal(err) } reader, err := l.Reader() if err != nil { t.Fatal(err) } defer reader.Close() layerBytes, err := ioutil.ReadAll(reader) if err != nil { t.Fatal(err) } if string(layerBytes) != string(blob.contents) { t.Fatal("Incorrect blob") } } }
func TestPush(t *testing.T) { name := "hello/world" tag := "sometag" testBlobs := []testBlob{ { digest: "tarsum.v2+sha256:12345", contents: []byte("some contents"), }, { digest: "tarsum.v2+sha256:98765", contents: []byte("some other contents"), }, } uploadLocations := make([]string, len(testBlobs)) blobs := make([]manifest.FSLayer, len(testBlobs)) history := make([]manifest.History, len(testBlobs)) for i, blob := range testBlobs { // TODO(bbland): this is returning the same location for all uploads, // because we can't know which blob will get which location. // It's sort of okay because we're using unique digests, but this needs // to change at some point. uploadLocations[i] = fmt.Sprintf("/v2/%s/blobs/test-uuid", name) blobs[i] = manifest.FSLayer{BlobSum: blob.digest} history[i] = manifest.History{V1Compatibility: blob.digest.String()} } m := &manifest.SignedManifest{ Manifest: manifest.Manifest{ Name: name, Tag: tag, Architecture: "x86", FSLayers: blobs, History: history, Versioned: manifest.Versioned{ SchemaVersion: 1, }, }, } var err error m.Raw, err = json.Marshal(m) blobRequestResponseMappings := make([]testutil.RequestResponseMapping, 2*len(testBlobs)) for i, blob := range testBlobs { blobRequestResponseMappings[2*i] = testutil.RequestResponseMapping{ Request: testutil.Request{ Method: "POST", Route: "/v2/" + name + "/blobs/uploads/", }, Response: testutil.Response{ StatusCode: http.StatusAccepted, Headers: http.Header(map[string][]string{ "Location": {uploadLocations[i]}, }), }, } blobRequestResponseMappings[2*i+1] = testutil.RequestResponseMapping{ Request: testutil.Request{ Method: "PUT", Route: uploadLocations[i], QueryParams: map[string][]string{ "digest": {blob.digest.String()}, }, Body: blob.contents, }, Response: testutil.Response{ StatusCode: http.StatusCreated, }, } } handler := testutil.NewHandler(append(blobRequestResponseMappings, testutil.RequestResponseMapping{ Request: testutil.Request{ Method: "PUT", Route: "/v2/" + name + "/manifests/" + tag, Body: m.Raw, }, Response: testutil.Response{ StatusCode: http.StatusOK, }, })) var server *httptest.Server // HACK(stevvooe): Super hack to follow: the request response map approach // above does not let us correctly format the location header to the // server url. This handler intercepts and re-writes the location header // to the server url. hack := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w = &headerInterceptingResponseWriter{ResponseWriter: w, serverURL: server.URL} handler.ServeHTTP(w, r) }) server = httptest.NewServer(hack) client, err := New(server.URL) if err != nil { t.Fatalf("error creating client: %v", err) } objectStore := &memoryObjectStore{ mutex: new(sync.Mutex), manifestStorage: make(map[string]*manifest.SignedManifest), layerStorage: make(map[digest.Digest]Layer), } for _, blob := range testBlobs { l, err := objectStore.Layer(blob.digest) if err != nil { t.Fatal(err) } writer, err := l.Writer() if err != nil { t.Fatal(err) } writer.SetSize(len(blob.contents)) writer.Write(blob.contents) writer.Close() } objectStore.WriteManifest(name, tag, m) err = Push(client, objectStore, name, tag) if err != nil { t.Fatal(err) } }
func TestManifestTagsPaginated(t *testing.T) { s := httptest.NewServer(http.NotFoundHandler()) defer s.Close() repo, _ := reference.ParseNamed("test.example.com/repo/tags/list") tagsList := []string{"tag1", "tag2", "funtag"} var m testutil.RequestResponseMap for i := 0; i < 3; i++ { body, err := json.Marshal(map[string]interface{}{ "name": "test.example.com/repo/tags/list", "tags": []string{tagsList[i]}, }) if err != nil { t.Fatal(err) } queryParams := make(map[string][]string) if i > 0 { queryParams["n"] = []string{"1"} queryParams["last"] = []string{tagsList[i-1]} } headers := http.Header(map[string][]string{ "Content-Length": {fmt.Sprint(len(body))}, "Last-Modified": {time.Now().Add(-1 * time.Second).Format(time.ANSIC)}, }) if i < 2 { headers.Set("Link", "<"+s.URL+"/v2/"+repo.Name()+"/tags/list?n=1&last="+tagsList[i]+`>; rel="next"`) } m = append(m, testutil.RequestResponseMapping{ Request: testutil.Request{ Method: "GET", Route: "/v2/" + repo.Name() + "/tags/list", QueryParams: queryParams, }, Response: testutil.Response{ StatusCode: http.StatusOK, Body: body, Headers: headers, }, }) } s.Config.Handler = testutil.NewHandler(m) r, err := NewRepository(context.Background(), repo, s.URL, nil) if err != nil { t.Fatal(err) } ctx := context.Background() tagService := r.Tags(ctx) tags, err := tagService.All(ctx) if err != nil { t.Fatal(tags, err) } if len(tags) != 3 { t.Fatalf("Wrong number of tags returned: %d, expected 3", len(tags)) } expected := map[string]struct{}{ "tag1": {}, "tag2": {}, "funtag": {}, } for _, t := range tags { delete(expected, t) } if len(expected) != 0 { t.Fatalf("unexpected tags returned: %v", expected) } }