Merge pull request #13584 from wojtek-t/remaining_test_refactorings

Refactor registry tests to reduce dependency on go-etcd.
This commit is contained in:
Quinton Hoole 2015-09-04 13:12:45 -07:00
commit 49702f9059
9 changed files with 188 additions and 863 deletions

View File

@ -23,7 +23,6 @@ import (
"testing" "testing"
"time" "time"
"github.com/coreos/go-etcd/etcd"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors" "k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/rest" "k8s.io/kubernetes/pkg/api/rest"
@ -544,7 +543,7 @@ func (t *Tester) testDeleteNoGraceful(obj runtime.Object, setFn SetFunc, getFn G
func (t *Tester) testDeleteNonExist(obj runtime.Object) { func (t *Tester) testDeleteNonExist(obj runtime.Object) {
objectMeta := t.getObjectMetaOrFail(obj) objectMeta := t.getObjectMetaOrFail(obj)
t.withStorageError(&etcd.EtcdError{ErrorCode: tools.EtcdErrorCodeNotFound}, func() { t.withStorageError(tools.EtcdErrorNotFound, func() {
_, err := t.storage.(rest.GracefulDeleter).Delete(t.TestContext(), 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.Errorf("unexpected error: %v", err) t.Errorf("unexpected error: %v", err)

View File

@ -17,20 +17,12 @@ limitations under the License.
package etcd package etcd
import ( import (
"reflect"
"testing" "testing"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/testapi"
etcdgeneric "k8s.io/kubernetes/pkg/registry/generic/etcd"
"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"
) )
var testTTL uint64 = 60 var testTTL uint64 = 60
@ -41,199 +33,56 @@ func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) {
return NewREST(etcdStorage, testTTL), fakeClient return NewREST(etcdStorage, testTTL), fakeClient
} }
func TestEventCreate(t *testing.T) { func validNewEvent(namespace string) *api.Event {
eventA := &api.Event{ return &api.Event{
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault}, ObjectMeta: api.ObjectMeta{
Reason: "forTesting", Name: "foo",
InvolvedObject: api.ObjectReference{Name: "bar", Namespace: api.NamespaceDefault}, Namespace: namespace,
}
eventB := &api.Event{
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault},
Reason: "forTesting",
InvolvedObject: api.ObjectReference{Name: "bar", Namespace: api.NamespaceDefault},
}
nodeWithEventA := tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Value: runtime.EncodeOrDie(testapi.Codec(), eventA),
ModifiedIndex: 1,
CreatedIndex: 1,
TTL: int64(testTTL),
},
}, },
E: nil, Reason: "forTesting",
} InvolvedObject: api.ObjectReference{
Name: "bar",
emptyNode := tools.EtcdResponseWithError{ Namespace: namespace,
R: &etcd.Response{},
E: tools.EtcdErrorNotFound,
}
ctx := api.NewDefaultContext()
key := "foo"
path, err := etcdgeneric.NamespaceKeyFunc(ctx, "/events", key)
path = etcdtest.AddPrefix(path)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
table := map[string]struct {
existing tools.EtcdResponseWithError
expect tools.EtcdResponseWithError
toCreate runtime.Object
errOK func(error) bool
}{
"normal": {
existing: emptyNode,
expect: nodeWithEventA,
toCreate: eventA,
errOK: func(err error) bool { return err == nil },
}, },
"preExisting": {
existing: nodeWithEventA,
expect: nodeWithEventA,
toCreate: eventB,
errOK: errors.IsAlreadyExists,
},
}
for name, item := range table {
storage, fakeClient := newStorage(t)
fakeClient.Data[path] = item.existing
_, err := storage.Create(ctx, item.toCreate)
if !item.errOK(err) {
t.Errorf("%v: unexpected error: %v", name, err)
}
// nullify fields set by infrastructure
received := fakeClient.Data[path]
var event api.Event
if err := testapi.Codec().DecodeInto([]byte(received.R.Node.Value), &event); err != nil {
t.Errorf("unexpected error: %v", err)
}
event.ObjectMeta.CreationTimestamp = util.Time{}
event.ObjectMeta.UID = ""
received.R.Node.Value = runtime.EncodeOrDie(testapi.Codec(), &event)
if e, a := item.expect, received; !reflect.DeepEqual(e, a) {
t.Errorf("%v:\n%s", name, util.ObjectDiff(e, a))
}
} }
} }
func TestEventUpdate(t *testing.T) { func TestCreate(t *testing.T) {
eventA := &api.Event{ storage, fakeClient := newStorage(t)
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault}, test := registrytest.New(t, fakeClient, storage.Etcd)
Reason: "forTesting", event := validNewEvent(test.TestNamespace())
InvolvedObject: api.ObjectReference{Name: "foo", Namespace: api.NamespaceDefault}, event.ObjectMeta = api.ObjectMeta{}
} test.TestCreate(
eventB := &api.Event{ // valid
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault}, event,
Reason: "for testing again", // invalid
InvolvedObject: api.ObjectReference{Name: "foo", Namespace: api.NamespaceDefault}, &api.Event{},
} )
eventC := &api.Event{ }
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: api.NamespaceDefault, ResourceVersion: "1"},
Reason: "for testing again something else", func TestUpdate(t *testing.T) {
InvolvedObject: api.ObjectReference{Name: "foo", Namespace: api.NamespaceDefault}, storage, fakeClient := newStorage(t)
} test := registrytest.New(t, fakeClient, storage.Etcd).AllowCreateOnUpdate()
test.TestUpdate(
nodeWithEventA := tools.EtcdResponseWithError{ // valid
R: &etcd.Response{ validNewEvent(test.TestNamespace()),
Node: &etcd.Node{ // valid updateFunc
Value: runtime.EncodeOrDie(testapi.Codec(), eventA), func(obj runtime.Object) runtime.Object {
ModifiedIndex: 1, object := obj.(*api.Event)
CreatedIndex: 1, object.Reason = "forDifferentTesting"
TTL: int64(testTTL), return object
}, },
}, // invalid updateFunc
E: nil, func(obj runtime.Object) runtime.Object {
} object := obj.(*api.Event)
object.InvolvedObject.Namespace = "different-namespace"
nodeWithEventB := tools.EtcdResponseWithError{ return object
R: &etcd.Response{ },
Node: &etcd.Node{ )
Value: runtime.EncodeOrDie(testapi.Codec(), eventB), }
ModifiedIndex: 1,
CreatedIndex: 1, func TestDelete(t *testing.T) {
TTL: int64(testTTL), storage, fakeClient := newStorage(t)
}, test := registrytest.New(t, fakeClient, storage.Etcd)
}, test.TestDelete(validNewEvent(test.TestNamespace()))
E: nil,
}
nodeWithEventC := tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Value: runtime.EncodeOrDie(testapi.Codec(), eventC),
ModifiedIndex: 1,
CreatedIndex: 1,
TTL: int64(testTTL),
},
},
E: nil,
}
emptyNode := tools.EtcdResponseWithError{
R: &etcd.Response{},
E: tools.EtcdErrorNotFound,
}
ctx := api.NewDefaultContext()
key := "foo"
path, err := etcdgeneric.NamespaceKeyFunc(ctx, "/events", key)
path = etcdtest.AddPrefix(path)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
table := map[string]struct {
existing tools.EtcdResponseWithError
expect tools.EtcdResponseWithError
toUpdate runtime.Object
errOK func(error) bool
}{
"doesNotExist": {
existing: emptyNode,
expect: nodeWithEventA,
toUpdate: eventA,
errOK: func(err error) bool { return err == nil },
},
"doesNotExist2": {
existing: emptyNode,
expect: nodeWithEventB,
toUpdate: eventB,
errOK: func(err error) bool { return err == nil },
},
"replaceExisting": {
existing: nodeWithEventA,
expect: nodeWithEventC,
toUpdate: eventC,
errOK: func(err error) bool { return err == nil },
},
}
for name, item := range table {
storage, fakeClient := newStorage(t)
fakeClient.Data[path] = item.existing
_, _, err := storage.Update(ctx, item.toUpdate)
if !item.errOK(err) {
t.Errorf("%v: unexpected error: %v", name, err)
}
// nullify fields set by infrastructure
received := fakeClient.Data[path]
var event api.Event
if err := testapi.Codec().DecodeInto([]byte(received.R.Node.Value), &event); err != nil {
t.Errorf("unexpected error: %v", err)
}
event.ObjectMeta.CreationTimestamp = util.Time{}
event.ObjectMeta.UID = ""
received.R.Node.Value = runtime.EncodeOrDie(testapi.Codec(), &event)
if e, a := item.expect, received; !reflect.DeepEqual(e, a) {
t.Errorf("%v:\n%s", name, util.ObjectGoPrintDiff(e, a))
}
}
} }

