Merge pull request #13509 from wojtek-t/refactor_etcd_delete_test

Refactor registry etcd delete tests
This commit is contained in:
Piotr Szczesniak 2015-09-04 09:03:26 +02:00
commit fcbf63f3f3
24 changed files with 497 additions and 896 deletions

View File

@ -42,6 +42,7 @@ type Tester struct {
clusterScope bool clusterScope bool
createOnUpdate bool createOnUpdate bool
generatesName bool generatesName bool
returnDeletedObject bool
} }
type injectErrorFunc func(err error) type injectErrorFunc func(err error)
@ -75,6 +76,11 @@ func (t *Tester) GeneratesName() *Tester {
return t return t
} }
func (t *Tester) ReturnDeletedObject() *Tester {
t.returnDeletedObject = true
return t
}
// TestNamespace returns the namespace that will be used when creating contexts. // TestNamespace returns the namespace that will be used when creating contexts.
// Returns NamespaceNone for cluster-scoped objects. // Returns NamespaceNone for cluster-scoped objects.
func (t *Tester) TestNamespace() string { 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 GetFunc func(api.Context, runtime.Object) (runtime.Object, error)
type InitWatchFunc func() type InitWatchFunc func()
type InjectErrFunc func(err error) type InjectErrFunc func(err error)
type IsErrorFunc func(err error) bool
type SetFunc func(api.Context, runtime.Object) error type SetFunc func(api.Context, runtime.Object) error
type SetRVFunc func(uint64) type SetRVFunc func(uint64)
type UpdateFunc func(runtime.Object) runtime.Object 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. // Test deleting an object.
// TODO(wojtek-t): Change it to use AssignFunc instead. func (t *Tester) TestDelete(valid runtime.Object, setFn SetFunc, getFn GetFunc, isNotFoundFn IsErrorFunc) {
func (t *Tester) TestDelete(createFn func() runtime.Object, wasGracefulFn func() bool, invalid ...runtime.Object) { t.testDeleteNonExist(copyOrDie(valid))
t.TestDeleteNonExist(createFn) t.testDeleteNoGraceful(copyOrDie(valid), setFn, getFn, isNotFoundFn)
t.TestDeleteNoGraceful(createFn, wasGracefulFn)
t.TestDeleteInvokesValidation(invalid...)
// TODO: Test delete namespace mismatch rejection
// once #5684 is fixed.
} }
// Test graceful deletion. // Test gracefully deleting an object.
// TODO(wojtek-t): Change it to use AssignFunc instead. func (t *Tester) TestDeleteGraceful(valid runtime.Object, setFn SetFunc, getFn GetFunc, expectedGrace int64) {
func (t *Tester) TestDeleteGraceful(createFn func() runtime.Object, expectedGrace int64, wasGracefulFn func() bool) { t.testDeleteGracefulHasDefault(copyOrDie(valid), setFn, getFn, expectedGrace)
t.TestDeleteGracefulHasDefault(createFn(), expectedGrace, wasGracefulFn) t.testDeleteGracefulWithValue(copyOrDie(valid), setFn, getFn, expectedGrace)
t.TestDeleteGracefulWithValue(createFn(), expectedGrace, wasGracefulFn) t.testDeleteGracefulUsesZeroOnNil(copyOrDie(valid), setFn, expectedGrace)
t.TestDeleteGracefulUsesZeroOnNil(createFn(), 0) t.testDeleteGracefulExtend(copyOrDie(valid), setFn, getFn, expectedGrace)
t.TestDeleteGracefulExtend(createFn(), expectedGrace, wasGracefulFn) t.testDeleteGracefulImmediate(copyOrDie(valid), setFn, getFn, expectedGrace)
t.TestDeleteGracefulImmediate(createFn(), expectedGrace, wasGracefulFn)
} }
// Test getting object. // Test getting object.
func (t *Tester) TestGet(obj runtime.Object) { func (t *Tester) TestGet(valid runtime.Object) {
t.testGetFound(obj) t.testGetFound(copyOrDie(valid))
t.testGetNotFound(obj) t.testGetNotFound(copyOrDie(valid))
t.testGetMimatchedNamespace(obj) t.testGetMimatchedNamespace(copyOrDie(valid))
if !t.clusterScope { if !t.clusterScope {
t.testGetDifferentNamespace(obj) t.testGetDifferentNamespace(copyOrDie(valid))
} }
} }
// Test listing objects. // 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.testListError()
t.testListFound(obj, assignFn) t.testListFound(copyOrDie(valid), assignFn)
t.testListNotFound(assignFn, setRVFn) t.testListNotFound(assignFn, setRVFn)
t.testListMatchLabels(obj, assignFn) t.testListMatchLabels(copyOrDie(valid), assignFn)
} }
// Test watching objects. // Test watching objects.
func (t *Tester) TestWatch( 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) { labelsPass, labelsFail []labels.Set, fieldsPass, fieldsFail []fields.Set, actions []string) {
t.testWatch(initWatchFn, injectErrFn) t.testWatch(initWatchFn, injectErrFn)
t.testWatchLabels(copyOrDie(obj), initWatchFn, emitFn, labelsPass, labelsFail, actions) t.testWatchLabels(copyOrDie(valid), initWatchFn, emitFn, labelsPass, labelsFail, actions)
t.testWatchFields(copyOrDie(obj), initWatchFn, emitFn, fieldsPass, fieldsFail, actions) t.testWatchFields(copyOrDie(valid), initWatchFn, emitFn, fieldsPass, fieldsFail, actions)
} }
// ============================================================================= // =============================================================================
@ -512,26 +514,40 @@ func (t *Tester) testUpdateRejectsMismatchedNamespace(obj runtime.Object, setFn
// ============================================================================= // =============================================================================
// Deletion tests. // Deletion tests.
func (t *Tester) TestDeleteInvokesValidation(invalid ...runtime.Object) { func (t *Tester) testDeleteNoGraceful(obj runtime.Object, setFn SetFunc, getFn GetFunc, isNotFoundFn IsErrorFunc) {
for i, obj := range invalid {
objectMeta := t.getObjectMetaOrFail(obj)
ctx := t.TestContext() ctx := t.TestContext()
_, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, nil)
if !errors.IsInvalid(err) { foo := copyOrDie(obj)
t.Errorf("%d: Expected to get an invalid resource error, got %v", i, err) 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)
} }
} }
func (t *Tester) TestDeleteNonExist(createFn func() runtime.Object) { _, err = getFn(ctx, foo)
existing := createFn() if err == nil || !isNotFoundFn(err) {
objectMeta := t.getObjectMetaOrFail(existing) t.Errorf("unexpected error: %v", err)
context := t.TestContext() }
}
func (t *Tester) testDeleteNonExist(obj runtime.Object) {
objectMeta := t.getObjectMetaOrFail(obj)
t.withStorageError(&etcd.EtcdError{ErrorCode: tools.EtcdErrorCodeNotFound}, func() { 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) { 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. // Graceful Deletion tests.
func (t *Tester) TestDeleteNoGraceful(createFn func() runtime.Object, wasGracefulFn func() bool) { func (t *Tester) testDeleteGracefulHasDefault(obj runtime.Object, setFn SetFunc, getFn GetFunc, expectedGrace int64) {
existing := createFn() ctx := t.TestContext()
objectMeta := t.getObjectMetaOrFail(existing)
ctx := api.WithNamespace(t.TestContext(), objectMeta.Namespace) foo := copyOrDie(obj)
_, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(10)) t.setObjectMeta(foo, "foo1")
if err != nil { if err := setFn(ctx, foo); err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
if _, err := t.storage.(rest.Getter).Get(ctx, objectMeta.Name); !errors.IsNotFound(err) { objectMeta := t.getObjectMetaOrFail(foo)
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)
_, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, &api.DeleteOptions{}) _, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, &api.DeleteOptions{})
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
if !wasGracefulFn() { if _, err := getFn(ctx, foo); err != nil {
t.Errorf("did not gracefully delete resource") t.Fatalf("did not gracefully delete resource", err)
return
} }
object, err := t.storage.(rest.Getter).Get(ctx, objectMeta.Name) object, err := t.storage.(rest.Getter).Get(ctx, objectMeta.Name)
if err != nil { if err != nil {
t.Errorf("unexpected error, object should exist: %v", err) t.Fatalf("unexpected error, object should exist: %v", err)
return
} }
objectMeta, err = api.ObjectMetaFor(object) objectMeta = t.getObjectMetaOrFail(object)
if err != nil { if objectMeta.DeletionTimestamp == nil || objectMeta.DeletionGracePeriodSeconds == nil || *objectMeta.DeletionGracePeriodSeconds != expectedGrace {
t.Fatalf("object does not have ObjectMeta: %v\n%#v", err, object) t.Errorf("unexpected deleted meta: %#v", objectMeta)
}
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)
} }
} }
func (t *Tester) TestDeleteGracefulWithValue(existing runtime.Object, expectedGrace int64, wasGracefulFn func() bool) { func (t *Tester) testDeleteGracefulWithValue(obj runtime.Object, setFn SetFunc, getFn GetFunc, expectedGrace int64) {
objectMeta, err := api.ObjectMetaFor(existing) ctx := t.TestContext()
if err != nil {
t.Fatalf("object does not have ObjectMeta: %v\n%#v", err, existing)
}
ctx := api.WithNamespace(t.TestContext(), objectMeta.Namespace) foo := copyOrDie(obj)
_, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(expectedGrace+2)) 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 { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
if !wasGracefulFn() { if _, err := getFn(ctx, foo); err != nil {
t.Errorf("did not gracefully delete resource") t.Fatalf("did not gracefully delete resource", err)
} }
object, err := t.storage.(rest.Getter).Get(ctx, objectMeta.Name) object, err := t.storage.(rest.Getter).Get(ctx, objectMeta.Name)
if err != nil { if err != nil {
t.Errorf("unexpected error, object should exist: %v", err) t.Errorf("unexpected error, object should exist: %v", err)
} }
objectMeta, err = api.ObjectMetaFor(object) objectMeta = t.getObjectMetaOrFail(object)
if err != nil { if objectMeta.DeletionTimestamp == nil || objectMeta.DeletionGracePeriodSeconds == nil || *objectMeta.DeletionGracePeriodSeconds != expectedGrace+2 {
t.Fatalf("object does not have ObjectMeta: %v\n%#v", err, object) t.Errorf("unexpected deleted meta: %#v", objectMeta)
}
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)
} }
} }
func (t *Tester) TestDeleteGracefulExtend(existing runtime.Object, expectedGrace int64, wasGracefulFn func() bool) { func (t *Tester) testDeleteGracefulExtend(obj runtime.Object, setFn SetFunc, getFn GetFunc, expectedGrace int64) {
objectMeta, err := api.ObjectMetaFor(existing) ctx := t.TestContext()
if err != nil {
t.Fatalf("object does not have ObjectMeta: %v\n%#v", err, existing)
}
ctx := api.WithNamespace(t.TestContext(), objectMeta.Namespace) foo := copyOrDie(obj)
_, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(expectedGrace)) 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 { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
if !wasGracefulFn() { if _, err := getFn(ctx, foo); err != nil {
t.Errorf("did not gracefully delete resource") t.Fatalf("did not gracefully delete resource", err)
} }
// second delete duration is ignored // second delete duration is ignored
_, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(expectedGrace+2)) _, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(expectedGrace+2))
if err != nil { if err != nil {
@ -642,35 +635,29 @@ func (t *Tester) TestDeleteGracefulExtend(existing runtime.Object, expectedGrace
if err != nil { if err != nil {
t.Errorf("unexpected error, object should exist: %v", err) t.Errorf("unexpected error, object should exist: %v", err)
} }
objectMeta, err = api.ObjectMetaFor(object) objectMeta = t.getObjectMetaOrFail(object)
if err != nil { if objectMeta.DeletionTimestamp == nil || objectMeta.DeletionGracePeriodSeconds == nil || *objectMeta.DeletionGracePeriodSeconds != expectedGrace {
t.Fatalf("object does not have ObjectMeta: %v\n%#v", err, object) t.Errorf("unexpected deleted meta: %#v", objectMeta)
}
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)
} }
} }
func (t *Tester) TestDeleteGracefulImmediate(existing runtime.Object, expectedGrace int64, wasGracefulFn func() bool) { func (t *Tester) testDeleteGracefulImmediate(obj runtime.Object, setFn SetFunc, getFn GetFunc, expectedGrace int64) {
objectMeta, err := api.ObjectMetaFor(existing) ctx := t.TestContext()
if err != nil {
t.Fatalf("object does not have ObjectMeta: %v\n%#v", err, existing)
}
ctx := api.WithNamespace(t.TestContext(), objectMeta.Namespace) foo := copyOrDie(obj)
_, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(expectedGrace)) 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 { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)
} }
if !wasGracefulFn() { if _, err := getFn(ctx, foo); err != nil {
t.Errorf("did not gracefully delete resource") t.Fatalf("did not gracefully delete resource", err)
} }
// second delete is immediate, resource is deleted // second delete is immediate, resource is deleted
out, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(0)) out, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, api.NewDeleteOptions(0))
if err != nil { if err != nil {
@ -680,19 +667,21 @@ func (t *Tester) TestDeleteGracefulImmediate(existing runtime.Object, expectedGr
if !errors.IsNotFound(err) { if !errors.IsNotFound(err) {
t.Errorf("unexpected error, object should be deleted immediately: %v", err) t.Errorf("unexpected error, object should be deleted immediately: %v", err)
} }
objectMeta, err = api.ObjectMetaFor(out) objectMeta = t.getObjectMetaOrFail(out)
if err != nil {
t.Errorf("unexpected error: %v", err)
return
}
if objectMeta.DeletionTimestamp == nil || objectMeta.DeletionGracePeriodSeconds == nil || *objectMeta.DeletionGracePeriodSeconds != 0 { if objectMeta.DeletionTimestamp == nil || objectMeta.DeletionGracePeriodSeconds == nil || *objectMeta.DeletionGracePeriodSeconds != 0 {
t.Errorf("unexpected deleted meta: %#v", objectMeta) t.Errorf("unexpected deleted meta: %#v", objectMeta)
} }
} }
func (t *Tester) TestDeleteGracefulUsesZeroOnNil(existing runtime.Object, expectedGrace int64) { func (t *Tester) testDeleteGracefulUsesZeroOnNil(obj runtime.Object, setFn SetFunc, expectedGrace int64) {
objectMeta := t.getObjectMetaOrFail(existing) ctx := t.TestContext()
ctx := api.WithNamespace(t.TestContext(), objectMeta.Namespace)
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) _, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, nil)
if err != nil { if err != nil {
t.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)

View File

@ -19,16 +19,12 @@ package etcd
import ( import (
"testing" "testing"
"github.com/coreos/go-etcd/etcd"
"k8s.io/kubernetes/pkg/api" "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/fields"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/registry/registrytest"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/tools" "k8s.io/kubernetes/pkg/tools"
"k8s.io/kubernetes/pkg/tools/etcdtest"
) )
func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) { 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) { func TestGenerationNumber(t *testing.T) {
storage, _ := newStorage(t) storage, _ := newStorage(t)
modifiedSno := *validNewController() 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)
}

View File

@ -19,17 +19,13 @@ package etcd
import ( import (
"testing" "testing"
"github.com/coreos/go-etcd/etcd"
"k8s.io/kubernetes/pkg/api" "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/expapi"
"k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/registry/registrytest"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/tools" "k8s.io/kubernetes/pkg/tools"
"k8s.io/kubernetes/pkg/tools/etcdtest"
) )
func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) { 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) { func TestGet(t *testing.T) {
storage, fakeClient := newStorage(t) storage, fakeClient := newStorage(t)
test := registrytest.New(t, fakeClient, storage.Etcd) 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)
}

