2015-05-27 19:23:49 +00:00
|
|
|
package notifications
|
|
|
|
|
|
|
|
import (
|
|
|
|
"testing"
|
|
|
|
|
2016-03-18 22:30:47 +00:00
|
|
|
"github.com/docker/distribution"
|
2015-08-21 04:24:30 +00:00
|
|
|
"github.com/docker/distribution/manifest/schema1"
|
2015-12-15 22:35:23 +00:00
|
|
|
"github.com/docker/distribution/reference"
|
2015-05-27 19:23:49 +00:00
|
|
|
"github.com/docker/distribution/registry/api/v2"
|
|
|
|
"github.com/docker/distribution/uuid"
|
2016-01-20 19:21:04 +00:00
|
|
|
"github.com/docker/libtrust"
|
2016-12-17 00:28:34 +00:00
|
|
|
"github.com/opencontainers/go-digest"
|
2015-05-27 19:23:49 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
// common environment for expected manifest events.
|
|
|
|
|
|
|
|
repo = "test/repo"
|
|
|
|
source = SourceRecord{
|
|
|
|
Addr: "remote.test",
|
|
|
|
InstanceID: uuid.Generate().String(),
|
|
|
|
}
|
2016-02-23 01:49:23 +00:00
|
|
|
ub = mustUB(v2.NewURLBuilderFromString("http://test.example.com/", false))
|
2015-05-27 19:23:49 +00:00
|
|
|
|
|
|
|
actor = ActorRecord{
|
|
|
|
Name: "test",
|
|
|
|
}
|
|
|
|
request = RequestRecord{}
|
2015-08-21 04:24:30 +00:00
|
|
|
m = schema1.Manifest{
|
2015-05-27 19:23:49 +00:00
|
|
|
Name: repo,
|
|
|
|
Tag: "latest",
|
|
|
|
}
|
|
|
|
|
2015-08-21 04:24:30 +00:00
|
|
|
sm *schema1.SignedManifest
|
2015-05-27 19:23:49 +00:00
|
|
|
payload []byte
|
|
|
|
dgst digest.Digest
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestEventBridgeManifestPulled(t *testing.T) {
|
|
|
|
l := createTestEnv(t, testSinkFn(func(events ...Event) error {
|
|
|
|
checkCommonManifest(t, EventActionPull, events...)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}))
|
|
|
|
|
2017-01-14 01:06:03 +00:00
|
|
|
repoRef, _ := reference.WithName(repo)
|
2015-12-15 22:35:23 +00:00
|
|
|
if err := l.ManifestPulled(repoRef, sm); err != nil {
|
2015-05-27 19:23:49 +00:00
|
|
|
t.Fatalf("unexpected error notifying manifest pull: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestEventBridgeManifestPushed(t *testing.T) {
|
|
|
|
l := createTestEnv(t, testSinkFn(func(events ...Event) error {
|
|
|
|
checkCommonManifest(t, EventActionPush, events...)
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}))
|
|
|
|
|
2017-01-14 01:06:03 +00:00
|
|
|
repoRef, _ := reference.WithName(repo)
|
2015-12-15 22:35:23 +00:00
|
|
|
if err := l.ManifestPushed(repoRef, sm); err != nil {
|
2015-05-27 19:23:49 +00:00
|
|
|
t.Fatalf("unexpected error notifying manifest pull: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-18 22:30:47 +00:00
|
|
|
func TestEventBridgeManifestPushedWithTag(t *testing.T) {
|
|
|
|
l := createTestEnv(t, testSinkFn(func(events ...Event) error {
|
|
|
|
checkCommonManifest(t, EventActionPush, events...)
|
|
|
|
if events[0].Target.Tag != "latest" {
|
|
|
|
t.Fatalf("missing or unexpected tag: %#v", events[0].Target)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}))
|
|
|
|
|
2017-01-14 01:06:03 +00:00
|
|
|
repoRef, _ := reference.WithName(repo)
|
2016-03-18 22:30:47 +00:00
|
|
|
if err := l.ManifestPushed(repoRef, sm, distribution.WithTag(m.Tag)); err != nil {
|
|
|
|
t.Fatalf("unexpected error notifying manifest pull: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestEventBridgeManifestPulledWithTag(t *testing.T) {
|
|
|
|
l := createTestEnv(t, testSinkFn(func(events ...Event) error {
|
|
|
|
checkCommonManifest(t, EventActionPull, events...)
|
|
|
|
if events[0].Target.Tag != "latest" {
|
|
|
|
t.Fatalf("missing or unexpected tag: %#v", events[0].Target)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}))
|
|
|
|
|
2017-01-14 01:06:03 +00:00
|
|
|
repoRef, _ := reference.WithName(repo)
|
2016-03-18 22:30:47 +00:00
|
|
|
if err := l.ManifestPulled(repoRef, sm, distribution.WithTag(m.Tag)); err != nil {
|
|
|
|
t.Fatalf("unexpected error notifying manifest pull: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-27 19:23:49 +00:00
|
|
|
func TestEventBridgeManifestDeleted(t *testing.T) {
|
|
|
|
l := createTestEnv(t, testSinkFn(func(events ...Event) error {
|
2016-01-28 17:56:37 +00:00
|
|
|
checkDeleted(t, EventActionDelete, events...)
|
2018-07-18 18:25:59 +00:00
|
|
|
if events[0].Target.Digest != dgst {
|
|
|
|
t.Fatalf("unexpected digest on event target: %q != %q", events[0].Target.Digest, dgst)
|
|
|
|
}
|
2015-05-27 19:23:49 +00:00
|
|
|
return nil
|
|
|
|
}))
|
|
|
|
|
2017-01-14 01:06:03 +00:00
|
|
|
repoRef, _ := reference.WithName(repo)
|
2016-01-28 17:56:37 +00:00
|
|
|
if err := l.ManifestDeleted(repoRef, dgst); err != nil {
|
2015-05-27 19:23:49 +00:00
|
|
|
t.Fatalf("unexpected error notifying manifest pull: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-18 18:25:59 +00:00
|
|
|
func TestEventBridgeTagDeleted(t *testing.T) {
|
|
|
|
l := createTestEnv(t, testSinkFn(func(events ...Event) error {
|
|
|
|
checkDeleted(t, EventActionDelete, events...)
|
|
|
|
if events[0].Target.Tag != m.Tag {
|
|
|
|
t.Fatalf("unexpected tag on event target: %q != %q", events[0].Target.Tag, m.Tag)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}))
|
|
|
|
|
|
|
|
repoRef, _ := reference.WithName(repo)
|
|
|
|
if err := l.TagDeleted(repoRef, m.Tag); err != nil {
|
|
|
|
t.Fatalf("unexpected error notifying tag deletion: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-03 05:58:52 +00:00
|
|
|
func TestEventBridgeRepoDeleted(t *testing.T) {
|
|
|
|
l := createTestEnv(t, testSinkFn(func(events ...Event) error {
|
|
|
|
checkDeleted(t, EventActionDelete, events...)
|
|
|
|
return nil
|
|
|
|
}))
|
|
|
|
|
|
|
|
repoRef, _ := reference.WithName(repo)
|
|
|
|
if err := l.RepoDeleted(repoRef); err != nil {
|
|
|
|
t.Fatalf("unexpected error notifying repo deletion: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-27 19:23:49 +00:00
|
|
|
func createTestEnv(t *testing.T, fn testSinkFn) Listener {
|
|
|
|
pk, err := libtrust.GenerateECP256PrivateKey()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error generating private key: %v", err)
|
|
|
|
}
|
|
|
|
|
2015-08-21 04:24:30 +00:00
|
|
|
sm, err = schema1.Sign(&m, pk)
|
2015-05-27 19:23:49 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error signing manifest: %v", err)
|
|
|
|
}
|
|
|
|
|
2016-01-20 19:21:04 +00:00
|
|
|
payload = sm.Canonical
|
2015-12-14 22:30:51 +00:00
|
|
|
dgst = digest.FromBytes(payload)
|
2015-05-27 19:23:49 +00:00
|
|
|
|
|
|
|
return NewBridge(ub, source, actor, request, fn)
|
|
|
|
}
|
|
|
|
|
2016-01-28 17:56:37 +00:00
|
|
|
func checkDeleted(t *testing.T, action string, events ...Event) {
|
|
|
|
if len(events) != 1 {
|
|
|
|
t.Fatalf("unexpected number of events: %v != 1", len(events))
|
|
|
|
}
|
|
|
|
|
|
|
|
event := events[0]
|
|
|
|
|
|
|
|
if event.Source != source {
|
|
|
|
t.Fatalf("source not equal: %#v != %#v", event.Source, source)
|
|
|
|
}
|
|
|
|
|
|
|
|
if event.Request != request {
|
|
|
|
t.Fatalf("request not equal: %#v != %#v", event.Request, request)
|
|
|
|
}
|
|
|
|
|
|
|
|
if event.Actor != actor {
|
|
|
|
t.Fatalf("request not equal: %#v != %#v", event.Actor, actor)
|
|
|
|
}
|
|
|
|
|
|
|
|
if event.Target.Repository != repo {
|
|
|
|
t.Fatalf("unexpected repository: %q != %q", event.Target.Repository, repo)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-27 19:23:49 +00:00
|
|
|
func checkCommonManifest(t *testing.T, action string, events ...Event) {
|
|
|
|
checkCommon(t, events...)
|
|
|
|
|
|
|
|
event := events[0]
|
|
|
|
if event.Action != action {
|
|
|
|
t.Fatalf("unexpected event action: %q != %q", event.Action, action)
|
|
|
|
}
|
|
|
|
|
2017-01-14 01:06:03 +00:00
|
|
|
repoRef, _ := reference.WithName(repo)
|
2015-12-16 00:43:13 +00:00
|
|
|
ref, _ := reference.WithDigest(repoRef, dgst)
|
|
|
|
u, err := ub.BuildManifestURL(ref)
|
2015-05-27 19:23:49 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error building expected url: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if event.Target.URL != u {
|
2015-08-21 04:50:15 +00:00
|
|
|
t.Fatalf("incorrect url passed: \n%q != \n%q", event.Target.URL, u)
|
2015-05-27 19:23:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func checkCommon(t *testing.T, events ...Event) {
|
|
|
|
if len(events) != 1 {
|
|
|
|
t.Fatalf("unexpected number of events: %v != 1", len(events))
|
|
|
|
}
|
|
|
|
|
|
|
|
event := events[0]
|
|
|
|
|
|
|
|
if event.Source != source {
|
|
|
|
t.Fatalf("source not equal: %#v != %#v", event.Source, source)
|
|
|
|
}
|
|
|
|
|
|
|
|
if event.Request != request {
|
|
|
|
t.Fatalf("request not equal: %#v != %#v", event.Request, request)
|
|
|
|
}
|
|
|
|
|
|
|
|
if event.Actor != actor {
|
|
|
|
t.Fatalf("request not equal: %#v != %#v", event.Actor, actor)
|
|
|
|
}
|
|
|
|
|
|
|
|
if event.Target.Digest != dgst {
|
|
|
|
t.Fatalf("unexpected digest on event target: %q != %q", event.Target.Digest, dgst)
|
|
|
|
}
|
|
|
|
|
|
|
|
if event.Target.Length != int64(len(payload)) {
|
|
|
|
t.Fatalf("unexpected target length: %v != %v", event.Target.Length, len(payload))
|
|
|
|
}
|
|
|
|
|
|
|
|
if event.Target.Repository != repo {
|
|
|
|
t.Fatalf("unexpected repository: %q != %q", event.Target.Repository, repo)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
type testSinkFn func(events ...Event) error
|
|
|
|
|
|
|
|
func (tsf testSinkFn) Write(events ...Event) error {
|
|
|
|
return tsf(events...)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tsf testSinkFn) Close() error { return nil }
|
|
|
|
|
|
|
|
func mustUB(ub *v2.URLBuilder, err error) *v2.URLBuilder {
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return ub
|
|
|
|
}
|