Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Make mock fetcher generally available #1455

Merged
merged 1 commit into from
Aug 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 6 additions & 62 deletions internal/graph/graph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,75 +16,19 @@ limitations under the License.
package graph

import (
"bytes"
"context"
"encoding/json"
"github.com/opencontainers/go-digest"
"oras.land/oras-go/v2/content/memory"
"reflect"
"testing"

ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"oras.land/oras-go/v2/content"
"oras.land/oras/internal/docker"
"oras.land/oras/internal/testutils"
)

type contentFetcher struct {
content.Fetcher
}

func newTestFetcher(t *testing.T) (subject, config, ociImage, dockerImage, index ocispec.Descriptor, fetcher content.Fetcher) {
var blobs [][]byte
ctx := context.Background()
memoryStorage := memory.New()
appendBlob := func(mediaType string, blob []byte) ocispec.Descriptor {
blobs = append(blobs, blob)
desc := ocispec.Descriptor{
MediaType: mediaType,
Digest: digest.FromBytes(blob),
Size: int64(len(blob)),
}
if err := memoryStorage.Push(ctx, desc, bytes.NewReader(blob)); err != nil {
t.Errorf("Error pushing %v\n", err)
}
return desc
}
generateImage := func(subject *ocispec.Descriptor, mediaType string, config ocispec.Descriptor, layers ...ocispec.Descriptor) ocispec.Descriptor {
manifest := ocispec.Manifest{
MediaType: mediaType,
Subject: subject,
Config: config,
Layers: layers,
}
manifestJSON, err := json.Marshal(manifest)
if err != nil {
t.Fatal(err)
}
return appendBlob(mediaType, manifestJSON)
}
generateIndex := func(manifests ...ocispec.Descriptor) ocispec.Descriptor {
index := ocispec.Index{
Manifests: manifests,
}
indexJSON, err := json.Marshal(index)
if err != nil {
t.Fatal(err)
}
return appendBlob(ocispec.MediaTypeImageIndex, indexJSON)
}

subject = appendBlob(ocispec.MediaTypeImageLayer, []byte("blob"))
imageType := "test.image"
config = appendBlob(imageType, []byte("config content"))
ociImage = generateImage(&subject, ocispec.MediaTypeImageManifest, config)
dockerImage = generateImage(&subject, docker.MediaTypeManifest, config)
index = generateIndex(subject)

return subject, config, ociImage, dockerImage, index, &contentFetcher{Fetcher: memoryStorage}
}

