|
@@ -18,6 +18,7 @@ import (
|
|
|
"github.com/docker/distribution/manifest/ocischema"
|
|
|
"github.com/docker/distribution/manifest/schema1"
|
|
|
"github.com/docker/distribution/manifest/schema2"
|
|
|
+ "github.com/docker/distribution/reference"
|
|
|
"github.com/google/go-cmp/cmp/cmpopts"
|
|
|
digest "github.com/opencontainers/go-digest"
|
|
|
specs "github.com/opencontainers/image-spec/specs-go/v1"
|
|
@@ -40,6 +41,11 @@ func (m *mockManifestGetter) Get(ctx context.Context, dgst digest.Digest, option
|
|
|
return manifest, nil
|
|
|
}
|
|
|
|
|
|
+func (m *mockManifestGetter) Exists(ctx context.Context, dgst digest.Digest) (bool, error) {
|
|
|
+ _, ok := m.manifests[dgst]
|
|
|
+ return ok, nil
|
|
|
+}
|
|
|
+
|
|
|
type memoryLabelStore struct {
|
|
|
mu sync.Mutex
|
|
|
labels map[digest.Digest]map[string]string
|
|
@@ -77,7 +83,9 @@ func (s *memoryLabelStore) Update(dgst digest.Digest, update map[string]string)
|
|
|
for k, v := range update {
|
|
|
labels[k] = v
|
|
|
}
|
|
|
-
|
|
|
+ if s.labels == nil {
|
|
|
+ s.labels = map[digest.Digest]map[string]string{}
|
|
|
+ }
|
|
|
s.labels[dgst] = labels
|
|
|
|
|
|
return labels, nil
|
|
@@ -126,7 +134,7 @@ func TestManifestStore(t *testing.T) {
|
|
|
assert.NilError(t, err)
|
|
|
dgst := digest.Canonical.FromBytes(serialized)
|
|
|
|
|
|
- setupTest := func(t *testing.T) (specs.Descriptor, *mockManifestGetter, *manifestStore, content.Store, func(*testing.T)) {
|
|
|
+ setupTest := func(t *testing.T) (reference.Named, specs.Descriptor, *mockManifestGetter, *manifestStore, content.Store, func(*testing.T)) {
|
|
|
root, err := ioutil.TempDir("", strings.Replace(t.Name(), "/", "_", -1))
|
|
|
assert.NilError(t, err)
|
|
|
defer func() {
|
|
@@ -142,7 +150,10 @@ func TestManifestStore(t *testing.T) {
|
|
|
store := &manifestStore{local: cs, remote: mg}
|
|
|
desc := specs.Descriptor{Digest: dgst, MediaType: specs.MediaTypeImageManifest, Size: int64(len(serialized))}
|
|
|
|
|
|
- return desc, mg, store, cs, func(t *testing.T) {
|
|
|
+ ref, err := reference.Parse("foo/bar")
|
|
|
+ assert.NilError(t, err)
|
|
|
+
|
|
|
+ return ref.(reference.Named), desc, mg, store, cs, func(t *testing.T) {
|
|
|
assert.Check(t, os.RemoveAll(root))
|
|
|
}
|
|
|
}
|
|
@@ -183,22 +194,22 @@ func TestManifestStore(t *testing.T) {
|
|
|
}
|
|
|
|
|
|
t.Run("no remote or local", func(t *testing.T) {
|
|
|
- desc, _, store, cs, teardown := setupTest(t)
|
|
|
+ ref, desc, _, store, cs, teardown := setupTest(t)
|
|
|
defer teardown(t)
|
|
|
|
|
|
- _, err = store.Get(ctx, desc)
|
|
|
+ _, err = store.Get(ctx, desc, ref)
|
|
|
checkIngest(t, cs, desc)
|
|
|
// This error is what our digest getter returns when it doesn't know about the manifest
|
|
|
assert.Error(t, err, distribution.ErrManifestUnknown{Tag: dgst.String()}.Error())
|
|
|
})
|
|
|
|
|
|
t.Run("no local cache", func(t *testing.T) {
|
|
|
- desc, mg, store, cs, teardown := setupTest(t)
|
|
|
+ ref, desc, mg, store, cs, teardown := setupTest(t)
|
|
|
defer teardown(t)
|
|
|
|
|
|
mg.manifests[desc.Digest] = m
|
|
|
|
|
|
- m2, err := store.Get(ctx, desc)
|
|
|
+ m2, err := store.Get(ctx, desc, ref)
|
|
|
checkIngest(t, cs, desc)
|
|
|
assert.NilError(t, err)
|
|
|
assert.Check(t, cmp.DeepEqual(m, m2, cmpopts.IgnoreUnexported(ocischema.DeserializedManifest{})))
|
|
@@ -208,23 +219,34 @@ func TestManifestStore(t *testing.T) {
|
|
|
assert.NilError(t, err)
|
|
|
assert.Check(t, cmp.Equal(i.Digest, desc.Digest))
|
|
|
|
|
|
+ distKey, distSource := makeDistributionSourceLabel(ref)
|
|
|
+ assert.Check(t, hasDistributionSource(i.Labels[distKey], distSource))
|
|
|
+
|
|
|
// Now check again, this should not hit the remote
|
|
|
- m2, err = store.Get(ctx, desc)
|
|
|
+ m2, err = store.Get(ctx, desc, ref)
|
|
|
checkIngest(t, cs, desc)
|
|
|
assert.NilError(t, err)
|
|
|
assert.Check(t, cmp.DeepEqual(m, m2, cmpopts.IgnoreUnexported(ocischema.DeserializedManifest{})))
|
|
|
assert.Check(t, cmp.Equal(mg.gets, 1))
|
|
|
+
|
|
|
+ t.Run("digested", func(t *testing.T) {
|
|
|
+ ref, err := reference.WithDigest(ref, desc.Digest)
|
|
|
+ assert.NilError(t, err)
|
|
|
+
|
|
|
+ _, err = store.Get(ctx, desc, ref)
|
|
|
+ assert.NilError(t, err)
|
|
|
+ })
|
|
|
})
|
|
|
|
|
|
t.Run("with local cache", func(t *testing.T) {
|
|
|
- desc, mg, store, cs, teardown := setupTest(t)
|
|
|
+ ref, desc, mg, store, cs, teardown := setupTest(t)
|
|
|
defer teardown(t)
|
|
|
|
|
|
// first add the manifest to the coontent store
|
|
|
writeManifest(t, cs, desc)
|
|
|
|
|
|
// now do the get
|
|
|
- m2, err := store.Get(ctx, desc)
|
|
|
+ m2, err := store.Get(ctx, desc, ref)
|
|
|
checkIngest(t, cs, desc)
|
|
|
assert.NilError(t, err)
|
|
|
assert.Check(t, cmp.DeepEqual(m, m2, cmpopts.IgnoreUnexported(ocischema.DeserializedManifest{})))
|
|
@@ -238,13 +260,13 @@ func TestManifestStore(t *testing.T) {
|
|
|
// This is for the case of pull by digest where we don't know the media type of the manifest until it's actually pulled.
|
|
|
t.Run("unknown media type", func(t *testing.T) {
|
|
|
t.Run("no cache", func(t *testing.T) {
|
|
|
- desc, mg, store, cs, teardown := setupTest(t)
|
|
|
+ ref, desc, mg, store, cs, teardown := setupTest(t)
|
|
|
defer teardown(t)
|
|
|
|
|
|
mg.manifests[desc.Digest] = m
|
|
|
desc.MediaType = ""
|
|
|
|
|
|
- m2, err := store.Get(ctx, desc)
|
|
|
+ m2, err := store.Get(ctx, desc, ref)
|
|
|
checkIngest(t, cs, desc)
|
|
|
assert.NilError(t, err)
|
|
|
assert.Check(t, cmp.DeepEqual(m, m2, cmpopts.IgnoreUnexported(ocischema.DeserializedManifest{})))
|
|
@@ -253,13 +275,13 @@ func TestManifestStore(t *testing.T) {
|
|
|
|
|
|
t.Run("with cache", func(t *testing.T) {
|
|
|
t.Run("cached manifest has media type", func(t *testing.T) {
|
|
|
- desc, mg, store, cs, teardown := setupTest(t)
|
|
|
+ ref, desc, mg, store, cs, teardown := setupTest(t)
|
|
|
defer teardown(t)
|
|
|
|
|
|
writeManifest(t, cs, desc)
|
|
|
desc.MediaType = ""
|
|
|
|
|
|
- m2, err := store.Get(ctx, desc)
|
|
|
+ m2, err := store.Get(ctx, desc, ref)
|
|
|
checkIngest(t, cs, desc)
|
|
|
assert.NilError(t, err)
|
|
|
assert.Check(t, cmp.DeepEqual(m, m2, cmpopts.IgnoreUnexported(ocischema.DeserializedManifest{})))
|
|
@@ -267,13 +289,13 @@ func TestManifestStore(t *testing.T) {
|
|
|
})
|
|
|
|
|
|
t.Run("cached manifest has no media type", func(t *testing.T) {
|
|
|
- desc, mg, store, cs, teardown := setupTest(t)
|
|
|
+ ref, desc, mg, store, cs, teardown := setupTest(t)
|
|
|
defer teardown(t)
|
|
|
|
|
|
desc.MediaType = ""
|
|
|
writeManifest(t, cs, desc)
|
|
|
|
|
|
- m2, err := store.Get(ctx, desc)
|
|
|
+ m2, err := store.Get(ctx, desc, ref)
|
|
|
checkIngest(t, cs, desc)
|
|
|
assert.NilError(t, err)
|
|
|
assert.Check(t, cmp.DeepEqual(m, m2, cmpopts.IgnoreUnexported(ocischema.DeserializedManifest{})))
|
|
@@ -288,14 +310,14 @@ func TestManifestStore(t *testing.T) {
|
|
|
// Also makes sure the ingests are aborted.
|
|
|
t.Run("error persisting manifest", func(t *testing.T) {
|
|
|
t.Run("error on writer", func(t *testing.T) {
|
|
|
- desc, mg, store, cs, teardown := setupTest(t)
|
|
|
+ ref, desc, mg, store, cs, teardown := setupTest(t)
|
|
|
defer teardown(t)
|
|
|
mg.manifests[desc.Digest] = m
|
|
|
|
|
|
csW := &testingContentStoreWrapper{ContentStore: store.local, errorOnWriter: errors.New("random error")}
|
|
|
store.local = csW
|
|
|
|
|
|
- m2, err := store.Get(ctx, desc)
|
|
|
+ m2, err := store.Get(ctx, desc, ref)
|
|
|
checkIngest(t, cs, desc)
|
|
|
assert.NilError(t, err)
|
|
|
assert.Check(t, cmp.DeepEqual(m, m2, cmpopts.IgnoreUnexported(ocischema.DeserializedManifest{})))
|
|
@@ -307,14 +329,14 @@ func TestManifestStore(t *testing.T) {
|
|
|
})
|
|
|
|
|
|
t.Run("error on commit", func(t *testing.T) {
|
|
|
- desc, mg, store, cs, teardown := setupTest(t)
|
|
|
+ ref, desc, mg, store, cs, teardown := setupTest(t)
|
|
|
defer teardown(t)
|
|
|
mg.manifests[desc.Digest] = m
|
|
|
|
|
|
csW := &testingContentStoreWrapper{ContentStore: store.local, errorOnCommit: errors.New("random error")}
|
|
|
store.local = csW
|
|
|
|
|
|
- m2, err := store.Get(ctx, desc)
|
|
|
+ m2, err := store.Get(ctx, desc, ref)
|
|
|
checkIngest(t, cs, desc)
|
|
|
assert.NilError(t, err)
|
|
|
assert.Check(t, cmp.DeepEqual(m, m2, cmpopts.IgnoreUnexported(ocischema.DeserializedManifest{})))
|