View File

@ -21,29 +21,17 @@ 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/expapi"
"k8s.io/kubernetes/pkg/registry/registrytest"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
"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"
"k8s.io/kubernetes/pkg/expapi"
"github.com/coreos/go-etcd/etcd"
) )
func newEtcdStorage(t *testing.T) (*tools.FakeEtcdClient, storage.Interface) { func newStorage(t *testing.T) (*ScaleREST, *tools.FakeEtcdClient) {
fakeEtcdClient := tools.NewFakeEtcdClient(t) etcdStorage, fakeClient := registrytest.NewEtcdStorage(t)
fakeEtcdClient.TestIndex = true return NewStorage(etcdStorage).Scale, fakeClient
etcdStorage := etcdstorage.NewEtcdStorage(fakeEtcdClient, testapi.Codec(), etcdtest.PathPrefix())
return fakeEtcdClient, etcdStorage
}
func newStorage(t *testing.T) (*RcREST, *ScaleREST, *tools.FakeEtcdClient, storage.Interface) {
fakeEtcdClient, etcdStorage := newEtcdStorage(t)
storage := NewStorage(etcdStorage)
return storage.ReplicationController, storage.Scale, fakeEtcdClient, etcdStorage
} }
var validPodTemplate = api.PodTemplate{ var validPodTemplate = api.PodTemplate{
@ -90,43 +78,32 @@ var validScale = expapi.Scale{
} }
func TestGet(t *testing.T) { func TestGet(t *testing.T) {
expect := &validScale storage, fakeClient := newStorage(t)
fakeEtcdClient, etcdStorage := newEtcdStorage(t)
ctx := api.WithNamespace(api.NewContext(), "test")
key := etcdtest.AddPrefix("/controllers/test/foo") key := etcdtest.AddPrefix("/controllers/test/foo")
fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{ if _, err := fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), &validController), 0); err != nil {
R: &etcd.Response{ t.Fatalf("unexpected error: %v", err)
Node: &etcd.Node{
Value: runtime.EncodeOrDie(testapi.Codec(), &validController),
ModifiedIndex: 1,
},
},
} }
storage := NewStorage(etcdStorage).Scale
obj, err := storage.Get(api.WithNamespace(api.NewContext(), "test"), "foo") expect := &validScale
obj, err := storage.Get(ctx, "foo")
scale := obj.(*expapi.Scale) scale := obj.(*expapi.Scale)
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
if e, a := expect, scale; !api.Semantic.DeepEqual(e, a) { if e, a := expect, scale; !api.Semantic.DeepEqual(e, a) {
t.Errorf("Unexpected scale: %s", util.ObjectDiff(e, a)) t.Errorf("unexpected scale: %s", util.ObjectDiff(e, a))
} }
} }
func TestUpdate(t *testing.T) { func TestUpdate(t *testing.T) {
fakeEtcdClient, etcdStorage := newEtcdStorage(t) storage, fakeClient := newStorage(t)
storage := NewStorage(etcdStorage).Scale
ctx := api.WithNamespace(api.NewContext(), "test")
key := etcdtest.AddPrefix("/controllers/test/foo") key := etcdtest.AddPrefix("/controllers/test/foo")
fakeEtcdClient.Data[key] = tools.EtcdResponseWithError{ if _, err := fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), &validController), 0); err != nil {
R: &etcd.Response{ t.Fatalf("unexpected error: %v", err)
Node: &etcd.Node{
Value: runtime.EncodeOrDie(testapi.Codec(), &validController),
ModifiedIndex: 1,
},
},
} }
replicas := 12 replicas := 12
update := expapi.Scale{ update := expapi.Scale{
@ -136,13 +113,12 @@ func TestUpdate(t *testing.T) {
}, },
} }
_, _, err := storage.Update(api.WithNamespace(api.NewContext(), "test"), &update) if _, _, err := storage.Update(ctx, &update); err != nil {
if err != nil { t.Fatalf("unexpected error: %v", err)
t.Fatalf("Unexpected error: %v", err)
} }
response, err := fakeEtcdClient.Get(key, false, false) response, err := fakeClient.Get(key, false, false)
if err != nil { if err != nil {
t.Fatalf("Unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
var controller api.ReplicationController var controller api.ReplicationController

View File

@ -28,8 +28,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, *tools.FakeEtcdClient) { func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) {
@ -62,11 +60,11 @@ func TestCreate(t *testing.T) {
} }
func TestCreateSetsFields(t *testing.T) { func TestCreateSetsFields(t *testing.T) {
storage, fakeClient := newStorage(t) storage, _ := newStorage(t)
namespace := validNewNamespace() namespace := validNewNamespace()
ctx := api.NewContext() ctx := api.NewContext()
_, err := storage.Create(ctx, namespace) _, err := storage.Create(ctx, namespace)
if err != fakeClient.Err { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
@ -129,58 +127,46 @@ func TestWatch(t *testing.T) {
func TestDeleteNamespaceWithIncompleteFinalizers(t *testing.T) { func TestDeleteNamespaceWithIncompleteFinalizers(t *testing.T) {
storage, fakeClient := newStorage(t) storage, fakeClient := newStorage(t)
fakeClient.ChangeIndex = 1 key := etcdtest.AddPrefix("namespaces/foo")
key := etcdtest.AddPrefix("/namespaces/foo") ctx := api.NewContext()
now := util.Now() now := util.Now()
fakeClient.Data[key] = tools.EtcdResponseWithError{ namespace := &api.Namespace{
R: &etcd.Response{ ObjectMeta: api.ObjectMeta{
Node: &etcd.Node{ Name: "foo",
Value: runtime.EncodeOrDie(testapi.Codec(), &api.Namespace{ DeletionTimestamp: &now,
ObjectMeta: api.ObjectMeta{
Name: "foo",
DeletionTimestamp: &now,
},
Spec: api.NamespaceSpec{
Finalizers: []api.FinalizerName{api.FinalizerKubernetes},
},
Status: api.NamespaceStatus{Phase: api.NamespaceActive},
}),
ModifiedIndex: 1,
CreatedIndex: 1,
},
}, },
Spec: api.NamespaceSpec{
Finalizers: []api.FinalizerName{api.FinalizerKubernetes},
},
Status: api.NamespaceStatus{Phase: api.NamespaceActive},
} }
_, err := storage.Delete(api.NewContext(), "foo", nil) if _, err := fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), namespace), 0); err != nil {
if err == nil { t.Fatalf("unexpected error: %v", err)
t.Fatalf("expected error: %v", err) }
if _, err := storage.Delete(ctx, "foo", nil); err == nil {
t.Errorf("unexpected error: %v", err)
} }
} }
func TestDeleteNamespaceWithCompleteFinalizers(t *testing.T) { func TestDeleteNamespaceWithCompleteFinalizers(t *testing.T) {
storage, fakeClient := newStorage(t) storage, fakeClient := newStorage(t)
fakeClient.ChangeIndex = 1 key := etcdtest.AddPrefix("namespaces/foo")
key := etcdtest.AddPrefix("/namespaces/foo") ctx := api.NewContext()
now := util.Now() now := util.Now()
fakeClient.Data[key] = tools.EtcdResponseWithError{ namespace := &api.Namespace{
R: &etcd.Response{ ObjectMeta: api.ObjectMeta{
Node: &etcd.Node{ Name: "foo",
Value: runtime.EncodeOrDie(testapi.Codec(), &api.Namespace{ DeletionTimestamp: &now,
ObjectMeta: api.ObjectMeta{
Name: "foo",
DeletionTimestamp: &now,
},
Spec: api.NamespaceSpec{
Finalizers: []api.FinalizerName{},
},
Status: api.NamespaceStatus{Phase: api.NamespaceActive},
}),
ModifiedIndex: 1,
CreatedIndex: 1,
},
}, },
Spec: api.NamespaceSpec{
Finalizers: []api.FinalizerName{},
},
Status: api.NamespaceStatus{Phase: api.NamespaceActive},
} }
_, err := storage.Delete(api.NewContext(), "foo", nil) if _, err := fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), namespace), 0); err != nil {
if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
if _, err := storage.Delete(ctx, "foo", nil); err != nil {
t.Errorf("unexpected error: %v", err)
}
} }

View File

@ -34,8 +34,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, *BindingREST, *StatusREST, *tools.FakeEtcdClient) { func newStorage(t *testing.T) (*REST, *BindingREST, *StatusREST, *tools.FakeEtcdClient) {
@ -256,14 +254,10 @@ func TestResourceLocation(t *testing.T) {
ctx := api.NewDefaultContext() ctx := api.NewDefaultContext()
for _, tc := range testCases { for _, tc := range testCases {
storage, _, _, fakeClient := newStorage(t) storage, _, _, fakeClient := newStorage(t)
key, _ := storage.Etcd.KeyFunc(ctx, "foo") key, _ := storage.KeyFunc(ctx, tc.pod.Name)
key = etcdtest.AddPrefix(key) key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{ if _, err := fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), &tc.pod), 0); err != nil {
R: &etcd.Response{ t.Fatalf("unexpected error: %v", err)
Node: &etcd.Node{
Value: runtime.EncodeOrDie(testapi.Codec(), &tc.pod),
},
},
} }
redirector := rest.Redirector(storage) redirector := rest.Redirector(storage)
@ -284,33 +278,6 @@ func TestResourceLocation(t *testing.T) {
} }
} }
func TestDeletePod(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.Pod{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Namespace: api.NamespaceDefault,
},
Spec: api.PodSpec{NodeName: "machine"},
}),
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) {
storage, _, _, fakeClient := newStorage(t) storage, _, _, fakeClient := newStorage(t)
test := registrytest.New(t, fakeClient, storage.Etcd) test := registrytest.New(t, fakeClient, storage.Etcd)
@ -351,12 +318,7 @@ func TestEtcdCreate(t *testing.T) {
fakeClient.TestIndex = true fakeClient.TestIndex = true
key, _ := storage.KeyFunc(ctx, "foo") key, _ := storage.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key) key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{ fakeClient.ExpectNotFoundGet(key)
R: &etcd.Response{
Node: nil,
},
E: tools.EtcdErrorNotFound,
}
_, err := storage.Create(ctx, validNewPod()) _, err := storage.Create(ctx, validNewPod())
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
@ -395,12 +357,7 @@ func TestEtcdCreateBindingNoPod(t *testing.T) {
key, _ := storage.KeyFunc(ctx, "foo") key, _ := storage.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key) key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{ fakeClient.ExpectNotFoundGet(key)
R: &etcd.Response{
Node: nil,
},
E: tools.EtcdErrorNotFound,
}
// Assume that a pod has undergone the following: // Assume that a pod has undergone the following:
// - Create (apiserver) // - Create (apiserver)
// - Schedule (scheduler) // - Schedule (scheduler)
@ -443,12 +400,7 @@ func TestEtcdCreateWithContainersNotFound(t *testing.T) {
fakeClient.TestIndex = true fakeClient.TestIndex = true
key, _ := storage.KeyFunc(ctx, "foo") key, _ := storage.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key) key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{ fakeClient.ExpectNotFoundGet(key)
R: &etcd.Response{
Node: nil,
},
E: tools.EtcdErrorNotFound,
}
_, err := storage.Create(ctx, validNewPod()) _, err := storage.Create(ctx, validNewPod())
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
@ -490,12 +442,7 @@ func TestEtcdCreateWithConflict(t *testing.T) {
ctx := api.NewDefaultContext() ctx := api.NewDefaultContext()
fakeClient.TestIndex = true fakeClient.TestIndex = true
key, _ := storage.KeyFunc(ctx, "foo") key, _ := storage.KeyFunc(ctx, "foo")
fakeClient.Data[key] = tools.EtcdResponseWithError{ fakeClient.ExpectNotFoundGet(key)
R: &etcd.Response{
Node: nil,
},
E: tools.EtcdErrorNotFound,
}
_, err := storage.Create(ctx, validNewPod()) _, err := storage.Create(ctx, validNewPod())
if err != nil { if err != nil {
@ -528,12 +475,7 @@ func TestEtcdCreateWithExistingContainers(t *testing.T) {
fakeClient.TestIndex = true fakeClient.TestIndex = true
key, _ := storage.KeyFunc(ctx, "foo") key, _ := storage.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key) key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{ fakeClient.ExpectNotFoundGet(key)
R: &etcd.Response{
Node: nil,
},
E: tools.EtcdErrorNotFound,
}
_, err := storage.Create(ctx, validNewPod()) _, err := storage.Create(ctx, validNewPod())
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
@ -564,9 +506,7 @@ func TestEtcdCreateWithExistingContainers(t *testing.T) {
} }
func TestEtcdCreateBinding(t *testing.T) { func TestEtcdCreateBinding(t *testing.T) {
storage, bindingStorage, _, fakeClient := newStorage(t)
ctx := api.NewDefaultContext() ctx := api.NewDefaultContext()
fakeClient.TestIndex = true
testCases := map[string]struct { testCases := map[string]struct {
binding api.Binding binding api.Binding
@ -609,14 +549,11 @@ func TestEtcdCreateBinding(t *testing.T) {
}, },
} }
for k, test := range testCases { for k, test := range testCases {
storage, bindingStorage, _, fakeClient := newStorage(t)
key, _ := storage.KeyFunc(ctx, "foo") key, _ := storage.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key) key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{ fakeClient.ExpectNotFoundGet(key)
R: &etcd.Response{
Node: nil,
},
E: tools.EtcdErrorNotFound,
}
if _, err := storage.Create(ctx, validNewPod()); err != nil { if _, err := storage.Create(ctx, validNewPod()); err != nil {
t.Fatalf("%s: unexpected error: %v", k, err) t.Fatalf("%s: unexpected error: %v", k, err)
} }

View File

@ -20,32 +20,26 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/coreos/go-etcd/etcd"
"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/registry/registrytest"
"k8s.io/kubernetes/pkg/registry/service/allocator" "k8s.io/kubernetes/pkg/registry/service/allocator"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
"k8s.io/kubernetes/pkg/tools" "k8s.io/kubernetes/pkg/tools"
"k8s.io/kubernetes/pkg/tools/etcdtest" "k8s.io/kubernetes/pkg/tools/etcdtest"
) )
func newEtcdStorage(t *testing.T) (*tools.FakeEtcdClient, storage.Interface) { func newStorage(t *testing.T) (*Etcd, *tools.FakeEtcdClient, allocator.Interface) {
fakeEtcdClient := tools.NewFakeEtcdClient(t) etcdStorage, fakeClient := registrytest.NewEtcdStorage(t)
fakeEtcdClient.TestIndex = true mem := allocator.NewAllocationMap(100, "rangeSpecValue")
etcdStorage := etcdstorage.NewEtcdStorage(fakeEtcdClient, testapi.Codec(), etcdtest.PathPrefix()) etcd := NewEtcd(mem, "/ranges/serviceips", "serviceipallocation", etcdStorage)
return fakeEtcdClient, etcdStorage return etcd, fakeClient, mem
} }
func newStorage(t *testing.T) (*Etcd, allocator.Interface, *tools.FakeEtcdClient) { func validNewRangeAllocation() *api.RangeAllocation {
fakeEtcdClient, s := newEtcdStorage(t) return &api.RangeAllocation{
Range: "rangeSpecValue",
mem := allocator.NewAllocationMap(100, "rangeSpecValue") }
etcd := NewEtcd(mem, "/ranges/serviceips", "serviceipallocation", s)
return etcd, mem, fakeEtcdClient
} }
func key() string { func key() string {
@ -54,31 +48,18 @@ func key() string {
} }
func TestEmpty(t *testing.T) { func TestEmpty(t *testing.T) {
storage, _, ecli := newStorage(t) storage, fakeClient, _ := newStorage(t)
ecli.ExpectNotFoundGet(key()) fakeClient.ExpectNotFoundGet(key())
if _, err := storage.Allocate(1); !strings.Contains(err.Error(), "cannot allocate resources of type serviceipallocation at this time") { if _, err := storage.Allocate(1); !strings.Contains(err.Error(), "cannot allocate resources of type serviceipallocation at this time") {
t.Fatal(err) t.Fatal(err)
} }
} }
func initialObject(ecli *tools.FakeEtcdClient) {
ecli.Data[key()] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
CreatedIndex: 1,
ModifiedIndex: 2,
Value: runtime.EncodeOrDie(testapi.Codec(), &api.RangeAllocation{
Range: "rangeSpecValue",
}),
},
},
E: nil,
}
}
func TestStore(t *testing.T) { func TestStore(t *testing.T) {
storage, backing, ecli := newStorage(t) storage, fakeClient, backing := newStorage(t)
initialObject(ecli) if _, err := fakeClient.Set(key(), runtime.EncodeOrDie(testapi.Codec(), validNewRangeAllocation()), 0); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if _, err := storage.Allocate(2); err != nil { if _, err := storage.Allocate(2); err != nil {
t.Fatal(err) t.Fatal(err)
@ -94,7 +75,7 @@ func TestStore(t *testing.T) {
t.Fatal("Expected allocation to fail") t.Fatal("Expected allocation to fail")
} }
obj := ecli.Data[key()] obj := fakeClient.Data[key()]
if obj.R == nil || obj.R.Node == nil { if obj.R == nil || obj.R.Node == nil {
t.Fatalf("%s is empty: %#v", key(), obj) t.Fatalf("%s is empty: %#v", key(), obj)
} }
@ -106,7 +87,7 @@ func TestStore(t *testing.T) {
if err := storage.storage.Get(key(), allocation, false); err != nil { if err := storage.storage.Get(key(), allocation, false); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if allocation.ResourceVersion != "1" { if allocation.ResourceVersion != "2" {
t.Fatalf("%#v", allocation) t.Fatalf("%#v", allocation)
} }
if allocation.Range != "rangeSpecValue" { if allocation.Range != "rangeSpecValue" {

View File

@ -21,29 +21,19 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/coreos/go-etcd/etcd"
"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/registry/registrytest"
"k8s.io/kubernetes/pkg/registry/service/allocator" "k8s.io/kubernetes/pkg/registry/service/allocator"
allocator_etcd "k8s.io/kubernetes/pkg/registry/service/allocator/etcd" allocator_etcd "k8s.io/kubernetes/pkg/registry/service/allocator/etcd"
"k8s.io/kubernetes/pkg/registry/service/ipallocator" "k8s.io/kubernetes/pkg/registry/service/ipallocator"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
"k8s.io/kubernetes/pkg/tools" "k8s.io/kubernetes/pkg/tools"
"k8s.io/kubernetes/pkg/tools/etcdtest" "k8s.io/kubernetes/pkg/tools/etcdtest"
) )
func newEtcdStorage(t *testing.T) (*tools.FakeEtcdClient, storage.Interface) { func newStorage(t *testing.T) (*tools.FakeEtcdClient, ipallocator.Interface, allocator.Interface) {
fakeEtcdClient := tools.NewFakeEtcdClient(t) etcdStorage, fakeClient := registrytest.NewEtcdStorage(t)
fakeEtcdClient.TestIndex = true
etcdStorage := etcdstorage.NewEtcdStorage(fakeEtcdClient, testapi.Codec(), etcdtest.PathPrefix())
return fakeEtcdClient, etcdStorage
}
func newStorage(t *testing.T) (ipallocator.Interface, allocator.Interface, *tools.FakeEtcdClient) {
fakeEtcdClient, etcdStorage := newEtcdStorage(t)
_, cidr, err := net.ParseCIDR("192.168.1.0/24") _, cidr, err := net.ParseCIDR("192.168.1.0/24")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -57,7 +47,14 @@ func newStorage(t *testing.T) (ipallocator.Interface, allocator.Interface, *tool
return etcd return etcd
}) })
return storage, backing, fakeEtcdClient return fakeClient, storage, backing
}
func validNewRangeAllocation() *api.RangeAllocation {
_, cidr, _ := net.ParseCIDR("192.168.1.0/24")
return &api.RangeAllocation{
Range: cidr.String(),
}
} }
func key() string { func key() string {
@ -66,44 +63,30 @@ func key() string {
} }
func TestEmpty(t *testing.T) { func TestEmpty(t *testing.T) {
storage, _, ecli := newStorage(t) fakeClient, storage, _ := newStorage(t)
ecli.ExpectNotFoundGet(key()) fakeClient.ExpectNotFoundGet(key())
if err := storage.Allocate(net.ParseIP("192.168.1.2")); !strings.Contains(err.Error(), "cannot allocate resources of type serviceipallocation at this time") { if err := storage.Allocate(net.ParseIP("192.168.1.2")); !strings.Contains(err.Error(), "cannot allocate resources of type serviceipallocation at this time") {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestErrors(t *testing.T) { func TestErrors(t *testing.T) {
storage, _, _ := newStorage(t) _, storage, _ := newStorage(t)
if err := storage.Allocate(net.ParseIP("192.168.0.0")); err != ipallocator.ErrNotInRange { if err := storage.Allocate(net.ParseIP("192.168.0.0")); err != ipallocator.ErrNotInRange {
t.Fatal(err) t.Fatal(err)
} }
} }
func initialObject(ecli *tools.FakeEtcdClient) {
_, cidr, _ := net.ParseCIDR("192.168.1.0/24")
ecli.Data[key()] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
CreatedIndex: 1,
ModifiedIndex: 2,
Value: runtime.EncodeOrDie(testapi.Codec(), &api.RangeAllocation{
Range: cidr.String(),
}),
},
},
E: nil,
}
}
func TestStore(t *testing.T) { func TestStore(t *testing.T) {
storage, r, ecli := newStorage(t) fakeClient, storage, backing := newStorage(t)
initialObject(ecli) if _, err := fakeClient.Set(key(), runtime.EncodeOrDie(testapi.Codec(), validNewRangeAllocation()), 0); err != nil {
t.Fatalf("unexpected error: %v", err)
}
if err := storage.Allocate(net.ParseIP("192.168.1.2")); err != nil { if err := storage.Allocate(net.ParseIP("192.168.1.2")); err != nil {
t.Fatal(err) t.Fatal(err)
} }
ok, err := r.Allocate(1) ok, err := backing.Allocate(1)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -114,7 +97,7 @@ func TestStore(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
obj := ecli.Data[key()] obj := fakeClient.Data[key()]
if obj.R == nil || obj.R.Node == nil { if obj.R == nil || obj.R.Node == nil {
t.Fatalf("%s is empty: %#v", key(), obj) t.Fatalf("%s is empty: %#v", key(), obj)
} }

View File

@ -1,335 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package service
import (
"strconv"
"testing"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
etcdgeneric "k8s.io/kubernetes/pkg/registry/generic/etcd"
etcdservice "k8s.io/kubernetes/pkg/registry/service/etcd"
"k8s.io/kubernetes/pkg/runtime"
etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
"k8s.io/kubernetes/pkg/tools"
"k8s.io/kubernetes/pkg/tools/etcdtest"
"k8s.io/kubernetes/pkg/util"
"github.com/coreos/go-etcd/etcd"
)
func NewTestEtcdRegistry(client tools.EtcdClient) (Registry, *etcdservice.REST) {
storage := etcdstorage.NewEtcdStorage(client, testapi.Codec(), etcdtest.PathPrefix())
rest := etcdservice.NewREST(storage)
registry := NewRegistry(rest)
return registry, rest
}
func makeTestService(name string) *api.Service {
return &api.Service{
ObjectMeta: api.ObjectMeta{Name: name, Namespace: "default"},
Spec: api.ServiceSpec{
Ports: []api.ServicePort{
{Name: "port", Protocol: api.ProtocolTCP, Port: 12345, TargetPort: util.NewIntOrStringFromInt(12345)},
},
Type: api.ServiceTypeClusterIP,
SessionAffinity: api.ServiceAffinityNone,
},
}
}
func TestEtcdListServicesNotFound(t *testing.T) {
fakeClient := tools.NewFakeEtcdClient(t)
registry, rest := NewTestEtcdRegistry(fakeClient)
ctx := api.NewDefaultContext()
key := rest.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{},
E: tools.EtcdErrorNotFound,
}
services, err := registry.ListServices(ctx, labels.Everything(), fields.Everything())
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if len(services.Items) != 0 {
t.Errorf("Unexpected services list: %#v", services)
}
}
func TestEtcdListServices(t *testing.T) {
ctx := api.NewDefaultContext()
fakeClient := tools.NewFakeEtcdClient(t)
registry, rest := NewTestEtcdRegistry(fakeClient)
key := rest.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Nodes: []*etcd.Node{
{
Value: runtime.EncodeOrDie(testapi.Codec(), makeTestService("foo")),
},
{
Value: runtime.EncodeOrDie(testapi.Codec(), makeTestService("bar")),
},
},
},
},
E: nil,
}
services, err := registry.ListServices(ctx, labels.Everything(), fields.Everything())
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if len(services.Items) != 2 || services.Items[0].Name != "foo" || services.Items[1].Name != "bar" {
t.Errorf("Unexpected service list: %#v", services)
}
}
func TestEtcdCreateService(t *testing.T) {
ctx := api.NewDefaultContext()
fakeClient := tools.NewFakeEtcdClient(t)
registry, rest := NewTestEtcdRegistry(fakeClient)
_, err := registry.CreateService(ctx, makeTestService("foo"))
if err != nil {
t.Errorf("unexpected error: %v", err)
}
key, _ := rest.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key)
resp, err := fakeClient.Get(key, false, false)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
var service api.Service
err = testapi.Codec().DecodeInto([]byte(resp.Node.Value), &service)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if service.Name != "foo" {
t.Errorf("Unexpected service: %#v %s", service, resp.Node.Value)
}
}
func TestEtcdCreateServiceAlreadyExisting(t *testing.T) {
ctx := api.NewDefaultContext()
fakeClient := tools.NewFakeEtcdClient(t)
registry, rest := NewTestEtcdRegistry(fakeClient)
key, _ := rest.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), makeTestService("foo")), 0)
_, err := registry.CreateService(ctx, makeTestService("foo"))
if !errors.IsAlreadyExists(err) {
t.Errorf("expected already exists err, got %#v", err)
}
}
// TestEtcdGetServiceDifferentNamespace ensures same-name services in different namespaces do not clash
func TestEtcdGetServiceDifferentNamespace(t *testing.T) {
fakeClient := tools.NewFakeEtcdClient(t)
registry, rest := NewTestEtcdRegistry(fakeClient)
ctx1 := api.NewDefaultContext()
ctx2 := api.WithNamespace(api.NewContext(), "other")
key1, _ := rest.KeyFunc(ctx1, "foo")
key2, _ := rest.KeyFunc(ctx2, "foo")
key1 = etcdtest.AddPrefix(key1)
key2 = etcdtest.AddPrefix(key2)
fakeClient.Set(key1, runtime.EncodeOrDie(testapi.Codec(), &api.Service{ObjectMeta: api.ObjectMeta{Namespace: "default", Name: "foo"}}), 0)
fakeClient.Set(key2, runtime.EncodeOrDie(testapi.Codec(), &api.Service{ObjectMeta: api.ObjectMeta{Namespace: "other", Name: "foo"}}), 0)
service1, err := registry.GetService(ctx1, "foo")
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if service1.Name != "foo" {
t.Errorf("Unexpected service: %#v", service1)
}
if service1.Namespace != "default" {
t.Errorf("Unexpected service: %#v", service1)
}
service2, err := registry.GetService(ctx2, "foo")
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if service2.Name != "foo" {
t.Errorf("Unexpected service: %#v", service2)
}
if service2.Namespace != "other" {
t.Errorf("Unexpected service: %#v", service2)
}
}
func TestEtcdGetService(t *testing.T) {
ctx := api.NewDefaultContext()
fakeClient := tools.NewFakeEtcdClient(t)
registry, rest := NewTestEtcdRegistry(fakeClient)
key, _ := rest.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), makeTestService("foo")), 0)
service, err := registry.GetService(ctx, "foo")
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if service.Name != "foo" {
t.Errorf("Unexpected service: %#v", service)
}
}
func TestEtcdGetServiceNotFound(t *testing.T) {
ctx := api.NewDefaultContext()
fakeClient := tools.NewFakeEtcdClient(t)
registry, rest := NewTestEtcdRegistry(fakeClient)
key, _ := rest.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: nil,
},
E: tools.EtcdErrorNotFound,
}
_, err := registry.GetService(ctx, "foo")
if !errors.IsNotFound(err) {
t.Errorf("Unexpected error returned: %#v", err)
}
}
func TestEtcdDeleteService(t *testing.T) {
ctx := api.NewDefaultContext()
fakeClient := tools.NewFakeEtcdClient(t)
registry, _ := NewTestEtcdRegistry(fakeClient)
key, _ := etcdgeneric.NamespaceKeyFunc(ctx, "/services/specs", "foo")
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), makeTestService("foo")), 0)
path, _ := etcdgeneric.NamespaceKeyFunc(ctx, "/services/endpoints", "foo")
endpointsKey := etcdtest.AddPrefix(path)
fakeClient.Set(endpointsKey, runtime.EncodeOrDie(testapi.Codec(), &api.Endpoints{ObjectMeta: api.ObjectMeta{Name: "foo"}}), 0)
err := registry.DeleteService(ctx, "foo")
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if len(fakeClient.DeletedKeys) != 1 {
t.Errorf("Expected 2 delete, found %#v", fakeClient.DeletedKeys)
}
if fakeClient.DeletedKeys[0] != key {
t.Errorf("Unexpected key: %s, expected %s", fakeClient.DeletedKeys[0], key)
}
}
func TestEtcdUpdateService(t *testing.T) {
ctx := api.NewDefaultContext()
fakeClient := tools.NewFakeEtcdClient(t)
fakeClient.TestIndex = true
registry, rest := NewTestEtcdRegistry(fakeClient)
key, _ := rest.KeyFunc(ctx, "uniquefoo")
key = etcdtest.AddPrefix(key)
resp, _ := fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), makeTestService("uniquefoo")), 0)
testService := api.Service{
ObjectMeta: api.ObjectMeta{
Name: "uniquefoo",
ResourceVersion: strconv.FormatUint(resp.Node.ModifiedIndex, 10),
Labels: map[string]string{
"baz": "bar",
},
},
Spec: api.ServiceSpec{
Ports: []api.ServicePort{
{Name: "port", Protocol: api.ProtocolTCP, Port: 12345, TargetPort: util.NewIntOrStringFromInt(12345)},
},
Selector: map[string]string{
"baz": "bar",
},
SessionAffinity: "None",
Type: api.ServiceTypeClusterIP,
},
}
_, err := registry.UpdateService(ctx, &testService)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
svc, err := registry.GetService(ctx, "uniquefoo")
if err != nil {
t.Errorf("unexpected error: %v", err)
}
// Clear modified indices before the equality test.
svc.ResourceVersion = ""
testService.ResourceVersion = ""
if !api.Semantic.DeepEqual(*svc, testService) {
t.Errorf("Unexpected service: got\n %#v\n, wanted\n %#v", svc, testService)
}
}
func TestEtcdWatchServices(t *testing.T) {
ctx := api.NewDefaultContext()
fakeClient := tools.NewFakeEtcdClient(t)
registry, _ := NewTestEtcdRegistry(fakeClient)
watching, err := registry.WatchServices(ctx,
labels.Everything(),
fields.SelectorFromSet(fields.Set{"name": "foo"}),
"1",
)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
fakeClient.WaitForWatchCompletion()
select {
case _, ok := <-watching.ResultChan():
if !ok {
t.Errorf("watching channel should be open")
}
default:
}
fakeClient.WatchInjectError <- nil
if _, ok := <-watching.ResultChan(); ok {
t.Errorf("watching channel should be closed")
}
watching.Stop()
}
// TODO We need a test for the compare and swap behavior. This basically requires two things:
// 1) Add a per-operation synchronization channel to the fake etcd client, such that any operation waits on that
// channel, this will enable us to orchestrate the flow of etcd requests in the test.
// 2) We need to make the map from key to (response, error) actually be a [](response, error) and pop
// our way through the responses. That will enable us to hand back multiple different responses for
// the same key.
// Once that infrastructure is in place, the test looks something like:
// Routine #1 Routine #2
// Read
// Wait for sync on update Read
// Update
// Update
// In the buggy case, this will result in lost data. In the correct case, the second update should fail
// and be retried.

