...

Source file src/github.com/docker/distribution/notifications/listener_test.go

Documentation: github.com/docker/distribution/notifications

     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  	// Now take the registry through a number of operations
    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  // checkExerciseRegistry takes the registry through all of its operations,
   117  // carrying out generic checks.
   118  func checkExerciseRepository(t *testing.T, repository distribution.Repository, remover distribution.RepositoryRemover) {
   119  	// TODO(stevvooe): This would be a nice testutil function. Basically, it
   120  	// takes the registry through a common set of operations. This could be
   121  	// used to make cross-cutting updates by changing internals that affect
   122  	// update counts. Basically, it would make writing tests a lot easier.
   123  
   124  	ctx := context.Background()
   125  	tag := "thetag"
   126  	// todo: change this to use Builder
   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  		// Use the resumes, as well!
   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  		// Then fetch the blobs
   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