func TestSuccessors(t *testing.T) {
subject, config, ociImage, dockerImage, index, fetcher := newTestFetcher(t)
mockFetcher := testutils.NewMockFetcher(t)
fetcher := mockFetcher.Fetcher
ctx := context.Background()
type args struct {
ctx context.Context
Expand All @@ -101,9 +45,9 @@ func TestSuccessors(t *testing.T) {
}{
{"should failed to get non-existent OCI image", args{ctx, fetcher, ocispec.Descriptor{MediaType: ocispec.MediaTypeImageManifest}}, nil, nil, nil, true},
{"should failed to get non-existent docker image", args{ctx, fetcher, ocispec.Descriptor{MediaType: docker.MediaTypeManifest}}, nil, nil, nil, true},
{"should get success of a docker image", args{ctx, fetcher, dockerImage}, nil, &subject, &config, false},
{"should get success of an OCI image", args{ctx, fetcher, ociImage}, nil, &subject, &config, false},
{"should get success of an index", args{ctx, fetcher, index}, []ocispec.Descriptor{subject}, nil, nil, false},
{"should get success of a docker image", args{ctx, fetcher, mockFetcher.DockerImage}, nil, &mockFetcher.Subject, &mockFetcher.Config, false},
{"should get success of an OCI image", args{ctx, fetcher, mockFetcher.OciImage}, nil, &mockFetcher.Subject, &mockFetcher.Config, false},
{"should get success of an index", args{ctx, fetcher, mockFetcher.Index}, []ocispec.Descriptor{mockFetcher.Subject}, nil, nil, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
101 changes: 101 additions & 0 deletions internal/testutils/fetcher.go
TerryHowe marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
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 testutils

import (
"bytes"
"context"
"encoding/json"
"github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"oras.land/oras-go/v2/content"
"oras.land/oras-go/v2/content/memory"
"oras.land/oras/internal/docker"
"testing"
)

type MockFetcher struct {
t *testing.T
store *memory.Store
Fetcher content.Fetcher
Subject ocispec.Descriptor
Config ocispec.Descriptor
OciImage ocispec.Descriptor
DockerImage ocispec.Descriptor
Index ocispec.Descriptor
}

// NewMockFetcher creates a MockFetcher and populates it.
func NewMockFetcher(t *testing.T) (mockFetcher MockFetcher) {
mockFetcher = MockFetcher{store: memory.New(), t: t}
mockFetcher.Subject = mockFetcher.PushBlob(ocispec.MediaTypeImageLayer, []byte("blob"))
imageType := "test.image"
mockFetcher.Config = mockFetcher.PushBlob(imageType, []byte("config content"))
mockFetcher.OciImage = mockFetcher.PushOCIImage(&mockFetcher.Subject, mockFetcher.Config)
mockFetcher.DockerImage = mockFetcher.PushDockerImage(&mockFetcher.Subject, mockFetcher.Config)
mockFetcher.Index = mockFetcher.PushIndex(mockFetcher.Subject)
mockFetcher.Fetcher = mockFetcher.store
TerryHowe marked this conversation as resolved.
Show resolved Hide resolved
return mockFetcher
}

// PushBlob pushes a blob to the memory store.
func (mf *MockFetcher) PushBlob(mediaType string, blob []byte) ocispec.Descriptor {
desc := ocispec.Descriptor{
MediaType: mediaType,
Digest: digest.FromBytes(blob),
Size: int64(len(blob)),
}
if err := mf.store.Push(context.Background(), desc, bytes.NewReader(blob)); err != nil {
mf.t.Fatal(err)

Check warning on line 62 in internal/testutils/fetcher.go

View check run for this annotation

Codecov / codecov/patch

internal/testutils/fetcher.go#L62

Added line #L62 was not covered by tests
}
return desc
}

func (mf *MockFetcher) pushImage(subject *ocispec.Descriptor, mediaType string, config ocispec.Descriptor, layers ...ocispec.Descriptor) ocispec.Descriptor {
manifest := ocispec.Manifest{
MediaType: mediaType,
Subject: subject,
Config: config,
Layers: layers,
}
manifestJSON, err := json.Marshal(manifest)
if err != nil {
mf.t.Fatal(err)

Check warning on line 76 in internal/testutils/fetcher.go

View check run for this annotation

Codecov / codecov/patch

internal/testutils/fetcher.go#L76

Added line #L76 was not covered by tests
TerryHowe marked this conversation as resolved.
Show resolved Hide resolved
}
return mf.PushBlob(mediaType, manifestJSON)
}

// PushOCIImage pushes the given subject, config and layers as a OCI image.
func (mf *MockFetcher) PushOCIImage(subject *ocispec.Descriptor, config ocispec.Descriptor, layers ...ocispec.Descriptor) ocispec.Descriptor {
return mf.pushImage(subject, ocispec.MediaTypeImageManifest, config, layers...)
}

// PushDockerImage pushes the given subject, config and layers as a Docker image.
func (mf *MockFetcher) PushDockerImage(subject *ocispec.Descriptor, config ocispec.Descriptor, layers ...ocispec.Descriptor) ocispec.Descriptor {
return mf.pushImage(subject, docker.MediaTypeManifest, config, layers...)
}

// PushIndex pushes the manifests as an index.
func (mf *MockFetcher) PushIndex(manifests ...ocispec.Descriptor) ocispec.Descriptor {
index := ocispec.Index{
Manifests: manifests,
}
indexJSON, err := json.Marshal(index)
if err != nil {
mf.t.Fatal(err)

Check warning on line 98 in internal/testutils/fetcher.go

View check run for this annotation

Codecov / codecov/patch

internal/testutils/fetcher.go#L98

Added line #L98 was not covered by tests
}
return mf.PushBlob(ocispec.MediaTypeImageIndex, indexJSON)
}
Loading