From 97b4a64e2ce0d6db030e6a65c22ee7c4745ce85b Mon Sep 17 00:00:00 2001 From: Wojciech Tyczynski Date: Tue, 1 Sep 2015 15:27:13 +0200 Subject: [PATCH] Refactor registry etcd delete tests --- pkg/api/rest/resttest/resttest.go | 263 +++++++++--------- pkg/registry/controller/etcd/etcd_test.go | 66 +---- pkg/registry/daemon/etcd/etcd_test.go | 66 +---- pkg/registry/deployment/etcd/etcd_test.go | 65 +---- pkg/registry/endpoint/etcd/etcd_test.go | 90 ++---- .../horizontalpodautoscaler/etcd/etcd_test.go | 53 ++-- .../horizontalpodautoscaler/strategy.go | 25 +- pkg/registry/limitrange/etcd/etcd_test.go | 29 ++ pkg/registry/minion/etcd/etcd_test.go | 59 +--- pkg/registry/namespace/etcd/etcd_test.go | 75 ++--- pkg/registry/namespace/strategy.go | 7 +- .../persistentvolume/etcd/etcd_test.go | 89 ++---- pkg/registry/persistentvolume/strategy.go | 3 +- .../persistentvolumeclaim/etcd/etcd_test.go | 125 ++------- .../persistentvolumeclaim/strategy.go | 3 +- pkg/registry/pod/etcd/etcd_test.go | 113 +------- pkg/registry/podtemplate/etcd/etcd_test.go | 29 ++ pkg/registry/podtemplate/strategy.go | 25 +- pkg/registry/registrytest/etcd.go | 31 +++ pkg/registry/resourcequota/etcd/etcd_test.go | 58 +--- pkg/registry/secret/etcd/etcd_test.go | 29 ++ pkg/registry/service/etcd/etcd_test.go | 6 + pkg/registry/serviceaccount/etcd/etcd_test.go | 31 +++ .../thirdpartyresource/etcd/etcd_test.go | 53 ++-- 24 files changed, 497 insertions(+), 896 deletions(-) diff --git a/pkg/api/rest/resttest/resttest.go b/pkg/api/rest/resttest/resttest.go index 23b5a87221a..adf2d7e3e9d 100644 --- a/pkg/api/rest/resttest/resttest.go +++ b/pkg/api/rest/resttest/resttest.go @@ -37,11 +37,12 @@ import ( type Tester struct { *testing.T - storage rest.Storage - storageError injectErrorFunc - clusterScope bool - createOnUpdate bool - generatesName bool + storage rest.Storage + storageError injectErrorFunc + clusterScope bool + createOnUpdate bool + generatesName bool + returnDeletedObject bool } type injectErrorFunc func(err error) @@ -75,6 +76,11 @@ func (t *Tester) GeneratesName() *Tester { return t } +func (t *Tester) ReturnDeletedObject() *Tester { + t.returnDeletedObject = true + return t +} + // TestNamespace returns the namespace that will be used when creating contexts. // Returns NamespaceNone for cluster-scoped objects. func (t *Tester) TestNamespace() string { @@ -125,6 +131,7 @@ type EmitFunc func(runtime.Object, string) error type GetFunc func(api.Context, runtime.Object) (runtime.Object, error) type InitWatchFunc func() type InjectErrFunc func(err error) +type IsErrorFunc func(err error) bool type SetFunc func(api.Context, runtime.Object) error type SetRVFunc func(uint64) type UpdateFunc func(runtime.Object) runtime.Object @@ -160,50 +167,45 @@ func (t *Tester) TestUpdate(valid runtime.Object, setFn SetFunc, setRVFn SetRVFu } // Test deleting an object. -// TODO(wojtek-t): Change it to use AssignFunc instead. -func (t *Tester) TestDelete(createFn func() runtime.Object, wasGracefulFn func() bool, invalid ...runtime.Object) { - t.TestDeleteNonExist(createFn) - t.TestDeleteNoGraceful(createFn, wasGracefulFn) - t.TestDeleteInvokesValidation(invalid...) - // TODO: Test delete namespace mismatch rejection - // once #5684 is fixed. +func (t *Tester) TestDelete(valid runtime.Object, setFn SetFunc, getFn GetFunc, isNotFoundFn IsErrorFunc) { + t.testDeleteNonExist(copyOrDie(valid)) + t.testDeleteNoGraceful(copyOrDie(valid), setFn, getFn, isNotFoundFn) } -// Test graceful deletion. -// TODO(wojtek-t): Change it to use AssignFunc instead. -func (t *Tester) TestDeleteGraceful(createFn func() runtime.Object, expectedGrace int64, wasGracefulFn func() bool) { - t.TestDeleteGracefulHasDefault(createFn(), expectedGrace, wasGracefulFn) - t.TestDeleteGracefulWithValue(createFn(), expectedGrace, wasGracefulFn) - t.TestDeleteGracefulUsesZeroOnNil(createFn(), 0) - t.TestDeleteGracefulExtend(createFn(), expectedGrace, wasGracefulFn) - t.TestDeleteGracefulImmediate(createFn(), expectedGrace, wasGracefulFn) +// Test gracefully deleting an object. +func (t *Tester) TestDeleteGraceful(valid runtime.Object, setFn SetFunc, getFn GetFunc, expectedGrace int64) { + t.testDeleteGracefulHasDefault(copyOrDie(valid), setFn, getFn, expectedGrace) + t.testDeleteGracefulWithValue(copyOrDie(valid), setFn, getFn, expectedGrace) + t.testDeleteGracefulUsesZeroOnNil(copyOrDie(valid), setFn, expectedGrace) + t.testDeleteGracefulExtend(copyOrDie(valid), setFn, getFn, expectedGrace) + t.testDeleteGracefulImmediate(copyOrDie(valid), setFn, getFn, expectedGrace) } // Test getting object. -func (t *Tester) TestGet(obj runtime.Object) { - t.testGetFound(obj) - t.testGetNotFound(obj) - t.testGetMimatchedNamespace(obj) +func (t *Tester) TestGet(valid runtime.Object) { + t.testGetFound(copyOrDie(valid)) + t.testGetNotFound(copyOrDie(valid)) + t.testGetMimatchedNamespace(copyOrDie(valid)) if !t.clusterScope { - t.testGetDifferentNamespace(obj) + t.testGetDifferentNamespace(copyOrDie(valid)) } } // Test listing objects. -func (t *Tester) TestList(obj runtime.Object, assignFn AssignFunc, setRVFn SetRVFunc) { +func (t *Tester) TestList(valid runtime.Object, assignFn AssignFunc, setRVFn SetRVFunc) { t.testListError() - t.testListFound(obj, assignFn) + t.testListFound(copyOrDie(valid), assignFn) t.testListNotFound(assignFn, setRVFn) - t.testListMatchLabels(obj, assignFn) + t.testListMatchLabels(copyOrDie(valid), assignFn) } // Test watching objects. func (t *Tester) TestWatch( - obj runtime.Object, initWatchFn InitWatchFunc, injectErrFn InjectErrFunc, emitFn EmitFunc, + valid runtime.Object, initWatchFn InitWatchFunc, injectErrFn InjectErrFunc, emitFn EmitFunc, labelsPass, labelsFail []labels.Set, fieldsPass, fieldsFail []fields.Set, actions []string) { t.testWatch(initWatchFn, injectErrFn) - t.testWatchLabels(copyOrDie(obj), initWatchFn, emitFn, labelsPass, labelsFail, actions) - t.testWatchFields(copyOrDie(obj), initWatchFn, emitFn, fieldsPass, fieldsFail, actions) + t.testWatchLabels(copyOrDie(valid), initWatchFn, emitFn, labelsPass, labelsFail, actions) + t.testWatchFields(copyOrDie(valid), initWatchFn, emitFn, fieldsPass, fieldsFail, actions) } // ============================================================================= @@ -512,26 +514,40 @@ func (t *Tester) testUpdateRejectsMismatchedNamespace(obj runtime.Object, setFn // ============================================================================= // Deletion tests. -func (t *Tester) TestDeleteInvokesValidation(invalid ...runtime.Object) { - for i, obj := range invalid { - objectMeta := t.getObjectMetaOrFail(obj) - ctx := t.TestContext() - _, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, nil) - if !errors.IsInvalid(err) { - t.Errorf("%d: Expected to get an invalid resource error, got %v", i, err) +func (t *Tester) testDeleteNoGraceful(obj runtime.Object, setFn SetFunc, getFn GetFunc, isNotFoundFn IsErrorFunc) { + ctx := t.TestContext() + + foo := copyOrDie(obj) + t.setObjectMeta(foo, "foo1") + if err := setFn(ctx, foo); err != nil { + t.Errorf("unexpected error: %v", err) + } + objectMeta := t.getObjectMetaOrFail(foo) + obj, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(10)) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if !t.returnDeletedObject { + if status, ok := obj.(*api.Status); !ok { + t.Errorf("expected status of delete, got %v", status) + } else if status.Status != api.StatusSuccess { + t.Errorf("expected success, got: %v", status.Status) } } + + _, err = getFn(ctx, foo) + if err == nil || !isNotFoundFn(err) { + t.Errorf("unexpected error: %v", err) + } } -func (t *Tester) TestDeleteNonExist(createFn func() runtime.Object) { - existing := createFn() - objectMeta := t.getObjectMetaOrFail(existing) - context := t.TestContext() +func (t *Tester) testDeleteNonExist(obj runtime.Object) { + objectMeta := t.getObjectMetaOrFail(obj) t.withStorageError(&etcd.EtcdError{ErrorCode: tools.EtcdErrorCodeNotFound}, func() { - _, err := t.storage.(rest.GracefulDeleter).Delete(context, objectMeta.Name, nil) + _, err := t.storage.(rest.GracefulDeleter).Delete(t.TestContext(), objectMeta.Name, nil) if err == nil || !errors.IsNotFound(err) { - t.Fatalf("Unexpected error: %v", err) + t.Errorf("unexpected error: %v", err) } }) } @@ -539,100 +555,77 @@ func (t *Tester) TestDeleteNonExist(createFn func() runtime.Object) { // ============================================================================= // Graceful Deletion tests. -func (t *Tester) TestDeleteNoGraceful(createFn func() runtime.Object, wasGracefulFn func() bool) { - existing := createFn() - objectMeta := t.getObjectMetaOrFail(existing) - ctx := api.WithNamespace(t.TestContext(), objectMeta.Namespace) - _, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(10)) - if err != nil { +func (t *Tester) testDeleteGracefulHasDefault(obj runtime.Object, setFn SetFunc, getFn GetFunc, expectedGrace int64) { + ctx := t.TestContext() + + foo := copyOrDie(obj) + t.setObjectMeta(foo, "foo1") + if err := setFn(ctx, foo); err != nil { t.Errorf("unexpected error: %v", err) } - if _, err := t.storage.(rest.Getter).Get(ctx, objectMeta.Name); !errors.IsNotFound(err) { - t.Errorf("unexpected error, object should not exist: %v", err) - } - if wasGracefulFn() { - t.Errorf("resource should not support graceful delete") - } -} - -func (t *Tester) TestDeleteGracefulHasDefault(existing runtime.Object, expectedGrace int64, wasGracefulFn func() bool) { - objectMeta := t.getObjectMetaOrFail(existing) - ctx := api.WithNamespace(t.TestContext(), objectMeta.Namespace) + objectMeta := t.getObjectMetaOrFail(foo) _, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, &api.DeleteOptions{}) if err != nil { t.Errorf("unexpected error: %v", err) } - if !wasGracefulFn() { - t.Errorf("did not gracefully delete resource") - return + if _, err := getFn(ctx, foo); err != nil { + t.Fatalf("did not gracefully delete resource", err) } + object, err := t.storage.(rest.Getter).Get(ctx, objectMeta.Name) if err != nil { - t.Errorf("unexpected error, object should exist: %v", err) - return + t.Fatalf("unexpected error, object should exist: %v", err) } - objectMeta, err = api.ObjectMetaFor(object) - if err != nil { - t.Fatalf("object does not have ObjectMeta: %v\n%#v", err, object) - } - if objectMeta.DeletionTimestamp == nil { - t.Errorf("did not set deletion timestamp") - } - if objectMeta.DeletionGracePeriodSeconds == nil { - t.Fatalf("did not set deletion grace period seconds") - } - if *objectMeta.DeletionGracePeriodSeconds != expectedGrace { - t.Errorf("actual grace period does not match expected: %d", *objectMeta.DeletionGracePeriodSeconds) + objectMeta = t.getObjectMetaOrFail(object) + if objectMeta.DeletionTimestamp == nil || objectMeta.DeletionGracePeriodSeconds == nil || *objectMeta.DeletionGracePeriodSeconds != expectedGrace { + t.Errorf("unexpected deleted meta: %#v", objectMeta) } } -func (t *Tester) TestDeleteGracefulWithValue(existing runtime.Object, expectedGrace int64, wasGracefulFn func() bool) { - objectMeta, err := api.ObjectMetaFor(existing) - if err != nil { - t.Fatalf("object does not have ObjectMeta: %v\n%#v", err, existing) - } +func (t *Tester) testDeleteGracefulWithValue(obj runtime.Object, setFn SetFunc, getFn GetFunc, expectedGrace int64) { + ctx := t.TestContext() - ctx := api.WithNamespace(t.TestContext(), objectMeta.Namespace) - _, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(expectedGrace+2)) + foo := copyOrDie(obj) + t.setObjectMeta(foo, "foo2") + if err := setFn(ctx, foo); err != nil { + t.Errorf("unexpected error: %v", err) + } + objectMeta := t.getObjectMetaOrFail(foo) + _, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(expectedGrace+2)) if err != nil { t.Errorf("unexpected error: %v", err) } - if !wasGracefulFn() { - t.Errorf("did not gracefully delete resource") + if _, err := getFn(ctx, foo); err != nil { + t.Fatalf("did not gracefully delete resource", err) } + object, err := t.storage.(rest.Getter).Get(ctx, objectMeta.Name) if err != nil { t.Errorf("unexpected error, object should exist: %v", err) } - objectMeta, err = api.ObjectMetaFor(object) - if err != nil { - t.Fatalf("object does not have ObjectMeta: %v\n%#v", err, object) - } - if objectMeta.DeletionTimestamp == nil { - t.Errorf("did not set deletion timestamp") - } - if objectMeta.DeletionGracePeriodSeconds == nil { - t.Fatalf("did not set deletion grace period seconds") - } - if *objectMeta.DeletionGracePeriodSeconds != expectedGrace+2 { - t.Errorf("actual grace period does not match expected: %d", *objectMeta.DeletionGracePeriodSeconds) + objectMeta = t.getObjectMetaOrFail(object) + if objectMeta.DeletionTimestamp == nil || objectMeta.DeletionGracePeriodSeconds == nil || *objectMeta.DeletionGracePeriodSeconds != expectedGrace+2 { + t.Errorf("unexpected deleted meta: %#v", objectMeta) } } -func (t *Tester) TestDeleteGracefulExtend(existing runtime.Object, expectedGrace int64, wasGracefulFn func() bool) { - objectMeta, err := api.ObjectMetaFor(existing) - if err != nil { - t.Fatalf("object does not have ObjectMeta: %v\n%#v", err, existing) - } +func (t *Tester) testDeleteGracefulExtend(obj runtime.Object, setFn SetFunc, getFn GetFunc, expectedGrace int64) { + ctx := t.TestContext() - ctx := api.WithNamespace(t.TestContext(), objectMeta.Namespace) - _, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(expectedGrace)) + foo := copyOrDie(obj) + t.setObjectMeta(foo, "foo3") + if err := setFn(ctx, foo); err != nil { + t.Errorf("unexpected error: %v", err) + } + objectMeta := t.getObjectMetaOrFail(foo) + _, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(expectedGrace)) if err != nil { t.Errorf("unexpected error: %v", err) } - if !wasGracefulFn() { - t.Errorf("did not gracefully delete resource") + if _, err := getFn(ctx, foo); err != nil { + t.Fatalf("did not gracefully delete resource", err) } + // second delete duration is ignored _, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(expectedGrace+2)) if err != nil { @@ -642,35 +635,29 @@ func (t *Tester) TestDeleteGracefulExtend(existing runtime.Object, expectedGrace if err != nil { t.Errorf("unexpected error, object should exist: %v", err) } - objectMeta, err = api.ObjectMetaFor(object) - if err != nil { - t.Fatalf("object does not have ObjectMeta: %v\n%#v", err, object) - } - if objectMeta.DeletionTimestamp == nil { - t.Errorf("did not set deletion timestamp") - } - if objectMeta.DeletionGracePeriodSeconds == nil { - t.Fatalf("did not set deletion grace period seconds") - } - if *objectMeta.DeletionGracePeriodSeconds != expectedGrace { - t.Errorf("actual grace period does not match expected: %d", *objectMeta.DeletionGracePeriodSeconds) + objectMeta = t.getObjectMetaOrFail(object) + if objectMeta.DeletionTimestamp == nil || objectMeta.DeletionGracePeriodSeconds == nil || *objectMeta.DeletionGracePeriodSeconds != expectedGrace { + t.Errorf("unexpected deleted meta: %#v", objectMeta) } } -func (t *Tester) TestDeleteGracefulImmediate(existing runtime.Object, expectedGrace int64, wasGracefulFn func() bool) { - objectMeta, err := api.ObjectMetaFor(existing) - if err != nil { - t.Fatalf("object does not have ObjectMeta: %v\n%#v", err, existing) - } +func (t *Tester) testDeleteGracefulImmediate(obj runtime.Object, setFn SetFunc, getFn GetFunc, expectedGrace int64) { + ctx := t.TestContext() - ctx := api.WithNamespace(t.TestContext(), objectMeta.Namespace) - _, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(expectedGrace)) + foo := copyOrDie(obj) + t.setObjectMeta(foo, "foo4") + if err := setFn(ctx, foo); err != nil { + t.Errorf("unexpected error: %v", err) + } + objectMeta := t.getObjectMetaOrFail(foo) + _, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(expectedGrace)) if err != nil { t.Errorf("unexpected error: %v", err) } - if !wasGracefulFn() { - t.Errorf("did not gracefully delete resource") + if _, err := getFn(ctx, foo); err != nil { + t.Fatalf("did not gracefully delete resource", err) } + // second delete is immediate, resource is deleted out, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(0)) if err != nil { @@ -680,19 +667,21 @@ func (t *Tester) TestDeleteGracefulImmediate(existing runtime.Object, expectedGr if !errors.IsNotFound(err) { t.Errorf("unexpected error, object should be deleted immediately: %v", err) } - objectMeta, err = api.ObjectMetaFor(out) - if err != nil { - t.Errorf("unexpected error: %v", err) - return - } + objectMeta = t.getObjectMetaOrFail(out) if objectMeta.DeletionTimestamp == nil || objectMeta.DeletionGracePeriodSeconds == nil || *objectMeta.DeletionGracePeriodSeconds != 0 { t.Errorf("unexpected deleted meta: %#v", objectMeta) } } -func (t *Tester) TestDeleteGracefulUsesZeroOnNil(existing runtime.Object, expectedGrace int64) { - objectMeta := t.getObjectMetaOrFail(existing) - ctx := api.WithNamespace(t.TestContext(), objectMeta.Namespace) +func (t *Tester) testDeleteGracefulUsesZeroOnNil(obj runtime.Object, setFn SetFunc, expectedGrace int64) { + ctx := t.TestContext() + + foo := copyOrDie(obj) + t.setObjectMeta(foo, "foo5") + if err := setFn(ctx, foo); err != nil { + t.Errorf("unexpected error: %v", err) + } + objectMeta := t.getObjectMetaOrFail(foo) _, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, nil) if err != nil { t.Errorf("unexpected error: %v", err) diff --git a/pkg/registry/controller/etcd/etcd_test.go b/pkg/registry/controller/etcd/etcd_test.go index ea66f992d8a..909e529963c 100644 --- a/pkg/registry/controller/etcd/etcd_test.go +++ b/pkg/registry/controller/etcd/etcd_test.go @@ -19,16 +19,12 @@ package etcd import ( "testing" - "github.com/coreos/go-etcd/etcd" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/rest/resttest" - "k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/tools" - "k8s.io/kubernetes/pkg/tools/etcdtest" ) func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) { @@ -127,6 +123,12 @@ func TestUpdate(t *testing.T) { ) } +func TestDelete(t *testing.T) { + storage, fakeClient := newStorage(t) + test := registrytest.New(t, fakeClient, storage.Etcd) + test.TestDelete(validNewController()) +} + func TestGenerationNumber(t *testing.T) { storage, _ := newStorage(t) modifiedSno := *validNewController() @@ -218,59 +220,3 @@ func TestWatch(t *testing.T) { }, ) } - -func TestEtcdDeleteController(t *testing.T) { - ctx := api.NewDefaultContext() - storage, fakeClient := newStorage(t) - key, _ := storage.KeyFunc(ctx, validController.Name) - key = etcdtest.AddPrefix(key) - - fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), validController), 0) - obj, err := storage.Delete(ctx, validController.Name, nil) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - if status, ok := obj.(*api.Status); !ok { - t.Errorf("Expected status of delete, got %#v", status) - } else if status.Status != api.StatusSuccess { - t.Errorf("Expected success, got %#v", status.Status) - } - if len(fakeClient.DeletedKeys) != 1 { - t.Errorf("Expected 1 delete, found %#v", fakeClient.DeletedKeys) - } - if fakeClient.DeletedKeys[0] != key { - t.Errorf("Unexpected key: %s, expected %s", fakeClient.DeletedKeys[0], key) - } -} - -func TestDelete(t *testing.T) { - ctx := api.NewDefaultContext() - storage, fakeClient := newStorage(t) - test := resttest.New(t, storage, fakeClient.SetError) - key, _ := storage.KeyFunc(ctx, validController.Name) - key = etcdtest.AddPrefix(key) - - createFn := func() runtime.Object { - rc := *validNewController() - rc.ResourceVersion = "1" - fakeClient.Data[key] = tools.EtcdResponseWithError{ - R: &etcd.Response{ - Node: &etcd.Node{ - Value: runtime.EncodeOrDie(testapi.Codec(), &rc), - ModifiedIndex: 1, - }, - }, - } - return &rc - } - gracefulSetFn := func() bool { - // If the controller is still around after trying to delete either the delete - // failed, or we're deleting it gracefully. - if fakeClient.Data[key].R.Node != nil { - return true - } - return false - } - - test.TestDelete(createFn, gracefulSetFn) -} diff --git a/pkg/registry/daemon/etcd/etcd_test.go b/pkg/registry/daemon/etcd/etcd_test.go index 17fb74c5a66..ff289c2ddbc 100755 --- a/pkg/registry/daemon/etcd/etcd_test.go +++ b/pkg/registry/daemon/etcd/etcd_test.go @@ -19,17 +19,13 @@ package etcd import ( "testing" - "github.com/coreos/go-etcd/etcd" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/rest/resttest" - "k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/expapi" "k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/tools" - "k8s.io/kubernetes/pkg/tools/etcdtest" ) func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) { @@ -121,6 +117,12 @@ func TestUpdate(t *testing.T) { ) } +func TestDelete(t *testing.T) { + storage, fakeClient := newStorage(t) + test := registrytest.New(t, fakeClient, storage.Etcd) + test.TestDelete(validNewDaemon()) +} + func TestGet(t *testing.T) { storage, fakeClient := newStorage(t) test := registrytest.New(t, fakeClient, storage.Etcd) @@ -158,59 +160,3 @@ func TestWatch(t *testing.T) { }, ) } - -func TestEtcdDeleteDaemon(t *testing.T) { - ctx := api.NewDefaultContext() - storage, fakeClient := newStorage(t) - key, err := storage.KeyFunc(ctx, validDaemon.Name) - key = etcdtest.AddPrefix(key) - - fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), validDaemon), 0) - obj, err := storage.Delete(ctx, validDaemon.Name, nil) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - if status, ok := obj.(*api.Status); !ok { - t.Errorf("Expected status of delete, got %#v", status) - } else if status.Status != api.StatusSuccess { - t.Errorf("Expected success, got %#v", status.Status) - } - if len(fakeClient.DeletedKeys) != 1 { - t.Errorf("Expected 1 delete, found %#v", fakeClient.DeletedKeys) - } - if fakeClient.DeletedKeys[0] != key { - t.Errorf("Unexpected key: %s, expected %s", fakeClient.DeletedKeys[0], key) - } -} - -func TestDelete(t *testing.T) { - ctx := api.NewDefaultContext() - storage, fakeClient := newStorage(t) - test := resttest.New(t, storage, fakeClient.SetError) - key, _ := storage.KeyFunc(ctx, validDaemon.Name) - key = etcdtest.AddPrefix(key) - - createFn := func() runtime.Object { - dc := validNewDaemon() - dc.ResourceVersion = "1" - fakeClient.Data[key] = tools.EtcdResponseWithError{ - R: &etcd.Response{ - Node: &etcd.Node{ - Value: runtime.EncodeOrDie(testapi.Codec(), dc), - ModifiedIndex: 1, - }, - }, - } - return dc - } - gracefulSetFn := func() bool { - // If the daemon is still around after trying to delete either the delete - // failed, or we're deleting it gracefully. - if fakeClient.Data[key].R.Node != nil { - return true - } - return false - } - - test.TestDelete(createFn, gracefulSetFn) -} diff --git a/pkg/registry/deployment/etcd/etcd_test.go b/pkg/registry/deployment/etcd/etcd_test.go index 6c91b34d53b..9a3a2ac6206 100755 --- a/pkg/registry/deployment/etcd/etcd_test.go +++ b/pkg/registry/deployment/etcd/etcd_test.go @@ -19,17 +19,13 @@ package etcd import ( "testing" - "github.com/coreos/go-etcd/etcd" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/rest/resttest" - "k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/expapi" "k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/tools" - "k8s.io/kubernetes/pkg/tools/etcdtest" ) func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) { @@ -122,6 +118,12 @@ func TestUpdate(t *testing.T) { ) } +func TestDelete(t *testing.T) { + storage, fakeClient := newStorage(t) + test := registrytest.New(t, fakeClient, storage.Etcd) + test.TestDelete(validNewDeployment()) +} + func TestGet(t *testing.T) { storage, fakeClient := newStorage(t) test := registrytest.New(t, fakeClient, storage.Etcd) @@ -157,58 +159,3 @@ func TestWatch(t *testing.T) { }, ) } - -func TestEtcdDelete(t *testing.T) { - ctx := api.NewDefaultContext() - storage, fakeClient := newStorage(t) - key, err := storage.KeyFunc(ctx, validDeployment.Name) - key = etcdtest.AddPrefix(key) - - fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), validNewDeployment()), 0) - obj, err := storage.Delete(ctx, validDeployment.Name, nil) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - if status, ok := obj.(*api.Status); !ok { - t.Errorf("Expected status of delete, got %#v", status) - } else if status.Status != api.StatusSuccess { - t.Errorf("Expected success, got %#v", status.Status) - } - if len(fakeClient.DeletedKeys) != 1 { - t.Errorf("Expected 1 delete, found %#v", fakeClient.DeletedKeys) - } - if fakeClient.DeletedKeys[0] != key { - t.Errorf("Unexpected key: %s, expected %s", fakeClient.DeletedKeys[0], key) - } -} - -func TestDelete(t *testing.T) { - ctx := api.NewDefaultContext() - storage, fakeClient := newStorage(t) - test := resttest.New(t, storage, fakeClient.SetError) - key, _ := storage.KeyFunc(ctx, validDeployment.Name) - key = etcdtest.AddPrefix(key) - - createFn := func() runtime.Object { - dc := validNewDeployment() - dc.ResourceVersion = "1" - fakeClient.Data[key] = tools.EtcdResponseWithError{ - R: &etcd.Response{ - Node: &etcd.Node{ - Value: runtime.EncodeOrDie(testapi.Codec(), dc), - ModifiedIndex: 1, - }, - }, - } - return dc - } - gracefulSetFn := func() bool { - // If the deployment is still around after trying to delete either the delete - // failed, or we're deleting it gracefully. - if fakeClient.Data[key].R.Node != nil { - return true - } - return false - } - test.TestDelete(createFn, gracefulSetFn) -} diff --git a/pkg/registry/endpoint/etcd/etcd_test.go b/pkg/registry/endpoint/etcd/etcd_test.go index 9c77fa01146..cff15c74962 100644 --- a/pkg/registry/endpoint/etcd/etcd_test.go +++ b/pkg/registry/endpoint/etcd/etcd_test.go @@ -20,15 +20,11 @@ import ( "testing" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/rest/resttest" - "k8s.io/kubernetes/pkg/api/testapi" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/tools" - "k8s.io/kubernetes/pkg/tools/etcdtest" - "k8s.io/kubernetes/pkg/util" - - "github.com/coreos/go-etcd/etcd" ) func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) { @@ -93,31 +89,9 @@ func TestUpdate(t *testing.T) { } func TestDelete(t *testing.T) { - ctx := api.NewDefaultContext() storage, fakeClient := newStorage(t) - test := resttest.New(t, storage, fakeClient.SetError) - - endpoints := validChangedEndpoints() - key, _ := storage.KeyFunc(ctx, endpoints.Name) - key = etcdtest.AddPrefix(key) - createFn := func() runtime.Object { - fakeClient.Data[key] = tools.EtcdResponseWithError{ - R: &etcd.Response{ - Node: &etcd.Node{ - Value: runtime.EncodeOrDie(testapi.Codec(), endpoints), - ModifiedIndex: 1, - }, - }, - } - return endpoints - } - gracefulSetFn := func() bool { - if fakeClient.Data[key].R.Node == nil { - return false - } - return fakeClient.Data[key].R.Node.TTL == 30 - } - test.TestDelete(createFn, gracefulSetFn) + test := registrytest.New(t, fakeClient, storage.Etcd) + test.TestDelete(validNewEndpoints()) } func TestGet(t *testing.T) { @@ -132,43 +106,25 @@ func TestList(t *testing.T) { test.TestList(validNewEndpoints()) } -func TestEndpointsDecode(t *testing.T) { - storage, _ := newStorage(t) - expected := validNewEndpoints() - body, err := testapi.Codec().Encode(expected) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - - actual := storage.New() - if err := testapi.Codec().DecodeInto(body, actual); err != nil { - t.Fatalf("unexpected error: %v", err) - } - - if !api.Semantic.DeepEqual(expected, actual) { - t.Errorf("mismatch: %s", util.ObjectDiff(expected, actual)) - } -} - -func TestDeleteEndpoints(t *testing.T) { - ctx := api.NewDefaultContext() +func TestWatch(t *testing.T) { storage, fakeClient := newStorage(t) - endpoints := validNewEndpoints() - name := endpoints.Name - key, _ := storage.KeyFunc(ctx, name) - key = etcdtest.AddPrefix(key) - fakeClient.ChangeIndex = 1 - fakeClient.Data[key] = tools.EtcdResponseWithError{ - R: &etcd.Response{ - Node: &etcd.Node{ - Value: runtime.EncodeOrDie(testapi.Codec(), endpoints), - ModifiedIndex: 1, - CreatedIndex: 1, - }, + test := registrytest.New(t, fakeClient, storage.Etcd) + test.TestWatch( + validNewEndpoints(), + // matching labels + []labels.Set{}, + // not matching labels + []labels.Set{ + {"foo": "bar"}, }, - } - _, err := storage.Delete(ctx, name, nil) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } + // matching fields + []fields.Set{ + {"metadata.name": "foo"}, + }, + // not matching fields + []fields.Set{ + {"metadata.name": "bar"}, + {"name": "foo"}, + }, + ) } diff --git a/pkg/registry/horizontalpodautoscaler/etcd/etcd_test.go b/pkg/registry/horizontalpodautoscaler/etcd/etcd_test.go index b0f33a7796f..826d52dd3ea 100644 --- a/pkg/registry/horizontalpodautoscaler/etcd/etcd_test.go +++ b/pkg/registry/horizontalpodautoscaler/etcd/etcd_test.go @@ -21,17 +21,14 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/resource" - "k8s.io/kubernetes/pkg/api/rest/resttest" - "k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/expapi" // Ensure that expapi/v1 package is initialized. _ "k8s.io/kubernetes/pkg/expapi/v1" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/tools" - "k8s.io/kubernetes/pkg/tools/etcdtest" - - "github.com/coreos/go-etcd/etcd" ) func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) { @@ -85,30 +82,9 @@ func TestUpdate(t *testing.T) { } func TestDelete(t *testing.T) { - ctx := api.NewDefaultContext() storage, fakeClient := newStorage(t) - test := resttest.New(t, storage, fakeClient.SetError) - autoscaler := validNewHorizontalPodAutoscaler("foo2") - key, _ := storage.KeyFunc(ctx, "foo2") - key = etcdtest.AddPrefix(key) - createFn := func() runtime.Object { - fakeClient.Data[key] = tools.EtcdResponseWithError{ - R: &etcd.Response{ - Node: &etcd.Node{ - Value: runtime.EncodeOrDie(testapi.Codec(), autoscaler), - ModifiedIndex: 1, - }, - }, - } - return autoscaler - } - gracefulSetFn := func() bool { - if fakeClient.Data[key].R.Node == nil { - return false - } - return fakeClient.Data[key].R.Node.TTL == 30 - } - test.TestDelete(createFn, gracefulSetFn) + test := registrytest.New(t, fakeClient, storage.Etcd) + test.TestDelete(validNewHorizontalPodAutoscaler("foo")) } func TestGet(t *testing.T) { @@ -122,3 +98,24 @@ func TestList(t *testing.T) { test := registrytest.New(t, fakeClient, storage.Etcd) test.TestList(validNewHorizontalPodAutoscaler("foo")) } + +func TestWatch(t *testing.T) { + storage, fakeClient := newStorage(t) + test := registrytest.New(t, fakeClient, storage.Etcd) + test.TestWatch( + validNewHorizontalPodAutoscaler("foo"), + // matching labels + []labels.Set{}, + // not matching labels + []labels.Set{ + {"foo": "bar"}, + }, + // matching fields + []fields.Set{}, + // not matching fields + []fields.Set{ + {"metadata.name": "bar"}, + {"name": "foo"}, + }, + ) +} diff --git a/pkg/registry/horizontalpodautoscaler/strategy.go b/pkg/registry/horizontalpodautoscaler/strategy.go index 3a5487eb4ec..e0de495bcdf 100644 --- a/pkg/registry/horizontalpodautoscaler/strategy.go +++ b/pkg/registry/horizontalpodautoscaler/strategy.go @@ -74,13 +74,20 @@ func (autoscalerStrategy) AllowUnconditionalUpdate() bool { return true } -// MatchAutoscaler returns a generic matcher for a given label and field selector. -func MatchAutoscaler(label labels.Selector, field fields.Selector) generic.Matcher { - return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { - autoscaler, ok := obj.(*expapi.HorizontalPodAutoscaler) - if !ok { - return false, fmt.Errorf("not a horizontal pod autoscaler") - } - return label.Matches(labels.Set(autoscaler.Labels)), nil - }) +func AutoscalerToSelectableFields(limitRange *expapi.HorizontalPodAutoscaler) fields.Set { + return fields.Set{} +} + +func MatchAutoscaler(label labels.Selector, field fields.Selector) generic.Matcher { + return &generic.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { + hpa, ok := obj.(*expapi.HorizontalPodAutoscaler) + if !ok { + return nil, nil, fmt.Errorf("given object is not a horizontal pod autoscaler.") + } + return labels.Set(hpa.ObjectMeta.Labels), AutoscalerToSelectableFields(hpa), nil + }, + } } diff --git a/pkg/registry/limitrange/etcd/etcd_test.go b/pkg/registry/limitrange/etcd/etcd_test.go index a4a3ca09a38..c08e627cc31 100644 --- a/pkg/registry/limitrange/etcd/etcd_test.go +++ b/pkg/registry/limitrange/etcd/etcd_test.go @@ -21,6 +21,8 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/resource" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/tools" @@ -97,6 +99,12 @@ func TestUpdate(t *testing.T) { ) } +func TestDelete(t *testing.T) { + storage, fakeClient := newStorage(t) + test := registrytest.New(t, fakeClient, storage.Etcd) + test.TestDelete(validNewLimitRange()) +} + func TestGet(t *testing.T) { storage, fakeClient := newStorage(t) test := registrytest.New(t, fakeClient, storage.Etcd) @@ -108,3 +116,24 @@ func TestList(t *testing.T) { test := registrytest.New(t, fakeClient, storage.Etcd) test.TestList(validNewLimitRange()) } + +func TestWatch(t *testing.T) { + storage, fakeClient := newStorage(t) + test := registrytest.New(t, fakeClient, storage.Etcd) + test.TestWatch( + validNewLimitRange(), + // matching labels + []labels.Set{}, + // not matching labels + []labels.Set{ + {"foo": "bar"}, + }, + // matching fields + []fields.Set{}, + // not matching fields + []fields.Set{ + {"metadata.name": "bar"}, + {"name": "foo"}, + }, + ) +} diff --git a/pkg/registry/minion/etcd/etcd_test.go b/pkg/registry/minion/etcd/etcd_test.go index 721883794fe..e89051eb5c7 100644 --- a/pkg/registry/minion/etcd/etcd_test.go +++ b/pkg/registry/minion/etcd/etcd_test.go @@ -22,16 +22,11 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/resource" - "k8s.io/kubernetes/pkg/api/rest/resttest" - "k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/tools" - "k8s.io/kubernetes/pkg/tools/etcdtest" - - "github.com/coreos/go-etcd/etcd" ) type fakeConnectionInfoGetter struct { @@ -67,12 +62,6 @@ func validNewNode() *api.Node { } } -func validChangedNode() *api.Node { - node := validNewNode() - node.ResourceVersion = "1" - return node -} - func TestCreate(t *testing.T) { storage, fakeClient := newStorage(t) test := registrytest.New(t, fakeClient, storage.Etcd).ClusterScope() @@ -104,31 +93,9 @@ func TestUpdate(t *testing.T) { } func TestDelete(t *testing.T) { - ctx := api.NewContext() storage, fakeClient := newStorage(t) - test := resttest.New(t, storage, fakeClient.SetError).ClusterScope() - - node := validChangedNode() - key, _ := storage.KeyFunc(ctx, node.Name) - key = etcdtest.AddPrefix(key) - createFn := func() runtime.Object { - fakeClient.Data[key] = tools.EtcdResponseWithError{ - R: &etcd.Response{ - Node: &etcd.Node{ - Value: runtime.EncodeOrDie(testapi.Codec(), node), - ModifiedIndex: 1, - }, - }, - } - return node - } - gracefulSetFn := func() bool { - if fakeClient.Data[key].R.Node == nil { - return false - } - return fakeClient.Data[key].R.Node.TTL == 30 - } - test.TestDelete(createFn, gracefulSetFn) + test := registrytest.New(t, fakeClient, storage.Etcd).ClusterScope() + test.TestDelete(validNewNode()) } func TestGet(t *testing.T) { @@ -143,7 +110,7 @@ func TestList(t *testing.T) { test.TestList(validNewNode()) } -func TestWatchNodes(t *testing.T) { +func TestWatch(t *testing.T) { storage, fakeClient := newStorage(t) test := registrytest.New(t, fakeClient, storage.Etcd).ClusterScope() test.TestWatch( @@ -167,23 +134,3 @@ func TestWatchNodes(t *testing.T) { }, ) } - -func TestEtcdDeleteNode(t *testing.T) { - ctx := api.NewContext() - storage, fakeClient := newStorage(t) - node := validNewNode() - key, _ := storage.KeyFunc(ctx, node.Name) - key = etcdtest.AddPrefix(key) - fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), node), 0) - _, err := storage.Delete(ctx, node.Name, nil) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - - if len(fakeClient.DeletedKeys) != 1 { - t.Errorf("Expected 1 delete, found %#v", fakeClient.DeletedKeys) - } - if fakeClient.DeletedKeys[0] != key { - t.Errorf("Unexpected key: %s, expected %s", fakeClient.DeletedKeys[0], key) - } -} diff --git a/pkg/registry/namespace/etcd/etcd_test.go b/pkg/registry/namespace/etcd/etcd_test.go index a2fb036b88a..4112a20e34c 100644 --- a/pkg/registry/namespace/etcd/etcd_test.go +++ b/pkg/registry/namespace/etcd/etcd_test.go @@ -21,6 +21,8 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/testapi" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/tools" @@ -59,15 +61,6 @@ func TestCreate(t *testing.T) { ) } -func expectNamespace(t *testing.T, out runtime.Object) (*api.Namespace, bool) { - namespace, ok := out.(*api.Namespace) - if !ok || namespace == nil { - t.Errorf("Expected an api.Namespace object, was %#v", out) - return nil, false - } - return namespace, true -} - func TestCreateSetsFields(t *testing.T) { storage, fakeClient := newStorage(t) namespace := validNewNamespace() @@ -93,24 +86,10 @@ func TestCreateSetsFields(t *testing.T) { } } -func TestNamespaceDecode(t *testing.T) { - storage, _ := newStorage(t) - expected := validNewNamespace() - expected.Status.Phase = api.NamespaceActive - expected.Spec.Finalizers = []api.FinalizerName{api.FinalizerKubernetes} - body, err := testapi.Codec().Encode(expected) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - - actual := storage.New() - if err := testapi.Codec().DecodeInto(body, actual); err != nil { - t.Fatalf("unexpected error: %v", err) - } - - if !api.Semantic.DeepEqual(expected, actual) { - t.Errorf("mismatch: %s", util.ObjectDiff(expected, actual)) - } +func TestDelete(t *testing.T) { + storage, fakeClient := newStorage(t) + test := registrytest.New(t, fakeClient, storage.Etcd).ClusterScope().ReturnDeletedObject() + test.TestDelete(validNewNamespace()) } func TestGet(t *testing.T) { @@ -125,31 +104,27 @@ func TestList(t *testing.T) { test.TestList(validNewNamespace()) } -func TestDeleteNamespace(t *testing.T) { +func TestWatch(t *testing.T) { storage, fakeClient := newStorage(t) - fakeClient.ChangeIndex = 1 - ctx := api.NewContext() - key, err := storage.Etcd.KeyFunc(ctx, "foo") - key = etcdtest.AddPrefix(key) - fakeClient.Data[key] = tools.EtcdResponseWithError{ - R: &etcd.Response{ - Node: &etcd.Node{ - Value: runtime.EncodeOrDie(testapi.Codec(), &api.Namespace{ - ObjectMeta: api.ObjectMeta{ - Name: "foo", - }, - Status: api.NamespaceStatus{Phase: api.NamespaceActive}, - }), - ModifiedIndex: 1, - CreatedIndex: 1, - }, + test := registrytest.New(t, fakeClient, storage.Etcd).ClusterScope() + test.TestWatch( + validNewNamespace(), + // matching labels + []labels.Set{}, + // not matching labels + []labels.Set{ + {"foo": "bar"}, }, - } - _, err = storage.Delete(api.NewContext(), "foo", nil) - - if err != nil { - t.Fatalf("unexpected error: %v", err) - } + // matching fields + []fields.Set{ + {"metadata.name": "foo"}, + {"name": "foo"}, + }, + // not matching fields + []fields.Set{ + {"metadata.name": "bar"}, + }, + ) } func TestDeleteNamespaceWithIncompleteFinalizers(t *testing.T) { diff --git a/pkg/registry/namespace/strategy.go b/pkg/registry/namespace/strategy.go index 9f81bf2e45f..424684f28c6 100644 --- a/pkg/registry/namespace/strategy.go +++ b/pkg/registry/namespace/strategy.go @@ -143,10 +143,11 @@ func MatchNamespace(label labels.Selector, field fields.Selector) generic.Matche } // NamespaceToSelectableFields returns a label set that represents the object -// TODO: fields are not labels, and the validation rules for them do not apply. func NamespaceToSelectableFields(namespace *api.Namespace) labels.Set { return labels.Set{ - "name": namespace.Name, - "status.phase": string(namespace.Status.Phase), + "metadata.name": namespace.Name, + "status.phase": string(namespace.Status.Phase), + // This is a bug, but we need to support it for backward compatibility. + "name": namespace.Name, } } diff --git a/pkg/registry/persistentvolume/etcd/etcd_test.go b/pkg/registry/persistentvolume/etcd/etcd_test.go index 088e7ce2832..8bc00c5a2c9 100644 --- a/pkg/registry/persistentvolume/etcd/etcd_test.go +++ b/pkg/registry/persistentvolume/etcd/etcd_test.go @@ -21,15 +21,14 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/resource" - "k8s.io/kubernetes/pkg/api/rest/resttest" "k8s.io/kubernetes/pkg/api/testapi" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/tools" "k8s.io/kubernetes/pkg/tools/etcdtest" "k8s.io/kubernetes/pkg/util" - - "github.com/coreos/go-etcd/etcd" ) func newStorage(t *testing.T) (*REST, *StatusREST, *tools.FakeEtcdClient) { @@ -101,31 +100,9 @@ func TestUpdate(t *testing.T) { } func TestDelete(t *testing.T) { - ctx := api.NewContext() storage, _, fakeClient := newStorage(t) - test := resttest.New(t, storage, fakeClient.SetError).ClusterScope() - - pv := validChangedPersistentVolume() - key, _ := storage.KeyFunc(ctx, pv.Name) - key = etcdtest.AddPrefix(key) - createFn := func() runtime.Object { - fakeClient.Data[key] = tools.EtcdResponseWithError{ - R: &etcd.Response{ - Node: &etcd.Node{ - Value: runtime.EncodeOrDie(testapi.Codec(), pv), - ModifiedIndex: 1, - }, - }, - } - return pv - } - gracefulSetFn := func() bool { - if fakeClient.Data[key].R.Node == nil { - return false - } - return fakeClient.Data[key].R.Node.TTL == 30 - } - test.TestDelete(createFn, gracefulSetFn) + test := registrytest.New(t, fakeClient, storage.Etcd).ClusterScope().ReturnDeletedObject() + test.TestDelete(validNewPersistentVolume("foo")) } func TestGet(t *testing.T) { @@ -140,48 +117,30 @@ func TestList(t *testing.T) { test.TestList(validNewPersistentVolume("foo")) } -func TestPersistentVolumesDecode(t *testing.T) { - storage, _, _ := newStorage(t) - expected := validNewPersistentVolume("foo") - body, err := testapi.Codec().Encode(expected) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - - actual := storage.New() - if err := testapi.Codec().DecodeInto(body, actual); err != nil { - t.Fatalf("unexpected error: %v", err) - } - - if !api.Semantic.DeepEqual(expected, actual) { - t.Errorf("mismatch: %s", util.ObjectDiff(expected, actual)) - } -} - -func TestDeletePersistentVolumes(t *testing.T) { - ctx := api.NewContext() +func TestWatch(t *testing.T) { storage, _, fakeClient := newStorage(t) - persistentVolume := validNewPersistentVolume("foo") - name := persistentVolume.Name - key, _ := storage.KeyFunc(ctx, name) - key = etcdtest.AddPrefix(key) - fakeClient.ChangeIndex = 1 - fakeClient.Data[key] = tools.EtcdResponseWithError{ - R: &etcd.Response{ - Node: &etcd.Node{ - Value: runtime.EncodeOrDie(testapi.Codec(), persistentVolume), - ModifiedIndex: 1, - CreatedIndex: 1, - }, + test := registrytest.New(t, fakeClient, storage.Etcd).ClusterScope() + test.TestWatch( + validNewPersistentVolume("foo"), + // matching labels + []labels.Set{}, + // not matching labels + []labels.Set{ + {"foo": "bar"}, }, - } - _, err := storage.Delete(ctx, name, nil) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } + // matching fields + []fields.Set{ + {"metadata.name": "foo"}, + {"name": "foo"}, + }, + // not matching fields + []fields.Set{ + {"metadata.name": "bar"}, + }, + ) } -func TestEtcdUpdateStatus(t *testing.T) { +func TestUpdateStatus(t *testing.T) { storage, statusStorage, fakeClient := newStorage(t) fakeClient.TestIndex = true diff --git a/pkg/registry/persistentvolume/strategy.go b/pkg/registry/persistentvolume/strategy.go index d7056cedca8..2def1d0d8b2 100644 --- a/pkg/registry/persistentvolume/strategy.go +++ b/pkg/registry/persistentvolume/strategy.go @@ -103,9 +103,10 @@ func MatchPersistentVolumes(label labels.Selector, field fields.Selector) generi } // PersistentVolumeToSelectableFields returns a label set that represents the object -// TODO: fields are not labels, and the validation rules for them do not apply. func PersistentVolumeToSelectableFields(persistentvolume *api.PersistentVolume) labels.Set { return labels.Set{ + "metadata.name": persistentvolume.Name, + // This is a bug, but we need to support it for backward compatibility. "name": persistentvolume.Name, } } diff --git a/pkg/registry/persistentvolumeclaim/etcd/etcd_test.go b/pkg/registry/persistentvolumeclaim/etcd/etcd_test.go index 66f284f2aef..049b2d128c5 100644 --- a/pkg/registry/persistentvolumeclaim/etcd/etcd_test.go +++ b/pkg/registry/persistentvolumeclaim/etcd/etcd_test.go @@ -21,15 +21,14 @@ import ( "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/resource" - "k8s.io/kubernetes/pkg/api/rest/resttest" "k8s.io/kubernetes/pkg/api/testapi" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/tools" "k8s.io/kubernetes/pkg/tools/etcdtest" "k8s.io/kubernetes/pkg/util" - - "github.com/coreos/go-etcd/etcd" ) func newStorage(t *testing.T) (*REST, *StatusREST, *tools.FakeEtcdClient) { @@ -59,12 +58,6 @@ func validNewPersistentVolumeClaim(name, ns string) *api.PersistentVolumeClaim { return pv } -func validChangedPersistentVolumeClaim() *api.PersistentVolumeClaim { - pv := validNewPersistentVolumeClaim("foo", api.NamespaceDefault) - pv.ResourceVersion = "1" - return pv -} - func TestCreate(t *testing.T) { storage, _, fakeClient := newStorage(t) test := registrytest.New(t, fakeClient, storage.Etcd) @@ -100,31 +93,9 @@ func TestUpdate(t *testing.T) { } func TestDelete(t *testing.T) { - ctx := api.NewDefaultContext() storage, _, fakeClient := newStorage(t) - test := resttest.New(t, storage, fakeClient.SetError) - - pv := validChangedPersistentVolumeClaim() - key, _ := storage.KeyFunc(ctx, pv.Name) - key = etcdtest.AddPrefix(key) - createFn := func() runtime.Object { - fakeClient.Data[key] = tools.EtcdResponseWithError{ - R: &etcd.Response{ - Node: &etcd.Node{ - Value: runtime.EncodeOrDie(testapi.Codec(), pv), - ModifiedIndex: 1, - }, - }, - } - return pv - } - gracefulSetFn := func() bool { - if fakeClient.Data[key].R.Node == nil { - return false - } - return fakeClient.Data[key].R.Node.TTL == 30 - } - test.TestDelete(createFn, gracefulSetFn) + test := registrytest.New(t, fakeClient, storage.Etcd).ReturnDeletedObject() + test.TestDelete(validNewPersistentVolumeClaim("foo", api.NamespaceDefault)) } func TestGet(t *testing.T) { @@ -139,78 +110,30 @@ func TestList(t *testing.T) { test.TestList(validNewPersistentVolumeClaim("foo", api.NamespaceDefault)) } -func TestPersistentVolumeClaimsDecode(t *testing.T) { - storage, _, _ := newStorage(t) - expected := validNewPersistentVolumeClaim("foo", api.NamespaceDefault) - body, err := testapi.Codec().Encode(expected) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - - actual := storage.New() - if err := testapi.Codec().DecodeInto(body, actual); err != nil { - t.Fatalf("unexpected error: %v", err) - } - - if !api.Semantic.DeepEqual(expected, actual) { - t.Errorf("mismatch: %s", util.ObjectDiff(expected, actual)) - } -} - -func TestEtcdUpdatePersistentVolumeClaims(t *testing.T) { - ctx := api.NewDefaultContext() +func TestWatch(t *testing.T) { storage, _, fakeClient := newStorage(t) - persistentVolume := validChangedPersistentVolumeClaim() - - key, _ := storage.KeyFunc(ctx, "foo") - key = etcdtest.AddPrefix(key) - fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), validNewPersistentVolumeClaim("foo", api.NamespaceDefault)), 0) - - _, _, err := storage.Update(ctx, persistentVolume) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - - response, err := fakeClient.Get(key, false, false) - if err != nil { - t.Fatalf("Unexpected error %v", err) - } - var persistentVolumeOut api.PersistentVolumeClaim - err = testapi.Codec().DecodeInto([]byte(response.Node.Value), &persistentVolumeOut) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - - persistentVolume.ObjectMeta.ResourceVersion = persistentVolumeOut.ObjectMeta.ResourceVersion - if !api.Semantic.DeepEqual(persistentVolume, &persistentVolumeOut) { - t.Errorf("Unexpected persistentVolume: %#v, expected %#v", &persistentVolumeOut, persistentVolume) - } -} - -func TestDeletePersistentVolumeClaims(t *testing.T) { - ctx := api.NewDefaultContext() - storage, _, fakeClient := newStorage(t) - pvClaim := validNewPersistentVolumeClaim("foo", api.NamespaceDefault) - name := pvClaim.Name - key, _ := storage.KeyFunc(ctx, name) - key = etcdtest.AddPrefix(key) - fakeClient.ChangeIndex = 1 - fakeClient.Data[key] = tools.EtcdResponseWithError{ - R: &etcd.Response{ - Node: &etcd.Node{ - Value: runtime.EncodeOrDie(testapi.Codec(), pvClaim), - ModifiedIndex: 1, - CreatedIndex: 1, - }, + test := registrytest.New(t, fakeClient, storage.Etcd) + test.TestWatch( + validNewPersistentVolumeClaim("foo", api.NamespaceDefault), + // matching labels + []labels.Set{}, + // not matching labels + []labels.Set{ + {"foo": "bar"}, }, - } - _, err := storage.Delete(ctx, name, nil) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } + // matching fields + []fields.Set{ + {"metadata.name": "foo"}, + {"name": "foo"}, + }, + // not matching fields + []fields.Set{ + {"metadata.name": "bar"}, + }, + ) } -func TestEtcdUpdateStatus(t *testing.T) { +func TestUpdateStatus(t *testing.T) { storage, statusStorage, fakeClient := newStorage(t) ctx := api.NewDefaultContext() fakeClient.TestIndex = true diff --git a/pkg/registry/persistentvolumeclaim/strategy.go b/pkg/registry/persistentvolumeclaim/strategy.go index 193b57a016e..a6185d95d3f 100644 --- a/pkg/registry/persistentvolumeclaim/strategy.go +++ b/pkg/registry/persistentvolumeclaim/strategy.go @@ -103,9 +103,10 @@ func MatchPersistentVolumeClaim(label labels.Selector, field fields.Selector) ge } // PersistentVolumeClaimToSelectableFields returns a label set that represents the object -// TODO: fields are not labels, and the validation rules for them do not apply. func PersistentVolumeClaimToSelectableFields(persistentvolumeclaim *api.PersistentVolumeClaim) labels.Set { return labels.Set{ + "metadata.name": persistentvolumeclaim.Name, + // This is a bug, but we need to support it for backward compatibility. "name": persistentvolumeclaim.Name, } } diff --git a/pkg/registry/pod/etcd/etcd_test.go b/pkg/registry/pod/etcd/etcd_test.go index 78d3e890b6b..2559a0e38c8 100644 --- a/pkg/registry/pod/etcd/etcd_test.go +++ b/pkg/registry/pod/etcd/etcd_test.go @@ -25,7 +25,6 @@ import ( "k8s.io/kubernetes/pkg/api/errors" etcderrors "k8s.io/kubernetes/pkg/api/errors/etcd" "k8s.io/kubernetes/pkg/api/rest" - "k8s.io/kubernetes/pkg/api/rest/resttest" "k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/labels" @@ -122,50 +121,12 @@ func TestUpdate(t *testing.T) { func TestDelete(t *testing.T) { storage, _, _, fakeClient := newStorage(t) - ctx := api.NewDefaultContext() - key, _ := storage.Etcd.KeyFunc(ctx, "foo") - key = etcdtest.AddPrefix(key) - test := resttest.New(t, storage, fakeClient.SetError) + test := registrytest.New(t, fakeClient, storage.Etcd).ReturnDeletedObject() + test.TestDelete(validNewPod()) - expectedNode := "some-node" - createFn := func() runtime.Object { - pod := validChangedPod() - pod.Spec.NodeName = expectedNode - fakeClient.Data[key] = tools.EtcdResponseWithError{ - R: &etcd.Response{ - Node: &etcd.Node{ - Value: runtime.EncodeOrDie(testapi.Codec(), pod), - ModifiedIndex: 1, - }, - }, - } - return pod - } - gracefulSetFn := func() bool { - if fakeClient.Data[key].R.Node == nil { - return false - } - obj, err := testapi.Codec().Decode([]byte(fakeClient.Data[key].R.Node.Value)) - if err != nil { - return false - } - pod := obj.(*api.Pod) - t.Logf("found object %#v", pod.ObjectMeta) - return pod.DeletionTimestamp != nil && pod.DeletionGracePeriodSeconds != nil && *pod.DeletionGracePeriodSeconds != 0 - } - test.TestDeleteGraceful(createFn, 30, gracefulSetFn) - - expectedNode = "" - test.TestDelete(createFn, gracefulSetFn) -} - -func expectPod(t *testing.T, out runtime.Object) (*api.Pod, bool) { - pod, ok := out.(*api.Pod) - if !ok || pod == nil { - t.Errorf("Expected an api.Pod object, was %#v", out) - return nil, false - } - return pod, true + scheduledPod := validNewPod() + scheduledPod.Spec.NodeName = "some-node" + test.TestDeleteGraceful(scheduledPod, 30) } func TestCreateRegistryError(t *testing.T) { @@ -200,24 +161,6 @@ func TestCreateSetsFields(t *testing.T) { } } -func TestPodDecode(t *testing.T) { - storage, _, _, _ := newStorage(t) - expected := validNewPod() - body, err := testapi.Codec().Encode(expected) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - - actual := storage.New() - if err := testapi.Codec().DecodeInto(body, actual); err != nil { - t.Fatalf("unexpected error: %v", err) - } - - if !api.Semantic.DeepEqual(expected, actual) { - t.Errorf("mismatch: %s", util.ObjectDiff(expected, actual)) - } -} - func TestResourceLocation(t *testing.T) { expectedIP := "1.2.3.4" testCases := []struct { @@ -854,49 +797,3 @@ func TestEtcdUpdateStatus(t *testing.T) { t.Errorf("unexpected object: %s", util.ObjectDiff(&expected, podOut)) } } - -func TestEtcdDeletePod(t *testing.T) { - storage, _, _, fakeClient := newStorage(t) - ctx := api.NewDefaultContext() - fakeClient.TestIndex = true - - key, _ := storage.KeyFunc(ctx, "foo") - key = etcdtest.AddPrefix(key) - fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), &api.Pod{ - ObjectMeta: api.ObjectMeta{Name: "foo"}, - Spec: api.PodSpec{NodeName: "machine"}, - }), 0) - _, err := storage.Delete(ctx, "foo", api.NewDeleteOptions(0)) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - - if len(fakeClient.DeletedKeys) != 1 { - t.Errorf("Expected 1 delete, found %#v", fakeClient.DeletedKeys) - } else if fakeClient.DeletedKeys[0] != key { - t.Errorf("Unexpected key: %s, expected %s", fakeClient.DeletedKeys[0], key) - } -} - -func TestEtcdDeletePodMultipleContainers(t *testing.T) { - storage, _, _, fakeClient := newStorage(t) - ctx := api.NewDefaultContext() - fakeClient.TestIndex = true - key, _ := storage.KeyFunc(ctx, "foo") - key = etcdtest.AddPrefix(key) - fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), &api.Pod{ - ObjectMeta: api.ObjectMeta{Name: "foo"}, - Spec: api.PodSpec{NodeName: "machine"}, - }), 0) - _, err := storage.Delete(ctx, "foo", api.NewDeleteOptions(0)) - if err != nil { - t.Errorf("unexpected error: %v", err) - } - - if len(fakeClient.DeletedKeys) != 1 { - t.Errorf("Expected 1 delete, found %#v", fakeClient.DeletedKeys) - } - if fakeClient.DeletedKeys[0] != key { - t.Errorf("Unexpected key: %s, expected %s", fakeClient.DeletedKeys[0], key) - } -} diff --git a/pkg/registry/podtemplate/etcd/etcd_test.go b/pkg/registry/podtemplate/etcd/etcd_test.go index ba32c04b2c9..8fc83cc8e3b 100644 --- a/pkg/registry/podtemplate/etcd/etcd_test.go +++ b/pkg/registry/podtemplate/etcd/etcd_test.go @@ -20,6 +20,8 @@ import ( "testing" "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/tools" @@ -87,6 +89,12 @@ func TestUpdate(t *testing.T) { ) } +func TestDelete(t *testing.T) { + storage, fakeClient := newStorage(t) + test := registrytest.New(t, fakeClient, storage.Etcd).ReturnDeletedObject() + test.TestDelete(validNewPodTemplate("foo")) +} + func TestGet(t *testing.T) { storage, fakeClient := newStorage(t) test := registrytest.New(t, fakeClient, storage.Etcd) @@ -98,3 +106,24 @@ func TestList(t *testing.T) { test := registrytest.New(t, fakeClient, storage.Etcd) test.TestList(validNewPodTemplate("foo")) } + +func TestWatch(t *testing.T) { + storage, fakeClient := newStorage(t) + test := registrytest.New(t, fakeClient, storage.Etcd) + test.TestWatch( + validNewPodTemplate("foo"), + // matching labels + []labels.Set{}, + // not matching labels + []labels.Set{ + {"foo": "bar"}, + }, + // matching fields + []fields.Set{}, + // not matching fields + []fields.Set{ + {"metadata.name": "bar"}, + {"name": "foo"}, + }, + ) +} diff --git a/pkg/registry/podtemplate/strategy.go b/pkg/registry/podtemplate/strategy.go index d28300e9861..a3868254db1 100644 --- a/pkg/registry/podtemplate/strategy.go +++ b/pkg/registry/podtemplate/strategy.go @@ -73,13 +73,20 @@ func (podTemplateStrategy) AllowUnconditionalUpdate() bool { return true } -// MatchPodTemplate returns a generic matcher for a given label and field selector. -func MatchPodTemplate(label labels.Selector, field fields.Selector) generic.Matcher { - return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { - podObj, ok := obj.(*api.PodTemplate) - if !ok { - return false, fmt.Errorf("not a pod template") - } - return label.Matches(labels.Set(podObj.Labels)), nil - }) +func PodTemplateToSelectableFields(podTemplate *api.PodTemplate) fields.Set { + return fields.Set{} +} + +func MatchPodTemplate(label labels.Selector, field fields.Selector) generic.Matcher { + return &generic.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) { + pt, ok := obj.(*api.PodTemplate) + if !ok { + return nil, nil, fmt.Errorf("given object is not a pod template.") + } + return labels.Set(pt.ObjectMeta.Labels), PodTemplateToSelectableFields(pt), nil + }, + } } diff --git a/pkg/registry/registrytest/etcd.go b/pkg/registry/registrytest/etcd.go index 60b5f8465aa..95f8aecc19b 100644 --- a/pkg/registry/registrytest/etcd.go +++ b/pkg/registry/registrytest/etcd.go @@ -75,6 +75,11 @@ func (t *Tester) GeneratesName() *Tester { return t } +func (t *Tester) ReturnDeletedObject() *Tester { + t.tester = t.tester.ReturnDeletedObject() + return t +} + func (t *Tester) TestCreate(valid runtime.Object, invalid ...runtime.Object) { t.tester.TestCreate( valid, @@ -99,6 +104,24 @@ func (t *Tester) TestUpdate(valid runtime.Object, validUpdateFunc UpdateFunc, in ) } +func (t *Tester) TestDelete(valid runtime.Object) { + t.tester.TestDelete( + valid, + t.setObject, + t.getObject, + isNotFoundEtcdError, + ) +} + +func (t *Tester) TestDeleteGraceful(valid runtime.Object, expectedGrace int64) { + t.tester.TestDeleteGraceful( + valid, + t.setObject, + t.getObject, + expectedGrace, + ) +} + func (t *Tester) TestGet(valid runtime.Object) { t.tester.TestGet(valid) } @@ -219,3 +242,11 @@ func (t *Tester) emitObject(obj runtime.Object, action string) error { } return nil } + +func isNotFoundEtcdError(err error) bool { + etcdError, ok := err.(*etcd.EtcdError) + if !ok { + return false + } + return etcdError.ErrorCode == tools.EtcdErrorCodeNotFound +} diff --git a/pkg/registry/resourcequota/etcd/etcd_test.go b/pkg/registry/resourcequota/etcd/etcd_test.go index b7c92d1170c..6999bd13623 100644 --- a/pkg/registry/resourcequota/etcd/etcd_test.go +++ b/pkg/registry/resourcequota/etcd/etcd_test.go @@ -30,8 +30,6 @@ import ( "k8s.io/kubernetes/pkg/tools" "k8s.io/kubernetes/pkg/tools/etcdtest" "k8s.io/kubernetes/pkg/util" - - "github.com/coreos/go-etcd/etcd" ) func newStorage(t *testing.T) (*REST, *StatusREST, *tools.FakeEtcdClient) { @@ -74,15 +72,6 @@ func TestCreate(t *testing.T) { ) } -func expectResourceQuota(t *testing.T, out runtime.Object) (*api.ResourceQuota, bool) { - resourcequota, ok := out.(*api.ResourceQuota) - if !ok || resourcequota == nil { - t.Errorf("Expected an api.ResourceQuota object, was %#v", out) - return nil, false - } - return resourcequota, true -} - func TestCreateRegistryError(t *testing.T) { storage, _, fakeClient := newStorage(t) fakeClient.Err = fmt.Errorf("test error") @@ -116,49 +105,10 @@ func TestCreateSetsFields(t *testing.T) { } } -func TestResourceQuotaDecode(t *testing.T) { - storage, _, _ := newStorage(t) - expected := validNewResourceQuota() - body, err := testapi.Codec().Encode(expected) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - - actual := storage.New() - if err := testapi.Codec().DecodeInto(body, actual); err != nil { - t.Fatalf("unexpected error: %v", err) - } - - if !api.Semantic.DeepEqual(expected, actual) { - t.Errorf("mismatch: %s", util.ObjectDiff(expected, actual)) - } -} - -func TestDeleteResourceQuota(t *testing.T) { +func TestDelete(t *testing.T) { storage, _, fakeClient := newStorage(t) - fakeClient.ChangeIndex = 1 - ctx := api.NewDefaultContext() - key, _ := storage.Etcd.KeyFunc(ctx, "foo") - key = etcdtest.AddPrefix(key) - fakeClient.Data[key] = tools.EtcdResponseWithError{ - R: &etcd.Response{ - Node: &etcd.Node{ - Value: runtime.EncodeOrDie(testapi.Codec(), &api.ResourceQuota{ - ObjectMeta: api.ObjectMeta{ - Name: "foo", - Namespace: api.NamespaceDefault, - }, - Status: api.ResourceQuotaStatus{}, - }), - ModifiedIndex: 1, - CreatedIndex: 1, - }, - }, - } - _, err := storage.Delete(api.NewDefaultContext(), "foo", nil) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } + test := registrytest.New(t, fakeClient, storage.Etcd).ReturnDeletedObject() + test.TestDelete(validNewResourceQuota()) } func TestGet(t *testing.T) { @@ -195,7 +145,7 @@ func TestWatch(t *testing.T) { ) } -func TestEtcdUpdateStatus(t *testing.T) { +func TestUpdateStatus(t *testing.T) { storage, status, fakeClient := newStorage(t) ctx := api.NewDefaultContext() diff --git a/pkg/registry/secret/etcd/etcd_test.go b/pkg/registry/secret/etcd/etcd_test.go index 469068f5e80..e7506c12123 100644 --- a/pkg/registry/secret/etcd/etcd_test.go +++ b/pkg/registry/secret/etcd/etcd_test.go @@ -20,6 +20,8 @@ import ( "testing" "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/tools" @@ -78,6 +80,12 @@ func TestUpdate(t *testing.T) { ) } +func TestDelete(t *testing.T) { + storage, fakeClient := newStorage(t) + test := registrytest.New(t, fakeClient, storage.Etcd) + test.TestDelete(validNewSecret("foo")) +} + func TestGet(t *testing.T) { storage, fakeClient := newStorage(t) test := registrytest.New(t, fakeClient, storage.Etcd) @@ -89,3 +97,24 @@ func TestList(t *testing.T) { test := registrytest.New(t, fakeClient, storage.Etcd) test.TestList(validNewSecret("foo")) } + +func TestWatch(t *testing.T) { + storage, fakeClient := newStorage(t) + test := registrytest.New(t, fakeClient, storage.Etcd) + test.TestWatch( + validNewSecret("foo"), + // matching labels + []labels.Set{}, + // not matching labels + []labels.Set{ + {"foo": "bar"}, + }, + // matching fields + []fields.Set{}, + // not matching fields + []fields.Set{ + {"metadata.name": "bar"}, + {"name": "foo"}, + }, + ) +} diff --git a/pkg/registry/service/etcd/etcd_test.go b/pkg/registry/service/etcd/etcd_test.go index 4e3a6120eb5..580d0a093a6 100644 --- a/pkg/registry/service/etcd/etcd_test.go +++ b/pkg/registry/service/etcd/etcd_test.go @@ -106,6 +106,12 @@ func TestUpdate(t *testing.T) { ) } +func TestDelete(t *testing.T) { + storage, fakeClient := newStorage(t) + test := registrytest.New(t, fakeClient, storage.Etcd).AllowCreateOnUpdate() + test.TestDelete(validService()) +} + func TestGet(t *testing.T) { storage, fakeClient := newStorage(t) test := registrytest.New(t, fakeClient, storage.Etcd).AllowCreateOnUpdate() diff --git a/pkg/registry/serviceaccount/etcd/etcd_test.go b/pkg/registry/serviceaccount/etcd/etcd_test.go index 43a9eecdb63..b102f965a30 100644 --- a/pkg/registry/serviceaccount/etcd/etcd_test.go +++ b/pkg/registry/serviceaccount/etcd/etcd_test.go @@ -20,6 +20,8 @@ import ( "testing" "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/tools" @@ -71,6 +73,12 @@ func TestUpdate(t *testing.T) { ) } +func TestDelete(t *testing.T) { + storage, fakeClient := newStorage(t) + test := registrytest.New(t, fakeClient, storage.Etcd).ReturnDeletedObject() + test.TestDelete(validNewServiceAccount("foo")) +} + func TestGet(t *testing.T) { storage, fakeClient := newStorage(t) test := registrytest.New(t, fakeClient, storage.Etcd) @@ -82,3 +90,26 @@ func TestList(t *testing.T) { test := registrytest.New(t, fakeClient, storage.Etcd) test.TestList(validNewServiceAccount("foo")) } + +func TestWatch(t *testing.T) { + storage, fakeClient := newStorage(t) + test := registrytest.New(t, fakeClient, storage.Etcd) + test.TestWatch( + validNewServiceAccount("foo"), + // matching labels + []labels.Set{}, + // not matching labels + []labels.Set{ + {"foo": "bar"}, + }, + // matching fields + []fields.Set{ + {"metadata.name": "foo"}, + }, + // not matching fields + []fields.Set{ + {"metadata.name": "bar"}, + {"name": "foo"}, + }, + ) +} diff --git a/pkg/registry/thirdpartyresource/etcd/etcd_test.go b/pkg/registry/thirdpartyresource/etcd/etcd_test.go index e95b0cd20cd..0f2cea31d53 100644 --- a/pkg/registry/thirdpartyresource/etcd/etcd_test.go +++ b/pkg/registry/thirdpartyresource/etcd/etcd_test.go @@ -20,17 +20,14 @@ import ( "testing" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/rest/resttest" - "k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/expapi" // Ensure that expapi/v1 package is initialized. _ "k8s.io/kubernetes/pkg/expapi/v1" + "k8s.io/kubernetes/pkg/fields" + "k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/tools" - "k8s.io/kubernetes/pkg/tools/etcdtest" - - "github.com/coreos/go-etcd/etcd" ) func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) { @@ -81,30 +78,9 @@ func TestUpdate(t *testing.T) { } func TestDelete(t *testing.T) { - ctx := api.NewDefaultContext() storage, fakeClient := newStorage(t) - test := resttest.New(t, storage, fakeClient.SetError) - rsrc := validNewThirdPartyResource("foo2") - key, _ := storage.KeyFunc(ctx, "foo2") - key = etcdtest.AddPrefix(key) - createFn := func() runtime.Object { - fakeClient.Data[key] = tools.EtcdResponseWithError{ - R: &etcd.Response{ - Node: &etcd.Node{ - Value: runtime.EncodeOrDie(testapi.Codec(), rsrc), - ModifiedIndex: 1, - }, - }, - } - return rsrc - } - gracefulSetFn := func() bool { - if fakeClient.Data[key].R.Node == nil { - return false - } - return fakeClient.Data[key].R.Node.TTL == 30 - } - test.TestDeleteNoGraceful(createFn, gracefulSetFn) + test := registrytest.New(t, fakeClient, storage.Etcd) + test.TestDelete(validNewThirdPartyResource("foo")) } func TestGet(t *testing.T) { @@ -118,3 +94,24 @@ func TestList(t *testing.T) { test := registrytest.New(t, fakeClient, storage.Etcd) test.TestList(validNewThirdPartyResource("foo")) } + +func TestWatch(t *testing.T) { + storage, fakeClient := newStorage(t) + test := registrytest.New(t, fakeClient, storage.Etcd) + test.TestWatch( + validNewThirdPartyResource("foo"), + // matching labels + []labels.Set{}, + // not matching labels + []labels.Set{ + {"foo": "bar"}, + }, + // matching fields + []fields.Set{}, + // not matching fields + []fields.Set{ + {"metadata.name": "bar"}, + {"name": "foo"}, + }, + ) +}