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  }