package oci import ( "encoding/json" "net/http" "net/http/httptest" "testing" ) func TestManifestGetByTag(t *testing.T) { fdb := newFakeDB() fdb.addRepo("myrepo", 1) content := []byte(`{"schemaVersion":2}`) fdb.addManifest(1, "latest", "sha256:aaaa", "application/vnd.oci.image.manifest.v1+json", content) h := NewHandler(fdb, newFakeBlobs(), allowAll(), nil) router := testRouter(h) req := authedRequest("GET", "/v2/myrepo/manifests/latest", nil) rr := httptest.NewRecorder() router.ServeHTTP(rr, req) if rr.Code != http.StatusOK { t.Fatalf("status: got %d, want %d", rr.Code, http.StatusOK) } if ct := rr.Header().Get("Content-Type"); ct != "application/vnd.oci.image.manifest.v1+json" { t.Fatalf("Content-Type: got %q", ct) } if dcd := rr.Header().Get("Docker-Content-Digest"); dcd != "sha256:aaaa" { t.Fatalf("Docker-Content-Digest: got %q", dcd) } if cl := rr.Header().Get("Content-Length"); cl != "19" { t.Fatalf("Content-Length: got %q, want %q", cl, "19") } if rr.Body.String() != `{"schemaVersion":2}` { t.Fatalf("body: got %q", rr.Body.String()) } } func TestManifestGetByDigest(t *testing.T) { fdb := newFakeDB() fdb.addRepo("myrepo", 1) content := []byte(`{"schemaVersion":2}`) fdb.addManifest(1, "latest", "sha256:aaaa", "application/vnd.oci.image.manifest.v1+json", content) h := NewHandler(fdb, newFakeBlobs(), allowAll(), nil) router := testRouter(h) req := authedRequest("GET", "/v2/myrepo/manifests/sha256:aaaa", nil) rr := httptest.NewRecorder() router.ServeHTTP(rr, req) if rr.Code != http.StatusOK { t.Fatalf("status: got %d, want %d", rr.Code, http.StatusOK) } if dcd := rr.Header().Get("Docker-Content-Digest"); dcd != "sha256:aaaa" { t.Fatalf("Docker-Content-Digest: got %q", dcd) } if rr.Body.String() != `{"schemaVersion":2}` { t.Fatalf("body: got %q", rr.Body.String()) } } func TestManifestHead(t *testing.T) { fdb := newFakeDB() fdb.addRepo("myrepo", 1) content := []byte(`{"schemaVersion":2}`) fdb.addManifest(1, "latest", "sha256:aaaa", "application/vnd.oci.image.manifest.v1+json", content) h := NewHandler(fdb, newFakeBlobs(), allowAll(), nil) router := testRouter(h) req := authedRequest("HEAD", "/v2/myrepo/manifests/latest", nil) rr := httptest.NewRecorder() router.ServeHTTP(rr, req) if rr.Code != http.StatusOK { t.Fatalf("status: got %d, want %d", rr.Code, http.StatusOK) } if ct := rr.Header().Get("Content-Type"); ct != "application/vnd.oci.image.manifest.v1+json" { t.Fatalf("Content-Type: got %q", ct) } if dcd := rr.Header().Get("Docker-Content-Digest"); dcd != "sha256:aaaa" { t.Fatalf("Docker-Content-Digest: got %q", dcd) } if cl := rr.Header().Get("Content-Length"); cl != "19" { t.Fatalf("Content-Length: got %q, want %q", cl, "19") } if rr.Body.Len() != 0 { t.Fatalf("HEAD body should be empty, got %d bytes", rr.Body.Len()) } } func TestManifestGetRepoNotFound(t *testing.T) { fdb := newFakeDB() // No repos added. h := NewHandler(fdb, newFakeBlobs(), allowAll(), nil) router := testRouter(h) req := authedRequest("GET", "/v2/nosuchrepo/manifests/latest", nil) rr := httptest.NewRecorder() router.ServeHTTP(rr, req) if rr.Code != http.StatusNotFound { t.Fatalf("status: got %d, want %d", rr.Code, http.StatusNotFound) } var body ociErrorResponse if err := json.NewDecoder(rr.Body).Decode(&body); err != nil { t.Fatalf("decode error body: %v", err) } if len(body.Errors) != 1 || body.Errors[0].Code != "NAME_UNKNOWN" { t.Fatalf("error code: got %+v, want NAME_UNKNOWN", body.Errors) } } func TestManifestGetManifestNotFoundByTag(t *testing.T) { fdb := newFakeDB() fdb.addRepo("myrepo", 1) // No manifests added. h := NewHandler(fdb, newFakeBlobs(), allowAll(), nil) router := testRouter(h) req := authedRequest("GET", "/v2/myrepo/manifests/nonexistent", nil) rr := httptest.NewRecorder() router.ServeHTTP(rr, req) if rr.Code != http.StatusNotFound { t.Fatalf("status: got %d, want %d", rr.Code, http.StatusNotFound) } var body ociErrorResponse if err := json.NewDecoder(rr.Body).Decode(&body); err != nil { t.Fatalf("decode error body: %v", err) } if len(body.Errors) != 1 || body.Errors[0].Code != "MANIFEST_UNKNOWN" { t.Fatalf("error code: got %+v, want MANIFEST_UNKNOWN", body.Errors) } } func TestManifestGetManifestNotFoundByDigest(t *testing.T) { fdb := newFakeDB() fdb.addRepo("myrepo", 1) // No manifests added. h := NewHandler(fdb, newFakeBlobs(), allowAll(), nil) router := testRouter(h) req := authedRequest("GET", "/v2/myrepo/manifests/sha256:nonexistent", nil) rr := httptest.NewRecorder() router.ServeHTTP(rr, req) if rr.Code != http.StatusNotFound { t.Fatalf("status: got %d, want %d", rr.Code, http.StatusNotFound) } var body ociErrorResponse if err := json.NewDecoder(rr.Body).Decode(&body); err != nil { t.Fatalf("decode error body: %v", err) } if len(body.Errors) != 1 || body.Errors[0].Code != "MANIFEST_UNKNOWN" { t.Fatalf("error code: got %+v, want MANIFEST_UNKNOWN", body.Errors) } } func TestManifestGetMultiSegmentRepo(t *testing.T) { fdb := newFakeDB() fdb.addRepo("org/team/app", 1) content := []byte(`{"layers":[]}`) fdb.addManifest(1, "v1.0", "sha256:cccc", "application/vnd.oci.image.manifest.v1+json", content) h := NewHandler(fdb, newFakeBlobs(), allowAll(), nil) router := testRouter(h) req := authedRequest("GET", "/v2/org/team/app/manifests/v1.0", nil) rr := httptest.NewRecorder() router.ServeHTTP(rr, req) if rr.Code != http.StatusOK { t.Fatalf("status: got %d, want %d", rr.Code, http.StatusOK) } if dcd := rr.Header().Get("Docker-Content-Digest"); dcd != "sha256:cccc" { t.Fatalf("Docker-Content-Digest: got %q", dcd) } }