Skip to content

Commit

Permalink
fix and improve tests
Browse files Browse the repository at this point in the history
Signed-off-by: Lixia (Sylvia) Lei <lixlei@microsoft.com>
  • Loading branch information
Wwwsylvia committed Jul 10, 2023
1 parent 0f9f01b commit f5578ca
Show file tree
Hide file tree
Showing 4 changed files with 256 additions and 98 deletions.
76 changes: 1 addition & 75 deletions content/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package content
import (
"context"
"encoding/json"
"fmt"

ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"oras.land/oras-go/v2/internal/docker"
Expand Down Expand Up @@ -47,7 +46,7 @@ type ReadOnlyGraphStorage interface {
}

// Successors returns the nodes directly pointed by the current node.
// In other words, it returns the "children" of the current descriptor.
// In other words, returns the "children" of the current descriptor.
func Successors(ctx context.Context, fetcher Fetcher, node ocispec.Descriptor) ([]ocispec.Descriptor, error) {
switch node.MediaType {
case docker.MediaTypeManifest:
Expand Down Expand Up @@ -121,76 +120,3 @@ func Successors(ctx context.Context, fetcher Fetcher, node ocispec.Descriptor) (
}
return nil, nil
}

// SuccessorsParts returns the parts of the nodes directly pointed by the
// current node, in following order:
// - Subject (If present for OCI Image Manifest and OCI Image Index)
// - Config (If present for OCI Image Manifest and Docker Manifest)
// - Layers (For OCI Image Manifest and Docker Manifest), or Blobs (For OCI
// Artifact Manifest), or Manifests (For OCI Image Index or Docker Manifest
// List)
func SuccessorsParts(ctx context.Context, fetcher Fetcher, desc ocispec.Descriptor) (subject, config *ocispec.Descriptor, items []ocispec.Descriptor, err error) {
switch desc.MediaType {
case docker.MediaTypeManifest:
content, err := FetchAll(ctx, fetcher, desc)
if err != nil {
return nil, nil, nil, err
}
// OCI manifest schema can be used to marshal docker manifest
var manifest ocispec.Manifest
if err := json.Unmarshal(content, &manifest); err != nil {
return nil, nil, nil, fmt.Errorf("failed to unmarshal %s: %s: %w", desc.Digest.String(), desc.MediaType, err)
}
config = &manifest.Config
items = manifest.Layers
case ocispec.MediaTypeImageManifest:
content, err := FetchAll(ctx, fetcher, desc)
if err != nil {
return nil, nil, nil, err
}
var manifest ocispec.Manifest
if err := json.Unmarshal(content, &manifest); err != nil {
return nil, nil, nil, fmt.Errorf("failed to unmarshal %s: %s: %w", desc.Digest.String(), desc.MediaType, err)
}
subject = manifest.Subject
config = &manifest.Config
items = manifest.Layers
case docker.MediaTypeManifestList:
content, err := FetchAll(ctx, fetcher, desc)
if err != nil {
return nil, nil, nil, err
}

// OCI Index schema can be used to marshal docker manifest list
var index ocispec.Index
if err := json.Unmarshal(content, &index); err != nil {
return nil, nil, nil, fmt.Errorf("failed to unmarshal %s: %s: %w", desc.Digest.String(), desc.MediaType, err)
}
items = index.Manifests
case ocispec.MediaTypeImageIndex:
content, err := FetchAll(ctx, fetcher, desc)
if err != nil {
return nil, nil, nil, err
}

var index ocispec.Index
if err := json.Unmarshal(content, &index); err != nil {
return nil, nil, nil, fmt.Errorf("failed to unmarshal %s: %s: %w", desc.Digest.String(), desc.MediaType, err)
}
subject = index.Subject
items = index.Manifests
case spec.MediaTypeArtifactManifest:
content, err := FetchAll(ctx, fetcher, desc)
if err != nil {
return nil, nil, nil, err
}

var manifest spec.Artifact
if err := json.Unmarshal(content, &manifest); err != nil {
return nil, nil, nil, fmt.Errorf("failed to unmarshal %s: %s: %w", desc.Digest.String(), desc.MediaType, err)
}
subject = manifest.Subject
items = manifest.Blobs
}
return
}
71 changes: 51 additions & 20 deletions content/graph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func TestSuccessors_dockerManifest(t *testing.T) {
if err != nil {
t.Fatal("Successors() error =", err)
}
if want := descs[0:4]; !equalDescriptorSet(got, want) {
if want := descs[0:4]; !reflect.DeepEqual(got, want) {
t.Errorf("Successors() = %v, want %v", got, want)
}
}
Expand Down Expand Up @@ -131,7 +131,7 @@ func TestSuccessors_imageManifest(t *testing.T) {
if err != nil {
t.Fatal("Successors() error =", err)
}
if want := descs[0:4]; !equalDescriptorSet(got, want) {
if want := descs[0:4]; !reflect.DeepEqual(got, want) {
t.Errorf("Successors() = %v, want %v", got, want)
}

Expand All @@ -141,7 +141,7 @@ func TestSuccessors_imageManifest(t *testing.T) {
if err != nil {
t.Fatal("Successors() error =", err)
}
if want := descs[4:7]; !equalDescriptorSet(got, want) {
if want := descs[4:7]; !reflect.DeepEqual(got, want) {
t.Errorf("Successors() = %v, want %v", got, want)
}
}
Expand Down Expand Up @@ -204,7 +204,7 @@ func TestSuccessors_dockerManifestList(t *testing.T) {
if err != nil {
t.Fatal("Successors() error =", err)
}
if want := descs[4:6]; !equalDescriptorSet(got, want) {
if want := descs[4:6]; !reflect.DeepEqual(got, want) {
t.Errorf("Successors() = %v, want %v", got, want)
}
}
Expand Down Expand Up @@ -272,7 +272,7 @@ func TestSuccessors_imageIndex(t *testing.T) {
if err != nil {
t.Fatal("Successors() error =", err)
}
if want := append([]ocispec.Descriptor{descs[8]}, descs[4:6]...); !equalDescriptorSet(got, want) {
if want := append([]ocispec.Descriptor{descs[8]}, descs[4:6]...); !reflect.DeepEqual(got, want) {
t.Errorf("Successors() = %v, want %v", got, want)
}
}
Expand Down Expand Up @@ -324,7 +324,7 @@ func TestSuccessors_artifactManifest(t *testing.T) {
if err != nil {
t.Fatal("Successors() error =", err)
}
if want := descs[0:3]; !equalDescriptorSet(got, want) {
if want := descs[0:3]; !reflect.DeepEqual(got, want) {
t.Errorf("Successors() = %v, want %v", got, want)
}

Expand All @@ -334,27 +334,58 @@ func TestSuccessors_artifactManifest(t *testing.T) {
if err != nil {
t.Fatal("Successors() error =", err)
}
if want := descs[3:5]; !equalDescriptorSet(got, want) {
if want := descs[3:5]; !reflect.DeepEqual(got, want) {
t.Errorf("Successors() = %v, want %v", got, want)
}
}

func equalDescriptorSet(actual []ocispec.Descriptor, expected []ocispec.Descriptor) bool {
if len(actual) != len(expected) {
return false
func TestSuccessors_otherMediaType(t *testing.T) {
storage := cas.NewMemory()

// generate test content
var blobs [][]byte
var descs []ocispec.Descriptor
appendBlob := func(mediaType string, blob []byte) {
blobs = append(blobs, blob)
descs = append(descs, ocispec.Descriptor{
MediaType: mediaType,
Digest: digest.FromBytes(blob),
Size: int64(len(blob)),
})
}
contains := func(node ocispec.Descriptor) bool {
for _, candidate := range actual {
if reflect.DeepEqual(candidate, node) {
return true
}
generateManifest := func(mediaType string, config ocispec.Descriptor, layers ...ocispec.Descriptor) {
manifest := ocispec.Manifest{
Config: config,
Layers: layers,
}
manifestJSON, err := json.Marshal(manifest)
if err != nil {
t.Fatal(err)
}
return false
appendBlob(mediaType, manifestJSON)
}
for _, node := range expected {
if !contains(node) {
return false

appendBlob(ocispec.MediaTypeImageConfig, []byte("config")) // Blob 0
appendBlob(ocispec.MediaTypeImageLayer, []byte("foo")) // Blob 1
appendBlob(ocispec.MediaTypeImageLayer, []byte("bar")) // Blob 2
appendBlob(ocispec.MediaTypeImageLayer, []byte("hello")) // Blob 3
generateManifest("whatever", descs[0], descs[1:4]...) // Blob 4

ctx := context.Background()
for i := range blobs {
err := storage.Push(ctx, descs[i], bytes.NewReader(blobs[i]))
if err != nil {
t.Fatalf("failed to push test content to src: %d: %v", i, err)
}
}
return true

// test Successors: other media type
manifestDesc := descs[4]
got, err := content.Successors(ctx, storage, manifestDesc)
if err != nil {
t.Fatal("Successors() error =", err)
}
if got != nil {
t.Errorf("Successors() = %v, want nil", got)
}
}
5 changes: 2 additions & 3 deletions internal/manifestutil/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ import (
"oras.land/oras-go/v2/internal/docker"
)

// TODO: unit tests

// Config returns the config of desc, if present.
func Config(ctx context.Context, fetcher content.Fetcher, desc ocispec.Descriptor) (*ocispec.Descriptor, error) {
switch desc.MediaType {
Expand All @@ -49,12 +47,13 @@ func Config(ctx context.Context, fetcher content.Fetcher, desc ocispec.Descripto
// Manifest returns the manifests of desc, if present.
func Manifests(ctx context.Context, fetcher content.Fetcher, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
switch desc.MediaType {
case ocispec.MediaTypeImageIndex:
case docker.MediaTypeManifestList, ocispec.MediaTypeImageIndex:
content, err := content.FetchAll(ctx, fetcher, desc)
if err != nil {
return nil, err
}

// OCI manifest index schema can be used to marshal docker manifest list
var index ocispec.Index
if err := json.Unmarshal(content, &index); err != nil {
return nil, err
Expand Down
Loading

0 comments on commit f5578ca

Please sign in to comment.