github.com/lusis/distribution@v2.0.1+incompatible/registry/storage/layer_test.go (about) 1 package storage 2 3 import ( 4 "bytes" 5 "crypto/sha256" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "os" 10 "testing" 11 12 "github.com/docker/distribution" 13 "github.com/docker/distribution/digest" 14 "github.com/docker/distribution/registry/storage/cache" 15 storagedriver "github.com/docker/distribution/registry/storage/driver" 16 "github.com/docker/distribution/registry/storage/driver/inmemory" 17 "github.com/docker/distribution/testutil" 18 "golang.org/x/net/context" 19 ) 20 21 // TestSimpleLayerUpload covers the layer upload process, exercising common 22 // error paths that might be seen during an upload. 23 func TestSimpleLayerUpload(t *testing.T) { 24 randomDataReader, tarSumStr, err := testutil.CreateRandomTarFile() 25 26 if err != nil { 27 t.Fatalf("error creating random reader: %v", err) 28 } 29 30 dgst := digest.Digest(tarSumStr) 31 32 if err != nil { 33 t.Fatalf("error allocating upload store: %v", err) 34 } 35 36 ctx := context.Background() 37 imageName := "foo/bar" 38 driver := inmemory.New() 39 registry := NewRegistryWithDriver(driver, cache.NewInMemoryLayerInfoCache()) 40 repository, err := registry.Repository(ctx, imageName) 41 if err != nil { 42 t.Fatalf("unexpected error getting repo: %v", err) 43 } 44 ls := repository.Layers() 45 46 h := sha256.New() 47 rd := io.TeeReader(randomDataReader, h) 48 49 layerUpload, err := ls.Upload() 50 51 if err != nil { 52 t.Fatalf("unexpected error starting layer upload: %s", err) 53 } 54 55 // Cancel the upload then restart it 56 if err := layerUpload.Cancel(); err != nil { 57 t.Fatalf("unexpected error during upload cancellation: %v", err) 58 } 59 60 // Do a resume, get unknown upload 61 layerUpload, err = ls.Resume(layerUpload.UUID()) 62 if err != distribution.ErrLayerUploadUnknown { 63 t.Fatalf("unexpected error resuming upload, should be unkown: %v", err) 64 } 65 66 // Restart! 67 layerUpload, err = ls.Upload() 68 if err != nil { 69 t.Fatalf("unexpected error starting layer upload: %s", err) 70 } 71 72 // Get the size of our random tarfile 73 randomDataSize, err := seekerSize(randomDataReader) 74 if err != nil { 75 t.Fatalf("error getting seeker size of random data: %v", err) 76 } 77 78 nn, err := io.Copy(layerUpload, rd) 79 if err != nil { 80 t.Fatalf("unexpected error uploading layer data: %v", err) 81 } 82 83 if nn != randomDataSize { 84 t.Fatalf("layer data write incomplete") 85 } 86 87 offset, err := layerUpload.Seek(0, os.SEEK_CUR) 88 if err != nil { 89 t.Fatalf("unexpected error seeking layer upload: %v", err) 90 } 91 92 if offset != nn { 93 t.Fatalf("layerUpload not updated with correct offset: %v != %v", offset, nn) 94 } 95 layerUpload.Close() 96 97 // Do a resume, for good fun 98 layerUpload, err = ls.Resume(layerUpload.UUID()) 99 if err != nil { 100 t.Fatalf("unexpected error resuming upload: %v", err) 101 } 102 103 sha256Digest := digest.NewDigest("sha256", h) 104 layer, err := layerUpload.Finish(dgst) 105 106 if err != nil { 107 t.Fatalf("unexpected error finishing layer upload: %v", err) 108 } 109 110 // After finishing an upload, it should no longer exist. 111 if _, err := ls.Resume(layerUpload.UUID()); err != distribution.ErrLayerUploadUnknown { 112 t.Fatalf("expected layer upload to be unknown, got %v", err) 113 } 114 115 // Test for existence. 116 exists, err := ls.Exists(layer.Digest()) 117 if err != nil { 118 t.Fatalf("unexpected error checking for existence: %v", err) 119 } 120 121 if !exists { 122 t.Fatalf("layer should now exist") 123 } 124 125 h.Reset() 126 nn, err = io.Copy(h, layer) 127 if err != nil { 128 t.Fatalf("error reading layer: %v", err) 129 } 130 131 if nn != randomDataSize { 132 t.Fatalf("incorrect read length") 133 } 134 135 if digest.NewDigest("sha256", h) != sha256Digest { 136 t.Fatalf("unexpected digest from uploaded layer: %q != %q", digest.NewDigest("sha256", h), sha256Digest) 137 } 138 } 139 140 // TestSimpleLayerRead just creates a simple layer file and ensures that basic 141 // open, read, seek, read works. More specific edge cases should be covered in 142 // other tests. 143 func TestSimpleLayerRead(t *testing.T) { 144 ctx := context.Background() 145 imageName := "foo/bar" 146 driver := inmemory.New() 147 registry := NewRegistryWithDriver(driver, cache.NewInMemoryLayerInfoCache()) 148 repository, err := registry.Repository(ctx, imageName) 149 if err != nil { 150 t.Fatalf("unexpected error getting repo: %v", err) 151 } 152 ls := repository.Layers() 153 154 randomLayerReader, tarSumStr, err := testutil.CreateRandomTarFile() 155 if err != nil { 156 t.Fatalf("error creating random data: %v", err) 157 } 158 159 dgst := digest.Digest(tarSumStr) 160 161 // Test for existence. 162 exists, err := ls.Exists(dgst) 163 if err != nil { 164 t.Fatalf("unexpected error checking for existence: %v", err) 165 } 166 167 if exists { 168 t.Fatalf("layer should not exist") 169 } 170 171 // Try to get the layer and make sure we get a not found error 172 layer, err := ls.Fetch(dgst) 173 if err == nil { 174 t.Fatalf("error expected fetching unknown layer") 175 } 176 177 switch err.(type) { 178 case distribution.ErrUnknownLayer: 179 err = nil 180 default: 181 t.Fatalf("unexpected error fetching non-existent layer: %v", err) 182 } 183 184 randomLayerDigest, err := writeTestLayer(driver, defaultPathMapper, imageName, dgst, randomLayerReader) 185 if err != nil { 186 t.Fatalf("unexpected error writing test layer: %v", err) 187 } 188 189 randomLayerSize, err := seekerSize(randomLayerReader) 190 if err != nil { 191 t.Fatalf("error getting seeker size for random layer: %v", err) 192 } 193 194 layer, err = ls.Fetch(dgst) 195 if err != nil { 196 t.Fatal(err) 197 } 198 defer layer.Close() 199 200 // Now check the sha digest and ensure its the same 201 h := sha256.New() 202 nn, err := io.Copy(h, layer) 203 if err != nil && err != io.EOF { 204 t.Fatalf("unexpected error copying to hash: %v", err) 205 } 206 207 if nn != randomLayerSize { 208 t.Fatalf("stored incorrect number of bytes in layer: %d != %d", nn, randomLayerSize) 209 } 210 211 sha256Digest := digest.NewDigest("sha256", h) 212 if sha256Digest != randomLayerDigest { 213 t.Fatalf("fetched digest does not match: %q != %q", sha256Digest, randomLayerDigest) 214 } 215 216 // Now seek back the layer, read the whole thing and check against randomLayerData 217 offset, err := layer.Seek(0, os.SEEK_SET) 218 if err != nil { 219 t.Fatalf("error seeking layer: %v", err) 220 } 221 222 if offset != 0 { 223 t.Fatalf("seek failed: expected 0 offset, got %d", offset) 224 } 225 226 p, err := ioutil.ReadAll(layer) 227 if err != nil { 228 t.Fatalf("error reading all of layer: %v", err) 229 } 230 231 if len(p) != int(randomLayerSize) { 232 t.Fatalf("layer data read has different length: %v != %v", len(p), randomLayerSize) 233 } 234 235 // Reset the randomLayerReader and read back the buffer 236 _, err = randomLayerReader.Seek(0, os.SEEK_SET) 237 if err != nil { 238 t.Fatalf("error resetting layer reader: %v", err) 239 } 240 241 randomLayerData, err := ioutil.ReadAll(randomLayerReader) 242 if err != nil { 243 t.Fatalf("random layer read failed: %v", err) 244 } 245 246 if !bytes.Equal(p, randomLayerData) { 247 t.Fatalf("layer data not equal") 248 } 249 } 250 251 // TestLayerUploadZeroLength uploads zero-length 252 func TestLayerUploadZeroLength(t *testing.T) { 253 ctx := context.Background() 254 imageName := "foo/bar" 255 driver := inmemory.New() 256 registry := NewRegistryWithDriver(driver, cache.NewInMemoryLayerInfoCache()) 257 repository, err := registry.Repository(ctx, imageName) 258 if err != nil { 259 t.Fatalf("unexpected error getting repo: %v", err) 260 } 261 ls := repository.Layers() 262 263 upload, err := ls.Upload() 264 if err != nil { 265 t.Fatalf("unexpected error starting upload: %v", err) 266 } 267 268 io.Copy(upload, bytes.NewReader([]byte{})) 269 270 dgst, err := digest.FromReader(bytes.NewReader([]byte{})) 271 if err != nil { 272 t.Fatalf("error getting zero digest: %v", err) 273 } 274 275 if dgst != digest.DigestSha256EmptyTar { 276 // sanity check on zero digest 277 t.Fatalf("digest not as expected: %v != %v", dgst, digest.DigestTarSumV1EmptyTar) 278 } 279 280 layer, err := upload.Finish(dgst) 281 if err != nil { 282 t.Fatalf("unexpected error finishing upload: %v", err) 283 } 284 285 if layer.Digest() != dgst { 286 t.Fatalf("unexpected digest: %v != %v", layer.Digest(), dgst) 287 } 288 } 289 290 // writeRandomLayer creates a random layer under name and tarSum using driver 291 // and pathMapper. An io.ReadSeeker with the data is returned, along with the 292 // sha256 hex digest. 293 func writeRandomLayer(driver storagedriver.StorageDriver, pathMapper *pathMapper, name string) (rs io.ReadSeeker, tarSum digest.Digest, sha256digest digest.Digest, err error) { 294 reader, tarSumStr, err := testutil.CreateRandomTarFile() 295 if err != nil { 296 return nil, "", "", err 297 } 298 299 tarSum = digest.Digest(tarSumStr) 300 301 // Now, actually create the layer. 302 randomLayerDigest, err := writeTestLayer(driver, pathMapper, name, tarSum, ioutil.NopCloser(reader)) 303 304 if _, err := reader.Seek(0, os.SEEK_SET); err != nil { 305 return nil, "", "", err 306 } 307 308 return reader, tarSum, randomLayerDigest, err 309 } 310 311 // seekerSize seeks to the end of seeker, checks the size and returns it to 312 // the original state, returning the size. The state of the seeker should be 313 // treated as unknown if an error is returned. 314 func seekerSize(seeker io.ReadSeeker) (int64, error) { 315 current, err := seeker.Seek(0, os.SEEK_CUR) 316 if err != nil { 317 return 0, err 318 } 319 320 end, err := seeker.Seek(0, os.SEEK_END) 321 if err != nil { 322 return 0, err 323 } 324 325 resumed, err := seeker.Seek(current, os.SEEK_SET) 326 if err != nil { 327 return 0, err 328 } 329 330 if resumed != current { 331 return 0, fmt.Errorf("error returning seeker to original state, could not seek back to original location") 332 } 333 334 return end, nil 335 } 336 337 // createTestLayer creates a simple test layer in the provided driver under 338 // tarsum dgst, returning the sha256 digest location. This is implemented 339 // piecemeal and should probably be replaced by the uploader when it's ready. 340 func writeTestLayer(driver storagedriver.StorageDriver, pathMapper *pathMapper, name string, dgst digest.Digest, content io.Reader) (digest.Digest, error) { 341 h := sha256.New() 342 rd := io.TeeReader(content, h) 343 344 p, err := ioutil.ReadAll(rd) 345 346 if err != nil { 347 return "", nil 348 } 349 350 blobDigestSHA := digest.NewDigest("sha256", h) 351 352 blobPath, err := pathMapper.path(blobDataPathSpec{ 353 digest: dgst, 354 }) 355 356 if err := driver.PutContent(blobPath, p); err != nil { 357 return "", err 358 } 359 360 if err != nil { 361 return "", err 362 } 363 364 layerLinkPath, err := pathMapper.path(layerLinkPathSpec{ 365 name: name, 366 digest: dgst, 367 }) 368 369 if err != nil { 370 return "", err 371 } 372 373 if err := driver.PutContent(layerLinkPath, []byte(dgst)); err != nil { 374 return "", nil 375 } 376 377 return blobDigestSHA, err 378 }