Skip to content

Commit

Permalink
refactor: Make mock fetcher generally available
Browse files Browse the repository at this point in the history
Signed-off-by: Terry Howe <terrylhowe@gmail.com>
  • Loading branch information
TerryHowe committed Jul 24, 2024
1 parent 92bf5e3 commit 17fe489
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 62 deletions.
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
96 changes: 96 additions & 0 deletions internal/testutils/fetcher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
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
}

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
return mockFetcher
}

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 60 in internal/testutils/fetcher.go

View check run for this annotation

Codecov / codecov/patch

internal/testutils/fetcher.go#L60

Added line #L60 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 74 in internal/testutils/fetcher.go

View check run for this annotation

Codecov / codecov/patch

internal/testutils/fetcher.go#L74

Added line #L74 was not covered by tests
}
return mf.PushBlob(mediaType, manifestJSON)
}

func (mf *MockFetcher) PushOCIImage(subject *ocispec.Descriptor, config ocispec.Descriptor, layers ...ocispec.Descriptor) ocispec.Descriptor {
return mf.pushImage(subject, ocispec.MediaTypeImageManifest, config, layers...)
}

func (mf *MockFetcher) PushDockerImage(subject *ocispec.Descriptor, config ocispec.Descriptor, layers ...ocispec.Descriptor) ocispec.Descriptor {
return mf.pushImage(subject, docker.MediaTypeManifest, config, layers...)
}

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 93 in internal/testutils/fetcher.go

View check run for this annotation

Codecov / codecov/patch

internal/testutils/fetcher.go#L93

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

0 comments on commit 17fe489

Please sign in to comment.