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

Consolidate interface mocks in a testing subpackage #1577

Merged
merged 6 commits into from Jun 14, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 17 additions & 2 deletions copy/manifest_test.go
Expand Up @@ -7,6 +7,7 @@ import (
"testing"

"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/internal/testing/mocks"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/types"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
Expand Down Expand Up @@ -198,6 +199,20 @@ func TestDetermineManifestConversion(t *testing.T) {
assert.Error(t, err)
}

// fakeUnparsedImage is an implementation of types.UnparsedImage which only returns itself as a MIME type in Manifest,
// except that "" means “reading the manifest should fail”
type fakeUnparsedImage struct {
mocks.ForbiddenUnparsedImage
mt string
}

func (f fakeUnparsedImage) Manifest(ctx context.Context) ([]byte, string, error) {
if f.mt == "" {
return nil, "", errors.New("Manifest() directed to fail")
}
return nil, f.mt, nil
}

func TestIsMultiImage(t *testing.T) {
// MIME type is available; more or less a smoke test, other cases are handled in manifest.MIMETypeIsMultiImage
for _, c := range []struct {
Expand All @@ -209,14 +224,14 @@ func TestIsMultiImage(t *testing.T) {
{v1.MediaTypeImageManifest, false},
{v1.MediaTypeImageIndex, true},
} {
src := fakeImageSource(c.mt)
src := fakeUnparsedImage{mocks.ForbiddenUnparsedImage{}, c.mt}
res, err := isMultiImage(context.Background(), src)
require.NoError(t, err)
assert.Equal(t, c.expected, res, c.mt)
}

// Error getting manifest MIME type
src := fakeImageSource("")
src := fakeUnparsedImage{mocks.ForbiddenUnparsedImage{}, ""}
_, err := isMultiImage(context.Background(), src)
assert.Error(t, err)
}
Expand Down
81 changes: 18 additions & 63 deletions internal/image/docker_schema2_test.go
Expand Up @@ -12,6 +12,7 @@ import (
"time"

"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/internal/testing/mocks"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/types"
"github.com/opencontainers/go-digest"
Expand All @@ -21,31 +22,6 @@ import (
"github.com/stretchr/testify/require"
)

// unusedImageSource is used when we don't expect the ImageSource to be used in our tests.
type unusedImageSource struct{}

func (f unusedImageSource) Reference() types.ImageReference {
panic("Unexpected call to a mock function")
}
func (f unusedImageSource) Close() error {
panic("Unexpected call to a mock function")
}
func (f unusedImageSource) GetManifest(context.Context, *digest.Digest) ([]byte, string, error) {
panic("Unexpected call to a mock function")
}
func (f unusedImageSource) HasThreadSafeGetBlob() bool {
panic("Unexpected call to a mock function")
}
func (f unusedImageSource) GetBlob(context.Context, types.BlobInfo, types.BlobInfoCache) (io.ReadCloser, int64, error) {
panic("Unexpected call to a mock function")
}
func (f unusedImageSource) GetSignatures(context.Context, *digest.Digest) ([][]byte, error) {
panic("Unexpected call to a mock function")
}
func (f unusedImageSource) LayerInfosForCopy(context.Context, *digest.Digest) ([]types.BlobInfo, error) {
panic("Unexpected call to a mock function")
}

func manifestSchema2FromFixture(t *testing.T, src types.ImageSource, fixture string, mustFail bool) genericManifest {
manifest, err := os.ReadFile(filepath.Join("fixtures", fixture))
require.NoError(t, err)
Expand Down Expand Up @@ -96,7 +72,7 @@ func manifestSchema2FromComponentsLikeFixture(configBlob []byte) genericManifest
func TestManifestSchema2FromManifest(t *testing.T) {
// This just tests that the JSON can be loaded; we test that the parsed
// values are correctly returned in tests for the individual getter methods.
_ = manifestSchema2FromFixture(t, unusedImageSource{}, "schema2.json", false)
_ = manifestSchema2FromFixture(t, mocks.ForbiddenImageSource{}, "schema2.json", false)

_, err := manifestSchema2FromManifest(nil, []byte{})
assert.Error(t, err)
Expand All @@ -110,7 +86,7 @@ func TestManifestSchema2FromComponents(t *testing.T) {

func TestManifestSchema2Serialize(t *testing.T) {
for _, m := range []genericManifest{
manifestSchema2FromFixture(t, unusedImageSource{}, "schema2.json", false),
manifestSchema2FromFixture(t, mocks.ForbiddenImageSource{}, "schema2.json", false),
manifestSchema2FromComponentsLikeFixture(nil),
} {
serialized, err := m.serialize()
Expand All @@ -134,7 +110,7 @@ func TestManifestSchema2Serialize(t *testing.T) {

func TestManifestSchema2ManifestMIMEType(t *testing.T) {
for _, m := range []genericManifest{
manifestSchema2FromFixture(t, unusedImageSource{}, "schema2.json", false),
manifestSchema2FromFixture(t, mocks.ForbiddenImageSource{}, "schema2.json", false),
manifestSchema2FromComponentsLikeFixture(nil),
} {
assert.Equal(t, manifest.DockerV2Schema2MediaType, m.manifestMIMEType())
Expand All @@ -143,7 +119,7 @@ func TestManifestSchema2ManifestMIMEType(t *testing.T) {

func TestManifestSchema2ConfigInfo(t *testing.T) {
for _, m := range []genericManifest{
manifestSchema2FromFixture(t, unusedImageSource{}, "schema2.json", false),
manifestSchema2FromFixture(t, mocks.ForbiddenImageSource{}, "schema2.json", false),
manifestSchema2FromComponentsLikeFixture(nil),
} {
assert.Equal(t, types.BlobInfo{
Expand All @@ -156,8 +132,8 @@ func TestManifestSchema2ConfigInfo(t *testing.T) {

// configBlobImageSource allows testing various GetBlob behaviors in .ConfigBlob()
type configBlobImageSource struct {
unusedImageSource // We inherit almost all of the methods, which just panic()
f func(digest digest.Digest) (io.ReadCloser, int64, error)
mocks.ForbiddenImageSource // We inherit almost all of the methods, which just panic()
f func(digest digest.Digest) (io.ReadCloser, int64, error)
}

func (f configBlobImageSource) GetBlob(ctx context.Context, info types.BlobInfo, _ types.BlobInfoCache) (io.ReadCloser, int64, error) {
Expand Down Expand Up @@ -197,7 +173,7 @@ func TestManifestSchema2ConfigBlob(t *testing.T) {
} {
var src types.ImageSource
if c.cbISfn != nil {
src = configBlobImageSource{unusedImageSource{}, c.cbISfn}
src = configBlobImageSource{f: c.cbISfn}
} else {
src = nil
}
Expand Down Expand Up @@ -225,7 +201,7 @@ func TestManifestSchema2ConfigBlob(t *testing.T) {

func TestManifestSchema2LayerInfo(t *testing.T) {
for _, m := range []genericManifest{
manifestSchema2FromFixture(t, unusedImageSource{}, "schema2.json", false),
manifestSchema2FromFixture(t, mocks.ForbiddenImageSource{}, "schema2.json", false),
manifestSchema2FromComponentsLikeFixture(nil),
} {
assert.Equal(t, []types.BlobInfo{
Expand Down Expand Up @@ -260,7 +236,7 @@ func TestManifestSchema2LayerInfo(t *testing.T) {

func TestManifestSchema2EmbeddedDockerReferenceConflicts(t *testing.T) {
for _, m := range []genericManifest{
manifestSchema2FromFixture(t, unusedImageSource{}, "schema2.json", false),
manifestSchema2FromFixture(t, mocks.ForbiddenImageSource{}, "schema2.json", false),
manifestSchema2FromComponentsLikeFixture(nil),
} {
for _, name := range []string{"busybox", "example.com:5555/ns/repo:tag"} {
Expand Down Expand Up @@ -316,7 +292,7 @@ func TestManifestSchema2Inspect(t *testing.T) {

func TestManifestSchema2UpdatedImageNeedsLayerDiffIDs(t *testing.T) {
for _, m := range []genericManifest{
manifestSchema2FromFixture(t, unusedImageSource{}, "schema2.json", false),
manifestSchema2FromFixture(t, mocks.ForbiddenImageSource{}, "schema2.json", false),
manifestSchema2FromComponentsLikeFixture(nil),
} {
assert.False(t, m.UpdatedImageNeedsLayerDiffIDs(types.ManifestUpdateOptions{
Expand All @@ -332,38 +308,17 @@ type schema2ImageSource struct {
}

func (s2is *schema2ImageSource) Reference() types.ImageReference {
return refImageReferenceMock{s2is.ref}
return refImageReferenceMock{ref: s2is.ref}
}

// refImageReferenceMock is a mock of types.ImageReference which returns itself in DockerReference.
type refImageReferenceMock struct{ reference.Named }

func (ref refImageReferenceMock) Transport() types.ImageTransport {
panic("unexpected call to a mock function")
}
func (ref refImageReferenceMock) StringWithinTransport() string {
panic("unexpected call to a mock function")
type refImageReferenceMock struct {
mocks.ForbiddenImageReference // We inherit almost all of the methods, which just panic()
ref reference.Named
}

func (ref refImageReferenceMock) DockerReference() reference.Named {
return ref.Named
}
func (ref refImageReferenceMock) PolicyConfigurationIdentity() string {
panic("unexpected call to a mock function")
}
func (ref refImageReferenceMock) PolicyConfigurationNamespaces() []string {
panic("unexpected call to a mock function")
}
func (ref refImageReferenceMock) NewImage(ctx context.Context, sys *types.SystemContext) (types.ImageCloser, error) {
panic("unexpected call to a mock function")
}
func (ref refImageReferenceMock) NewImageSource(ctx context.Context, sys *types.SystemContext) (types.ImageSource, error) {
panic("unexpected call to a mock function")
}
func (ref refImageReferenceMock) NewImageDestination(ctx context.Context, sys *types.SystemContext) (types.ImageDestination, error) {
panic("unexpected call to a mock function")
}
func (ref refImageReferenceMock) DeleteImage(ctx context.Context, sys *types.SystemContext) error {
panic("unexpected call to a mock function")
return ref.ref
}

func newSchema2ImageSource(t *testing.T, dockerRef string) *schema2ImageSource {
Expand All @@ -389,7 +344,7 @@ type memoryImageDest struct {
}

func (d *memoryImageDest) Reference() types.ImageReference {
return refImageReferenceMock{d.ref}
return refImageReferenceMock{ref: d.ref}
}
func (d *memoryImageDest) Close() error {
panic("Unexpected call to a mock function")
Expand Down
19 changes: 10 additions & 9 deletions internal/image/oci_test.go
Expand Up @@ -11,6 +11,7 @@ import (
"time"

"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/internal/testing/mocks"
"github.com/containers/image/v5/manifest"
"github.com/containers/image/v5/types"
"github.com/opencontainers/go-digest"
Expand Down Expand Up @@ -75,7 +76,7 @@ func manifestOCI1FromComponentsLikeFixture(configBlob []byte) genericManifest {
func TestManifestOCI1FromManifest(t *testing.T) {
// This just tests that the JSON can be loaded; we test that the parsed
// values are correctly returned in tests for the individual getter methods.
_ = manifestOCI1FromFixture(t, unusedImageSource{}, "oci1.json")
_ = manifestOCI1FromFixture(t, mocks.ForbiddenImageSource{}, "oci1.json")

_, err := manifestOCI1FromManifest(nil, []byte{})
assert.Error(t, err)
Expand All @@ -89,7 +90,7 @@ func TestManifestOCI1FromComponents(t *testing.T) {

func TestManifestOCI1Serialize(t *testing.T) {
for _, m := range []genericManifest{
manifestOCI1FromFixture(t, unusedImageSource{}, "oci1.json"),
manifestOCI1FromFixture(t, mocks.ForbiddenImageSource{}, "oci1.json"),
manifestOCI1FromComponentsLikeFixture(nil),
} {
serialized, err := m.serialize()
Expand All @@ -113,7 +114,7 @@ func TestManifestOCI1Serialize(t *testing.T) {

func TestManifestOCI1ManifestMIMEType(t *testing.T) {
for _, m := range []genericManifest{
manifestOCI1FromFixture(t, unusedImageSource{}, "oci1.json"),
manifestOCI1FromFixture(t, mocks.ForbiddenImageSource{}, "oci1.json"),
manifestOCI1FromComponentsLikeFixture(nil),
} {
assert.Equal(t, imgspecv1.MediaTypeImageManifest, m.manifestMIMEType())
Expand All @@ -122,7 +123,7 @@ func TestManifestOCI1ManifestMIMEType(t *testing.T) {

func TestManifestOCI1ConfigInfo(t *testing.T) {
for _, m := range []genericManifest{
manifestOCI1FromFixture(t, unusedImageSource{}, "oci1.json"),
manifestOCI1FromFixture(t, mocks.ForbiddenImageSource{}, "oci1.json"),
manifestOCI1FromComponentsLikeFixture(nil),
} {
assert.Equal(t, types.BlobInfo{
Expand Down Expand Up @@ -166,7 +167,7 @@ func TestManifestOCI1ConfigBlob(t *testing.T) {
} {
var src types.ImageSource
if c.cbISfn != nil {
src = configBlobImageSource{unusedImageSource{}, c.cbISfn}
src = configBlobImageSource{f: c.cbISfn}
} else {
src = nil
}
Expand Down Expand Up @@ -194,7 +195,7 @@ func TestManifestOCI1ConfigBlob(t *testing.T) {

func TestManifestOCI1LayerInfo(t *testing.T) {
for _, m := range []genericManifest{
manifestOCI1FromFixture(t, unusedImageSource{}, "oci1.json"),
manifestOCI1FromFixture(t, mocks.ForbiddenImageSource{}, "oci1.json"),
manifestOCI1FromComponentsLikeFixture(nil),
} {
assert.Equal(t, []types.BlobInfo{
Expand Down Expand Up @@ -235,7 +236,7 @@ func TestManifestOCI1LayerInfo(t *testing.T) {

func TestManifestOCI1EmbeddedDockerReferenceConflicts(t *testing.T) {
for _, m := range []genericManifest{
manifestOCI1FromFixture(t, unusedImageSource{}, "oci1.json"),
manifestOCI1FromFixture(t, mocks.ForbiddenImageSource{}, "oci1.json"),
manifestOCI1FromComponentsLikeFixture(nil),
} {
for _, name := range []string{"busybox", "example.com:5555/ns/repo:tag"} {
Expand Down Expand Up @@ -291,7 +292,7 @@ func TestManifestOCI1Inspect(t *testing.T) {

func TestManifestOCI1UpdatedImageNeedsLayerDiffIDs(t *testing.T) {
for _, m := range []genericManifest{
manifestOCI1FromFixture(t, unusedImageSource{}, "oci1.json"),
manifestOCI1FromFixture(t, mocks.ForbiddenImageSource{}, "oci1.json"),
manifestOCI1FromComponentsLikeFixture(nil),
} {
assert.False(t, m.UpdatedImageNeedsLayerDiffIDs(types.ManifestUpdateOptions{
Expand All @@ -307,7 +308,7 @@ type oci1ImageSource struct {
}

func (OCIis *oci1ImageSource) Reference() types.ImageReference {
return refImageReferenceMock{OCIis.ref}
return refImageReferenceMock{ref: OCIis.ref}
}

func newOCI1ImageSource(t *testing.T, dockerRef string) *oci1ImageSource {
Expand Down
56 changes: 56 additions & 0 deletions internal/testing/mocks/image_reference.go
@@ -0,0 +1,56 @@
package mocks

import (
"context"

"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/types"
)

// ForbiddenImageReference is used when we don’t expect the ImageReference to be used in our tests.
type ForbiddenImageReference struct{}

// Transport is a mock that panics.
func (ref ForbiddenImageReference) Transport() types.ImageTransport {
panic("unexpected call to a mock function")
}

// StringWithinTransport is a mock that panics.
func (ref ForbiddenImageReference) StringWithinTransport() string {
panic("unexpected call to a mock function")
}

// DockerReference is a mock that panics.
func (ref ForbiddenImageReference) DockerReference() reference.Named {
panic("unexpected call to a mock function")
}

// PolicyConfigurationIdentity is a mock that panics.
func (ref ForbiddenImageReference) PolicyConfigurationIdentity() string {
panic("unexpected call to a mock function")
}

// PolicyConfigurationNamespaces is a mock that panics.
func (ref ForbiddenImageReference) PolicyConfigurationNamespaces() []string {
panic("unexpected call to a mock function")
}

// NewImage is a mock that panics.
func (ref ForbiddenImageReference) NewImage(ctx context.Context, sys *types.SystemContext) (types.ImageCloser, error) {
panic("unexpected call to a mock function")
}

// NewImageSource is a mock that panics.
func (ref ForbiddenImageReference) NewImageSource(ctx context.Context, sys *types.SystemContext) (types.ImageSource, error) {
panic("unexpected call to a mock function")
}

// NewImageDestination is a mock that panics.
func (ref ForbiddenImageReference) NewImageDestination(ctx context.Context, sys *types.SystemContext) (types.ImageDestination, error) {
panic("unexpected call to a mock function")
}

// DeleteImage is a mock that panics.
func (ref ForbiddenImageReference) DeleteImage(ctx context.Context, sys *types.SystemContext) error {
panic("unexpected call to a mock function")
}