View File

@ -20,36 +20,19 @@ 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"
"k8s.io/kubernetes/pkg/expapi/v1" // Ensure that expapi/v1 package is initialized.
_ "k8s.io/kubernetes/pkg/expapi/v1"
"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/storage"
etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
"k8s.io/kubernetes/pkg/tools" "k8s.io/kubernetes/pkg/tools"
"k8s.io/kubernetes/pkg/tools/etcdtest"
"github.com/coreos/go-etcd/etcd"
) )
var scheme *runtime.Scheme func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient) {
var codec runtime.Codec etcdStorage, fakeClient := registrytest.NewEtcdStorage(t)
return NewREST(etcdStorage, "foo", "bar"), fakeClient
func init() {
// Ensure that expapi/v1 packege is used, so that it will get initialized and register HorizontalPodAutoscaler object.
_ = v1.ThirdPartyResourceData{}
}
func newStorage(t *testing.T) (*REST, *tools.FakeEtcdClient, storage.Interface) {
fakeEtcdClient := tools.NewFakeEtcdClient(t)
fakeEtcdClient.TestIndex = true
etcdStorage := etcdstorage.NewEtcdStorage(fakeEtcdClient, testapi.Codec(), etcdtest.PathPrefix())
storage := NewREST(etcdStorage, "foo", "bar")
return storage, fakeEtcdClient, etcdStorage
} }
func validNewThirdPartyResourceData(name string) *expapi.ThirdPartyResourceData { func validNewThirdPartyResourceData(name string) *expapi.ThirdPartyResourceData {
@ -63,8 +46,8 @@ func validNewThirdPartyResourceData(name string) *expapi.ThirdPartyResourceData
} }
func TestCreate(t *testing.T) { func TestCreate(t *testing.T) {
storage, fakeEtcdClient, _ := newStorage(t) storage, fakeClient := newStorage(t)
test := registrytest.New(t, fakeEtcdClient, storage.Etcd) test := registrytest.New(t, fakeClient, storage.Etcd)
rsrc := validNewThirdPartyResourceData("foo") rsrc := validNewThirdPartyResourceData("foo")
rsrc.ObjectMeta = api.ObjectMeta{} rsrc.ObjectMeta = api.ObjectMeta{}
test.TestCreate( test.TestCreate(
@ -76,7 +59,7 @@ func TestCreate(t *testing.T) {
} }
func TestUpdate(t *testing.T) { func TestUpdate(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)
test.TestUpdate( test.TestUpdate(
// valid // valid
@ -90,75 +73,41 @@ func TestUpdate(t *testing.T) {
) )
} }
func TestGet(t *testing.T) { func TestDelete(t *testing.T) {
storage, fakeEtcdClient, _ := newStorage(t) storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeEtcdClient.SetError) test := registrytest.New(t, fakeClient, storage.Etcd)
rsrc := validNewThirdPartyResourceData("foo") test.TestDelete(validNewThirdPartyResourceData("foo"))
test.TestGet(rsrc)
} }
func TestEmptyList(t *testing.T) { func TestGet(t *testing.T) {
ctx := api.NewDefaultContext() storage, fakeClient := newStorage(t)
registry, fakeClient, _ := newStorage(t) test := registrytest.New(t, fakeClient, storage.Etcd)
fakeClient.ChangeIndex = 1 test.TestGet(validNewThirdPartyResourceData("foo"))
key := registry.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{},
E: fakeClient.NewError(tools.EtcdErrorCodeNotFound),
}
rsrcList, err := registry.List(ctx, labels.Everything(), fields.Everything())
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(rsrcList.(*expapi.ThirdPartyResourceDataList).Items) != 0 {
t.Errorf("Unexpected non-zero autoscaler list: %#v", rsrcList)
}
if rsrcList.(*expapi.ThirdPartyResourceDataList).ResourceVersion != "1" {
t.Errorf("Unexpected resource version: %#v", rsrcList)
}
} }
func TestList(t *testing.T) { func TestList(t *testing.T) {
ctx := api.NewDefaultContext() storage, fakeClient := newStorage(t)
registry, fakeClient, _ := newStorage(t) test := registrytest.New(t, fakeClient, storage.Etcd)
fakeClient.ChangeIndex = 1 test.TestList(validNewThirdPartyResourceData("foo"))
key := registry.KeyRootFunc(ctx) }
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{ func TestWatch(t *testing.T) {
R: &etcd.Response{ storage, fakeClient := newStorage(t)
Node: &etcd.Node{ test := registrytest.New(t, fakeClient, storage.Etcd)
Nodes: []*etcd.Node{ test.TestWatch(
{ validNewThirdPartyResourceData("foo"),
Value: runtime.EncodeOrDie(testapi.Codec(), &expapi.ThirdPartyResourceData{ // matching labels
ObjectMeta: api.ObjectMeta{Name: "foo"}, []labels.Set{},
}), // not matching labels
}, []labels.Set{
{ {"foo": "bar"},
Value: runtime.EncodeOrDie(testapi.Codec(), &expapi.ThirdPartyResourceData{ },
ObjectMeta: api.ObjectMeta{Name: "bar"}, // matching fields
}), []fields.Set{},
}, // not matching fields
}, []fields.Set{
}, {"metadata.name": "bar"},
}, {"name": "foo"},
} },
obj, err := registry.List(ctx, labels.Everything(), fields.Everything()) )
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
rsrcList := obj.(*expapi.ThirdPartyResourceDataList)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(rsrcList.Items) != 2 {
t.Errorf("Unexpected ThirdPartyResourceData list: %#v", rsrcList)
}
if rsrcList.Items[0].Name != "foo" {
t.Errorf("Unexpected ThirdPartyResourceData: %#v", rsrcList.Items[0])
}
if rsrcList.Items[1].Name != "bar" {
t.Errorf("Unexpected ThirdPartyResourceData: %#v", rsrcList.Items[1])
}
} }