1 package notifications
2
3 import (
4 "io"
5 "reflect"
6 "testing"
7
8 "github.com/distribution/reference"
9 "github.com/docker/distribution"
10 "github.com/docker/distribution/context"
11 "github.com/docker/distribution/manifest"
12 "github.com/docker/distribution/manifest/schema1"
13 "github.com/docker/distribution/registry/storage"
14 "github.com/docker/distribution/registry/storage/cache/memory"
15 "github.com/docker/distribution/registry/storage/driver/inmemory"
16 "github.com/docker/distribution/testutil"
17 "github.com/docker/libtrust"
18 "github.com/opencontainers/go-digest"
19 )
20
21 func TestListener(t *testing.T) {
22 ctx := context.Background()
23 k, err := libtrust.GenerateECP256PrivateKey()
24 if err != nil {
25 t.Fatal(err)
26 }
27
28 registry, err := storage.NewRegistry(ctx, inmemory.New(), storage.BlobDescriptorCacheProvider(memory.NewInMemoryBlobDescriptorCacheProvider()), storage.EnableDelete, storage.EnableRedirect, storage.Schema1SigningKey(k), storage.EnableSchema1)
29 if err != nil {
30 t.Fatalf("error creating registry: %v", err)
31 }
32 tl := &testListener{
33 ops: make(map[string]int),
34 }
35
36 repoRef, _ := reference.WithName("foo/bar")
37 repository, err := registry.Repository(ctx, repoRef)
38 if err != nil {
39 t.Fatalf("unexpected error getting repo: %v", err)
40 }
41
42 remover, ok := registry.(distribution.RepositoryRemover)
43 if !ok {
44 t.Fatal("registry does not implement RepositoryRemover")
45 }
46 repository, remover = Listen(repository, remover, tl)
47
48
49 checkExerciseRepository(t, repository, remover)
50
51 expectedOps := map[string]int{
52 "manifest:push": 1,
53 "manifest:pull": 1,
54 "manifest:delete": 1,
55 "layer:push": 2,
56 "layer:pull": 2,
57 "layer:delete": 2,
58 "tag:delete": 1,
59 "repo:delete": 1,
60 }
61
62 if !reflect.DeepEqual(tl.ops, expectedOps) {
63 t.Fatalf("counts do not match:\n%v\n !=\n%v", tl.ops, expectedOps)
64 }
65 }
66
67 type testListener struct {
68 ops map[string]int
69 }
70
71 func (tl *testListener) ManifestPushed(repo reference.Named, m distribution.Manifest, options ...distribution.ManifestServiceOption) error {
72 tl.ops["manifest:push"]++
73 return nil
74 }
75
76 func (tl *testListener) ManifestPulled(repo reference.Named, m distribution.Manifest, options ...distribution.ManifestServiceOption) error {
77 tl.ops["manifest:pull"]++
78 return nil
79 }
80
81 func (tl *testListener) ManifestDeleted(repo reference.Named, d digest.Digest) error {
82 tl.ops["manifest:delete"]++
83 return nil
84 }
85
86 func (tl *testListener) BlobPushed(repo reference.Named, desc distribution.Descriptor) error {
87 tl.ops["layer:push"]++
88 return nil
89 }
90
91 func (tl *testListener) BlobPulled(repo reference.Named, desc distribution.Descriptor) error {
92 tl.ops["layer:pull"]++
93 return nil
94 }
95
96 func (tl *testListener) BlobMounted(repo reference.Named, desc distribution.Descriptor, fromRepo reference.Named) error {
97 tl.ops["layer:mount"]++
98 return nil
99 }
100
101 func (tl *testListener) BlobDeleted(repo reference.Named, d digest.Digest) error {
102 tl.ops["layer:delete"]++
103 return nil
104 }
105
106 func (tl *testListener) TagDeleted(repo reference.Named, tag string) error {
107 tl.ops["tag:delete"]++
108 return nil
109 }
110
111 func (tl *testListener) RepoDeleted(repo reference.Named) error {
112 tl.ops["repo:delete"]++
113 return nil
114 }
115
116
117
118 func checkExerciseRepository(t *testing.T, repository distribution.Repository, remover distribution.RepositoryRemover) {
119
120
121
122
123
124 ctx := context.Background()
125 tag := "thetag"
126
127
128 m := schema1.Manifest{
129 Versioned: manifest.Versioned{
130 SchemaVersion: 1,
131 },
132 Name: repository.Named().Name(),
133 Tag: tag,
134 }
135
136 var blobDigests []digest.Digest
137 blobs := repository.Blobs(ctx)
138 for i := 0; i < 2; i++ {
139 rs, dgst, err := testutil.CreateRandomTarFile()
140 if err != nil {
141 t.Fatalf("error creating test layer: %v", err)
142 }
143 blobDigests = append(blobDigests, dgst)
144
145 wr, err := blobs.Create(ctx)
146 if err != nil {
147 t.Fatalf("error creating layer upload: %v", err)
148 }
149
150
151 wr, err = blobs.Resume(ctx, wr.ID())
152 if err != nil {
153 t.Fatalf("error resuming layer upload: %v", err)
154 }
155
156 io.Copy(wr, rs)
157
158 if _, err := wr.Commit(ctx, distribution.Descriptor{Digest: dgst}); err != nil {
159 t.Fatalf("unexpected error finishing upload: %v", err)
160 }
161
162 m.FSLayers = append(m.FSLayers, schema1.FSLayer{
163 BlobSum: dgst,
164 })
165 m.History = append(m.History, schema1.History{
166 V1Compatibility: "",
167 })
168
169
170 if rc, err := blobs.Open(ctx, dgst); err != nil {
171 t.Fatalf("error fetching layer: %v", err)
172 } else {
173 defer rc.Close()
174 }
175 }
176
177 pk, err := libtrust.GenerateECP256PrivateKey()
178 if err != nil {
179 t.Fatalf("unexpected error generating key: %v", err)
180 }
181
182 sm, err := schema1.Sign(&m, pk)
183 if err != nil {
184 t.Fatalf("unexpected error signing manifest: %v", err)
185 }
186
187 manifests, err := repository.Manifests(ctx)
188 if err != nil {
189 t.Fatal(err.Error())
190 }
191
192 var digestPut digest.Digest
193 if digestPut, err = manifests.Put(ctx, sm); err != nil {
194 t.Fatalf("unexpected error putting the manifest: %v", err)
195 }
196
197 dgst := digest.FromBytes(sm.Canonical)
198 if dgst != digestPut {
199 t.Fatalf("mismatching digest from payload and put")
200 }
201
202 _, err = manifests.Get(ctx, dgst)
203 if err != nil {
204 t.Fatalf("unexpected error fetching manifest: %v", err)
205 }
206
207 err = manifests.Delete(ctx, dgst)
208 if err != nil {
209 t.Fatalf("unexpected error deleting blob: %v", err)
210 }
211
212 for _, d := range blobDigests {
213 err = blobs.Delete(ctx, d)
214 if err != nil {
215 t.Fatalf("unexpected error deleting blob: %v", err)
216 }
217 }
218
219 err = repository.Tags(ctx).Untag(ctx, m.Tag)
220 if err != nil {
221 t.Fatalf("unexpected error deleting tag: %v", err)
222 }
223
224 err = remover.Remove(ctx, repository.Named())
225 if err != nil {
226 t.Fatalf("unexpected error deleting repo: %v", err)
227 }
228 }
229
View as plain text