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  }