123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583 |
- package distribution
- import (
- "net/http"
- "reflect"
- "testing"
- "github.com/docker/distribution"
- "github.com/docker/distribution/context"
- "github.com/docker/distribution/manifest/schema2"
- "github.com/docker/distribution/reference"
- "github.com/docker/docker/distribution/metadata"
- "github.com/docker/docker/layer"
- "github.com/docker/docker/pkg/progress"
- "github.com/opencontainers/go-digest"
- )
- func TestGetRepositoryMountCandidates(t *testing.T) {
- for _, tc := range []struct {
- name string
- hmacKey string
- targetRepo string
- maxCandidates int
- metadata []metadata.V2Metadata
- candidates []metadata.V2Metadata
- }{
- {
- name: "empty metadata",
- targetRepo: "busybox",
- maxCandidates: -1,
- metadata: []metadata.V2Metadata{},
- candidates: []metadata.V2Metadata{},
- },
- {
- name: "one item not matching",
- targetRepo: "busybox",
- maxCandidates: -1,
- metadata: []metadata.V2Metadata{taggedMetadata("key", "dgst", "127.0.0.1/repo")},
- candidates: []metadata.V2Metadata{},
- },
- {
- name: "one item matching",
- targetRepo: "busybox",
- maxCandidates: -1,
- metadata: []metadata.V2Metadata{taggedMetadata("hash", "1", "docker.io/library/hello-world")},
- candidates: []metadata.V2Metadata{taggedMetadata("hash", "1", "docker.io/library/hello-world")},
- },
- {
- name: "allow missing SourceRepository",
- targetRepo: "busybox",
- maxCandidates: -1,
- metadata: []metadata.V2Metadata{
- {Digest: digest.Digest("1")},
- {Digest: digest.Digest("3")},
- {Digest: digest.Digest("2")},
- },
- candidates: []metadata.V2Metadata{},
- },
- {
- name: "handle docker.io",
- targetRepo: "user/app",
- maxCandidates: -1,
- metadata: []metadata.V2Metadata{
- {Digest: digest.Digest("1"), SourceRepository: "docker.io/user/foo"},
- {Digest: digest.Digest("3"), SourceRepository: "docker.io/user/bar"},
- {Digest: digest.Digest("2"), SourceRepository: "docker.io/library/app"},
- },
- candidates: []metadata.V2Metadata{
- {Digest: digest.Digest("3"), SourceRepository: "docker.io/user/bar"},
- {Digest: digest.Digest("1"), SourceRepository: "docker.io/user/foo"},
- {Digest: digest.Digest("2"), SourceRepository: "docker.io/library/app"},
- },
- },
- {
- name: "sort more items",
- hmacKey: "abcd",
- targetRepo: "127.0.0.1/foo/bar",
- maxCandidates: -1,
- metadata: []metadata.V2Metadata{
- taggedMetadata("hash", "1", "docker.io/library/hello-world"),
- taggedMetadata("efgh", "2", "127.0.0.1/hello-world"),
- taggedMetadata("abcd", "3", "docker.io/library/busybox"),
- taggedMetadata("hash", "4", "docker.io/library/busybox"),
- taggedMetadata("hash", "5", "127.0.0.1/foo"),
- taggedMetadata("hash", "6", "127.0.0.1/bar"),
- taggedMetadata("efgh", "7", "127.0.0.1/foo/bar"),
- taggedMetadata("abcd", "8", "127.0.0.1/xyz"),
- taggedMetadata("hash", "9", "127.0.0.1/foo/app"),
- },
- candidates: []metadata.V2Metadata{
- // first by matching hash
- taggedMetadata("abcd", "8", "127.0.0.1/xyz"),
- // then by longest matching prefix
- taggedMetadata("hash", "9", "127.0.0.1/foo/app"),
- taggedMetadata("hash", "5", "127.0.0.1/foo"),
- // sort the rest of the matching items in reversed order
- taggedMetadata("hash", "6", "127.0.0.1/bar"),
- taggedMetadata("efgh", "2", "127.0.0.1/hello-world"),
- },
- },
- {
- name: "limit max candidates",
- hmacKey: "abcd",
- targetRepo: "user/app",
- maxCandidates: 3,
- metadata: []metadata.V2Metadata{
- taggedMetadata("abcd", "1", "docker.io/user/app1"),
- taggedMetadata("abcd", "2", "docker.io/user/app/base"),
- taggedMetadata("hash", "3", "docker.io/user/app"),
- taggedMetadata("abcd", "4", "127.0.0.1/user/app"),
- taggedMetadata("hash", "5", "docker.io/user/foo"),
- taggedMetadata("hash", "6", "docker.io/app/bar"),
- },
- candidates: []metadata.V2Metadata{
- // first by matching hash
- taggedMetadata("abcd", "2", "docker.io/user/app/base"),
- taggedMetadata("abcd", "1", "docker.io/user/app1"),
- // then by longest matching prefix
- // "docker.io/usr/app" is excluded since candidates must
- // be from a different repository
- taggedMetadata("hash", "5", "docker.io/user/foo"),
- },
- },
- } {
- repoInfo, err := reference.ParseNormalizedNamed(tc.targetRepo)
- if err != nil {
- t.Fatalf("[%s] failed to parse reference name: %v", tc.name, err)
- }
- candidates := getRepositoryMountCandidates(repoInfo, []byte(tc.hmacKey), tc.maxCandidates, tc.metadata)
- if len(candidates) != len(tc.candidates) {
- t.Errorf("[%s] got unexpected number of candidates: %d != %d", tc.name, len(candidates), len(tc.candidates))
- }
- for i := 0; i < len(candidates) && i < len(tc.candidates); i++ {
- if !reflect.DeepEqual(candidates[i], tc.candidates[i]) {
- t.Errorf("[%s] candidate %d does not match expected: %#+v != %#+v", tc.name, i, candidates[i], tc.candidates[i])
- }
- }
- for i := len(candidates); i < len(tc.candidates); i++ {
- t.Errorf("[%s] missing expected candidate at position %d (%#+v)", tc.name, i, tc.candidates[i])
- }
- for i := len(tc.candidates); i < len(candidates); i++ {
- t.Errorf("[%s] got unexpected candidate at position %d (%#+v)", tc.name, i, candidates[i])
- }
- }
- }
- func TestLayerAlreadyExists(t *testing.T) {
- for _, tc := range []struct {
- name string
- metadata []metadata.V2Metadata
- targetRepo string
- hmacKey string
- maxExistenceChecks int
- checkOtherRepositories bool
- remoteBlobs map[digest.Digest]distribution.Descriptor
- remoteErrors map[digest.Digest]error
- expectedDescriptor distribution.Descriptor
- expectedExists bool
- expectedError error
- expectedRequests []string
- expectedAdditions []metadata.V2Metadata
- expectedRemovals []metadata.V2Metadata
- }{
- {
- name: "empty metadata",
- targetRepo: "busybox",
- maxExistenceChecks: 3,
- checkOtherRepositories: true,
- },
- {
- name: "single not existent metadata",
- targetRepo: "busybox",
- metadata: []metadata.V2Metadata{{Digest: digest.Digest("pear"), SourceRepository: "docker.io/library/busybox"}},
- maxExistenceChecks: 3,
- expectedRequests: []string{"pear"},
- expectedRemovals: []metadata.V2Metadata{{Digest: digest.Digest("pear"), SourceRepository: "docker.io/library/busybox"}},
- },
- {
- name: "access denied",
- targetRepo: "busybox",
- maxExistenceChecks: 1,
- metadata: []metadata.V2Metadata{{Digest: digest.Digest("apple"), SourceRepository: "docker.io/library/busybox"}},
- remoteErrors: map[digest.Digest]error{digest.Digest("apple"): distribution.ErrAccessDenied},
- expectedError: nil,
- expectedRequests: []string{"apple"},
- },
- {
- name: "not matching reposies",
- targetRepo: "busybox",
- maxExistenceChecks: 3,
- metadata: []metadata.V2Metadata{
- {Digest: digest.Digest("apple"), SourceRepository: "docker.io/library/hello-world"},
- {Digest: digest.Digest("orange"), SourceRepository: "docker.io/library/busybox/subapp"},
- {Digest: digest.Digest("pear"), SourceRepository: "docker.io/busybox"},
- {Digest: digest.Digest("plum"), SourceRepository: "busybox"},
- {Digest: digest.Digest("banana"), SourceRepository: "127.0.0.1/busybox"},
- },
- },
- {
- name: "check other repositories",
- targetRepo: "busybox",
- maxExistenceChecks: 10,
- checkOtherRepositories: true,
- metadata: []metadata.V2Metadata{
- {Digest: digest.Digest("apple"), SourceRepository: "docker.io/library/hello-world"},
- {Digest: digest.Digest("orange"), SourceRepository: "docker.io/busybox/subapp"},
- {Digest: digest.Digest("pear"), SourceRepository: "docker.io/busybox"},
- {Digest: digest.Digest("plum"), SourceRepository: "docker.io/library/busybox"},
- {Digest: digest.Digest("banana"), SourceRepository: "127.0.0.1/busybox"},
- },
- expectedRequests: []string{"plum", "apple", "pear", "orange", "banana"},
- expectedRemovals: []metadata.V2Metadata{
- {Digest: digest.Digest("plum"), SourceRepository: "docker.io/library/busybox"},
- },
- },
- {
- name: "find existing blob",
- targetRepo: "busybox",
- metadata: []metadata.V2Metadata{{Digest: digest.Digest("apple"), SourceRepository: "docker.io/library/busybox"}},
- maxExistenceChecks: 3,
- remoteBlobs: map[digest.Digest]distribution.Descriptor{digest.Digest("apple"): {Digest: digest.Digest("apple")}},
- expectedDescriptor: distribution.Descriptor{Digest: digest.Digest("apple"), MediaType: schema2.MediaTypeLayer},
- expectedExists: true,
- expectedRequests: []string{"apple"},
- },
- {
- name: "find existing blob with different hmac",
- targetRepo: "busybox",
- metadata: []metadata.V2Metadata{{SourceRepository: "docker.io/library/busybox", Digest: digest.Digest("apple"), HMAC: "dummyhmac"}},
- maxExistenceChecks: 3,
- remoteBlobs: map[digest.Digest]distribution.Descriptor{digest.Digest("apple"): {Digest: digest.Digest("apple")}},
- expectedDescriptor: distribution.Descriptor{Digest: digest.Digest("apple"), MediaType: schema2.MediaTypeLayer},
- expectedExists: true,
- expectedRequests: []string{"apple"},
- expectedAdditions: []metadata.V2Metadata{{Digest: digest.Digest("apple"), SourceRepository: "docker.io/library/busybox"}},
- },
- {
- name: "overwrite media types",
- targetRepo: "busybox",
- metadata: []metadata.V2Metadata{{Digest: digest.Digest("apple"), SourceRepository: "docker.io/library/busybox"}},
- hmacKey: "key",
- maxExistenceChecks: 3,
- remoteBlobs: map[digest.Digest]distribution.Descriptor{digest.Digest("apple"): {Digest: digest.Digest("apple"), MediaType: "custom-media-type"}},
- expectedDescriptor: distribution.Descriptor{Digest: digest.Digest("apple"), MediaType: schema2.MediaTypeLayer},
- expectedExists: true,
- expectedRequests: []string{"apple"},
- expectedAdditions: []metadata.V2Metadata{taggedMetadata("key", "apple", "docker.io/library/busybox")},
- },
- {
- name: "find existing blob among many",
- targetRepo: "127.0.0.1/myapp",
- hmacKey: "key",
- metadata: []metadata.V2Metadata{
- taggedMetadata("someotherkey", "pear", "127.0.0.1/myapp"),
- taggedMetadata("key", "apple", "127.0.0.1/myapp"),
- taggedMetadata("", "plum", "127.0.0.1/myapp"),
- },
- maxExistenceChecks: 3,
- remoteBlobs: map[digest.Digest]distribution.Descriptor{digest.Digest("pear"): {Digest: digest.Digest("pear")}},
- expectedDescriptor: distribution.Descriptor{Digest: digest.Digest("pear"), MediaType: schema2.MediaTypeLayer},
- expectedExists: true,
- expectedRequests: []string{"apple", "plum", "pear"},
- expectedAdditions: []metadata.V2Metadata{taggedMetadata("key", "pear", "127.0.0.1/myapp")},
- expectedRemovals: []metadata.V2Metadata{
- taggedMetadata("key", "apple", "127.0.0.1/myapp"),
- {Digest: digest.Digest("plum"), SourceRepository: "127.0.0.1/myapp"},
- },
- },
- {
- name: "reach maximum existence checks",
- targetRepo: "user/app",
- metadata: []metadata.V2Metadata{
- {Digest: digest.Digest("pear"), SourceRepository: "docker.io/user/app"},
- {Digest: digest.Digest("apple"), SourceRepository: "docker.io/user/app"},
- {Digest: digest.Digest("plum"), SourceRepository: "docker.io/user/app"},
- {Digest: digest.Digest("banana"), SourceRepository: "docker.io/user/app"},
- },
- maxExistenceChecks: 3,
- remoteBlobs: map[digest.Digest]distribution.Descriptor{digest.Digest("pear"): {Digest: digest.Digest("pear")}},
- expectedExists: false,
- expectedRequests: []string{"banana", "plum", "apple"},
- expectedRemovals: []metadata.V2Metadata{
- {Digest: digest.Digest("banana"), SourceRepository: "docker.io/user/app"},
- {Digest: digest.Digest("plum"), SourceRepository: "docker.io/user/app"},
- {Digest: digest.Digest("apple"), SourceRepository: "docker.io/user/app"},
- },
- },
- {
- name: "zero allowed existence checks",
- targetRepo: "user/app",
- metadata: []metadata.V2Metadata{
- {Digest: digest.Digest("pear"), SourceRepository: "docker.io/user/app"},
- {Digest: digest.Digest("apple"), SourceRepository: "docker.io/user/app"},
- {Digest: digest.Digest("plum"), SourceRepository: "docker.io/user/app"},
- {Digest: digest.Digest("banana"), SourceRepository: "docker.io/user/app"},
- },
- maxExistenceChecks: 0,
- remoteBlobs: map[digest.Digest]distribution.Descriptor{digest.Digest("pear"): {Digest: digest.Digest("pear")}},
- },
- {
- name: "stat single digest just once",
- targetRepo: "busybox",
- metadata: []metadata.V2Metadata{
- taggedMetadata("key1", "pear", "docker.io/library/busybox"),
- taggedMetadata("key2", "apple", "docker.io/library/busybox"),
- taggedMetadata("key3", "apple", "docker.io/library/busybox"),
- },
- maxExistenceChecks: 3,
- remoteBlobs: map[digest.Digest]distribution.Descriptor{digest.Digest("pear"): {Digest: digest.Digest("pear")}},
- expectedDescriptor: distribution.Descriptor{Digest: digest.Digest("pear"), MediaType: schema2.MediaTypeLayer},
- expectedExists: true,
- expectedRequests: []string{"apple", "pear"},
- expectedAdditions: []metadata.V2Metadata{{Digest: digest.Digest("pear"), SourceRepository: "docker.io/library/busybox"}},
- expectedRemovals: []metadata.V2Metadata{taggedMetadata("key3", "apple", "docker.io/library/busybox")},
- },
- {
- name: "don't stop on first error",
- targetRepo: "user/app",
- hmacKey: "key",
- metadata: []metadata.V2Metadata{
- taggedMetadata("key", "banana", "docker.io/user/app"),
- taggedMetadata("key", "orange", "docker.io/user/app"),
- taggedMetadata("key", "plum", "docker.io/user/app"),
- },
- maxExistenceChecks: 3,
- remoteErrors: map[digest.Digest]error{"orange": distribution.ErrAccessDenied},
- remoteBlobs: map[digest.Digest]distribution.Descriptor{digest.Digest("apple"): {}},
- expectedError: nil,
- expectedRequests: []string{"plum", "orange", "banana"},
- expectedRemovals: []metadata.V2Metadata{
- taggedMetadata("key", "plum", "docker.io/user/app"),
- taggedMetadata("key", "banana", "docker.io/user/app"),
- },
- },
- {
- name: "remove outdated metadata",
- targetRepo: "docker.io/user/app",
- metadata: []metadata.V2Metadata{
- {Digest: digest.Digest("plum"), SourceRepository: "docker.io/library/busybox"},
- {Digest: digest.Digest("orange"), SourceRepository: "docker.io/user/app"},
- },
- maxExistenceChecks: 3,
- remoteErrors: map[digest.Digest]error{"orange": distribution.ErrBlobUnknown},
- remoteBlobs: map[digest.Digest]distribution.Descriptor{digest.Digest("plum"): {}},
- expectedExists: false,
- expectedRequests: []string{"orange"},
- expectedRemovals: []metadata.V2Metadata{{Digest: digest.Digest("orange"), SourceRepository: "docker.io/user/app"}},
- },
- {
- name: "missing SourceRepository",
- targetRepo: "busybox",
- metadata: []metadata.V2Metadata{
- {Digest: digest.Digest("1")},
- {Digest: digest.Digest("3")},
- {Digest: digest.Digest("2")},
- },
- maxExistenceChecks: 3,
- expectedExists: false,
- expectedRequests: []string{"2", "3", "1"},
- },
- {
- name: "with and without SourceRepository",
- targetRepo: "busybox",
- metadata: []metadata.V2Metadata{
- {Digest: digest.Digest("1")},
- {Digest: digest.Digest("2"), SourceRepository: "docker.io/library/busybox"},
- {Digest: digest.Digest("3")},
- },
- remoteBlobs: map[digest.Digest]distribution.Descriptor{digest.Digest("1"): {Digest: digest.Digest("1")}},
- maxExistenceChecks: 3,
- expectedDescriptor: distribution.Descriptor{Digest: digest.Digest("1"), MediaType: schema2.MediaTypeLayer},
- expectedExists: true,
- expectedRequests: []string{"2", "3", "1"},
- expectedAdditions: []metadata.V2Metadata{{Digest: digest.Digest("1"), SourceRepository: "docker.io/library/busybox"}},
- expectedRemovals: []metadata.V2Metadata{
- {Digest: digest.Digest("2"), SourceRepository: "docker.io/library/busybox"},
- },
- },
- } {
- repoInfo, err := reference.ParseNormalizedNamed(tc.targetRepo)
- if err != nil {
- t.Fatalf("[%s] failed to parse reference name: %v", tc.name, err)
- }
- repo := &mockRepo{
- t: t,
- errors: tc.remoteErrors,
- blobs: tc.remoteBlobs,
- requests: []string{},
- }
- ctx := context.Background()
- ms := &mockV2MetadataService{}
- pd := &v2PushDescriptor{
- hmacKey: []byte(tc.hmacKey),
- repoInfo: repoInfo,
- layer: &storeLayer{
- Layer: layer.EmptyLayer,
- },
- repo: repo,
- v2MetadataService: ms,
- pushState: &pushState{remoteLayers: make(map[layer.DiffID]distribution.Descriptor)},
- checkedDigests: make(map[digest.Digest]struct{}),
- }
- desc, exists, err := pd.layerAlreadyExists(ctx, &progressSink{t}, layer.EmptyLayer.DiffID(), tc.checkOtherRepositories, tc.maxExistenceChecks, tc.metadata)
- if !reflect.DeepEqual(desc, tc.expectedDescriptor) {
- t.Errorf("[%s] got unexpected descriptor: %#+v != %#+v", tc.name, desc, tc.expectedDescriptor)
- }
- if exists != tc.expectedExists {
- t.Errorf("[%s] got unexpected exists: %t != %t", tc.name, exists, tc.expectedExists)
- }
- if !reflect.DeepEqual(err, tc.expectedError) {
- t.Errorf("[%s] got unexpected error: %#+v != %#+v", tc.name, err, tc.expectedError)
- }
- if len(repo.requests) != len(tc.expectedRequests) {
- t.Errorf("[%s] got unexpected number of requests: %d != %d", tc.name, len(repo.requests), len(tc.expectedRequests))
- }
- for i := 0; i < len(repo.requests) && i < len(tc.expectedRequests); i++ {
- if repo.requests[i] != tc.expectedRequests[i] {
- t.Errorf("[%s] request %d does not match expected: %q != %q", tc.name, i, repo.requests[i], tc.expectedRequests[i])
- }
- }
- for i := len(repo.requests); i < len(tc.expectedRequests); i++ {
- t.Errorf("[%s] missing expected request at position %d (%q)", tc.name, i, tc.expectedRequests[i])
- }
- for i := len(tc.expectedRequests); i < len(repo.requests); i++ {
- t.Errorf("[%s] got unexpected request at position %d (%q)", tc.name, i, repo.requests[i])
- }
- if len(ms.added) != len(tc.expectedAdditions) {
- t.Errorf("[%s] got unexpected number of additions: %d != %d", tc.name, len(ms.added), len(tc.expectedAdditions))
- }
- for i := 0; i < len(ms.added) && i < len(tc.expectedAdditions); i++ {
- if ms.added[i] != tc.expectedAdditions[i] {
- t.Errorf("[%s] added metadata at %d does not match expected: %q != %q", tc.name, i, ms.added[i], tc.expectedAdditions[i])
- }
- }
- for i := len(ms.added); i < len(tc.expectedAdditions); i++ {
- t.Errorf("[%s] missing expected addition at position %d (%q)", tc.name, i, tc.expectedAdditions[i])
- }
- for i := len(tc.expectedAdditions); i < len(ms.added); i++ {
- t.Errorf("[%s] unexpected metadata addition at position %d (%q)", tc.name, i, ms.added[i])
- }
- if len(ms.removed) != len(tc.expectedRemovals) {
- t.Errorf("[%s] got unexpected number of removals: %d != %d", tc.name, len(ms.removed), len(tc.expectedRemovals))
- }
- for i := 0; i < len(ms.removed) && i < len(tc.expectedRemovals); i++ {
- if ms.removed[i] != tc.expectedRemovals[i] {
- t.Errorf("[%s] removed metadata at %d does not match expected: %q != %q", tc.name, i, ms.removed[i], tc.expectedRemovals[i])
- }
- }
- for i := len(ms.removed); i < len(tc.expectedRemovals); i++ {
- t.Errorf("[%s] missing expected removal at position %d (%q)", tc.name, i, tc.expectedRemovals[i])
- }
- for i := len(tc.expectedRemovals); i < len(ms.removed); i++ {
- t.Errorf("[%s] removed unexpected metadata at position %d (%q)", tc.name, i, ms.removed[i])
- }
- }
- }
- func taggedMetadata(key string, dgst string, sourceRepo string) metadata.V2Metadata {
- meta := metadata.V2Metadata{
- Digest: digest.Digest(dgst),
- SourceRepository: sourceRepo,
- }
- meta.HMAC = metadata.ComputeV2MetadataHMAC([]byte(key), &meta)
- return meta
- }
- type mockRepo struct {
- t *testing.T
- errors map[digest.Digest]error
- blobs map[digest.Digest]distribution.Descriptor
- requests []string
- }
- var _ distribution.Repository = &mockRepo{}
- func (m *mockRepo) Named() reference.Named {
- m.t.Fatalf("Named() not implemented")
- return nil
- }
- func (m *mockRepo) Manifests(ctc context.Context, options ...distribution.ManifestServiceOption) (distribution.ManifestService, error) {
- m.t.Fatalf("Manifests() not implemented")
- return nil, nil
- }
- func (m *mockRepo) Tags(ctc context.Context) distribution.TagService {
- m.t.Fatalf("Tags() not implemented")
- return nil
- }
- func (m *mockRepo) Blobs(ctx context.Context) distribution.BlobStore {
- return &mockBlobStore{
- repo: m,
- }
- }
- type mockBlobStore struct {
- repo *mockRepo
- }
- var _ distribution.BlobStore = &mockBlobStore{}
- func (m *mockBlobStore) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
- m.repo.requests = append(m.repo.requests, dgst.String())
- if err, exists := m.repo.errors[dgst]; exists {
- return distribution.Descriptor{}, err
- }
- if desc, exists := m.repo.blobs[dgst]; exists {
- return desc, nil
- }
- return distribution.Descriptor{}, distribution.ErrBlobUnknown
- }
- func (m *mockBlobStore) Get(ctx context.Context, dgst digest.Digest) ([]byte, error) {
- m.repo.t.Fatal("Get() not implemented")
- return nil, nil
- }
- func (m *mockBlobStore) Open(ctx context.Context, dgst digest.Digest) (distribution.ReadSeekCloser, error) {
- m.repo.t.Fatal("Open() not implemented")
- return nil, nil
- }
- func (m *mockBlobStore) Put(ctx context.Context, mediaType string, p []byte) (distribution.Descriptor, error) {
- m.repo.t.Fatal("Put() not implemented")
- return distribution.Descriptor{}, nil
- }
- func (m *mockBlobStore) Create(ctx context.Context, options ...distribution.BlobCreateOption) (distribution.BlobWriter, error) {
- m.repo.t.Fatal("Create() not implemented")
- return nil, nil
- }
- func (m *mockBlobStore) Resume(ctx context.Context, id string) (distribution.BlobWriter, error) {
- m.repo.t.Fatal("Resume() not implemented")
- return nil, nil
- }
- func (m *mockBlobStore) Delete(ctx context.Context, dgst digest.Digest) error {
- m.repo.t.Fatal("Delete() not implemented")
- return nil
- }
- func (m *mockBlobStore) ServeBlob(ctx context.Context, w http.ResponseWriter, r *http.Request, dgst digest.Digest) error {
- m.repo.t.Fatalf("ServeBlob() not implemented")
- return nil
- }
- type mockV2MetadataService struct {
- added []metadata.V2Metadata
- removed []metadata.V2Metadata
- }
- var _ metadata.V2MetadataService = &mockV2MetadataService{}
- func (*mockV2MetadataService) GetMetadata(diffID layer.DiffID) ([]metadata.V2Metadata, error) {
- return nil, nil
- }
- func (*mockV2MetadataService) GetDiffID(dgst digest.Digest) (layer.DiffID, error) {
- return "", nil
- }
- func (m *mockV2MetadataService) Add(diffID layer.DiffID, metadata metadata.V2Metadata) error {
- m.added = append(m.added, metadata)
- return nil
- }
- func (m *mockV2MetadataService) TagAndAdd(diffID layer.DiffID, hmacKey []byte, meta metadata.V2Metadata) error {
- meta.HMAC = metadata.ComputeV2MetadataHMAC(hmacKey, &meta)
- m.Add(diffID, meta)
- return nil
- }
- func (m *mockV2MetadataService) Remove(metadata metadata.V2Metadata) error {
- m.removed = append(m.removed, metadata)
- return nil
- }
- type progressSink struct {
- t *testing.T
- }
- func (s *progressSink) WriteProgress(p progress.Progress) error {
- s.t.Logf("progress update: %#+v", p)
- return nil
- }
|