Merge pull request #13509 from wojtek-t/refactor_etcd_delete_test

Refactor registry etcd delete tests
pull/6/head
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
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)
func (t *Tester) testDeleteNoGraceful(obj runtime.Object, setFn SetFunc, getFn GetFunc, isNotFoundFn IsErrorFunc) {
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)
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)

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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"},
},
// matching fields
[]fields.Set{
{"metadata.name": "foo"},
},
}
_, err := storage.Delete(ctx, name, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
// not matching fields
[]fields.Set{
{"metadata.name": "bar"},
{"name": "foo"},
},
)
}

View File

@ -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"},
},
)
}

View File

@ -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
},
}
}

View File

@ -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"},
},
)
}

View File

@ -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)
}
}

View File

@ -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",
test := registrytest.New(t, fakeClient, storage.Etcd).ClusterScope()
test.TestWatch(
validNewNamespace(),
// matching labels
[]labels.Set{},
// not matching labels
[]labels.Set{
{"foo": "bar"},
},
Status: api.NamespaceStatus{Phase: api.NamespaceActive},
}),
ModifiedIndex: 1,
CreatedIndex: 1,
// matching fields
[]fields.Set{
{"metadata.name": "foo"},
{"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) {

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
// 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,
"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,
}
}

View File

@ -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"},
},
// matching fields
[]fields.Set{
{"metadata.name": "foo"},
{"name": "foo"},
},
}
_, err := storage.Delete(ctx, name, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
// 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

View File

@ -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,
}
}

View File

@ -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)
}
test := registrytest.New(t, fakeClient, storage.Etcd)
test.TestWatch(
validNewPersistentVolumeClaim("foo", api.NamespaceDefault),
// matching labels
[]labels.Set{},
// not matching labels
[]labels.Set{
{"foo": "bar"},
},
// matching fields
[]fields.Set{
{"metadata.name": "foo"},
{"name": "foo"},
},
// not matching fields
[]fields.Set{
{"metadata.name": "bar"},
},
)
}
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,
},
},
}
_, err := storage.Delete(ctx, name, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
func TestEtcdUpdateStatus(t *testing.T) {
func TestUpdateStatus(t *testing.T) {
storage, statusStorage, fakeClient := newStorage(t)
ctx := api.NewDefaultContext()
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
// 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,
}
}

View File

@ -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)
}
}

View File

@ -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"},
},
)
}

View File

@ -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
},
}
}

View File

@ -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
}

View File

@ -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()

View File

@ -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"},
},
)
}

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

View File

@ -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"},
},
)
}

View File

@ -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"},
},
)
}