View File

@ -19,17 +19,13 @@ package etcd
import ( import (
"testing" "testing"
"github.com/coreos/go-etcd/etcd"
"k8s.io/kubernetes/pkg/api" "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/expapi"
"k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/registry/registrytest"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/tools" "k8s.io/kubernetes/pkg/tools"
"k8s.io/kubernetes/pkg/tools/etcdtest"
) )
func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) { 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) { func TestGet(t *testing.T) {
storage, fakeClient := newStorage(t) storage, fakeClient := newStorage(t)
test := registrytest.New(t, fakeClient, storage.Etcd) 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)
}

View File

@ -20,15 +20,11 @@ import (
"testing" "testing"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/rest/resttest" "k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/registry/registrytest"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/tools" "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) { func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) {
@ -93,31 +89,9 @@ func TestUpdate(t *testing.T) {
} }
func TestDelete(t *testing.T) { func TestDelete(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t) storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError) test := registrytest.New(t, fakeClient, storage.Etcd)
test.TestDelete(validNewEndpoints())
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)
} }
func TestGet(t *testing.T) { func TestGet(t *testing.T) {
@ -132,43 +106,25 @@ func TestList(t *testing.T) {
test.TestList(validNewEndpoints()) test.TestList(validNewEndpoints())
} }
func TestEndpointsDecode(t *testing.T) { func TestWatch(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()
storage, fakeClient := newStorage(t) storage, fakeClient := newStorage(t)
endpoints := validNewEndpoints() test := registrytest.New(t, fakeClient, storage.Etcd)
name := endpoints.Name test.TestWatch(
key, _ := storage.KeyFunc(ctx, name) validNewEndpoints(),
key = etcdtest.AddPrefix(key) // matching labels
fakeClient.ChangeIndex = 1 []labels.Set{},
fakeClient.Data[key] = tools.EtcdResponseWithError{ // not matching labels
R: &etcd.Response{ []labels.Set{
Node: &etcd.Node{ {"foo": "bar"},
Value: runtime.EncodeOrDie(testapi.Codec(), endpoints),
ModifiedIndex: 1,
CreatedIndex: 1,
}, },
// matching fields
[]fields.Set{
{"metadata.name": "foo"},
}, },
} // not matching fields
_, err := storage.Delete(ctx, name, nil) []fields.Set{
if err != nil { {"metadata.name": "bar"},
t.Fatalf("unexpected error: %v", err) {"name": "foo"},
} },
)
} }

View File

@ -21,17 +21,14 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource" "k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/rest/resttest"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/expapi" "k8s.io/kubernetes/pkg/expapi"
// Ensure that expapi/v1 package is initialized. // Ensure that expapi/v1 package is initialized.
_ "k8s.io/kubernetes/pkg/expapi/v1" _ "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/registry/registrytest"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/tools" "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) { func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) {
@ -85,30 +82,9 @@ func TestUpdate(t *testing.T) {
} }
func TestDelete(t *testing.T) { func TestDelete(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t) storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError) test := registrytest.New(t, fakeClient, storage.Etcd)
autoscaler := validNewHorizontalPodAutoscaler("foo2") test.TestDelete(validNewHorizontalPodAutoscaler("foo"))
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)
} }
func TestGet(t *testing.T) { func TestGet(t *testing.T) {
@ -122,3 +98,24 @@ func TestList(t *testing.T) {
test := registrytest.New(t, fakeClient, storage.Etcd) test := registrytest.New(t, fakeClient, storage.Etcd)
test.TestList(validNewHorizontalPodAutoscaler("foo")) 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"},
},
)
}

View File

@ -74,13 +74,20 @@ func (autoscalerStrategy) AllowUnconditionalUpdate() bool {
return true return true
} }
// MatchAutoscaler returns a generic matcher for a given label and field selector. func AutoscalerToSelectableFields(limitRange *expapi.HorizontalPodAutoscaler) fields.Set {
return fields.Set{}
}
func MatchAutoscaler(label labels.Selector, field fields.Selector) generic.Matcher { func MatchAutoscaler(label labels.Selector, field fields.Selector) generic.Matcher {
return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { return &generic.SelectionPredicate{
autoscaler, ok := obj.(*expapi.HorizontalPodAutoscaler) Label: label,
Field: field,
GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
hpa, ok := obj.(*expapi.HorizontalPodAutoscaler)
if !ok { if !ok {
return false, fmt.Errorf("not a horizontal pod autoscaler") return nil, nil, fmt.Errorf("given object is not a horizontal pod autoscaler.")
}
return labels.Set(hpa.ObjectMeta.Labels), AutoscalerToSelectableFields(hpa), nil
},
} }
return label.Matches(labels.Set(autoscaler.Labels)), nil
})
} }

View File

@ -21,6 +21,8 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource" "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/registry/registrytest"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/tools" "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) { func TestGet(t *testing.T) {
storage, fakeClient := newStorage(t) storage, fakeClient := newStorage(t)
test := registrytest.New(t, fakeClient, storage.Etcd) test := registrytest.New(t, fakeClient, storage.Etcd)
@ -108,3 +116,24 @@ func TestList(t *testing.T) {
test := registrytest.New(t, fakeClient, storage.Etcd) test := registrytest.New(t, fakeClient, storage.Etcd)
test.TestList(validNewLimitRange()) 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"},
},
)
}

View File

@ -22,16 +22,11 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource" "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/fields"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/registry/registrytest" "k8s.io/kubernetes/pkg/registry/registrytest"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/tools" "k8s.io/kubernetes/pkg/tools"
"k8s.io/kubernetes/pkg/tools/etcdtest"
"github.com/coreos/go-etcd/etcd"
) )
type fakeConnectionInfoGetter struct { 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) { func TestCreate(t *testing.T) {
storage, fakeClient := newStorage(t) storage, fakeClient := newStorage(t)
test := registrytest.New(t, fakeClient, storage.Etcd).ClusterScope() test := registrytest.New(t, fakeClient, storage.Etcd).ClusterScope()
@ -104,31 +93,9 @@ func TestUpdate(t *testing.T) {
} }
func TestDelete(t *testing.T) { func TestDelete(t *testing.T) {
ctx := api.NewContext()
storage, fakeClient := newStorage(t) storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError).ClusterScope() test := registrytest.New(t, fakeClient, storage.Etcd).ClusterScope()
test.TestDelete(validNewNode())
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)
} }
func TestGet(t *testing.T) { func TestGet(t *testing.T) {
@ -143,7 +110,7 @@ func TestList(t *testing.T) {
test.TestList(validNewNode()) test.TestList(validNewNode())
} }
func TestWatchNodes(t *testing.T) { func TestWatch(t *testing.T) {
storage, fakeClient := newStorage(t) storage, fakeClient := newStorage(t)
test := registrytest.New(t, fakeClient, storage.Etcd).ClusterScope() test := registrytest.New(t, fakeClient, storage.Etcd).ClusterScope()
test.TestWatch( 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)
}
}

View File

@ -21,6 +21,8 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi" "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/registry/registrytest"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/tools" "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) { func TestCreateSetsFields(t *testing.T) {
storage, fakeClient := newStorage(t) storage, fakeClient := newStorage(t)
namespace := validNewNamespace() namespace := validNewNamespace()
@ -93,24 +86,10 @@ func TestCreateSetsFields(t *testing.T) {
} }
} }
func TestNamespaceDecode(t *testing.T) { func TestDelete(t *testing.T) {
storage, _ := newStorage(t) storage, fakeClient := newStorage(t)
expected := validNewNamespace() test := registrytest.New(t, fakeClient, storage.Etcd).ClusterScope().ReturnDeletedObject()
expected.Status.Phase = api.NamespaceActive test.TestDelete(validNewNamespace())
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 TestGet(t *testing.T) { func TestGet(t *testing.T) {
@ -125,31 +104,27 @@ func TestList(t *testing.T) {
test.TestList(validNewNamespace()) test.TestList(validNewNamespace())
} }
func TestDeleteNamespace(t *testing.T) { func TestWatch(t *testing.T) {
storage, fakeClient := newStorage(t) storage, fakeClient := newStorage(t)
fakeClient.ChangeIndex = 1 test := registrytest.New(t, fakeClient, storage.Etcd).ClusterScope()
ctx := api.NewContext() test.TestWatch(
key, err := storage.Etcd.KeyFunc(ctx, "foo") validNewNamespace(),
key = etcdtest.AddPrefix(key) // matching labels
fakeClient.Data[key] = tools.EtcdResponseWithError{ []labels.Set{},
R: &etcd.Response{ // not matching labels
Node: &etcd.Node{ []labels.Set{
Value: runtime.EncodeOrDie(testapi.Codec(), &api.Namespace{ {"foo": "bar"},
ObjectMeta: api.ObjectMeta{
Name: "foo",
}, },
Status: api.NamespaceStatus{Phase: api.NamespaceActive}, // matching fields
}), []fields.Set{
ModifiedIndex: 1, {"metadata.name": "foo"},
CreatedIndex: 1, {"name": "foo"},
}, },
// not matching fields
[]fields.Set{
{"metadata.name": "bar"},
}, },
} )
_, err = storage.Delete(api.NewContext(), "foo", nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
} }
func TestDeleteNamespaceWithIncompleteFinalizers(t *testing.T) { func TestDeleteNamespaceWithIncompleteFinalizers(t *testing.T) {

View File

@ -143,10 +143,11 @@ func MatchNamespace(label labels.Selector, field fields.Selector) generic.Matche
} }
// NamespaceToSelectableFields returns a label set that represents the object // 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 { func NamespaceToSelectableFields(namespace *api.Namespace) labels.Set {
return labels.Set{ return labels.Set{
"name": namespace.Name, "metadata.name": namespace.Name,
"status.phase": string(namespace.Status.Phase), "status.phase": string(namespace.Status.Phase),
// This is a bug, but we need to support it for backward compatibility.
"name": namespace.Name,
} }
} }

View File

@ -21,15 +21,14 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource" "k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/rest/resttest"
"k8s.io/kubernetes/pkg/api/testapi" "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/registry/registrytest"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/tools" "k8s.io/kubernetes/pkg/tools"
"k8s.io/kubernetes/pkg/tools/etcdtest" "k8s.io/kubernetes/pkg/tools/etcdtest"
"k8s.io/kubernetes/pkg/util" "k8s.io/kubernetes/pkg/util"
"github.com/coreos/go-etcd/etcd"
) )
func newStorage(t *testing.T) (*REST, *StatusREST, *tools.FakeEtcdClient) { func newStorage(t *testing.T) (*REST, *StatusREST, *tools.FakeEtcdClient) {
@ -101,31 +100,9 @@ func TestUpdate(t *testing.T) {
} }
func TestDelete(t *testing.T) { func TestDelete(t *testing.T) {
ctx := api.NewContext()
storage, _, fakeClient := newStorage(t) storage, _, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError).ClusterScope() test := registrytest.New(t, fakeClient, storage.Etcd).ClusterScope().ReturnDeletedObject()
test.TestDelete(validNewPersistentVolume("foo"))
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)
} }
func TestGet(t *testing.T) { func TestGet(t *testing.T) {
@ -140,48 +117,30 @@ func TestList(t *testing.T) {
test.TestList(validNewPersistentVolume("foo")) test.TestList(validNewPersistentVolume("foo"))
} }
func TestPersistentVolumesDecode(t *testing.T) { func TestWatch(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()
storage, _, fakeClient := newStorage(t) storage, _, fakeClient := newStorage(t)
persistentVolume := validNewPersistentVolume("foo") test := registrytest.New(t, fakeClient, storage.Etcd).ClusterScope()
name := persistentVolume.Name test.TestWatch(
key, _ := storage.KeyFunc(ctx, name) validNewPersistentVolume("foo"),
key = etcdtest.AddPrefix(key) // matching labels
fakeClient.ChangeIndex = 1 []labels.Set{},
fakeClient.Data[key] = tools.EtcdResponseWithError{ // not matching labels
R: &etcd.Response{ []labels.Set{
Node: &etcd.Node{ {"foo": "bar"},
Value: runtime.EncodeOrDie(testapi.Codec(), persistentVolume),
ModifiedIndex: 1,
CreatedIndex: 1,
}, },
// matching fields
[]fields.Set{
{"metadata.name": "foo"},
{"name": "foo"},
}, },
} // not matching fields
_, err := storage.Delete(ctx, name, nil) []fields.Set{
if err != nil { {"metadata.name": "bar"},
t.Fatalf("unexpected error: %v", err) },
} )
} }
func TestEtcdUpdateStatus(t *testing.T) { func TestUpdateStatus(t *testing.T) {
storage, statusStorage, fakeClient := newStorage(t) storage, statusStorage, fakeClient := newStorage(t)
fakeClient.TestIndex = true fakeClient.TestIndex = true

View File

@ -103,9 +103,10 @@ func MatchPersistentVolumes(label labels.Selector, field fields.Selector) generi
} }
// PersistentVolumeToSelectableFields returns a label set that represents the object // 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 { func PersistentVolumeToSelectableFields(persistentvolume *api.PersistentVolume) labels.Set {
return 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, "name": persistentvolume.Name,
} }
} }

View File

@ -21,15 +21,14 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource" "k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/rest/resttest"
"k8s.io/kubernetes/pkg/api/testapi" "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/registry/registrytest"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/tools" "k8s.io/kubernetes/pkg/tools"
"k8s.io/kubernetes/pkg/tools/etcdtest" "k8s.io/kubernetes/pkg/tools/etcdtest"
"k8s.io/kubernetes/pkg/util" "k8s.io/kubernetes/pkg/util"
"github.com/coreos/go-etcd/etcd"
) )
func newStorage(t *testing.T) (*REST, *StatusREST, *tools.FakeEtcdClient) { func newStorage(t *testing.T) (*REST, *StatusREST, *tools.FakeEtcdClient) {
@ -59,12 +58,6 @@ func validNewPersistentVolumeClaim(name, ns string) *api.PersistentVolumeClaim {
return pv return pv
} }
func validChangedPersistentVolumeClaim() *api.PersistentVolumeClaim {
pv := validNewPersistentVolumeClaim("foo", api.NamespaceDefault)
pv.ResourceVersion = "1"
return pv
}
func TestCreate(t *testing.T) { func TestCreate(t *testing.T) {
storage, _, fakeClient := newStorage(t) storage, _, fakeClient := newStorage(t)
test := registrytest.New(t, fakeClient, storage.Etcd) test := registrytest.New(t, fakeClient, storage.Etcd)
@ -100,31 +93,9 @@ func TestUpdate(t *testing.T) {
} }
func TestDelete(t *testing.T) { func TestDelete(t *testing.T) {
ctx := api.NewDefaultContext()
storage, _, fakeClient := newStorage(t) storage, _, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError) test := registrytest.New(t, fakeClient, storage.Etcd).ReturnDeletedObject()
test.TestDelete(validNewPersistentVolumeClaim("foo", api.NamespaceDefault))
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)
} }
func TestGet(t *testing.T) { func TestGet(t *testing.T) {
@ -139,78 +110,30 @@ func TestList(t *testing.T) {
test.TestList(validNewPersistentVolumeClaim("foo", api.NamespaceDefault)) test.TestList(validNewPersistentVolumeClaim("foo", api.NamespaceDefault))
} }
func TestPersistentVolumeClaimsDecode(t *testing.T) { func TestWatch(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()
storage, _, fakeClient := newStorage(t) storage, _, fakeClient := newStorage(t)
persistentVolume := validChangedPersistentVolumeClaim() test := registrytest.New(t, fakeClient, storage.Etcd)
test.TestWatch(
key, _ := storage.KeyFunc(ctx, "foo") validNewPersistentVolumeClaim("foo", api.NamespaceDefault),
key = etcdtest.AddPrefix(key) // matching labels
fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), validNewPersistentVolumeClaim("foo", api.NamespaceDefault)), 0) []labels.Set{},
// not matching labels
_, _, err := storage.Update(ctx, persistentVolume) []labels.Set{
if err != nil { {"foo": "bar"},
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,
}, },
// matching fields
[]fields.Set{
{"metadata.name": "foo"},
{"name": "foo"},
}, },
} // not matching fields
_, err := storage.Delete(ctx, name, nil) []fields.Set{
if err != nil { {"metadata.name": "bar"},
t.Fatalf("unexpected error: %v", err) },
} )
} }
func TestEtcdUpdateStatus(t *testing.T) { func TestUpdateStatus(t *testing.T) {
storage, statusStorage, fakeClient := newStorage(t) storage, statusStorage, fakeClient := newStorage(t)
ctx := api.NewDefaultContext() ctx := api.NewDefaultContext()
fakeClient.TestIndex = true fakeClient.TestIndex = true

View File

@ -103,9 +103,10 @@ func MatchPersistentVolumeClaim(label labels.Selector, field fields.Selector) ge
} }
// PersistentVolumeClaimToSelectableFields returns a label set that represents the object // 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 { func PersistentVolumeClaimToSelectableFields(persistentvolumeclaim *api.PersistentVolumeClaim) labels.Set {
return 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, "name": persistentvolumeclaim.Name,
} }
} }

View File

@ -25,7 +25,6 @@ import (
"k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/errors"
etcderrors "k8s.io/kubernetes/pkg/api/errors/etcd" etcderrors "k8s.io/kubernetes/pkg/api/errors/etcd"
"k8s.io/kubernetes/pkg/api/rest" "k8s.io/kubernetes/pkg/api/rest"
"k8s.io/kubernetes/pkg/api/rest/resttest"
"k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/fields" "k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
@ -122,50 +121,12 @@ func TestUpdate(t *testing.T) {
func TestDelete(t *testing.T) { func TestDelete(t *testing.T) {
storage, _, _, fakeClient := newStorage(t) storage, _, _, fakeClient := newStorage(t)
ctx := api.NewDefaultContext() test := registrytest.New(t, fakeClient, storage.Etcd).ReturnDeletedObject()
key, _ := storage.Etcd.KeyFunc(ctx, "foo") test.TestDelete(validNewPod())
key = etcdtest.AddPrefix(key)
test := resttest.New(t, storage, fakeClient.SetError)
expectedNode := "some-node" scheduledPod := validNewPod()
createFn := func() runtime.Object { scheduledPod.Spec.NodeName = "some-node"
pod := validChangedPod() test.TestDeleteGraceful(scheduledPod, 30)
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
} }
func TestCreateRegistryError(t *testing.T) { 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) { func TestResourceLocation(t *testing.T) {
expectedIP := "1.2.3.4" expectedIP := "1.2.3.4"
testCases := []struct { testCases := []struct {
@ -854,49 +797,3 @@ func TestEtcdUpdateStatus(t *testing.T) {
t.Errorf("unexpected object: %s", util.ObjectDiff(&expected, podOut)) 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)
}
}

View File

@ -20,6 +20,8 @@ import (
"testing" "testing"
"k8s.io/kubernetes/pkg/api" "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/registry/registrytest"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/tools" "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) { func TestGet(t *testing.T) {
storage, fakeClient := newStorage(t) storage, fakeClient := newStorage(t)
test := registrytest.New(t, fakeClient, storage.Etcd) test := registrytest.New(t, fakeClient, storage.Etcd)
@ -98,3 +106,24 @@ func TestList(t *testing.T) {
test := registrytest.New(t, fakeClient, storage.Etcd) test := registrytest.New(t, fakeClient, storage.Etcd)
test.TestList(validNewPodTemplate("foo")) 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"},
},
)
}

View File

@ -73,13 +73,20 @@ func (podTemplateStrategy) AllowUnconditionalUpdate() bool {
return true return true
} }
// MatchPodTemplate returns a generic matcher for a given label and field selector. func PodTemplateToSelectableFields(podTemplate *api.PodTemplate) fields.Set {
return fields.Set{}
}
func MatchPodTemplate(label labels.Selector, field fields.Selector) generic.Matcher { func MatchPodTemplate(label labels.Selector, field fields.Selector) generic.Matcher {
return generic.MatcherFunc(func(obj runtime.Object) (bool, error) { return &generic.SelectionPredicate{
podObj, ok := obj.(*api.PodTemplate) Label: label,
Field: field,
GetAttrs: func(obj runtime.Object) (labels.Set, fields.Set, error) {
pt, ok := obj.(*api.PodTemplate)
if !ok { if !ok {
return false, fmt.Errorf("not a pod template") return nil, nil, fmt.Errorf("given object is not a pod template.")
}
return labels.Set(pt.ObjectMeta.Labels), PodTemplateToSelectableFields(pt), nil
},
} }
return label.Matches(labels.Set(podObj.Labels)), nil
})
} }

View File

@ -75,6 +75,11 @@ func (t *Tester) GeneratesName() *Tester {
return t return t
} }
func (t *Tester) ReturnDeletedObject() *Tester {
t.tester = t.tester.ReturnDeletedObject()
return t
}
func (t *Tester) TestCreate(valid runtime.Object, invalid ...runtime.Object) { func (t *Tester) TestCreate(valid runtime.Object, invalid ...runtime.Object) {
t.tester.TestCreate( t.tester.TestCreate(
valid, 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) { func (t *Tester) TestGet(valid runtime.Object) {
t.tester.TestGet(valid) t.tester.TestGet(valid)
} }
@ -219,3 +242,11 @@ func (t *Tester) emitObject(obj runtime.Object, action string) error {
} }
return nil return nil
} }
func isNotFoundEtcdError(err error) bool {
etcdError, ok := err.(*etcd.EtcdError)
if !ok {
return false
}
return etcdError.ErrorCode == tools.EtcdErrorCodeNotFound
}

View File

@ -30,8 +30,6 @@ import (
"k8s.io/kubernetes/pkg/tools" "k8s.io/kubernetes/pkg/tools"
"k8s.io/kubernetes/pkg/tools/etcdtest" "k8s.io/kubernetes/pkg/tools/etcdtest"
"k8s.io/kubernetes/pkg/util" "k8s.io/kubernetes/pkg/util"
"github.com/coreos/go-etcd/etcd"
) )
func newStorage(t *testing.T) (*REST, *StatusREST, *tools.FakeEtcdClient) { 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) { func TestCreateRegistryError(t *testing.T) {
storage, _, fakeClient := newStorage(t) storage, _, fakeClient := newStorage(t)
fakeClient.Err = fmt.Errorf("test error") fakeClient.Err = fmt.Errorf("test error")
@ -116,49 +105,10 @@ func TestCreateSetsFields(t *testing.T) {
} }
} }
func TestResourceQuotaDecode(t *testing.T) { func TestDelete(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) {
storage, _, fakeClient := newStorage(t) storage, _, fakeClient := newStorage(t)
fakeClient.ChangeIndex = 1 test := registrytest.New(t, fakeClient, storage.Etcd).ReturnDeletedObject()
ctx := api.NewDefaultContext() test.TestDelete(validNewResourceQuota())
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)
}
} }
func TestGet(t *testing.T) { 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) storage, status, fakeClient := newStorage(t)
ctx := api.NewDefaultContext() ctx := api.NewDefaultContext()

View File

@ -20,6 +20,8 @@ import (
"testing" "testing"
"k8s.io/kubernetes/pkg/api" "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/registry/registrytest"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/tools" "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) { func TestGet(t *testing.T) {
storage, fakeClient := newStorage(t) storage, fakeClient := newStorage(t)
test := registrytest.New(t, fakeClient, storage.Etcd) test := registrytest.New(t, fakeClient, storage.Etcd)
@ -89,3 +97,24 @@ func TestList(t *testing.T) {
test := registrytest.New(t, fakeClient, storage.Etcd) test := registrytest.New(t, fakeClient, storage.Etcd)
test.TestList(validNewSecret("foo")) 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"},
},
)
}

View File

@ -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) { func TestGet(t *testing.T) {
storage, fakeClient := newStorage(t) storage, fakeClient := newStorage(t)
test := registrytest.New(t, fakeClient, storage.Etcd).AllowCreateOnUpdate() test := registrytest.New(t, fakeClient, storage.Etcd).AllowCreateOnUpdate()

View File

@ -20,6 +20,8 @@ import (
"testing" "testing"
"k8s.io/kubernetes/pkg/api" "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/registry/registrytest"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/tools" "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) { func TestGet(t *testing.T) {
storage, fakeClient := newStorage(t) storage, fakeClient := newStorage(t)
test := registrytest.New(t, fakeClient, storage.Etcd) test := registrytest.New(t, fakeClient, storage.Etcd)
@ -82,3 +90,26 @@ func TestList(t *testing.T) {
test := registrytest.New(t, fakeClient, storage.Etcd) test := registrytest.New(t, fakeClient, storage.Etcd)
test.TestList(validNewServiceAccount("foo")) 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"},
},
)
}

View File

@ -20,17 +20,14 @@ import (
"testing" "testing"
"k8s.io/kubernetes/pkg/api" "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/expapi"
// Ensure that expapi/v1 package is initialized. // Ensure that expapi/v1 package is initialized.
_ "k8s.io/kubernetes/pkg/expapi/v1" _ "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/registry/registrytest"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/tools" "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) { func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) {
@ -81,30 +78,9 @@ func TestUpdate(t *testing.T) {
} }
func TestDelete(t *testing.T) { func TestDelete(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t) storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError) test := registrytest.New(t, fakeClient, storage.Etcd)
rsrc := validNewThirdPartyResource("foo2") test.TestDelete(validNewThirdPartyResource("foo"))
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)
} }
func TestGet(t *testing.T) { func TestGet(t *testing.T) {
@ -118,3 +94,24 @@ func TestList(t *testing.T) {
test := registrytest.New(t, fakeClient, storage.Etcd) test := registrytest.New(t, fakeClient, storage.Etcd)
test.TestList(validNewThirdPartyResource("foo")) 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"},
},
)
}