From 7d537e959da74875f2138dd3f5b6edda2369848d Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Fri, 15 Dec 2023 14:33:05 +0800 Subject: [PATCH 01/13] feat: Referrers support for oci.Store Signed-off-by: Xiaoxuan Wang --- content/oci/oci.go | 78 ++++++++++++++++++ content/oci/oci_test.go | 174 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 252 insertions(+) diff --git a/content/oci/oci.go b/content/oci/oci.go index 1deca875..92bb4652 100644 --- a/content/oci/oci.go +++ b/content/oci/oci.go @@ -36,6 +36,7 @@ import ( "oras.land/oras-go/v2/internal/descriptor" "oras.land/oras-go/v2/internal/graph" "oras.land/oras-go/v2/internal/resolver" + "oras.land/oras-go/v2/internal/spec" ) // Store implements `oras.Target`, and represents a content store @@ -398,6 +399,83 @@ func (s *Store) writeIndexFile() error { return os.WriteFile(s.indexPath, indexJSON, 0666) } +// Referrers lists the descriptors of image or artifact manifests directly +// referencing the given manifest descriptor. +// +// fn is called on the referrer results. If artifactType is not empty, only +// referrers of the same artifact type are fed to fn. +// +// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#listing-referrers +func (s *Store) Referrers(ctx context.Context, desc ocispec.Descriptor, artifactType string, fn func(referrers []ocispec.Descriptor) error) error { + s.sync.RLock() + defer s.sync.RUnlock() + + if !descriptor.IsManifest(desc) { + return fmt.Errorf("the descriptor %v is not a manifest", desc) + } + var results []ocispec.Descriptor + predecessors, err := s.Predecessors(ctx, desc) + if err != nil { + return err + } + for _, node := range predecessors { + switch node.MediaType { + case ocispec.MediaTypeImageManifest: + fetched, err := content.FetchAll(ctx, s, node) + if err != nil { + return err + } + var manifest ocispec.Manifest + if err := json.Unmarshal(fetched, &manifest); err != nil { + return err + } + if manifest.Subject == nil || !content.Equal(*manifest.Subject, desc) { + continue + } + if manifest.ArtifactType != "" { + node.ArtifactType = manifest.ArtifactType + } else { + node.ArtifactType = manifest.Config.MediaType + } + node.Annotations = manifest.Annotations + case ocispec.MediaTypeImageIndex: + fetched, err := content.FetchAll(ctx, s, node) + if err != nil { + return err + } + var index ocispec.Index + if err := json.Unmarshal(fetched, &index); err != nil { + return err + } + if index.Subject == nil || !content.Equal(*index.Subject, desc) { + continue + } + node.ArtifactType = index.ArtifactType + node.Annotations = index.Annotations + case spec.MediaTypeArtifactManifest: + fetched, err := content.FetchAll(ctx, s, node) + if err != nil { + return err + } + var artifact spec.Artifact + if err := json.Unmarshal(fetched, &artifact); err != nil { + return err + } + if artifact.Subject == nil || !content.Equal(*artifact.Subject, desc) { + continue + } + node.ArtifactType = artifact.ArtifactType + node.Annotations = artifact.Annotations + default: + continue + } + if artifactType == "" || artifactType == node.ArtifactType { + results = append(results, node) + } + } + return fn(results) +} + // validateReference validates ref. func validateReference(ref string) error { if ref == "" { diff --git a/content/oci/oci_test.go b/content/oci/oci_test.go index bba9037a..bcdc0e4b 100644 --- a/content/oci/oci_test.go +++ b/content/oci/oci_test.go @@ -2378,6 +2378,180 @@ func TestStore_UntagErrorPath(t *testing.T) { } } +func TestStore_Referrers(t *testing.T) { + tempDir := t.TempDir() + s, err := New(tempDir) + if err != nil { + t.Fatal("New() error =", err) + } + ctx := context.Background() + + // generate test content + var blobs [][]byte + var descs []ocispec.Descriptor + appendBlob := func(mediaType string, artifactType string, blob []byte) { + blobs = append(blobs, blob) + descs = append(descs, ocispec.Descriptor{ + MediaType: mediaType, + ArtifactType: artifactType, + Annotations: map[string]string{"test": "content"}, + Digest: digest.FromBytes(blob), + Size: int64(len(blob)), + }) + } + generateImageManifest := func(config ocispec.Descriptor, subject *ocispec.Descriptor, layers ...ocispec.Descriptor) { + manifest := ocispec.Manifest{ + MediaType: ocispec.MediaTypeImageManifest, + Config: config, + Subject: subject, + Layers: layers, + Annotations: map[string]string{"test": "content"}, + } + manifestJSON, err := json.Marshal(manifest) + if err != nil { + t.Fatal(err) + } + appendBlob(ocispec.MediaTypeImageManifest, manifest.Config.MediaType, manifestJSON) + } + generateArtifactManifest := func(subject *ocispec.Descriptor, blobs ...ocispec.Descriptor) { + artifact := spec.Artifact{ + MediaType: spec.MediaTypeArtifactManifest, + ArtifactType: "artifact", + Subject: subject, + Blobs: blobs, + Annotations: map[string]string{"test": "content"}, + } + manifestJSON, err := json.Marshal(artifact) + if err != nil { + t.Fatal(err) + } + appendBlob(spec.MediaTypeArtifactManifest, artifact.ArtifactType, manifestJSON) + } + generateIndex := func(subject *ocispec.Descriptor, manifests ...ocispec.Descriptor) { + index := ocispec.Index{ + MediaType: ocispec.MediaTypeImageIndex, + ArtifactType: "index", + Subject: subject, + Manifests: manifests, + Annotations: map[string]string{"test": "content"}, + } + indexJSON, err := json.Marshal(index) + if err != nil { + t.Fatal(err) + } + appendBlob(ocispec.MediaTypeImageIndex, index.ArtifactType, indexJSON) + } + + appendBlob("image manifest", "image config", []byte("config")) // Blob 0 + appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("foo")) // Blob 1 + appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("bar")) // Blob 2 + appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("hello")) // Blob 3 + generateImageManifest(descs[0], nil, descs[1]) // Blob 4 + generateArtifactManifest(&descs[4], descs[2]) // Blob 5 + generateImageManifest(descs[0], &descs[5], descs[3]) // Blob 6 + generateIndex(&descs[6], descs[4:6]...) // Blob 7 + generateIndex(&descs[4], descs[5:8]...) // Blob 8 + + eg, egCtx := errgroup.WithContext(ctx) + for i := range blobs { + eg.Go(func(i int) func() error { + return func() error { + err := s.Push(egCtx, descs[i], bytes.NewReader(blobs[i])) + if err != nil { + return fmt.Errorf("failed to push test content to src: %d: %v", i, err) + } + return nil + } + }(i)) + } + if err := eg.Wait(); err != nil { + t.Fatal(err) + } + + // verify predecessors + wantedPredecessors := [][]ocispec.Descriptor{ + {descs[4], descs[6]}, // Blob 0 + {descs[4]}, // Blob 1 + {descs[5]}, // Blob 2 + {descs[6]}, // Blob 3 + {descs[5], descs[7], descs[8]}, // Blob 4 + {descs[6], descs[7], descs[8]}, // Blob 5 + {descs[7], descs[8]}, // Blob 6 + {descs[8]}, // Blob 7 + nil, // Blob 8 + } + for i, want := range wantedPredecessors { + predecessors, err := s.Predecessors(ctx, descs[i]) + if err != nil { + t.Errorf("Store.Predecessors(%d) error = %v", i, err) + } + if !equalDescriptorSet(predecessors, want) { + t.Errorf("Store.Predecessors(%d) = %v, want %v", i, predecessors, want) + } + } + + // verify referrers + wantedReferrers := [][]ocispec.Descriptor{ + nil, // Blob 0 + nil, // Blob 1 + nil, // Blob 2 + nil, // Blob 3 + {descs[5], descs[8]}, // Blob 4 + {descs[6]}, // Blob 5 + {descs[7]}, // Blob 6 + nil, // Blob 7 + nil, // Blob 8 + } + for i := 4; i < len(wantedReferrers); i++ { + want := wantedReferrers[i] + var results []ocispec.Descriptor + err := s.Referrers(ctx, descs[i], "", func(referrers []ocispec.Descriptor) error { + results = append(results, referrers...) + return nil + }) + if err != nil { + t.Errorf("Store.Referrers(%d) error = %v", i, err) + } + if !equalDescriptorSet(results, want) { + t.Errorf("Store.Predecessors(%d) = %v, want %v", i, results, want) + } + } + + // test filtering on ArtifactType + wantedReferrers = [][]ocispec.Descriptor{ + nil, // Blob 0 + nil, // Blob 1 + nil, // Blob 2 + nil, // Blob 3 + nil, // Blob 4 + {descs[6]}, // Blob 5 + nil, // Blob 6 + nil, // Blob 7 + nil, // Blob 8 + } + for i := 4; i < len(wantedReferrers); i++ { + want := wantedReferrers[i] + var results []ocispec.Descriptor + err := s.Referrers(ctx, descs[i], "image manifest", func(referrers []ocispec.Descriptor) error { + results = append(results, referrers...) + return nil + }) + if err != nil { + t.Errorf("Store.Referrers(%d) error = %v", i, err) + } + if !equalDescriptorSet(results, want) { + t.Errorf("Store.Predecessors(%d) = %v, want %v", i, results, want) + } + } +} + +func TestStore_ReferrersInterface(t *testing.T) { + var store interface{} = &Store{} + if _, ok := store.(registry.ReferrerLister); !ok { + t.Error("&Store{} does not conform to registry.ReferrerLister") + } +} + func equalDescriptorSet(actual []ocispec.Descriptor, expected []ocispec.Descriptor) bool { if len(actual) != len(expected) { return false From 7444a42093883c1557c37bfa5b16640c7fcc8ce4 Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Wed, 20 Dec 2023 12:43:28 +0800 Subject: [PATCH 02/13] generic implementation Signed-off-by: Xiaoxuan Wang --- content/oci/oci.go | 78 --------------------------------------- content/oci/oci_test.go | 11 +----- registry/repository.go | 82 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 87 deletions(-) diff --git a/content/oci/oci.go b/content/oci/oci.go index 92bb4652..1deca875 100644 --- a/content/oci/oci.go +++ b/content/oci/oci.go @@ -36,7 +36,6 @@ import ( "oras.land/oras-go/v2/internal/descriptor" "oras.land/oras-go/v2/internal/graph" "oras.land/oras-go/v2/internal/resolver" - "oras.land/oras-go/v2/internal/spec" ) // Store implements `oras.Target`, and represents a content store @@ -399,83 +398,6 @@ func (s *Store) writeIndexFile() error { return os.WriteFile(s.indexPath, indexJSON, 0666) } -// Referrers lists the descriptors of image or artifact manifests directly -// referencing the given manifest descriptor. -// -// fn is called on the referrer results. If artifactType is not empty, only -// referrers of the same artifact type are fed to fn. -// -// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#listing-referrers -func (s *Store) Referrers(ctx context.Context, desc ocispec.Descriptor, artifactType string, fn func(referrers []ocispec.Descriptor) error) error { - s.sync.RLock() - defer s.sync.RUnlock() - - if !descriptor.IsManifest(desc) { - return fmt.Errorf("the descriptor %v is not a manifest", desc) - } - var results []ocispec.Descriptor - predecessors, err := s.Predecessors(ctx, desc) - if err != nil { - return err - } - for _, node := range predecessors { - switch node.MediaType { - case ocispec.MediaTypeImageManifest: - fetched, err := content.FetchAll(ctx, s, node) - if err != nil { - return err - } - var manifest ocispec.Manifest - if err := json.Unmarshal(fetched, &manifest); err != nil { - return err - } - if manifest.Subject == nil || !content.Equal(*manifest.Subject, desc) { - continue - } - if manifest.ArtifactType != "" { - node.ArtifactType = manifest.ArtifactType - } else { - node.ArtifactType = manifest.Config.MediaType - } - node.Annotations = manifest.Annotations - case ocispec.MediaTypeImageIndex: - fetched, err := content.FetchAll(ctx, s, node) - if err != nil { - return err - } - var index ocispec.Index - if err := json.Unmarshal(fetched, &index); err != nil { - return err - } - if index.Subject == nil || !content.Equal(*index.Subject, desc) { - continue - } - node.ArtifactType = index.ArtifactType - node.Annotations = index.Annotations - case spec.MediaTypeArtifactManifest: - fetched, err := content.FetchAll(ctx, s, node) - if err != nil { - return err - } - var artifact spec.Artifact - if err := json.Unmarshal(fetched, &artifact); err != nil { - return err - } - if artifact.Subject == nil || !content.Equal(*artifact.Subject, desc) { - continue - } - node.ArtifactType = artifact.ArtifactType - node.Annotations = artifact.Annotations - default: - continue - } - if artifactType == "" || artifactType == node.ArtifactType { - results = append(results, node) - } - } - return fn(results) -} - // validateReference validates ref. func validateReference(ref string) error { if ref == "" { diff --git a/content/oci/oci_test.go b/content/oci/oci_test.go index bcdc0e4b..c948be3a 100644 --- a/content/oci/oci_test.go +++ b/content/oci/oci_test.go @@ -2505,7 +2505,7 @@ func TestStore_Referrers(t *testing.T) { for i := 4; i < len(wantedReferrers); i++ { want := wantedReferrers[i] var results []ocispec.Descriptor - err := s.Referrers(ctx, descs[i], "", func(referrers []ocispec.Descriptor) error { + err := registry.Referrers(ctx, s, descs[i], "", func(referrers []ocispec.Descriptor) error { results = append(results, referrers...) return nil }) @@ -2532,7 +2532,7 @@ func TestStore_Referrers(t *testing.T) { for i := 4; i < len(wantedReferrers); i++ { want := wantedReferrers[i] var results []ocispec.Descriptor - err := s.Referrers(ctx, descs[i], "image manifest", func(referrers []ocispec.Descriptor) error { + err := registry.Referrers(ctx, s, descs[i], "image manifest", func(referrers []ocispec.Descriptor) error { results = append(results, referrers...) return nil }) @@ -2545,13 +2545,6 @@ func TestStore_Referrers(t *testing.T) { } } -func TestStore_ReferrersInterface(t *testing.T) { - var store interface{} = &Store{} - if _, ok := store.(registry.ReferrerLister); !ok { - t.Error("&Store{} does not conform to registry.ReferrerLister") - } -} - func equalDescriptorSet(actual []ocispec.Descriptor, expected []ocispec.Descriptor) bool { if len(actual) != len(expected) { return false diff --git a/registry/repository.go b/registry/repository.go index b75b7b8e..36f73cba 100644 --- a/registry/repository.go +++ b/registry/repository.go @@ -17,10 +17,14 @@ package registry import ( "context" + "encoding/json" + "fmt" "io" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "oras.land/oras-go/v2/content" + "oras.land/oras-go/v2/internal/descriptor" + "oras.land/oras-go/v2/internal/spec" ) // Repository is an ORAS target and an union of the blob and the manifest CASs. @@ -134,3 +138,81 @@ func Tags(ctx context.Context, repo TagLister) ([]string, error) { } return res, nil } + +// Referrers lists the descriptors of image or artifact manifests directly +// referencing the given manifest descriptor. +// +// fn is called on the referrer results. If artifactType is not empty, only +// referrers of the same artifact type are fed to fn. +// +// Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#listing-referrers +func Referrers(ctx context.Context, store content.ReadOnlyGraphStorage, desc ocispec.Descriptor, artifactType string, fn func(referrers []ocispec.Descriptor) error) error { + if !descriptor.IsManifest(desc) { + return fmt.Errorf("the descriptor %v is not a manifest", desc) + } + // use the Referrer API if it is available + if rf, ok := store.(ReferrerLister); ok { + return rf.Referrers(ctx, desc, artifactType, fn) + } + var results []ocispec.Descriptor + predecessors, err := store.Predecessors(ctx, desc) + if err != nil { + return err + } + for _, node := range predecessors { + switch node.MediaType { + case ocispec.MediaTypeImageManifest: + fetched, err := content.FetchAll(ctx, store, node) + if err != nil { + return err + } + var manifest ocispec.Manifest + if err := json.Unmarshal(fetched, &manifest); err != nil { + return err + } + if manifest.Subject == nil || !content.Equal(*manifest.Subject, desc) { + continue + } + if manifest.ArtifactType != "" { + node.ArtifactType = manifest.ArtifactType + } else { + node.ArtifactType = manifest.Config.MediaType + } + node.Annotations = manifest.Annotations + case ocispec.MediaTypeImageIndex: + fetched, err := content.FetchAll(ctx, store, node) + if err != nil { + return err + } + var index ocispec.Index + if err := json.Unmarshal(fetched, &index); err != nil { + return err + } + if index.Subject == nil || !content.Equal(*index.Subject, desc) { + continue + } + node.ArtifactType = index.ArtifactType + node.Annotations = index.Annotations + case spec.MediaTypeArtifactManifest: + fetched, err := content.FetchAll(ctx, store, node) + if err != nil { + return err + } + var artifact spec.Artifact + if err := json.Unmarshal(fetched, &artifact); err != nil { + return err + } + if artifact.Subject == nil || !content.Equal(*artifact.Subject, desc) { + continue + } + node.ArtifactType = artifact.ArtifactType + node.Annotations = artifact.Annotations + default: + continue + } + if artifactType == "" || artifactType == node.ArtifactType { + results = append(results, node) + } + } + return fn(results) +} From b1205f4c1f53db8a08de44e2a7e17ef7aa36adee Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Wed, 20 Dec 2023 14:24:09 +0800 Subject: [PATCH 03/13] resolved comments Signed-off-by: Xiaoxuan Wang --- content/oci/oci_test.go | 167 ---------------------------------------- registry/repository.go | 3 +- 2 files changed, 2 insertions(+), 168 deletions(-) diff --git a/content/oci/oci_test.go b/content/oci/oci_test.go index c948be3a..bba9037a 100644 --- a/content/oci/oci_test.go +++ b/content/oci/oci_test.go @@ -2378,173 +2378,6 @@ func TestStore_UntagErrorPath(t *testing.T) { } } -func TestStore_Referrers(t *testing.T) { - tempDir := t.TempDir() - s, err := New(tempDir) - if err != nil { - t.Fatal("New() error =", err) - } - ctx := context.Background() - - // generate test content - var blobs [][]byte - var descs []ocispec.Descriptor - appendBlob := func(mediaType string, artifactType string, blob []byte) { - blobs = append(blobs, blob) - descs = append(descs, ocispec.Descriptor{ - MediaType: mediaType, - ArtifactType: artifactType, - Annotations: map[string]string{"test": "content"}, - Digest: digest.FromBytes(blob), - Size: int64(len(blob)), - }) - } - generateImageManifest := func(config ocispec.Descriptor, subject *ocispec.Descriptor, layers ...ocispec.Descriptor) { - manifest := ocispec.Manifest{ - MediaType: ocispec.MediaTypeImageManifest, - Config: config, - Subject: subject, - Layers: layers, - Annotations: map[string]string{"test": "content"}, - } - manifestJSON, err := json.Marshal(manifest) - if err != nil { - t.Fatal(err) - } - appendBlob(ocispec.MediaTypeImageManifest, manifest.Config.MediaType, manifestJSON) - } - generateArtifactManifest := func(subject *ocispec.Descriptor, blobs ...ocispec.Descriptor) { - artifact := spec.Artifact{ - MediaType: spec.MediaTypeArtifactManifest, - ArtifactType: "artifact", - Subject: subject, - Blobs: blobs, - Annotations: map[string]string{"test": "content"}, - } - manifestJSON, err := json.Marshal(artifact) - if err != nil { - t.Fatal(err) - } - appendBlob(spec.MediaTypeArtifactManifest, artifact.ArtifactType, manifestJSON) - } - generateIndex := func(subject *ocispec.Descriptor, manifests ...ocispec.Descriptor) { - index := ocispec.Index{ - MediaType: ocispec.MediaTypeImageIndex, - ArtifactType: "index", - Subject: subject, - Manifests: manifests, - Annotations: map[string]string{"test": "content"}, - } - indexJSON, err := json.Marshal(index) - if err != nil { - t.Fatal(err) - } - appendBlob(ocispec.MediaTypeImageIndex, index.ArtifactType, indexJSON) - } - - appendBlob("image manifest", "image config", []byte("config")) // Blob 0 - appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("foo")) // Blob 1 - appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("bar")) // Blob 2 - appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("hello")) // Blob 3 - generateImageManifest(descs[0], nil, descs[1]) // Blob 4 - generateArtifactManifest(&descs[4], descs[2]) // Blob 5 - generateImageManifest(descs[0], &descs[5], descs[3]) // Blob 6 - generateIndex(&descs[6], descs[4:6]...) // Blob 7 - generateIndex(&descs[4], descs[5:8]...) // Blob 8 - - eg, egCtx := errgroup.WithContext(ctx) - for i := range blobs { - eg.Go(func(i int) func() error { - return func() error { - err := s.Push(egCtx, descs[i], bytes.NewReader(blobs[i])) - if err != nil { - return fmt.Errorf("failed to push test content to src: %d: %v", i, err) - } - return nil - } - }(i)) - } - if err := eg.Wait(); err != nil { - t.Fatal(err) - } - - // verify predecessors - wantedPredecessors := [][]ocispec.Descriptor{ - {descs[4], descs[6]}, // Blob 0 - {descs[4]}, // Blob 1 - {descs[5]}, // Blob 2 - {descs[6]}, // Blob 3 - {descs[5], descs[7], descs[8]}, // Blob 4 - {descs[6], descs[7], descs[8]}, // Blob 5 - {descs[7], descs[8]}, // Blob 6 - {descs[8]}, // Blob 7 - nil, // Blob 8 - } - for i, want := range wantedPredecessors { - predecessors, err := s.Predecessors(ctx, descs[i]) - if err != nil { - t.Errorf("Store.Predecessors(%d) error = %v", i, err) - } - if !equalDescriptorSet(predecessors, want) { - t.Errorf("Store.Predecessors(%d) = %v, want %v", i, predecessors, want) - } - } - - // verify referrers - wantedReferrers := [][]ocispec.Descriptor{ - nil, // Blob 0 - nil, // Blob 1 - nil, // Blob 2 - nil, // Blob 3 - {descs[5], descs[8]}, // Blob 4 - {descs[6]}, // Blob 5 - {descs[7]}, // Blob 6 - nil, // Blob 7 - nil, // Blob 8 - } - for i := 4; i < len(wantedReferrers); i++ { - want := wantedReferrers[i] - var results []ocispec.Descriptor - err := registry.Referrers(ctx, s, descs[i], "", func(referrers []ocispec.Descriptor) error { - results = append(results, referrers...) - return nil - }) - if err != nil { - t.Errorf("Store.Referrers(%d) error = %v", i, err) - } - if !equalDescriptorSet(results, want) { - t.Errorf("Store.Predecessors(%d) = %v, want %v", i, results, want) - } - } - - // test filtering on ArtifactType - wantedReferrers = [][]ocispec.Descriptor{ - nil, // Blob 0 - nil, // Blob 1 - nil, // Blob 2 - nil, // Blob 3 - nil, // Blob 4 - {descs[6]}, // Blob 5 - nil, // Blob 6 - nil, // Blob 7 - nil, // Blob 8 - } - for i := 4; i < len(wantedReferrers); i++ { - want := wantedReferrers[i] - var results []ocispec.Descriptor - err := registry.Referrers(ctx, s, descs[i], "image manifest", func(referrers []ocispec.Descriptor) error { - results = append(results, referrers...) - return nil - }) - if err != nil { - t.Errorf("Store.Referrers(%d) error = %v", i, err) - } - if !equalDescriptorSet(results, want) { - t.Errorf("Store.Predecessors(%d) = %v, want %v", i, results, want) - } - } -} - func equalDescriptorSet(actual []ocispec.Descriptor, expected []ocispec.Descriptor) bool { if len(actual) != len(expected) { return false diff --git a/registry/repository.go b/registry/repository.go index 36f73cba..7d22475b 100644 --- a/registry/repository.go +++ b/registry/repository.go @@ -23,6 +23,7 @@ import ( ocispec "github.com/opencontainers/image-spec/specs-go/v1" "oras.land/oras-go/v2/content" + "oras.land/oras-go/v2/errdef" "oras.land/oras-go/v2/internal/descriptor" "oras.land/oras-go/v2/internal/spec" ) @@ -148,7 +149,7 @@ func Tags(ctx context.Context, repo TagLister) ([]string, error) { // Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#listing-referrers func Referrers(ctx context.Context, store content.ReadOnlyGraphStorage, desc ocispec.Descriptor, artifactType string, fn func(referrers []ocispec.Descriptor) error) error { if !descriptor.IsManifest(desc) { - return fmt.Errorf("the descriptor %v is not a manifest", desc) + return fmt.Errorf("the descriptor %v is not a manifest: %w", desc, errdef.ErrUnsupported) } // use the Referrer API if it is available if rf, ok := store.(ReferrerLister); ok { From 0b22ea74854dace01aad7a068a57146c843dfb34 Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Wed, 20 Dec 2023 15:46:55 +0800 Subject: [PATCH 04/13] added unit test Signed-off-by: Xiaoxuan Wang --- registry/repository_test.go | 238 ++++++++++++++++++++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 registry/repository_test.go diff --git a/registry/repository_test.go b/registry/repository_test.go new file mode 100644 index 00000000..d7642063 --- /dev/null +++ b/registry/repository_test.go @@ -0,0 +1,238 @@ +/* +Copyright The ORAS Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package registry + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "reflect" + "testing" + + "github.com/opencontainers/go-digest" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "golang.org/x/sync/errgroup" + "oras.land/oras-go/v2/content/memory" + "oras.land/oras-go/v2/internal/spec" +) + +// testStorage implements content.ReadOnlyGraphStorage +type testStorage struct { + store *memory.Store +} + +func (s *testStorage) Push(ctx context.Context, expected ocispec.Descriptor, reader io.Reader) error { + return s.store.Push(ctx, expected, reader) +} + +func (s *testStorage) Fetch(ctx context.Context, target ocispec.Descriptor) (io.ReadCloser, error) { + return s.store.Fetch(ctx, target) +} + +func (s *testStorage) Exists(ctx context.Context, target ocispec.Descriptor) (bool, error) { + return s.store.Exists(ctx, target) +} + +func (s *testStorage) Predecessors(ctx context.Context, node ocispec.Descriptor) ([]ocispec.Descriptor, error) { + return s.store.Predecessors(ctx, node) +} + +func TestReferrers(t *testing.T) { + s := testStorage{ + store: memory.New(), + } + ctx := context.Background() + + // generate test content + var blobs [][]byte + var descs []ocispec.Descriptor + appendBlob := func(mediaType string, artifactType string, blob []byte) { + blobs = append(blobs, blob) + descs = append(descs, ocispec.Descriptor{ + MediaType: mediaType, + ArtifactType: artifactType, + Annotations: map[string]string{"test": "content"}, + Digest: digest.FromBytes(blob), + Size: int64(len(blob)), + }) + } + generateImageManifest := func(config ocispec.Descriptor, subject *ocispec.Descriptor, layers ...ocispec.Descriptor) { + manifest := ocispec.Manifest{ + MediaType: ocispec.MediaTypeImageManifest, + Config: config, + Subject: subject, + Layers: layers, + Annotations: map[string]string{"test": "content"}, + } + manifestJSON, err := json.Marshal(manifest) + if err != nil { + t.Fatal(err) + } + appendBlob(ocispec.MediaTypeImageManifest, manifest.Config.MediaType, manifestJSON) + } + generateArtifactManifest := func(subject *ocispec.Descriptor, blobs ...ocispec.Descriptor) { + artifact := spec.Artifact{ + MediaType: spec.MediaTypeArtifactManifest, + ArtifactType: "artifact", + Subject: subject, + Blobs: blobs, + Annotations: map[string]string{"test": "content"}, + } + manifestJSON, err := json.Marshal(artifact) + if err != nil { + t.Fatal(err) + } + appendBlob(spec.MediaTypeArtifactManifest, artifact.ArtifactType, manifestJSON) + } + generateIndex := func(subject *ocispec.Descriptor, manifests ...ocispec.Descriptor) { + index := ocispec.Index{ + MediaType: ocispec.MediaTypeImageIndex, + ArtifactType: "index", + Subject: subject, + Manifests: manifests, + Annotations: map[string]string{"test": "content"}, + } + indexJSON, err := json.Marshal(index) + if err != nil { + t.Fatal(err) + } + appendBlob(ocispec.MediaTypeImageIndex, index.ArtifactType, indexJSON) + } + + appendBlob("image manifest", "image config", []byte("config")) // Blob 0 + appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("foo")) // Blob 1 + appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("bar")) // Blob 2 + appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("hello")) // Blob 3 + generateImageManifest(descs[0], nil, descs[1]) // Blob 4 + generateArtifactManifest(&descs[4], descs[2]) // Blob 5 + generateImageManifest(descs[0], &descs[5], descs[3]) // Blob 6 + generateIndex(&descs[6], descs[4:6]...) // Blob 7 + generateIndex(&descs[4], descs[5:8]...) // Blob 8 + + eg, egCtx := errgroup.WithContext(ctx) + for i := range blobs { + eg.Go(func(i int) func() error { + return func() error { + err := s.Push(egCtx, descs[i], bytes.NewReader(blobs[i])) + if err != nil { + return fmt.Errorf("failed to push test content to src: %d: %v", i, err) + } + return nil + } + }(i)) + } + if err := eg.Wait(); err != nil { + t.Fatal(err) + } + + // verify predecessors + wantedPredecessors := [][]ocispec.Descriptor{ + {descs[4], descs[6]}, // Blob 0 + {descs[4]}, // Blob 1 + {descs[5]}, // Blob 2 + {descs[6]}, // Blob 3 + {descs[5], descs[7], descs[8]}, // Blob 4 + {descs[6], descs[7], descs[8]}, // Blob 5 + {descs[7], descs[8]}, // Blob 6 + {descs[8]}, // Blob 7 + nil, // Blob 8 + } + for i, want := range wantedPredecessors { + predecessors, err := s.Predecessors(ctx, descs[i]) + if err != nil { + t.Errorf("Store.Predecessors(%d) error = %v", i, err) + } + if !equalDescriptorSet(predecessors, want) { + t.Errorf("Store.Predecessors(%d) = %v, want %v", i, predecessors, want) + } + } + + // verify referrers + wantedReferrers := [][]ocispec.Descriptor{ + nil, // Blob 0 + nil, // Blob 1 + nil, // Blob 2 + nil, // Blob 3 + {descs[5], descs[8]}, // Blob 4 + {descs[6]}, // Blob 5 + {descs[7]}, // Blob 6 + nil, // Blob 7 + nil, // Blob 8 + } + for i := 4; i < len(wantedReferrers); i++ { + want := wantedReferrers[i] + var results []ocispec.Descriptor + err := Referrers(ctx, &s, descs[i], "", func(referrers []ocispec.Descriptor) error { + results = append(results, referrers...) + return nil + }) + if err != nil { + t.Errorf("Store.Referrers(%d) error = %v", i, err) + } + if !equalDescriptorSet(results, want) { + t.Errorf("Store.Predecessors(%d) = %v, want %v", i, results, want) + } + } + + // test filtering on ArtifactType + wantedReferrers = [][]ocispec.Descriptor{ + nil, // Blob 0 + nil, // Blob 1 + nil, // Blob 2 + nil, // Blob 3 + nil, // Blob 4 + {descs[6]}, // Blob 5 + nil, // Blob 6 + nil, // Blob 7 + nil, // Blob 8 + } + for i := 4; i < len(wantedReferrers); i++ { + want := wantedReferrers[i] + var results []ocispec.Descriptor + err := Referrers(ctx, &s, descs[i], "image manifest", func(referrers []ocispec.Descriptor) error { + results = append(results, referrers...) + return nil + }) + if err != nil { + t.Errorf("Store.Referrers(%d) error = %v", i, err) + } + if !equalDescriptorSet(results, want) { + t.Errorf("Store.Predecessors(%d) = %v, want %v", i, results, want) + } + } +} + +func equalDescriptorSet(actual []ocispec.Descriptor, expected []ocispec.Descriptor) bool { + if len(actual) != len(expected) { + return false + } + contains := func(node ocispec.Descriptor) bool { + for _, candidate := range actual { + if reflect.DeepEqual(candidate, node) { + return true + } + } + return false + } + for _, node := range expected { + if !contains(node) { + return false + } + } + return true +} From a0dccadffba562b31ed6a4d249e772f1fa3554c7 Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Sun, 24 Dec 2023 18:10:02 +0800 Subject: [PATCH 05/13] changed the function signature Signed-off-by: Xiaoxuan Wang --- registry/repository.go | 44 ++++++++++++++++++++++--------------- registry/repository_test.go | 12 ++-------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/registry/repository.go b/registry/repository.go index 7d22475b..d244f44d 100644 --- a/registry/repository.go +++ b/registry/repository.go @@ -143,51 +143,57 @@ func Tags(ctx context.Context, repo TagLister) ([]string, error) { // Referrers lists the descriptors of image or artifact manifests directly // referencing the given manifest descriptor. // -// fn is called on the referrer results. If artifactType is not empty, only -// referrers of the same artifact type are fed to fn. -// // Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#listing-referrers -func Referrers(ctx context.Context, store content.ReadOnlyGraphStorage, desc ocispec.Descriptor, artifactType string, fn func(referrers []ocispec.Descriptor) error) error { + +func Referrers(ctx context.Context, store content.ReadOnlyGraphStorage, desc ocispec.Descriptor, artifactType string) ([]ocispec.Descriptor, error) { if !descriptor.IsManifest(desc) { - return fmt.Errorf("the descriptor %v is not a manifest: %w", desc, errdef.ErrUnsupported) + return nil, fmt.Errorf("the descriptor %v is not a manifest: %w", desc, errdef.ErrUnsupported) } + + var results []ocispec.Descriptor + // use the Referrer API if it is available if rf, ok := store.(ReferrerLister); ok { - return rf.Referrers(ctx, desc, artifactType, fn) + if err := rf.Referrers(ctx, desc, artifactType, func(referrers []ocispec.Descriptor) error { + results = append(results, referrers...) + return nil + }); err != nil { + return nil, err + } + return results, nil } - var results []ocispec.Descriptor + predecessors, err := store.Predecessors(ctx, desc) if err != nil { - return err + return nil, err } for _, node := range predecessors { switch node.MediaType { case ocispec.MediaTypeImageManifest: fetched, err := content.FetchAll(ctx, store, node) if err != nil { - return err + return nil, err } var manifest ocispec.Manifest if err := json.Unmarshal(fetched, &manifest); err != nil { - return err + return nil, err } if manifest.Subject == nil || !content.Equal(*manifest.Subject, desc) { continue } - if manifest.ArtifactType != "" { - node.ArtifactType = manifest.ArtifactType - } else { + node.ArtifactType = manifest.ArtifactType + if node.ArtifactType == "" { node.ArtifactType = manifest.Config.MediaType } node.Annotations = manifest.Annotations case ocispec.MediaTypeImageIndex: fetched, err := content.FetchAll(ctx, store, node) if err != nil { - return err + return nil, err } var index ocispec.Index if err := json.Unmarshal(fetched, &index); err != nil { - return err + return nil, err } if index.Subject == nil || !content.Equal(*index.Subject, desc) { continue @@ -197,11 +203,11 @@ func Referrers(ctx context.Context, store content.ReadOnlyGraphStorage, desc oci case spec.MediaTypeArtifactManifest: fetched, err := content.FetchAll(ctx, store, node) if err != nil { - return err + return nil, err } var artifact spec.Artifact if err := json.Unmarshal(fetched, &artifact); err != nil { - return err + return nil, err } if artifact.Subject == nil || !content.Equal(*artifact.Subject, desc) { continue @@ -212,8 +218,10 @@ func Referrers(ctx context.Context, store content.ReadOnlyGraphStorage, desc oci continue } if artifactType == "" || artifactType == node.ArtifactType { + // the field artifactType in referrers descriptor is allowed to be empty + // https://github.com/opencontainers/distribution-spec/issues/458 results = append(results, node) } } - return fn(results) + return results, nil } diff --git a/registry/repository_test.go b/registry/repository_test.go index d7642063..8a138441 100644 --- a/registry/repository_test.go +++ b/registry/repository_test.go @@ -176,11 +176,7 @@ func TestReferrers(t *testing.T) { } for i := 4; i < len(wantedReferrers); i++ { want := wantedReferrers[i] - var results []ocispec.Descriptor - err := Referrers(ctx, &s, descs[i], "", func(referrers []ocispec.Descriptor) error { - results = append(results, referrers...) - return nil - }) + results, err := Referrers(ctx, &s, descs[i], "") if err != nil { t.Errorf("Store.Referrers(%d) error = %v", i, err) } @@ -203,11 +199,7 @@ func TestReferrers(t *testing.T) { } for i := 4; i < len(wantedReferrers); i++ { want := wantedReferrers[i] - var results []ocispec.Descriptor - err := Referrers(ctx, &s, descs[i], "image manifest", func(referrers []ocispec.Descriptor) error { - results = append(results, referrers...) - return nil - }) + results, err := Referrers(ctx, &s, descs[i], "image manifest") if err != nil { t.Errorf("Store.Referrers(%d) error = %v", i, err) } From 7ec19a16a840faddb95ef90a7e60f9d1e253a26f Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Sun, 24 Dec 2023 19:33:03 +0800 Subject: [PATCH 06/13] added test cases Signed-off-by: Xiaoxuan Wang --- registry/repository_test.go | 77 ++++++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 9 deletions(-) diff --git a/registry/repository_test.go b/registry/repository_test.go index 8a138441..dcb71487 100644 --- a/registry/repository_test.go +++ b/registry/repository_test.go @@ -19,6 +19,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "io" "reflect" @@ -28,6 +29,8 @@ import ( ocispec "github.com/opencontainers/image-spec/specs-go/v1" "golang.org/x/sync/errgroup" "oras.land/oras-go/v2/content/memory" + "oras.land/oras-go/v2/errdef" + "oras.land/oras-go/v2/internal/docker" "oras.land/oras-go/v2/internal/spec" ) @@ -52,6 +55,16 @@ func (s *testStorage) Predecessors(ctx context.Context, node ocispec.Descriptor) return s.store.Predecessors(ctx, node) } +// TestReferrerLister implements content.ReadOnlyGraphStorage and registry.ReferrerLister +type TestReferrerLister struct { + *testStorage +} + +func (rl *TestReferrerLister) Referrers(ctx context.Context, desc ocispec.Descriptor, artifactType string, fn func(referrers []ocispec.Descriptor) error) error { + results := []ocispec.Descriptor{desc} + return fn(results) +} + func TestReferrers(t *testing.T) { s := testStorage{ store: memory.New(), @@ -113,6 +126,17 @@ func TestReferrers(t *testing.T) { } appendBlob(ocispec.MediaTypeImageIndex, index.ArtifactType, indexJSON) } + generateManifestList := func(manifests ...ocispec.Descriptor) { + index := ocispec.Index{ + ArtifactType: "manifest list", + Manifests: manifests, + } + indexJSON, err := json.Marshal(index) + if err != nil { + t.Fatal(err) + } + appendBlob(docker.MediaTypeManifestList, index.ArtifactType, indexJSON) + } appendBlob("image manifest", "image config", []byte("config")) // Blob 0 appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("foo")) // Blob 1 @@ -123,6 +147,7 @@ func TestReferrers(t *testing.T) { generateImageManifest(descs[0], &descs[5], descs[3]) // Blob 6 generateIndex(&descs[6], descs[4:6]...) // Blob 7 generateIndex(&descs[4], descs[5:8]...) // Blob 8 + generateManifestList(descs[4:7]...) // blob 9 eg, egCtx := errgroup.WithContext(ctx) for i := range blobs { @@ -142,15 +167,16 @@ func TestReferrers(t *testing.T) { // verify predecessors wantedPredecessors := [][]ocispec.Descriptor{ - {descs[4], descs[6]}, // Blob 0 - {descs[4]}, // Blob 1 - {descs[5]}, // Blob 2 - {descs[6]}, // Blob 3 - {descs[5], descs[7], descs[8]}, // Blob 4 - {descs[6], descs[7], descs[8]}, // Blob 5 - {descs[7], descs[8]}, // Blob 6 - {descs[8]}, // Blob 7 - nil, // Blob 8 + {descs[4], descs[6]}, // Blob 0 + {descs[4]}, // Blob 1 + {descs[5]}, // Blob 2 + {descs[6]}, // Blob 3 + {descs[5], descs[7], descs[8], descs[9]}, // Blob 4 + {descs[6], descs[7], descs[8], descs[9]}, // Blob 5 + {descs[7], descs[8], descs[9]}, // Blob 6 + {descs[8]}, // Blob 7 + nil, // Blob 8 + nil, // Blob 9 } for i, want := range wantedPredecessors { predecessors, err := s.Predecessors(ctx, descs[i]) @@ -173,6 +199,13 @@ func TestReferrers(t *testing.T) { {descs[7]}, // Blob 6 nil, // Blob 7 nil, // Blob 8 + nil, // Blob 9 + } + for i := 0; i <= 3; i++ { + _, err := Referrers(ctx, &s, descs[i], "") + if !errors.Is(err, errdef.ErrUnsupported) { + t.Errorf("Store.Referrers(%d) error = %v, want %v", i, err, errdef.ErrUnsupported) + } } for i := 4; i < len(wantedReferrers); i++ { want := wantedReferrers[i] @@ -196,6 +229,7 @@ func TestReferrers(t *testing.T) { nil, // Blob 6 nil, // Blob 7 nil, // Blob 8 + nil, // Blob 9 } for i := 4; i < len(wantedReferrers); i++ { want := wantedReferrers[i] @@ -207,6 +241,31 @@ func TestReferrers(t *testing.T) { t.Errorf("Store.Predecessors(%d) = %v, want %v", i, results, want) } } + + // test ReferrerLister + rl := TestReferrerLister{testStorage: &s} + wantedReferrers = [][]ocispec.Descriptor{ + nil, // Blob 0 + nil, // Blob 1 + nil, // Blob 2 + nil, // Blob 3 + {descs[4]}, // Blob 4 + {descs[5]}, // Blob 5 + {descs[6]}, // Blob 6 + {descs[7]}, // Blob 7 + {descs[8]}, // Blob 8 + {descs[9]}, // Blob 9 + } + for i := 4; i < len(wantedReferrers); i++ { + want := wantedReferrers[i] + results, err := Referrers(ctx, &rl, descs[i], "") + if err != nil { + t.Errorf("Store.Referrers(%d) error = %v", i, err) + } + if !equalDescriptorSet(results, want) { + t.Errorf("Store.Predecessors(%d) = %v, want %v", i, results, want) + } + } } func equalDescriptorSet(actual []ocispec.Descriptor, expected []ocispec.Descriptor) bool { From 70afd23369014987eb347c18e595932a33b1ca93 Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Mon, 25 Dec 2023 10:03:19 +0800 Subject: [PATCH 07/13] removed empty line Signed-off-by: Xiaoxuan Wang --- registry/repository.go | 1 - 1 file changed, 1 deletion(-) diff --git a/registry/repository.go b/registry/repository.go index d244f44d..394a9aa8 100644 --- a/registry/repository.go +++ b/registry/repository.go @@ -144,7 +144,6 @@ func Tags(ctx context.Context, repo TagLister) ([]string, error) { // referencing the given manifest descriptor. // // Reference: https://github.com/opencontainers/distribution-spec/blob/v1.1.0-rc3/spec.md#listing-referrers - func Referrers(ctx context.Context, store content.ReadOnlyGraphStorage, desc ocispec.Descriptor, artifactType string) ([]ocispec.Descriptor, error) { if !descriptor.IsManifest(desc) { return nil, fmt.Errorf("the descriptor %v is not a manifest: %w", desc, errdef.ErrUnsupported) From dea20f832dd06d801af07d866667a949aa8c2b5b Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Tue, 26 Dec 2023 13:48:29 +0800 Subject: [PATCH 08/13] increase coverage Signed-off-by: Xiaoxuan Wang --- registry/repository_test.go | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/registry/repository_test.go b/registry/repository_test.go index dcb71487..18411893 100644 --- a/registry/repository_test.go +++ b/registry/repository_test.go @@ -148,6 +148,7 @@ func TestReferrers(t *testing.T) { generateIndex(&descs[6], descs[4:6]...) // Blob 7 generateIndex(&descs[4], descs[5:8]...) // Blob 8 generateManifestList(descs[4:7]...) // blob 9 + generateImageManifest(descs[0], nil, descs[4]) // Blob 10 eg, egCtx := errgroup.WithContext(ctx) for i := range blobs { @@ -167,16 +168,16 @@ func TestReferrers(t *testing.T) { // verify predecessors wantedPredecessors := [][]ocispec.Descriptor{ - {descs[4], descs[6]}, // Blob 0 - {descs[4]}, // Blob 1 - {descs[5]}, // Blob 2 - {descs[6]}, // Blob 3 - {descs[5], descs[7], descs[8], descs[9]}, // Blob 4 - {descs[6], descs[7], descs[8], descs[9]}, // Blob 5 - {descs[7], descs[8], descs[9]}, // Blob 6 - {descs[8]}, // Blob 7 - nil, // Blob 8 - nil, // Blob 9 + {descs[4], descs[6], descs[10]}, // Blob 0 + {descs[4]}, // Blob 1 + {descs[5]}, // Blob 2 + {descs[6]}, // Blob 3 + {descs[5], descs[7], descs[8], descs[9], descs[10]}, // Blob 4 + {descs[6], descs[7], descs[8], descs[9]}, // Blob 5 + {descs[7], descs[8], descs[9]}, // Blob 6 + {descs[8]}, // Blob 7 + nil, // Blob 8 + nil, // Blob 9 } for i, want := range wantedPredecessors { predecessors, err := s.Predecessors(ctx, descs[i]) From 4e6c66fba276edb167fff2733bfdcb293d2b740e Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Tue, 26 Dec 2023 13:54:06 +0800 Subject: [PATCH 09/13] increase converage Signed-off-by: Xiaoxuan Wang --- registry/repository_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/registry/repository_test.go b/registry/repository_test.go index 18411893..1e1ca16e 100644 --- a/registry/repository_test.go +++ b/registry/repository_test.go @@ -149,6 +149,7 @@ func TestReferrers(t *testing.T) { generateIndex(&descs[4], descs[5:8]...) // Blob 8 generateManifestList(descs[4:7]...) // blob 9 generateImageManifest(descs[0], nil, descs[4]) // Blob 10 + generateArtifactManifest(nil, descs[5]) // Blob 11 eg, egCtx := errgroup.WithContext(ctx) for i := range blobs { @@ -173,7 +174,7 @@ func TestReferrers(t *testing.T) { {descs[5]}, // Blob 2 {descs[6]}, // Blob 3 {descs[5], descs[7], descs[8], descs[9], descs[10]}, // Blob 4 - {descs[6], descs[7], descs[8], descs[9]}, // Blob 5 + {descs[6], descs[7], descs[8], descs[9], descs[11]}, // Blob 5 {descs[7], descs[8], descs[9]}, // Blob 6 {descs[8]}, // Blob 7 nil, // Blob 8 From ba808c788810b66cf5a84b23f19fe19e2e59805e Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Tue, 26 Dec 2023 17:03:00 +0800 Subject: [PATCH 10/13] increase coverage Signed-off-by: Xiaoxuan Wang --- registry/repository_test.go | 138 ++++++++++++++++++++++++++++++++---- 1 file changed, 126 insertions(+), 12 deletions(-) diff --git a/registry/repository_test.go b/registry/repository_test.go index 1e1ca16e..8d025101 100644 --- a/registry/repository_test.go +++ b/registry/repository_test.go @@ -30,13 +30,17 @@ import ( "golang.org/x/sync/errgroup" "oras.land/oras-go/v2/content/memory" "oras.land/oras-go/v2/errdef" + "oras.land/oras-go/v2/internal/container/set" "oras.land/oras-go/v2/internal/docker" "oras.land/oras-go/v2/internal/spec" ) +var ErrBadFetch = errors.New("bad fetch error") + // testStorage implements content.ReadOnlyGraphStorage type testStorage struct { - store *memory.Store + store *memory.Store + badValues set.Set[digest.Digest] } func (s *testStorage) Push(ctx context.Context, expected ocispec.Descriptor, reader io.Reader) error { @@ -44,6 +48,9 @@ func (s *testStorage) Push(ctx context.Context, expected ocispec.Descriptor, rea } func (s *testStorage) Fetch(ctx context.Context, target ocispec.Descriptor) (io.ReadCloser, error) { + if s.badValues.Contains(target.Digest) { + return nil, ErrBadFetch + } return s.store.Fetch(ctx, target) } @@ -67,7 +74,8 @@ func (rl *TestReferrerLister) Referrers(ctx context.Context, desc ocispec.Descri func TestReferrers(t *testing.T) { s := testStorage{ - store: memory.New(), + store: memory.New(), + badValues: set.New[digest.Digest](), } ctx := context.Background() @@ -179,6 +187,8 @@ func TestReferrers(t *testing.T) { {descs[8]}, // Blob 7 nil, // Blob 8 nil, // Blob 9 + nil, // Blob 10 + nil, // Blob 11 } for i, want := range wantedPredecessors { predecessors, err := s.Predecessors(ctx, descs[i]) @@ -202,6 +212,8 @@ func TestReferrers(t *testing.T) { nil, // Blob 7 nil, // Blob 8 nil, // Blob 9 + nil, // Blob 10 + nil, // Blob 11 } for i := 0; i <= 3; i++ { _, err := Referrers(ctx, &s, descs[i], "") @@ -232,6 +244,8 @@ func TestReferrers(t *testing.T) { nil, // Blob 7 nil, // Blob 8 nil, // Blob 9 + nil, // Blob 10 + nil, // Blob 11 } for i := 4; i < len(wantedReferrers); i++ { want := wantedReferrers[i] @@ -247,16 +261,18 @@ func TestReferrers(t *testing.T) { // test ReferrerLister rl := TestReferrerLister{testStorage: &s} wantedReferrers = [][]ocispec.Descriptor{ - nil, // Blob 0 - nil, // Blob 1 - nil, // Blob 2 - nil, // Blob 3 - {descs[4]}, // Blob 4 - {descs[5]}, // Blob 5 - {descs[6]}, // Blob 6 - {descs[7]}, // Blob 7 - {descs[8]}, // Blob 8 - {descs[9]}, // Blob 9 + nil, // Blob 0 + nil, // Blob 1 + nil, // Blob 2 + nil, // Blob 3 + {descs[4]}, // Blob 4 + {descs[5]}, // Blob 5 + {descs[6]}, // Blob 6 + {descs[7]}, // Blob 7 + {descs[8]}, // Blob 8 + {descs[9]}, // Blob 9 + {descs[10]}, // Blob 10 + {descs[11]}, // Blob 11 } for i := 4; i < len(wantedReferrers); i++ { want := wantedReferrers[i] @@ -270,6 +286,104 @@ func TestReferrers(t *testing.T) { } } +func TestReferrers_BadFetch(t *testing.T) { + s := testStorage{ + store: memory.New(), + badValues: set.New[digest.Digest](), + } + ctx := context.Background() + + // generate test content + var blobs [][]byte + var descs []ocispec.Descriptor + appendBlob := func(mediaType string, artifactType string, blob []byte) { + blobs = append(blobs, blob) + descs = append(descs, ocispec.Descriptor{ + MediaType: mediaType, + ArtifactType: artifactType, + Annotations: map[string]string{"test": "content"}, + Digest: digest.FromBytes(blob), + Size: int64(len(blob)), + }) + } + generateImageManifest := func(config ocispec.Descriptor, subject *ocispec.Descriptor, layers ...ocispec.Descriptor) { + manifest := ocispec.Manifest{ + MediaType: ocispec.MediaTypeImageManifest, + Config: config, + Subject: subject, + Layers: layers, + Annotations: map[string]string{"test": "content"}, + } + manifestJSON, err := json.Marshal(manifest) + if err != nil { + t.Fatal(err) + } + appendBlob(ocispec.MediaTypeImageManifest, manifest.Config.MediaType, manifestJSON) + } + generateArtifactManifest := func(subject *ocispec.Descriptor, blobs ...ocispec.Descriptor) { + artifact := spec.Artifact{ + MediaType: spec.MediaTypeArtifactManifest, + ArtifactType: "artifact", + Subject: subject, + Blobs: blobs, + Annotations: map[string]string{"test": "content"}, + } + manifestJSON, err := json.Marshal(artifact) + if err != nil { + t.Fatal(err) + } + appendBlob(spec.MediaTypeArtifactManifest, artifact.ArtifactType, manifestJSON) + } + generateIndex := func(subject *ocispec.Descriptor, manifests ...ocispec.Descriptor) { + index := ocispec.Index{ + MediaType: ocispec.MediaTypeImageIndex, + ArtifactType: "index", + Subject: subject, + Manifests: manifests, + Annotations: map[string]string{"test": "content"}, + } + indexJSON, err := json.Marshal(index) + if err != nil { + t.Fatal(err) + } + appendBlob(ocispec.MediaTypeImageIndex, index.ArtifactType, indexJSON) + } + appendBlob("image manifest", "image config", []byte("config")) // Blob 0 + appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("foo")) // Blob 1 + appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("bar")) // Blob 2 + appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("hello")) // Blob 3 + generateImageManifest(descs[0], nil, descs[1]) // Blob 4 + generateImageManifest(descs[0], &descs[4], descs[2]) // Blob 5 + generateArtifactManifest(&descs[5], descs[3]) // Blob 6 + generateIndex(&descs[6], descs[5:8]...) // Blob 7 + s.badValues.Add(descs[5].Digest) + s.badValues.Add(descs[6].Digest) + s.badValues.Add(descs[7].Digest) + + eg, egCtx := errgroup.WithContext(ctx) + for i := range blobs { + eg.Go(func(i int) func() error { + return func() error { + err := s.Push(egCtx, descs[i], bytes.NewReader(blobs[i])) + if err != nil { + return fmt.Errorf("failed to push test content to src: %d: %v", i, err) + } + return nil + } + }(i)) + } + if err := eg.Wait(); err != nil { + t.Fatal(err) + } + + for i := 4; i < 7; i++ { + _, err := Referrers(ctx, &s, descs[i], "") + if !errors.Is(err, ErrBadFetch) { + t.Errorf("Store.Referrers(%d) error = %v, want %v", i, err, ErrBadFetch) + } + } +} + func equalDescriptorSet(actual []ocispec.Descriptor, expected []ocispec.Descriptor) bool { if len(actual) != len(expected) { return false From d29c51ac56386d8db25e205f5679ff731060176a Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Tue, 26 Dec 2023 17:16:28 +0800 Subject: [PATCH 11/13] increase coverage Signed-off-by: Xiaoxuan Wang --- registry/repository_test.go | 125 +++++++++++++++++++++++++++++++++--- 1 file changed, 115 insertions(+), 10 deletions(-) diff --git a/registry/repository_test.go b/registry/repository_test.go index 8d025101..efeb6d4e 100644 --- a/registry/repository_test.go +++ b/registry/repository_test.go @@ -39,8 +39,9 @@ var ErrBadFetch = errors.New("bad fetch error") // testStorage implements content.ReadOnlyGraphStorage type testStorage struct { - store *memory.Store - badValues set.Set[digest.Digest] + store *memory.Store + badFetch set.Set[digest.Digest] + badJson set.Set[digest.Digest] } func (s *testStorage) Push(ctx context.Context, expected ocispec.Descriptor, reader io.Reader) error { @@ -48,9 +49,12 @@ func (s *testStorage) Push(ctx context.Context, expected ocispec.Descriptor, rea } func (s *testStorage) Fetch(ctx context.Context, target ocispec.Descriptor) (io.ReadCloser, error) { - if s.badValues.Contains(target.Digest) { + if s.badFetch.Contains(target.Digest) { return nil, ErrBadFetch } + if s.badJson.Contains(target.Digest) { + return io.NopCloser(bytes.NewReader([]byte("bad json"))), nil + } return s.store.Fetch(ctx, target) } @@ -74,8 +78,9 @@ func (rl *TestReferrerLister) Referrers(ctx context.Context, desc ocispec.Descri func TestReferrers(t *testing.T) { s := testStorage{ - store: memory.New(), - badValues: set.New[digest.Digest](), + store: memory.New(), + badFetch: set.New[digest.Digest](), + badJson: set.New[digest.Digest](), } ctx := context.Background() @@ -288,8 +293,9 @@ func TestReferrers(t *testing.T) { func TestReferrers_BadFetch(t *testing.T) { s := testStorage{ - store: memory.New(), - badValues: set.New[digest.Digest](), + store: memory.New(), + badFetch: set.New[digest.Digest](), + badJson: set.New[digest.Digest](), } ctx := context.Background() @@ -356,9 +362,9 @@ func TestReferrers_BadFetch(t *testing.T) { generateImageManifest(descs[0], &descs[4], descs[2]) // Blob 5 generateArtifactManifest(&descs[5], descs[3]) // Blob 6 generateIndex(&descs[6], descs[5:8]...) // Blob 7 - s.badValues.Add(descs[5].Digest) - s.badValues.Add(descs[6].Digest) - s.badValues.Add(descs[7].Digest) + s.badFetch.Add(descs[5].Digest) + s.badFetch.Add(descs[6].Digest) + s.badFetch.Add(descs[7].Digest) eg, egCtx := errgroup.WithContext(ctx) for i := range blobs { @@ -384,6 +390,105 @@ func TestReferrers_BadFetch(t *testing.T) { } } +func TestReferrers_BadJson(t *testing.T) { + s := testStorage{ + store: memory.New(), + badFetch: set.New[digest.Digest](), + badJson: set.New[digest.Digest](), + } + ctx := context.Background() + + // generate test content + var blobs [][]byte + var descs []ocispec.Descriptor + appendBlob := func(mediaType string, artifactType string, blob []byte) { + blobs = append(blobs, blob) + descs = append(descs, ocispec.Descriptor{ + MediaType: mediaType, + ArtifactType: artifactType, + Annotations: map[string]string{"test": "content"}, + Digest: digest.FromBytes(blob), + Size: int64(len(blob)), + }) + } + generateImageManifest := func(config ocispec.Descriptor, subject *ocispec.Descriptor, layers ...ocispec.Descriptor) { + manifest := ocispec.Manifest{ + MediaType: ocispec.MediaTypeImageManifest, + Config: config, + Subject: subject, + Layers: layers, + Annotations: map[string]string{"test": "content"}, + } + manifestJSON, err := json.Marshal(manifest) + if err != nil { + t.Fatal(err) + } + appendBlob(ocispec.MediaTypeImageManifest, manifest.Config.MediaType, manifestJSON) + } + generateArtifactManifest := func(subject *ocispec.Descriptor, blobs ...ocispec.Descriptor) { + artifact := spec.Artifact{ + MediaType: spec.MediaTypeArtifactManifest, + ArtifactType: "artifact", + Subject: subject, + Blobs: blobs, + Annotations: map[string]string{"test": "content"}, + } + manifestJSON, err := json.Marshal(artifact) + if err != nil { + t.Fatal(err) + } + appendBlob(spec.MediaTypeArtifactManifest, artifact.ArtifactType, manifestJSON) + } + generateIndex := func(subject *ocispec.Descriptor, manifests ...ocispec.Descriptor) { + index := ocispec.Index{ + MediaType: ocispec.MediaTypeImageIndex, + ArtifactType: "index", + Subject: subject, + Manifests: manifests, + Annotations: map[string]string{"test": "content"}, + } + indexJSON, err := json.Marshal(index) + if err != nil { + t.Fatal(err) + } + appendBlob(ocispec.MediaTypeImageIndex, index.ArtifactType, indexJSON) + } + appendBlob("image manifest", "image config", []byte("config")) // Blob 0 + appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("foo")) // Blob 1 + appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("bar")) // Blob 2 + appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("hello")) // Blob 3 + generateImageManifest(descs[0], nil, descs[1]) // Blob 4 + generateImageManifest(descs[0], &descs[4], descs[2]) // Blob 5 + generateArtifactManifest(&descs[5], descs[3]) // Blob 6 + generateIndex(&descs[6], descs[5:8]...) // Blob 7 + s.badJson.Add(descs[5].Digest) + s.badJson.Add(descs[6].Digest) + s.badJson.Add(descs[7].Digest) + + eg, egCtx := errgroup.WithContext(ctx) + for i := range blobs { + eg.Go(func(i int) func() error { + return func() error { + err := s.Push(egCtx, descs[i], bytes.NewReader(blobs[i])) + if err != nil { + return fmt.Errorf("failed to push test content to src: %d: %v", i, err) + } + return nil + } + }(i)) + } + if err := eg.Wait(); err != nil { + t.Fatal(err) + } + + for i := 4; i < 7; i++ { + _, err := Referrers(ctx, &s, descs[i], "") + if err == nil { + t.Errorf("Store.Referrers(%d) error = %v, want Json Unmarshall error", i, err) + } + } +} + func equalDescriptorSet(actual []ocispec.Descriptor, expected []ocispec.Descriptor) bool { if len(actual) != len(expected) { return false From 8b7299c4d1aed21825463fb5fd8c1498c7a3d5fd Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Tue, 26 Dec 2023 17:40:33 +0800 Subject: [PATCH 12/13] increase coverage Signed-off-by: Xiaoxuan Wang --- registry/repository_test.go | 192 ++++++++++++++++++------------------ 1 file changed, 96 insertions(+), 96 deletions(-) diff --git a/registry/repository_test.go b/registry/repository_test.go index efeb6d4e..4a7626d3 100644 --- a/registry/repository_test.go +++ b/registry/repository_test.go @@ -361,7 +361,7 @@ func TestReferrers_BadFetch(t *testing.T) { generateImageManifest(descs[0], nil, descs[1]) // Blob 4 generateImageManifest(descs[0], &descs[4], descs[2]) // Blob 5 generateArtifactManifest(&descs[5], descs[3]) // Blob 6 - generateIndex(&descs[6], descs[5:8]...) // Blob 7 + generateIndex(&descs[6]) // Blob 7 s.badFetch.Add(descs[5].Digest) s.badFetch.Add(descs[6].Digest) s.badFetch.Add(descs[7].Digest) @@ -390,104 +390,104 @@ func TestReferrers_BadFetch(t *testing.T) { } } -func TestReferrers_BadJson(t *testing.T) { - s := testStorage{ - store: memory.New(), - badFetch: set.New[digest.Digest](), - badJson: set.New[digest.Digest](), - } - ctx := context.Background() +// func TestReferrers_BadJson(t *testing.T) { +// s := testStorage{ +// store: memory.New(), +// badFetch: set.New[digest.Digest](), +// badJson: set.New[digest.Digest](), +// } +// ctx := context.Background() - // generate test content - var blobs [][]byte - var descs []ocispec.Descriptor - appendBlob := func(mediaType string, artifactType string, blob []byte) { - blobs = append(blobs, blob) - descs = append(descs, ocispec.Descriptor{ - MediaType: mediaType, - ArtifactType: artifactType, - Annotations: map[string]string{"test": "content"}, - Digest: digest.FromBytes(blob), - Size: int64(len(blob)), - }) - } - generateImageManifest := func(config ocispec.Descriptor, subject *ocispec.Descriptor, layers ...ocispec.Descriptor) { - manifest := ocispec.Manifest{ - MediaType: ocispec.MediaTypeImageManifest, - Config: config, - Subject: subject, - Layers: layers, - Annotations: map[string]string{"test": "content"}, - } - manifestJSON, err := json.Marshal(manifest) - if err != nil { - t.Fatal(err) - } - appendBlob(ocispec.MediaTypeImageManifest, manifest.Config.MediaType, manifestJSON) - } - generateArtifactManifest := func(subject *ocispec.Descriptor, blobs ...ocispec.Descriptor) { - artifact := spec.Artifact{ - MediaType: spec.MediaTypeArtifactManifest, - ArtifactType: "artifact", - Subject: subject, - Blobs: blobs, - Annotations: map[string]string{"test": "content"}, - } - manifestJSON, err := json.Marshal(artifact) - if err != nil { - t.Fatal(err) - } - appendBlob(spec.MediaTypeArtifactManifest, artifact.ArtifactType, manifestJSON) - } - generateIndex := func(subject *ocispec.Descriptor, manifests ...ocispec.Descriptor) { - index := ocispec.Index{ - MediaType: ocispec.MediaTypeImageIndex, - ArtifactType: "index", - Subject: subject, - Manifests: manifests, - Annotations: map[string]string{"test": "content"}, - } - indexJSON, err := json.Marshal(index) - if err != nil { - t.Fatal(err) - } - appendBlob(ocispec.MediaTypeImageIndex, index.ArtifactType, indexJSON) - } - appendBlob("image manifest", "image config", []byte("config")) // Blob 0 - appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("foo")) // Blob 1 - appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("bar")) // Blob 2 - appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("hello")) // Blob 3 - generateImageManifest(descs[0], nil, descs[1]) // Blob 4 - generateImageManifest(descs[0], &descs[4], descs[2]) // Blob 5 - generateArtifactManifest(&descs[5], descs[3]) // Blob 6 - generateIndex(&descs[6], descs[5:8]...) // Blob 7 - s.badJson.Add(descs[5].Digest) - s.badJson.Add(descs[6].Digest) - s.badJson.Add(descs[7].Digest) +// // generate test content +// var blobs [][]byte +// var descs []ocispec.Descriptor +// appendBlob := func(mediaType string, artifactType string, blob []byte) { +// blobs = append(blobs, blob) +// descs = append(descs, ocispec.Descriptor{ +// MediaType: mediaType, +// ArtifactType: artifactType, +// Annotations: map[string]string{"test": "content"}, +// Digest: digest.FromBytes(blob), +// Size: int64(len(blob)), +// }) +// } +// generateImageManifest := func(config ocispec.Descriptor, subject *ocispec.Descriptor, layers ...ocispec.Descriptor) { +// manifest := ocispec.Manifest{ +// MediaType: ocispec.MediaTypeImageManifest, +// Config: config, +// Subject: subject, +// Layers: layers, +// Annotations: map[string]string{"test": "content"}, +// } +// manifestJSON, err := json.Marshal(manifest) +// if err != nil { +// t.Fatal(err) +// } +// appendBlob(ocispec.MediaTypeImageManifest, manifest.Config.MediaType, manifestJSON) +// } +// generateArtifactManifest := func(subject *ocispec.Descriptor, blobs ...ocispec.Descriptor) { +// artifact := spec.Artifact{ +// MediaType: spec.MediaTypeArtifactManifest, +// ArtifactType: "artifact", +// Subject: subject, +// Blobs: blobs, +// Annotations: map[string]string{"test": "content"}, +// } +// manifestJSON, err := json.Marshal(artifact) +// if err != nil { +// t.Fatal(err) +// } +// appendBlob(spec.MediaTypeArtifactManifest, artifact.ArtifactType, manifestJSON) +// } +// generateIndex := func(subject *ocispec.Descriptor, manifests ...ocispec.Descriptor) { +// index := ocispec.Index{ +// MediaType: ocispec.MediaTypeImageIndex, +// ArtifactType: "index", +// Subject: subject, +// Manifests: manifests, +// Annotations: map[string]string{"test": "content"}, +// } +// indexJSON, err := json.Marshal(index) +// if err != nil { +// t.Fatal(err) +// } +// appendBlob(ocispec.MediaTypeImageIndex, index.ArtifactType, indexJSON) +// } +// appendBlob("image manifest", "image config", []byte("config")) // Blob 0 +// appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("foo")) // Blob 1 +// appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("bar")) // Blob 2 +// appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("hello")) // Blob 3 +// generateImageManifest(descs[0], nil, descs[1]) // Blob 4 +// generateImageManifest(descs[0], &descs[4], descs[2]) // Blob 5 +// generateArtifactManifest(&descs[5], descs[3]) // Blob 6 +// generateIndex(&descs[6], descs[5:8]...) // Blob 7 +// s.badJson.Add(descs[5].Digest) +// s.badJson.Add(descs[6].Digest) +// s.badJson.Add(descs[7].Digest) - eg, egCtx := errgroup.WithContext(ctx) - for i := range blobs { - eg.Go(func(i int) func() error { - return func() error { - err := s.Push(egCtx, descs[i], bytes.NewReader(blobs[i])) - if err != nil { - return fmt.Errorf("failed to push test content to src: %d: %v", i, err) - } - return nil - } - }(i)) - } - if err := eg.Wait(); err != nil { - t.Fatal(err) - } +// eg, egCtx := errgroup.WithContext(ctx) +// for i := range blobs { +// eg.Go(func(i int) func() error { +// return func() error { +// err := s.Push(egCtx, descs[i], bytes.NewReader(blobs[i])) +// if err != nil { +// return fmt.Errorf("failed to push test content to src: %d: %v", i, err) +// } +// return nil +// } +// }(i)) +// } +// if err := eg.Wait(); err != nil { +// t.Fatal(err) +// } - for i := 4; i < 7; i++ { - _, err := Referrers(ctx, &s, descs[i], "") - if err == nil { - t.Errorf("Store.Referrers(%d) error = %v, want Json Unmarshall error", i, err) - } - } -} +// for i := 4; i < 7; i++ { +// _, err := Referrers(ctx, &s, descs[i], "") +// if err != nil { +// t.Errorf("Store.Referrers(%d) error = %v, want Json Unmarshall error", i, err) +// } +// } +// } func equalDescriptorSet(actual []ocispec.Descriptor, expected []ocispec.Descriptor) bool { if len(actual) != len(expected) { From 404b39d175f5345dc811d48edda675b5e6d3341c Mon Sep 17 00:00:00 2001 From: Xiaoxuan Wang Date: Tue, 26 Dec 2023 17:45:35 +0800 Subject: [PATCH 13/13] increase coverage Signed-off-by: Xiaoxuan Wang --- registry/repository_test.go | 105 ------------------------------------ 1 file changed, 105 deletions(-) diff --git a/registry/repository_test.go b/registry/repository_test.go index 4a7626d3..b41340ef 100644 --- a/registry/repository_test.go +++ b/registry/repository_test.go @@ -41,7 +41,6 @@ var ErrBadFetch = errors.New("bad fetch error") type testStorage struct { store *memory.Store badFetch set.Set[digest.Digest] - badJson set.Set[digest.Digest] } func (s *testStorage) Push(ctx context.Context, expected ocispec.Descriptor, reader io.Reader) error { @@ -52,9 +51,6 @@ func (s *testStorage) Fetch(ctx context.Context, target ocispec.Descriptor) (io. if s.badFetch.Contains(target.Digest) { return nil, ErrBadFetch } - if s.badJson.Contains(target.Digest) { - return io.NopCloser(bytes.NewReader([]byte("bad json"))), nil - } return s.store.Fetch(ctx, target) } @@ -80,7 +76,6 @@ func TestReferrers(t *testing.T) { s := testStorage{ store: memory.New(), badFetch: set.New[digest.Digest](), - badJson: set.New[digest.Digest](), } ctx := context.Background() @@ -295,7 +290,6 @@ func TestReferrers_BadFetch(t *testing.T) { s := testStorage{ store: memory.New(), badFetch: set.New[digest.Digest](), - badJson: set.New[digest.Digest](), } ctx := context.Background() @@ -390,105 +384,6 @@ func TestReferrers_BadFetch(t *testing.T) { } } -// func TestReferrers_BadJson(t *testing.T) { -// s := testStorage{ -// store: memory.New(), -// badFetch: set.New[digest.Digest](), -// badJson: set.New[digest.Digest](), -// } -// ctx := context.Background() - -// // generate test content -// var blobs [][]byte -// var descs []ocispec.Descriptor -// appendBlob := func(mediaType string, artifactType string, blob []byte) { -// blobs = append(blobs, blob) -// descs = append(descs, ocispec.Descriptor{ -// MediaType: mediaType, -// ArtifactType: artifactType, -// Annotations: map[string]string{"test": "content"}, -// Digest: digest.FromBytes(blob), -// Size: int64(len(blob)), -// }) -// } -// generateImageManifest := func(config ocispec.Descriptor, subject *ocispec.Descriptor, layers ...ocispec.Descriptor) { -// manifest := ocispec.Manifest{ -// MediaType: ocispec.MediaTypeImageManifest, -// Config: config, -// Subject: subject, -// Layers: layers, -// Annotations: map[string]string{"test": "content"}, -// } -// manifestJSON, err := json.Marshal(manifest) -// if err != nil { -// t.Fatal(err) -// } -// appendBlob(ocispec.MediaTypeImageManifest, manifest.Config.MediaType, manifestJSON) -// } -// generateArtifactManifest := func(subject *ocispec.Descriptor, blobs ...ocispec.Descriptor) { -// artifact := spec.Artifact{ -// MediaType: spec.MediaTypeArtifactManifest, -// ArtifactType: "artifact", -// Subject: subject, -// Blobs: blobs, -// Annotations: map[string]string{"test": "content"}, -// } -// manifestJSON, err := json.Marshal(artifact) -// if err != nil { -// t.Fatal(err) -// } -// appendBlob(spec.MediaTypeArtifactManifest, artifact.ArtifactType, manifestJSON) -// } -// generateIndex := func(subject *ocispec.Descriptor, manifests ...ocispec.Descriptor) { -// index := ocispec.Index{ -// MediaType: ocispec.MediaTypeImageIndex, -// ArtifactType: "index", -// Subject: subject, -// Manifests: manifests, -// Annotations: map[string]string{"test": "content"}, -// } -// indexJSON, err := json.Marshal(index) -// if err != nil { -// t.Fatal(err) -// } -// appendBlob(ocispec.MediaTypeImageIndex, index.ArtifactType, indexJSON) -// } -// appendBlob("image manifest", "image config", []byte("config")) // Blob 0 -// appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("foo")) // Blob 1 -// appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("bar")) // Blob 2 -// appendBlob(ocispec.MediaTypeImageLayer, "layer", []byte("hello")) // Blob 3 -// generateImageManifest(descs[0], nil, descs[1]) // Blob 4 -// generateImageManifest(descs[0], &descs[4], descs[2]) // Blob 5 -// generateArtifactManifest(&descs[5], descs[3]) // Blob 6 -// generateIndex(&descs[6], descs[5:8]...) // Blob 7 -// s.badJson.Add(descs[5].Digest) -// s.badJson.Add(descs[6].Digest) -// s.badJson.Add(descs[7].Digest) - -// eg, egCtx := errgroup.WithContext(ctx) -// for i := range blobs { -// eg.Go(func(i int) func() error { -// return func() error { -// err := s.Push(egCtx, descs[i], bytes.NewReader(blobs[i])) -// if err != nil { -// return fmt.Errorf("failed to push test content to src: %d: %v", i, err) -// } -// return nil -// } -// }(i)) -// } -// if err := eg.Wait(); err != nil { -// t.Fatal(err) -// } - -// for i := 4; i < 7; i++ { -// _, err := Referrers(ctx, &s, descs[i], "") -// if err != nil { -// t.Errorf("Store.Referrers(%d) error = %v, want Json Unmarshall error", i, err) -// } -// } -// } - func equalDescriptorSet(actual []ocispec.Descriptor, expected []ocispec.Descriptor) bool { if len(actual) != len(expected) { return false