Commit f6f2f41a authored by Timothy St. Clair's avatar Timothy St. Clair

Removal of fakeClient from registry/generic/etcd/etcd_test.go in leiu of

NewEtcdTestClientServer
parent 4711a873
...@@ -54,6 +54,8 @@ import ( ...@@ -54,6 +54,8 @@ import (
// logic specific to the API. // logic specific to the API.
// //
// TODO: make the default exposed methods exactly match a generic RESTStorage // TODO: make the default exposed methods exactly match a generic RESTStorage
// TODO: because all aspects of etcd have been removed it should really
// just be called a registry implementation.
type Etcd struct { type Etcd struct {
// Called to make a new object, should return e.g., &api.Pod{} // Called to make a new object, should return e.g., &api.Pod{}
NewFunc func() runtime.Object NewFunc func() runtime.Object
......
...@@ -19,6 +19,7 @@ package etcd ...@@ -19,6 +19,7 @@ package etcd
import ( import (
"fmt" "fmt"
"path" "path"
"reflect"
"testing" "testing"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
...@@ -27,13 +28,11 @@ import ( ...@@ -27,13 +28,11 @@ import (
"k8s.io/kubernetes/pkg/registry/generic" "k8s.io/kubernetes/pkg/registry/generic"
"k8s.io/kubernetes/pkg/runtime" "k8s.io/kubernetes/pkg/runtime"
etcdstorage "k8s.io/kubernetes/pkg/storage/etcd" etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
"k8s.io/kubernetes/pkg/tools" etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
storagetesting "k8s.io/kubernetes/pkg/storage/testing"
"k8s.io/kubernetes/pkg/tools/etcdtest" "k8s.io/kubernetes/pkg/tools/etcdtest"
"k8s.io/kubernetes/pkg/util"
"k8s.io/kubernetes/pkg/util/fielderrors" "k8s.io/kubernetes/pkg/util/fielderrors"
"k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/util/sets"
"github.com/coreos/go-etcd/etcd"
) )
type testRESTStrategy struct { type testRESTStrategy struct {
...@@ -68,13 +67,13 @@ func hasCreated(t *testing.T, pod *api.Pod) func(runtime.Object) bool { ...@@ -68,13 +67,13 @@ func hasCreated(t *testing.T, pod *api.Pod) func(runtime.Object) bool {
} }
} }
func NewTestGenericEtcdRegistry(t *testing.T) (*tools.FakeEtcdClient, *Etcd) { func NewTestGenericEtcdRegistry(t *testing.T) (*etcdtesting.EtcdTestServer, *Etcd) {
f := tools.NewFakeEtcdClient(t)
f.TestIndex = true
s := etcdstorage.NewEtcdStorage(f, testapi.Default.Codec(), etcdtest.PathPrefix())
strategy := &testRESTStrategy{api.Scheme, api.SimpleNameGenerator, true, false, true}
podPrefix := "/pods" podPrefix := "/pods"
return f, &Etcd{ server := etcdtesting.NewEtcdTestClientServer(t)
s := etcdstorage.NewEtcdStorage(server.Client, testapi.Default.Codec(), etcdtest.PathPrefix())
strategy := &testRESTStrategy{api.Scheme, api.SimpleNameGenerator, true, false, true}
return server, &Etcd{
NewFunc: func() runtime.Object { return &api.Pod{} }, NewFunc: func() runtime.Object { return &api.Pod{} },
NewListFunc: func() runtime.Object { return &api.PodList{} }, NewListFunc: func() runtime.Object { return &api.PodList{} },
EndpointName: "pods", EndpointName: "pods",
...@@ -129,96 +128,48 @@ func (everythingMatcher) MatchesSingle() (string, bool) { ...@@ -129,96 +128,48 @@ func (everythingMatcher) MatchesSingle() (string, bool) {
func TestEtcdList(t *testing.T) { func TestEtcdList(t *testing.T) {
podA := &api.Pod{ podA := &api.Pod{
ObjectMeta: api.ObjectMeta{Namespace: "test", Name: "foo"}, ObjectMeta: api.ObjectMeta{Namespace: "test", Name: "bar"},
Spec: api.PodSpec{NodeName: "machine"}, Spec: api.PodSpec{NodeName: "machine"},
} }
podB := &api.Pod{ podB := &api.Pod{
ObjectMeta: api.ObjectMeta{Namespace: "test", Name: "bar"}, ObjectMeta: api.ObjectMeta{Namespace: "test", Name: "foo"},
Spec: api.PodSpec{NodeName: "machine"}, Spec: api.PodSpec{NodeName: "machine"},
} }
singleElemListResp := &etcd.Response{
Node: &etcd.Node{
Value: runtime.EncodeOrDie(testapi.Default.Codec(), podA),
},
}
normalListResp := &etcd.Response{
Node: &etcd.Node{
Nodes: []*etcd.Node{
{Value: runtime.EncodeOrDie(testapi.Default.Codec(), podA)},
{Value: runtime.EncodeOrDie(testapi.Default.Codec(), podB)},
},
},
}
testContext := api.WithNamespace(api.NewContext(), "test") testContext := api.WithNamespace(api.NewContext(), "test")
noNamespaceContext := api.NewContext() noNamespaceContext := api.NewContext()
table := map[string]struct { table := map[string]struct {
in tools.EtcdResponseWithError in *api.PodList
m generic.Matcher m generic.Matcher
out runtime.Object out runtime.Object
context api.Context context api.Context
succeed bool
}{ }{
"empty": {
in: tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Nodes: []*etcd.Node{},
},
},
E: nil,
},
m: everythingMatcher{},
out: &api.PodList{Items: []api.Pod{}},
succeed: true,
},
"notFound": { "notFound": {
in: tools.EtcdResponseWithError{ in: nil,
R: &etcd.Response{},
E: tools.EtcdErrorNotFound,
},
m: everythingMatcher{}, m: everythingMatcher{},
out: &api.PodList{Items: []api.Pod{}}, out: &api.PodList{Items: []api.Pod{}},
succeed: true,
}, },
"normal": { "normal": {
in: tools.EtcdResponseWithError{ in: &api.PodList{Items: []api.Pod{*podA, *podB}},
R: normalListResp,
E: nil,
},
m: everythingMatcher{}, m: everythingMatcher{},
out: &api.PodList{Items: []api.Pod{*podA, *podB}}, out: &api.PodList{Items: []api.Pod{*podA, *podB}},
succeed: true,
}, },
"normalFiltered": { "normalFiltered": {
in: tools.EtcdResponseWithError{ in: &api.PodList{Items: []api.Pod{*podA, *podB}},
R: singleElemListResp,
E: nil,
},
m: setMatcher{sets.NewString("foo")}, m: setMatcher{sets.NewString("foo")},
out: &api.PodList{Items: []api.Pod{*podA}}, out: &api.PodList{Items: []api.Pod{*podB}},
succeed: true,
}, },
"normalFilteredNoNamespace": { "normalFilteredNoNamespace": {
in: tools.EtcdResponseWithError{ in: &api.PodList{Items: []api.Pod{*podA, *podB}},
R: normalListResp,
E: nil,
},
m: setMatcher{sets.NewString("foo")}, m: setMatcher{sets.NewString("foo")},
out: &api.PodList{Items: []api.Pod{*podA}}, out: &api.PodList{Items: []api.Pod{*podB}},
context: noNamespaceContext, context: noNamespaceContext,
succeed: true,
}, },
"normalFilteredMatchMultiple": { "normalFilteredMatchMultiple": {
in: tools.EtcdResponseWithError{ in: &api.PodList{Items: []api.Pod{*podA, *podB}},
R: normalListResp,
E: nil,
},
m: setMatcher{sets.NewString("foo", "makeMatchSingleReturnFalse")}, m: setMatcher{sets.NewString("foo", "makeMatchSingleReturnFalse")},
out: &api.PodList{Items: []api.Pod{*podA}}, out: &api.PodList{Items: []api.Pod{*podB}},
succeed: true,
}, },
} }
...@@ -227,29 +178,25 @@ func TestEtcdList(t *testing.T) { ...@@ -227,29 +178,25 @@ func TestEtcdList(t *testing.T) {
if item.context != nil { if item.context != nil {
ctx = item.context ctx = item.context
} }
fakeClient, registry := NewTestGenericEtcdRegistry(t) server, registry := NewTestGenericEtcdRegistry(t)
if name, ok := item.m.MatchesSingle(); ok {
if key, err := registry.KeyFunc(ctx, name); err == nil { if item.in != nil {
key = etcdtest.AddPrefix(key) if err := storagetesting.CreateList(t, "/pods", registry.Storage, item.in); err != nil {
fakeClient.Data[key] = item.in t.Errorf("Unexpected error %v", err)
} else {
key := registry.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = item.in
} }
} else {
key := registry.KeyRootFunc(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = item.in
} }
list, err := registry.ListPredicate(ctx, item.m, nil) list, err := registry.ListPredicate(ctx, item.m, nil)
if e, a := item.succeed, err == nil; e != a { if err != nil {
t.Errorf("%v: expected %v, got %v: %v", name, e, a, err) t.Errorf("Unexpected error %v", err)
continue continue
} }
// DeepDerivative e,a is needed here b/c the storage layer sets ResourceVersion
if e, a := item.out, list; !api.Semantic.DeepDerivative(e, a) { if e, a := item.out, list; !api.Semantic.DeepDerivative(e, a) {
t.Errorf("%v: Expected %#v, got %#v", name, e, a) t.Errorf("%v: Expected %#v, got %#v", name, e, a)
} }
server.Terminate(t)
} }
} }
...@@ -263,78 +210,50 @@ func TestEtcdCreate(t *testing.T) { ...@@ -263,78 +210,50 @@ func TestEtcdCreate(t *testing.T) {
Spec: api.PodSpec{NodeName: "machine2"}, Spec: api.PodSpec{NodeName: "machine2"},
} }
nodeWithPodA := tools.EtcdResponseWithError{ testContext := api.WithNamespace(api.NewContext(), "test")
R: &etcd.Response{ server, registry := NewTestGenericEtcdRegistry(t)
Node: &etcd.Node{ defer server.Terminate(t)
Value: runtime.EncodeOrDie(testapi.Default.Codec(), podA),
ModifiedIndex: 1,
CreatedIndex: 1,
},
},
E: nil,
}
emptyNode := tools.EtcdResponseWithError{ // create the object
R: &etcd.Response{}, objA, err := registry.Create(testContext, podA)
E: tools.EtcdErrorNotFound, if err != nil {
t.Errorf("Unexpected error: %v", err)
} }
testContext := api.WithNamespace(api.NewContext(), "test") // get the object
checkobj, err := registry.Get(testContext, podA.Name)
table := map[string]struct { if err != nil {
existing tools.EtcdResponseWithError t.Errorf("Unexpected error: %v", err)
expect tools.EtcdResponseWithError
toCreate runtime.Object
objOK func(obj runtime.Object) bool
errOK func(error) bool
}{
"normal": {
existing: emptyNode,
toCreate: podA,
objOK: hasCreated(t, podA),
errOK: func(err error) bool { return err == nil },
},
"preExisting": {
existing: nodeWithPodA,
expect: nodeWithPodA,
toCreate: podB,
errOK: errors.IsAlreadyExists,
},
} }
for name, item := range table { // verify objects are equal
fakeClient, registry := NewTestGenericEtcdRegistry(t) if e, a := objA, checkobj; !reflect.DeepEqual(e, a) {
path := etcdtest.AddPrefix("pods/foo") t.Errorf("Expected %#v, got %#v", e, a)
fakeClient.Data[path] = item.existing
obj, err := registry.Create(testContext, item.toCreate)
if !item.errOK(err) {
t.Errorf("%v: unexpected error: %v", name, err)
} }
actual := fakeClient.Data[path] // now try to create the second pod
if item.objOK != nil { _, err = registry.Create(testContext, podB)
if !item.objOK(obj) { if !errors.IsAlreadyExists(err) {
t.Errorf("%v: unexpected returned: %v", name, obj) t.Errorf("Unexpected error: %v", err)
} }
actualObj, err := api.Scheme.Decode([]byte(actual.R.Node.Value)) }
func updateAndVerify(t *testing.T, ctx api.Context, registry *Etcd, pod *api.Pod) bool {
obj, _, err := registry.Update(ctx, pod)
if err != nil { if err != nil {
t.Errorf("unable to decode stored value for %#v", actual) t.Errorf("Unexpected error: %v", err)
continue return false
}
if !item.objOK(actualObj) {
t.Errorf("%v: unexpected response: %v", name, actual)
}
} else {
if e, a := item.expect, actual; !api.Semantic.DeepDerivative(e, a) {
t.Errorf("%v:\n%s", name, util.ObjectDiff(e, a))
} }
checkObj, err := registry.Get(ctx, pod.Name)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return false
} }
if e, a := obj, checkObj; !reflect.DeepEqual(e, a) {
t.Errorf("Expected %#v, got %#v", e, a)
return false
} }
} return true
func podCopy(in *api.Pod) *api.Pod {
out := *in
return &out
} }
func TestEtcdUpdate(t *testing.T) { func TestEtcdUpdate(t *testing.T) {
...@@ -343,254 +262,106 @@ func TestEtcdUpdate(t *testing.T) { ...@@ -343,254 +262,106 @@ func TestEtcdUpdate(t *testing.T) {
Spec: api.PodSpec{NodeName: "machine"}, Spec: api.PodSpec{NodeName: "machine"},
} }
podB := &api.Pod{ podB := &api.Pod{
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "1"}, ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test"},
Spec: api.PodSpec{NodeName: "machine2"}, Spec: api.PodSpec{NodeName: "machine2"},
} }
podAWithResourceVersion := &api.Pod{ podAWithResourceVersion := &api.Pod{
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "3"}, ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "7"},
Spec: api.PodSpec{NodeName: "machine"}, Spec: api.PodSpec{NodeName: "machine"},
} }
nodeWithPodA := tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Value: runtime.EncodeOrDie(testapi.Default.Codec(), podA),
ModifiedIndex: 1,
CreatedIndex: 1,
},
},
E: nil,
}
newerNodeWithPodA := tools.EtcdResponseWithError{ testContext := api.WithNamespace(api.NewContext(), "test")
R: &etcd.Response{ server, registry := NewTestGenericEtcdRegistry(t)
Node: &etcd.Node{ defer server.Terminate(t)
Value: runtime.EncodeOrDie(testapi.Default.Codec(), podA),
ModifiedIndex: 2,
CreatedIndex: 1,
},
},
E: nil,
}
nodeWithPodB := tools.EtcdResponseWithError{ // Test1 try to update a non-existing node
R: &etcd.Response{ _, _, err := registry.Update(testContext, podA)
Node: &etcd.Node{ if !errors.IsNotFound(err) {
Value: runtime.EncodeOrDie(testapi.Default.Codec(), podB), t.Errorf("Unexpected error: %v", err)
ModifiedIndex: 1,
CreatedIndex: 1,
},
},
E: nil,
} }
nodeWithPodAWithResourceVersion := tools.EtcdResponseWithError{ // Test2 createIfNotFound and verify
R: &etcd.Response{ registry.UpdateStrategy.(*testRESTStrategy).allowCreateOnUpdate = true
Node: &etcd.Node{ if !updateAndVerify(t, testContext, registry, podA) {
Value: runtime.EncodeOrDie(testapi.Default.Codec(), podAWithResourceVersion), t.Errorf("Unexpected error updating podA")
ModifiedIndex: 3,
CreatedIndex: 1,
},
},
E: nil,
} }
emptyNode := tools.EtcdResponseWithError{ registry.UpdateStrategy.(*testRESTStrategy).allowCreateOnUpdate = false
R: &etcd.Response{},
E: tools.EtcdErrorNotFound,
}
testContext := api.WithNamespace(api.NewContext(), "test")
table := map[string]struct { // Test3 outofDate
existing tools.EtcdResponseWithError _, _, err = registry.Update(testContext, podAWithResourceVersion)
expect tools.EtcdResponseWithError if !errors.IsConflict(err) {
toUpdate runtime.Object t.Errorf("Unexpected error: %v", err)
allowCreate bool
allowUnconditionalUpdate bool
objOK func(obj runtime.Object) bool
errOK func(error) bool
}{
"normal": {
existing: nodeWithPodA,
expect: nodeWithPodB,
toUpdate: podCopy(podB),
errOK: func(err error) bool { return err == nil },
},
"notExisting": {
existing: emptyNode,
expect: emptyNode,
toUpdate: podCopy(podA),
errOK: func(err error) bool { return errors.IsNotFound(err) },
},
"createIfNotFound": {
existing: emptyNode,
toUpdate: podCopy(podA),
allowCreate: true,
objOK: hasCreated(t, podA),
errOK: func(err error) bool { return err == nil },
},
"outOfDate": {
existing: newerNodeWithPodA,
expect: newerNodeWithPodA,
toUpdate: podCopy(podB),
errOK: func(err error) bool { return errors.IsConflict(err) },
},
"unconditionalUpdate": {
existing: nodeWithPodAWithResourceVersion,
allowUnconditionalUpdate: true,
toUpdate: podCopy(podA),
objOK: func(obj runtime.Object) bool { return true },
errOK: func(err error) bool { return err == nil },
},
} }
for name, item := range table { // Test4 normal update and verify
fakeClient, registry := NewTestGenericEtcdRegistry(t) if !updateAndVerify(t, testContext, registry, podB) {
registry.UpdateStrategy.(*testRESTStrategy).allowCreateOnUpdate = item.allowCreate t.Errorf("Unexpected error updating podB")
registry.UpdateStrategy.(*testRESTStrategy).allowUnconditionalUpdate = item.allowUnconditionalUpdate
path := etcdtest.AddPrefix("pods/foo")
fakeClient.Data[path] = item.existing
obj, _, err := registry.Update(testContext, item.toUpdate)
if !item.errOK(err) {
t.Errorf("%v: unexpected error: %v", name, err)
} }
actual := fakeClient.Data[path] // Test5 unconditional update
if item.objOK != nil { // NOTE: The logic for unconditional updates doesn't make sense to me, and imho should be removed.
if !item.objOK(obj) { // doUnconditionalUpdate := resourceVersion == 0 && e.UpdateStrategy.AllowUnconditionalUpdate()
t.Errorf("%v: unexpected returned: %#v", name, obj) // ^^ That condition can *never be true due to the creation of root objects.
} //
actualObj, err := api.Scheme.Decode([]byte(actual.R.Node.Value)) // registry.UpdateStrategy.(*testRESTStrategy).allowUnconditionalUpdate = true
if err != nil { // updateAndVerify(t, testContext, registry, podAWithResourceVersion)
t.Errorf("unable to decode stored value for %#v", actual)
continue
}
if !item.objOK(actualObj) {
t.Errorf("%v: unexpected response: %#v", name, actual)
}
} else {
if e, a := item.expect, actual; !api.Semantic.DeepDerivative(e, a) {
t.Errorf("%v:\n%s", name, util.ObjectDiff(e, a))
}
}
}
} }
func TestEtcdGet(t *testing.T) { func TestEtcdGet(t *testing.T) {
podA := &api.Pod{ podA := &api.Pod{
ObjectMeta: api.ObjectMeta{Namespace: "test", Name: "foo", ResourceVersion: "1"}, ObjectMeta: api.ObjectMeta{Namespace: "test", Name: "foo"},
Spec: api.PodSpec{NodeName: "machine"}, Spec: api.PodSpec{NodeName: "machine"},
} }
nodeWithPodA := tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Value: runtime.EncodeOrDie(testapi.Default.Codec(), podA),
ModifiedIndex: 1,
CreatedIndex: 1,
},
},
E: nil,
}
emptyNode := tools.EtcdResponseWithError{
R: &etcd.Response{},
E: tools.EtcdErrorNotFound,
}
key := "foo"
table := map[string]struct {
existing tools.EtcdResponseWithError
expect runtime.Object
errOK func(error) bool
}{
"normal": {
existing: nodeWithPodA,
expect: podA,
errOK: func(err error) bool { return err == nil },
},
"notExisting": {
existing: emptyNode,
expect: nil,
errOK: errors.IsNotFound,
},
}
testContext := api.WithNamespace(api.NewContext(), "test") testContext := api.WithNamespace(api.NewContext(), "test")
server, registry := NewTestGenericEtcdRegistry(t)
defer server.Terminate(t)
for name, item := range table { _, err := registry.Get(testContext, podA.Name)
fakeClient, registry := NewTestGenericEtcdRegistry(t) if !errors.IsNotFound(err) {
path := etcdtest.AddPrefix("pods/foo") t.Errorf("Unexpected error: %v", err)
fakeClient.Data[path] = item.existing
got, err := registry.Get(testContext, key)
if !item.errOK(err) {
t.Errorf("%v: unexpected error: %v", name, err)
} }
if e, a := item.expect, got; !api.Semantic.DeepDerivative(e, a) { registry.UpdateStrategy.(*testRESTStrategy).allowCreateOnUpdate = true
t.Errorf("%v:\n%s", name, util.ObjectDiff(e, a)) if !updateAndVerify(t, testContext, registry, podA) {
} t.Errorf("Unexpected error updating podA")
} }
} }
func TestEtcdDelete(t *testing.T) { func TestEtcdDelete(t *testing.T) {
podA := &api.Pod{ podA := &api.Pod{
ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}, ObjectMeta: api.ObjectMeta{Name: "foo"},
Spec: api.PodSpec{NodeName: "machine"}, Spec: api.PodSpec{NodeName: "machine"},
} }
nodeWithPodA := tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Value: runtime.EncodeOrDie(testapi.Default.Codec(), podA),
ModifiedIndex: 1,
CreatedIndex: 1,
},
},
E: nil,
}
emptyNode := tools.EtcdResponseWithError{
R: &etcd.Response{},
E: tools.EtcdErrorNotFound,
}
testContext := api.WithNamespace(api.NewContext(), "test") testContext := api.WithNamespace(api.NewContext(), "test")
server, registry := NewTestGenericEtcdRegistry(t)
defer server.Terminate(t)
key := "foo" // test failure condition
_, err := registry.Delete(testContext, podA.Name, nil)
table := map[string]struct { if !errors.IsNotFound(err) {
existing tools.EtcdResponseWithError t.Errorf("Unexpected error: %v", err)
expect tools.EtcdResponseWithError
errOK func(error) bool
}{
"normal": {
existing: nodeWithPodA,
expect: emptyNode,
errOK: func(err error) bool { return err == nil },
},
"notExisting": {
existing: emptyNode,
expect: emptyNode,
errOK: func(err error) bool { return errors.IsNotFound(err) },
},
} }
for name, item := range table { // create pod
fakeClient, registry := NewTestGenericEtcdRegistry(t) _, err = registry.Create(testContext, podA)
path := etcdtest.AddPrefix("pods/foo") if err != nil {
fakeClient.Data[path] = item.existing t.Errorf("Unexpected error: %v", err)
obj, err := registry.Delete(testContext, key, nil)
if !item.errOK(err) {
t.Errorf("%v: unexpected error: %v (%#v)", name, err, obj)
} }
if item.expect.E != nil { // delete object
item.expect.E.(*etcd.EtcdError).Index = fakeClient.ChangeIndex _, err = registry.Delete(testContext, podA.Name, nil)
} if err != nil {
if e, a := item.expect, fakeClient.Data[path]; !api.Semantic.DeepDerivative(e, a) { t.Errorf("Unexpected error: %v", err)
t.Errorf("%v:\n%s", name, util.ObjectDiff(e, a))
} }
// try to get a item which should be deleted
_, err = registry.Get(testContext, podA.Name)
if !errors.IsNotFound(err) {
t.Errorf("Unexpected error: %v", err)
} }
} }
...@@ -623,40 +394,28 @@ func TestEtcdWatch(t *testing.T) { ...@@ -623,40 +394,28 @@ func TestEtcdWatch(t *testing.T) {
ObjectMeta: api.ObjectMeta{ ObjectMeta: api.ObjectMeta{
Name: "foo", Name: "foo",
Namespace: "test", Namespace: "test",
ResourceVersion: "1",
}, },
Spec: api.PodSpec{NodeName: "machine"}, Spec: api.PodSpec{NodeName: "machine"},
} }
respWithPodA := &etcd.Response{
Node: &etcd.Node{
Key: "/registry/pods/test/foo",
Value: runtime.EncodeOrDie(testapi.Default.Codec(), podA),
ModifiedIndex: 1,
CreatedIndex: 1,
},
Action: "create",
}
fakeClient, registry := NewTestGenericEtcdRegistry(t) server, registry := NewTestGenericEtcdRegistry(t)
wi, err := registry.WatchPredicate(ctx, m, "1") wi, err := registry.WatchPredicate(ctx, m, "0")
if err != nil { if err != nil {
t.Errorf("%v: unexpected error: %v", name, err) t.Errorf("%v: unexpected error: %v", name, err)
continue } else {
} obj, err := registry.Create(testContext, podA)
fakeClient.WaitForWatchCompletion() if err != nil {
go func() {
fakeClient.WatchResponse <- respWithPodA
}()
got, open := <-wi.ResultChan() got, open := <-wi.ResultChan()
if !open { if !open {
t.Errorf("%v: unexpected channel close", name) t.Errorf("%v: unexpected channel close", name)
continue } else {
if e, a := obj, got.Object; !reflect.DeepEqual(e, a) {
t.Errorf("Expected %#v, got %#v", e, a)
}
} }
if e, a := podA, got.Object; !api.Semantic.DeepDerivative(e, a) {
t.Errorf("%v: difference: %s", name, util.ObjectDiff(e, a))
} }
} }
server.Terminate(t)
}
} }
/*
Copyright 2015 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 testing
import (
"path"
"testing"
"golang.org/x/net/context"
"k8s.io/kubernetes/pkg/api/meta"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
)
// CreateObj will create a single object using the storage interface
func CreateObj(t *testing.T, helper storage.Interface, name string, obj, out runtime.Object, ttl uint64) error {
err := helper.Set(context.TODO(), name, obj, out, ttl)
if err != nil {
t.Errorf("Unexpected error %v", err)
}
return err
}
// CreateList will properly create a list using the storage interface
func CreateList(t *testing.T, prefix string, helper storage.Interface, list runtime.Object) error {
items, err := runtime.ExtractList(list)
if err != nil {
return err
}
for i := range items {
obj := items[i]
meta, err := meta.Accessor(obj)
if err != nil {
return err
}
err = CreateObj(t, helper, path.Join(prefix, meta.Name()), obj, obj, 0)
if err != nil {
return err
}
items[i] = obj
}
return runtime.SetList(list, items)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment