github.com/lusis/distribution@v2.0.1+incompatible/registry/storage/manifeststore_test.go (about) 1 package storage 2 3 import ( 4 "bytes" 5 "io" 6 "reflect" 7 "testing" 8 9 "github.com/docker/distribution/registry/storage/cache" 10 11 "github.com/docker/distribution" 12 "github.com/docker/distribution/digest" 13 "github.com/docker/distribution/manifest" 14 "github.com/docker/distribution/registry/storage/driver" 15 "github.com/docker/distribution/registry/storage/driver/inmemory" 16 "github.com/docker/distribution/testutil" 17 "github.com/docker/libtrust" 18 "golang.org/x/net/context" 19 ) 20 21 type manifestStoreTestEnv struct { 22 ctx context.Context 23 driver driver.StorageDriver 24 registry distribution.Namespace 25 repository distribution.Repository 26 name string 27 tag string 28 } 29 30 func newManifestStoreTestEnv(t *testing.T, name, tag string) *manifestStoreTestEnv { 31 ctx := context.Background() 32 driver := inmemory.New() 33 registry := NewRegistryWithDriver(driver, cache.NewInMemoryLayerInfoCache()) 34 35 repo, err := registry.Repository(ctx, name) 36 if err != nil { 37 t.Fatalf("unexpected error getting repo: %v", err) 38 } 39 40 return &manifestStoreTestEnv{ 41 ctx: ctx, 42 driver: driver, 43 registry: registry, 44 repository: repo, 45 name: name, 46 tag: tag, 47 } 48 } 49 50 func TestManifestStorage(t *testing.T) { 51 env := newManifestStoreTestEnv(t, "foo/bar", "thetag") 52 ms := env.repository.Manifests() 53 54 exists, err := ms.ExistsByTag(env.tag) 55 if err != nil { 56 t.Fatalf("unexpected error checking manifest existence: %v", err) 57 } 58 59 if exists { 60 t.Fatalf("manifest should not exist") 61 } 62 63 if _, err := ms.GetByTag(env.tag); true { 64 switch err.(type) { 65 case distribution.ErrManifestUnknown: 66 break 67 default: 68 t.Fatalf("expected manifest unknown error: %#v", err) 69 } 70 } 71 72 m := manifest.Manifest{ 73 Versioned: manifest.Versioned{ 74 SchemaVersion: 1, 75 }, 76 Name: env.name, 77 Tag: env.tag, 78 } 79 80 // Build up some test layers and add them to the manifest, saving the 81 // readseekers for upload later. 82 testLayers := map[digest.Digest]io.ReadSeeker{} 83 for i := 0; i < 2; i++ { 84 rs, ds, err := testutil.CreateRandomTarFile() 85 if err != nil { 86 t.Fatalf("unexpected error generating test layer file") 87 } 88 dgst := digest.Digest(ds) 89 90 testLayers[digest.Digest(dgst)] = rs 91 m.FSLayers = append(m.FSLayers, manifest.FSLayer{ 92 BlobSum: dgst, 93 }) 94 } 95 96 pk, err := libtrust.GenerateECP256PrivateKey() 97 if err != nil { 98 t.Fatalf("unexpected error generating private key: %v", err) 99 } 100 101 sm, err := manifest.Sign(&m, pk) 102 if err != nil { 103 t.Fatalf("error signing manifest: %v", err) 104 } 105 106 err = ms.Put(sm) 107 if err == nil { 108 t.Fatalf("expected errors putting manifest") 109 } 110 111 // TODO(stevvooe): We expect errors describing all of the missing layers. 112 113 // Now, upload the layers that were missing! 114 for dgst, rs := range testLayers { 115 upload, err := env.repository.Layers().Upload() 116 if err != nil { 117 t.Fatalf("unexpected error creating test upload: %v", err) 118 } 119 120 if _, err := io.Copy(upload, rs); err != nil { 121 t.Fatalf("unexpected error copying to upload: %v", err) 122 } 123 124 if _, err := upload.Finish(dgst); err != nil { 125 t.Fatalf("unexpected error finishing upload: %v", err) 126 } 127 } 128 129 if err = ms.Put(sm); err != nil { 130 t.Fatalf("unexpected error putting manifest: %v", err) 131 } 132 133 exists, err = ms.ExistsByTag(env.tag) 134 if err != nil { 135 t.Fatalf("unexpected error checking manifest existence: %v", err) 136 } 137 138 if !exists { 139 t.Fatalf("manifest should exist") 140 } 141 142 fetchedManifest, err := ms.GetByTag(env.tag) 143 if err != nil { 144 t.Fatalf("unexpected error fetching manifest: %v", err) 145 } 146 147 if !reflect.DeepEqual(fetchedManifest, sm) { 148 t.Fatalf("fetched manifest not equal: %#v != %#v", fetchedManifest, sm) 149 } 150 151 fetchedJWS, err := libtrust.ParsePrettySignature(fetchedManifest.Raw, "signatures") 152 if err != nil { 153 t.Fatalf("unexpected error parsing jws: %v", err) 154 } 155 156 payload, err := fetchedJWS.Payload() 157 if err != nil { 158 t.Fatalf("unexpected error extracting payload: %v", err) 159 } 160 161 // Now that we have a payload, take a moment to check that the manifest is 162 // return by the payload digest. 163 dgst, err := digest.FromBytes(payload) 164 if err != nil { 165 t.Fatalf("error getting manifest digest: %v", err) 166 } 167 168 exists, err = ms.Exists(dgst) 169 if err != nil { 170 t.Fatalf("error checking manifest existence by digest: %v", err) 171 } 172 173 if !exists { 174 t.Fatalf("manifest %s should exist", dgst) 175 } 176 177 fetchedByDigest, err := ms.Get(dgst) 178 if err != nil { 179 t.Fatalf("unexpected error fetching manifest by digest: %v", err) 180 } 181 182 if !reflect.DeepEqual(fetchedByDigest, fetchedManifest) { 183 t.Fatalf("fetched manifest not equal: %#v != %#v", fetchedByDigest, fetchedManifest) 184 } 185 186 sigs, err := fetchedJWS.Signatures() 187 if err != nil { 188 t.Fatalf("unable to extract signatures: %v", err) 189 } 190 191 if len(sigs) != 1 { 192 t.Fatalf("unexpected number of signatures: %d != %d", len(sigs), 1) 193 } 194 195 // Grabs the tags and check that this tagged manifest is present 196 tags, err := ms.Tags() 197 if err != nil { 198 t.Fatalf("unexpected error fetching tags: %v", err) 199 } 200 201 if len(tags) != 1 { 202 t.Fatalf("unexpected tags returned: %v", tags) 203 } 204 205 if tags[0] != env.tag { 206 t.Fatalf("unexpected tag found in tags: %v != %v", tags, []string{env.tag}) 207 } 208 209 // Now, push the same manifest with a different key 210 pk2, err := libtrust.GenerateECP256PrivateKey() 211 if err != nil { 212 t.Fatalf("unexpected error generating private key: %v", err) 213 } 214 215 sm2, err := manifest.Sign(&m, pk2) 216 if err != nil { 217 t.Fatalf("unexpected error signing manifest: %v", err) 218 } 219 220 jws2, err := libtrust.ParsePrettySignature(sm2.Raw, "signatures") 221 if err != nil { 222 t.Fatalf("error parsing signature: %v", err) 223 } 224 225 sigs2, err := jws2.Signatures() 226 if err != nil { 227 t.Fatalf("unable to extract signatures: %v", err) 228 } 229 230 if len(sigs2) != 1 { 231 t.Fatalf("unexpected number of signatures: %d != %d", len(sigs2), 1) 232 } 233 234 if err = ms.Put(sm2); err != nil { 235 t.Fatalf("unexpected error putting manifest: %v", err) 236 } 237 238 fetched, err := ms.GetByTag(env.tag) 239 if err != nil { 240 t.Fatalf("unexpected error fetching manifest: %v", err) 241 } 242 243 if _, err := manifest.Verify(fetched); err != nil { 244 t.Fatalf("unexpected error verifying manifest: %v", err) 245 } 246 247 // Assemble our payload and two signatures to get what we expect! 248 expectedJWS, err := libtrust.NewJSONSignature(payload, sigs[0], sigs2[0]) 249 if err != nil { 250 t.Fatalf("unexpected error merging jws: %v", err) 251 } 252 253 expectedSigs, err := expectedJWS.Signatures() 254 if err != nil { 255 t.Fatalf("unexpected error getting expected signatures: %v", err) 256 } 257 258 receivedJWS, err := libtrust.ParsePrettySignature(fetched.Raw, "signatures") 259 if err != nil { 260 t.Fatalf("unexpected error parsing jws: %v", err) 261 } 262 263 receivedPayload, err := receivedJWS.Payload() 264 if err != nil { 265 t.Fatalf("unexpected error extracting received payload: %v", err) 266 } 267 268 if !bytes.Equal(receivedPayload, payload) { 269 t.Fatalf("payloads are not equal") 270 } 271 272 receivedSigs, err := receivedJWS.Signatures() 273 if err != nil { 274 t.Fatalf("error getting signatures: %v", err) 275 } 276 277 for i, sig := range receivedSigs { 278 if !bytes.Equal(sig, expectedSigs[i]) { 279 t.Fatalf("mismatched signatures from remote: %v != %v", string(sig), string(expectedSigs[i])) 280 } 281 } 282 283 // TODO(stevvooe): Currently, deletes are not supported due to some 284 // complexity around managing tag indexes. We'll add this support back in 285 // when the manifest format has settled. For now, we expect an error for 286 // all deletes. 287 if err := ms.Delete(dgst); err == nil { 288 t.Fatalf("unexpected an error deleting manifest by digest: %v", err) 289 } 290 }