Commit 45ca956f authored by k8s-merge-robot's avatar k8s-merge-robot

Merge pull request #13201 from wojtek-t/refactor_etcd_update_test

Auto commit by PR queue bot
parents f1acdbe3 836be0c4
......@@ -36,10 +36,11 @@ import (
type Tester struct {
*testing.T
storage rest.Storage
storageError injectErrorFunc
clusterScope bool
generatesName bool
storage rest.Storage
storageError injectErrorFunc
clusterScope bool
createOnUpdate bool
generatesName bool
}
type injectErrorFunc func(err error)
......@@ -63,6 +64,11 @@ func (t *Tester) ClusterScope() *Tester {
return t
}
func (t *Tester) AllowCreateOnUpdate() *Tester {
t.createOnUpdate = true
return t
}
func (t *Tester) GeneratesName() *Tester {
t.generatesName = true
return t
......@@ -94,6 +100,17 @@ func (t *Tester) getObjectMetaOrFail(obj runtime.Object) *api.ObjectMeta {
return meta
}
func (t *Tester) setObjectMeta(obj runtime.Object, name string) {
meta := t.getObjectMetaOrFail(obj)
meta.Name = name
if t.clusterScope {
meta.Namespace = api.NamespaceNone
} else {
meta.Namespace = api.NamespaceValue(t.TestContext())
}
meta.GenerateName = ""
}
func copyOrDie(obj runtime.Object) runtime.Object {
out, err := api.Scheme.Copy(obj)
if err != nil {
......@@ -106,6 +123,7 @@ type AssignFunc func([]runtime.Object) []runtime.Object
type GetFunc func(api.Context, runtime.Object) (runtime.Object, error)
type SetFunc func(api.Context, runtime.Object) error
type SetRVFunc func(uint64)
type UpdateFunc func(runtime.Object) runtime.Object
// Test creating an object.
func (t *Tester) TestCreate(valid runtime.Object, setFn SetFunc, getFn GetFunc, invalid ...runtime.Object) {
......@@ -127,9 +145,14 @@ func (t *Tester) TestCreate(valid runtime.Object, setFn SetFunc, getFn GetFunc,
}
// Test updating an object.
func (t *Tester) TestUpdate(valid runtime.Object, existing, older runtime.Object) {
t.testUpdateFailsOnNotFound(copyOrDie(valid))
t.testUpdateFailsOnVersion(copyOrDie(older))
func (t *Tester) TestUpdate(valid runtime.Object, setFn SetFunc, setRVFn SetRVFunc, getFn GetFunc, updateFn UpdateFunc, invalidUpdateFn ...UpdateFunc) {
t.testUpdateEquals(copyOrDie(valid), setFn, getFn, updateFn)
t.testUpdateFailsOnVersionTooOld(copyOrDie(valid), setFn, setRVFn)
t.testUpdateOnNotFound(copyOrDie(valid))
if !t.clusterScope {
t.testUpdateRejectsMismatchedNamespace(copyOrDie(valid), setFn)
}
t.testUpdateInvokesValidation(copyOrDie(valid), setFn, invalidUpdateFn...)
}
// Test deleting an object.
......@@ -177,10 +200,7 @@ func (t *Tester) testCreateAlreadyExisting(obj runtime.Object, setFn SetFunc) {
ctx := t.TestContext()
foo := copyOrDie(obj)
fooMeta := t.getObjectMetaOrFail(foo)
fooMeta.Name = "foo1"
fooMeta.Namespace = api.NamespaceValue(ctx)
fooMeta.GenerateName = ""
t.setObjectMeta(foo, "foo1")
if err := setFn(ctx, foo); err != nil {
t.Errorf("unexpected error: %v", err)
}
......@@ -195,10 +215,7 @@ func (t *Tester) testCreateEquals(obj runtime.Object, getFn GetFunc) {
ctx := t.TestContext()
foo := copyOrDie(obj)
fooMeta := t.getObjectMetaOrFail(foo)
fooMeta.Name = "foo2"
fooMeta.Namespace = api.NamespaceValue(ctx)
fooMeta.GenerateName = ""
t.setObjectMeta(foo, "foo2")
created, err := t.storage.(rest.Creater).Create(ctx, foo)
if err != nil {
......@@ -357,16 +374,56 @@ func (t *Tester) testCreateResetsUserData(valid runtime.Object) {
// =============================================================================
// Update tests.
func (t *Tester) testUpdateFailsOnNotFound(valid runtime.Object) {
_, _, err := t.storage.(rest.Updater).Update(t.TestContext(), valid)
if err == nil {
t.Errorf("Expected an error, but we didn't get one")
} else if !errors.IsNotFound(err) {
t.Errorf("Expected NotFound error, got '%v'", err)
func (t *Tester) testUpdateEquals(obj runtime.Object, setFn SetFunc, getFn GetFunc, updateFn UpdateFunc) {
ctx := t.TestContext()
foo := copyOrDie(obj)
t.setObjectMeta(foo, "foo2")
if err := setFn(ctx, foo); err != nil {
t.Errorf("unexpected error: %v", err)
}
toUpdate, err := getFn(ctx, foo)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
toUpdate = updateFn(toUpdate)
updated, created, err := t.storage.(rest.Updater).Update(ctx, toUpdate)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if created {
t.Errorf("unexpected creation")
}
got, err := getFn(ctx, foo)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
// Set resource version which might be unset in created object.
updatedMeta := t.getObjectMetaOrFail(updated)
gotMeta := t.getObjectMetaOrFail(got)
updatedMeta.ResourceVersion = gotMeta.ResourceVersion
if e, a := updated, got; !api.Semantic.DeepEqual(e, a) {
t.Errorf("unexpected obj: %#v, expected %#v", e, a)
}
}
func (t *Tester) testUpdateFailsOnVersion(older runtime.Object) {
func (t *Tester) testUpdateFailsOnVersionTooOld(obj runtime.Object, setFn SetFunc, setRVFn SetRVFunc) {
ctx := t.TestContext()
foo := copyOrDie(obj)
t.setObjectMeta(foo, "foo3")
setRVFn(10)
if err := setFn(ctx, foo); err != nil {
t.Errorf("unexpected error: %v", err)
}
older := copyOrDie(foo)
olderMeta := t.getObjectMetaOrFail(older)
olderMeta.ResourceVersion = "8"
_, _, err := t.storage.(rest.Updater).Update(t.TestContext(), older)
if err == nil {
t.Errorf("Expected an error, but we didn't get one")
......@@ -375,6 +432,70 @@ func (t *Tester) testUpdateFailsOnVersion(older runtime.Object) {
}
}
func (t *Tester) testUpdateInvokesValidation(obj runtime.Object, setFn SetFunc, invalidUpdateFn ...UpdateFunc) {
ctx := t.TestContext()
foo := copyOrDie(obj)
t.setObjectMeta(foo, "foo4")
if err := setFn(ctx, foo); err != nil {
t.Errorf("unexpected error: %v", err)
}
for _, update := range invalidUpdateFn {
toUpdate := update(copyOrDie(foo))
got, created, err := t.storage.(rest.Updater).Update(t.TestContext(), toUpdate)
if got != nil || created {
t.Errorf("expected nil object and no creation")
}
if !errors.IsInvalid(err) && !errors.IsBadRequest(err) {
t.Errorf("expected invalid or bad request error, got %v", err)
}
}
}
func (t *Tester) testUpdateOnNotFound(obj runtime.Object) {
t.setObjectMeta(obj, "foo")
_, created, err := t.storage.(rest.Updater).Update(t.TestContext(), obj)
if t.createOnUpdate {
if err != nil {
t.Errorf("creation allowed on updated, but got an error: %v", err)
}
if !created {
t.Errorf("creation allowed on update, but object not created")
}
} else {
if err == nil {
t.Errorf("Expected an error, but we didn't get one")
} else if !errors.IsNotFound(err) {
t.Errorf("Expected NotFound error, got '%v'", err)
}
}
}
func (t *Tester) testUpdateRejectsMismatchedNamespace(obj runtime.Object, setFn SetFunc) {
ctx := t.TestContext()
foo := copyOrDie(obj)
t.setObjectMeta(foo, "foo1")
if err := setFn(ctx, foo); err != nil {
t.Errorf("unexpected error: %v", err)
}
objectMeta := t.getObjectMetaOrFail(obj)
objectMeta.Name = "foo1"
objectMeta.Namespace = "not-default"
obj, updated, err := t.storage.(rest.Updater).Update(t.TestContext(), obj)
if obj != nil || updated {
t.Errorf("expected nil object and not updated")
}
if err == nil {
t.Errorf("expected an error, but didn't get one")
} else if !strings.Contains(err.Error(), "does not match the namespace sent on the request") {
t.Errorf("expected 'does not match the namespace sent on the request' error, got '%v'", err.Error())
}
}
// =============================================================================
// Deletion tests.
......@@ -621,9 +742,7 @@ func (t *Tester) testGetDifferentNamespace(obj runtime.Object) {
func (t *Tester) testGetFound(obj runtime.Object) {
ctx := t.TestContext()
objMeta := t.getObjectMetaOrFail(obj)
objMeta.Name = "foo1"
objMeta.Namespace = api.NamespaceValue(ctx)
t.setObjectMeta(obj, "foo1")
existing, err := t.storage.(rest.Creater).Create(ctx, obj)
if err != nil {
......@@ -666,9 +785,7 @@ func (t *Tester) testGetMimatchedNamespace(obj runtime.Object) {
func (t *Tester) testGetNotFound(obj runtime.Object) {
ctx := t.TestContext()
objMeta := t.getObjectMetaOrFail(obj)
objMeta.Name = "foo2"
objMeta.Namespace = api.NamespaceValue(ctx)
t.setObjectMeta(obj, "foo2")
_, err := t.storage.(rest.Creater).Create(ctx, obj)
if err != nil {
t.Errorf("unexpected error: %v", err)
......@@ -717,13 +834,9 @@ func (t *Tester) testListFound(obj runtime.Object, assignFn AssignFunc) {
ctx := t.TestContext()
foo1 := copyOrDie(obj)
foo1Meta := t.getObjectMetaOrFail(foo1)
foo1Meta.Name = "foo1"
foo1Meta.Namespace = api.NamespaceValue(ctx)
t.setObjectMeta(foo1, "foo1")
foo2 := copyOrDie(obj)
foo2Meta := t.getObjectMetaOrFail(foo2)
foo2Meta.Name = "foo2"
foo2Meta.Namespace = api.NamespaceValue(ctx)
t.setObjectMeta(foo2, "foo2")
existing := assignFn([]runtime.Object{foo1, foo2})
......@@ -748,9 +861,7 @@ func (t *Tester) testListMatchLabels(obj runtime.Object, assignFn AssignFunc) {
testLabels := map[string]string{"key": "value"}
foo1 := copyOrDie(obj)
foo1Meta := t.getObjectMetaOrFail(foo1)
foo1Meta.Name = "foo1"
foo1Meta.Namespace = api.NamespaceValue(ctx)
t.setObjectMeta(foo1, "foo1")
foo2 := copyOrDie(obj)
foo2Meta := t.getObjectMetaOrFail(foo2)
foo2Meta.Name = "foo2"
......
......@@ -17,13 +17,11 @@ limitations under the License.
package etcd
import (
"strconv"
"testing"
"time"
"github.com/coreos/go-etcd/etcd"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/rest/resttest"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/fields"
......@@ -57,125 +55,104 @@ func createController(storage *REST, rc api.ReplicationController, t *testing.T)
return *newRc, nil
}
var validPodTemplate = api.PodTemplate{
Template: api.PodTemplateSpec{
func validNewController() *api.ReplicationController {
return &api.ReplicationController{
ObjectMeta: api.ObjectMeta{
Labels: map[string]string{"a": "b"},
Name: "foo",
Namespace: api.NamespaceDefault,
},
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "test",
Image: "test_image",
ImagePullPolicy: api.PullIfNotPresent,
Spec: api.ReplicationControllerSpec{
Selector: map[string]string{"a": "b"},
Template: &api.PodTemplateSpec{
ObjectMeta: api.ObjectMeta{
Labels: map[string]string{"a": "b"},
},
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "test",
Image: "test_image",
ImagePullPolicy: api.PullIfNotPresent,
},
},
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
},
},
RestartPolicy: api.RestartPolicyAlways,
DNSPolicy: api.DNSClusterFirst,
},
},
}
var validControllerSpec = api.ReplicationControllerSpec{
Selector: validPodTemplate.Template.Labels,
Template: &validPodTemplate.Template,
}
}
var validController = api.ReplicationController{
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: validControllerSpec,
}
var validController = *validNewController()
func TestCreate(t *testing.T) {
storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError)
controller := validNewController()
controller.ObjectMeta = api.ObjectMeta{}
test.TestCreate(
// valid
&api.ReplicationController{
Spec: api.ReplicationControllerSpec{
Replicas: 2,
Selector: map[string]string{"a": "b"},
Template: &validPodTemplate.Template,
},
},
controller,
func(ctx api.Context, obj runtime.Object) error {
return registrytest.SetObject(fakeClient, storage.KeyFunc, ctx, obj)
},
func(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
return registrytest.GetObject(fakeClient, storage.KeyFunc, storage.NewFunc, ctx, obj)
},
// invalid
// invalid (invalid selector)
&api.ReplicationController{
Spec: api.ReplicationControllerSpec{
Replicas: 2,
Selector: map[string]string{},
Template: &validPodTemplate.Template,
Template: validController.Spec.Template,
},
},
)
}
func TestEtcdControllerValidatesUpdate(t *testing.T) {
ctx := api.NewDefaultContext()
storage, _ := newStorage(t)
updateController, err := createController(storage, validController, t)
if err != nil {
t.Errorf("Failed to create controller, cannot proceed with test.")
}
updaters := []func(rc api.ReplicationController) (runtime.Object, bool, error){
func(rc api.ReplicationController) (runtime.Object, bool, error) {
rc.UID = "newUID"
return storage.Update(ctx, &rc)
func TestUpdate(t *testing.T) {
storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError)
test.TestUpdate(
// valid
validNewController(),
func(ctx api.Context, obj runtime.Object) error {
return registrytest.SetObject(fakeClient, storage.KeyFunc, ctx, obj)
},
func(rc api.ReplicationController) (runtime.Object, bool, error) {
rc.Name = ""
return storage.Update(ctx, &rc)
func(resourceVersion uint64) {
registrytest.SetResourceVersion(fakeClient, resourceVersion)
},
func(rc api.ReplicationController) (runtime.Object, bool, error) {
rc.Spec.Selector = map[string]string{}
return storage.Update(ctx, &rc)
func(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
return registrytest.GetObject(fakeClient, storage.KeyFunc, storage.NewFunc, ctx, obj)
},
}
for _, u := range updaters {
c, updated, err := u(updateController)
if c != nil || updated {
t.Errorf("Expected nil object and not created")
}
if !errors.IsInvalid(err) && !errors.IsBadRequest(err) {
t.Errorf("Expected invalid or bad request error, got %v of type %T", err, err)
}
}
}
func TestEtcdControllerValidatesNamespaceOnUpdate(t *testing.T) {
storage, _ := newStorage(t)
ns := "newnamespace"
// The update should fail if the namespace on the controller is set to something
// other than the namespace on the given context, even if the namespace on the
// controller is valid.
updateController, err := createController(storage, validController, t)
newNamespaceController := validController
newNamespaceController.Namespace = ns
_, err = createController(storage, newNamespaceController, t)
c, updated, err := storage.Update(api.WithNamespace(api.NewContext(), ns), &updateController)
if c != nil || updated {
t.Errorf("Expected nil object and not created")
}
// TODO: Be more paranoid about the type of error and make sure it has the substring
// "namespace" in it, once #5684 is fixed. Ideally this would be a NewBadRequest.
if err == nil {
t.Errorf("Expected an error, but we didn't get one")
}
// updateFunc
func(obj runtime.Object) runtime.Object {
object := obj.(*api.ReplicationController)
object.Spec.Replicas = object.Spec.Replicas + 1
return object
},
// invalid updateFunc
func(obj runtime.Object) runtime.Object {
object := obj.(*api.ReplicationController)
object.UID = "newUID"
return object
},
func(obj runtime.Object) runtime.Object {
object := obj.(*api.ReplicationController)
object.Name = ""
return object
},
func(obj runtime.Object) runtime.Object {
object := obj.(*api.ReplicationController)
object.Spec.Selector = map[string]string{}
return object
},
)
}
func TestGenerationNumber(t *testing.T) {
storage, _ := newStorage(t)
modifiedSno := validController
modifiedSno := *validNewController()
modifiedSno.Generation = 100
modifiedSno.Status.ObservedGeneration = 10
ctx := api.NewDefaultContext()
......@@ -225,17 +202,15 @@ func TestGenerationNumber(t *testing.T) {
func TestEtcdGetController(t *testing.T) {
storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError)
copy := validController
test.TestGet(&copy)
test.TestGet(validNewController())
}
func TestEtcdListControllers(t *testing.T) {
storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError)
key := etcdtest.AddPrefix(storage.KeyRootFunc(test.TestContext()))
copy := validController
test.TestList(
&copy,
validNewController(),
func(objects []runtime.Object) []runtime.Object {
return registrytest.SetObjectsForKey(fakeClient, key, objects)
},
......@@ -244,38 +219,13 @@ func TestEtcdListControllers(t *testing.T) {
})
}
func TestEtcdUpdateController(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t)
key, _ := storage.KeyFunc(ctx, validController.Name)
key = etcdtest.AddPrefix(key)
// set a key, then retrieve the current resource version and try updating it
resp, _ := fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), &validController), 0)
update := validController
update.ResourceVersion = strconv.FormatUint(resp.Node.ModifiedIndex, 10)
update.Spec.Replicas = validController.Spec.Replicas + 1
_, created, err := storage.Update(ctx, &update)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if created {
t.Errorf("expected an update but created flag was returned")
}
ctrl, err := storage.Get(ctx, validController.Name)
updatedController, _ := ctrl.(*api.ReplicationController)
if updatedController.Spec.Replicas != validController.Spec.Replicas+1 {
t.Errorf("Unexpected controller: %#v", ctrl)
}
}
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)
fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), validNewController()), 0)
obj, err := storage.Delete(ctx, validController.Name, nil)
if err != nil {
t.Errorf("unexpected error: %v", err)
......@@ -491,7 +441,7 @@ func TestDelete(t *testing.T) {
key = etcdtest.AddPrefix(key)
createFn := func() runtime.Object {
rc := validController
rc := *validNewController()
rc.ResourceVersion = "1"
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
......
......@@ -80,6 +80,33 @@ func TestCreate(t *testing.T) {
)
}
func TestUpdate(t *testing.T) {
storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError).AllowCreateOnUpdate()
test.TestUpdate(
// valid
validNewEndpoints(),
func(ctx api.Context, obj runtime.Object) error {
return registrytest.SetObject(fakeClient, storage.KeyFunc, ctx, obj)
},
func(resourceVersion uint64) {
registrytest.SetResourceVersion(fakeClient, resourceVersion)
},
func(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
return registrytest.GetObject(fakeClient, storage.KeyFunc, storage.NewFunc, ctx, obj)
},
// updateFunc
func(obj runtime.Object) runtime.Object {
object := obj.(*api.Endpoints)
object.Subsets = []api.EndpointSubset{{
Addresses: []api.EndpointAddress{{IP: "1.2.3.4"}, {IP: "5.6.7.8"}},
Ports: []api.EndpointPort{{Port: 80, Protocol: "TCP"}},
}}
return object
},
)
}
func TestDelete(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t)
......@@ -148,36 +175,6 @@ func TestEndpointsDecode(t *testing.T) {
}
}
func TestEtcdUpdateEndpoints(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t)
endpoints := validChangedEndpoints()
key, _ := storage.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), validNewEndpoints()), 0)
_, _, err := storage.Update(ctx, endpoints)
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 endpointsOut api.Endpoints
err = testapi.Codec().DecodeInto([]byte(response.Node.Value), &endpointsOut)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
endpoints.ObjectMeta.ResourceVersion = endpointsOut.ObjectMeta.ResourceVersion
if !api.Semantic.DeepEqual(endpoints, &endpointsOut) {
t.Errorf("Unexpected endpoints: %#v, expected %#v", &endpointsOut, endpoints)
}
}
func TestDeleteEndpoints(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t)
......
......@@ -78,26 +78,24 @@ func TestCreate(t *testing.T) {
func TestUpdate(t *testing.T) {
storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError)
key, err := storage.KeyFunc(test.TestContext(), "foo")
if err != nil {
t.Fatal(err)
}
key = etcdtest.AddPrefix(key)
fakeClient.ExpectNotFoundGet(key)
fakeClient.ChangeIndex = 2
autoscaler := validNewHorizontalPodAutoscaler("foo")
existing := validNewHorizontalPodAutoscaler("exists")
existing.Namespace = test.TestNamespace()
obj, err := storage.Create(test.TestContext(), existing)
if err != nil {
t.Fatalf("unable to create object: %v", err)
}
older := obj.(*expapi.HorizontalPodAutoscaler)
older.ResourceVersion = "1"
test.TestUpdate(
autoscaler,
existing,
older,
// valid
validNewHorizontalPodAutoscaler("foo"),
func(ctx api.Context, obj runtime.Object) error {
return registrytest.SetObject(fakeClient, storage.KeyFunc, ctx, obj)
},
func(resourceVersion uint64) {
registrytest.SetResourceVersion(fakeClient, resourceVersion)
},
func(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
return registrytest.GetObject(fakeClient, storage.KeyFunc, storage.NewFunc, ctx, obj)
},
// updateFunc
func(obj runtime.Object) runtime.Object {
object := obj.(*expapi.HorizontalPodAutoscaler)
object.Spec.MaxCount = object.Spec.MaxCount + 1
return object
},
)
}
......
......@@ -76,3 +76,39 @@ func TestCreate(t *testing.T) {
},
)
}
func TestUpdate(t *testing.T) {
storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError).AllowCreateOnUpdate()
test.TestUpdate(
// valid
validNewLimitRange(),
func(ctx api.Context, obj runtime.Object) error {
return registrytest.SetObject(fakeClient, storage.KeyFunc, ctx, obj)
},
func(resourceVersion uint64) {
registrytest.SetResourceVersion(fakeClient, resourceVersion)
},
func(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
return registrytest.GetObject(fakeClient, storage.KeyFunc, storage.NewFunc, ctx, obj)
},
// updateFunc
func(obj runtime.Object) runtime.Object {
object := obj.(*api.LimitRange)
object.Spec.Limits = []api.LimitRangeItem{
{
Type: api.LimitTypePod,
Max: api.ResourceList{
api.ResourceCPU: resource.MustParse("1000"),
api.ResourceMemory: resource.MustParse("100000"),
},
Min: api.ResourceList{
api.ResourceCPU: resource.MustParse("10"),
api.ResourceMemory: resource.MustParse("1000"),
},
},
}
return object
},
)
}
......@@ -95,6 +95,30 @@ func TestCreate(t *testing.T) {
)
}
func TestUpdate(t *testing.T) {
storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError).ClusterScope()
test.TestUpdate(
// valid
validNewNode(),
func(ctx api.Context, obj runtime.Object) error {
return registrytest.SetObject(fakeClient, storage.KeyFunc, ctx, obj)
},
func(resourceVersion uint64) {
registrytest.SetResourceVersion(fakeClient, resourceVersion)
},
func(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
return registrytest.GetObject(fakeClient, storage.KeyFunc, storage.NewFunc, ctx, obj)
},
// updateFunc
func(obj runtime.Object) runtime.Object {
object := obj.(*api.Node)
object.Spec.Unschedulable = !object.Spec.Unschedulable
return object
},
)
}
func TestDelete(t *testing.T) {
ctx := api.NewContext()
storage, fakeClient := newStorage(t)
......@@ -145,36 +169,6 @@ func TestEtcdListNodes(t *testing.T) {
})
}
func TestEtcdUpdateEndpoints(t *testing.T) {
ctx := api.NewContext()
storage, fakeClient := newStorage(t)
node := validChangedNode()
key, _ := storage.KeyFunc(ctx, node.Name)
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), validNewNode()), 0)
_, _, err := storage.Update(ctx, node)
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 nodeOut api.Node
err = testapi.Codec().DecodeInto([]byte(response.Node.Value), &nodeOut)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
node.ObjectMeta.ResourceVersion = nodeOut.ObjectMeta.ResourceVersion
if !api.Semantic.DeepEqual(node, &nodeOut) {
t.Errorf("Unexpected node: %#v, expected %#v", &nodeOut, node)
}
}
func TestEtcdDeleteNode(t *testing.T) {
ctx := api.NewContext()
storage, fakeClient := newStorage(t)
......
......@@ -89,6 +89,32 @@ func TestCreate(t *testing.T) {
)
}
func TestUpdate(t *testing.T) {
storage, _, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError).ClusterScope()
test.TestUpdate(
// valid
validNewPersistentVolume("foo"),
func(ctx api.Context, obj runtime.Object) error {
return registrytest.SetObject(fakeClient, storage.KeyFunc, ctx, obj)
},
func(resourceVersion uint64) {
registrytest.SetResourceVersion(fakeClient, resourceVersion)
},
func(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
return registrytest.GetObject(fakeClient, storage.KeyFunc, storage.NewFunc, ctx, obj)
},
// updateFunc
func(obj runtime.Object) runtime.Object {
object := obj.(*api.PersistentVolume)
object.Spec.Capacity = api.ResourceList{
api.ResourceName(api.ResourceStorage): resource.MustParse("20G"),
}
return object
},
)
}
func TestDelete(t *testing.T) {
ctx := api.NewContext()
storage, _, fakeClient := newStorage(t)
......@@ -157,36 +183,6 @@ func TestPersistentVolumesDecode(t *testing.T) {
}
}
func TestEtcdUpdatePersistentVolumes(t *testing.T) {
ctx := api.NewContext()
storage, _, fakeClient := newStorage(t)
persistentVolume := validChangedPersistentVolume()
key, _ := storage.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), validNewPersistentVolume("foo")), 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.PersistentVolume
err = testapi.Codec().DecodeInto([]byte(response.Node.Value), &persistentVolumeOut)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
persistentVolume.ObjectMeta.ResourceVersion = persistentVolumeOut.ObjectMeta.ResourceVersion
if !api.Semantic.DeepEqual(persistentVolume, &persistentVolumeOut) {
t.Errorf("Unexpected persistentVolume: %#v, expected %#v", &persistentVolumeOut, persistentVolume)
}
}
func TestDeletePersistentVolumes(t *testing.T) {
ctx := api.NewContext()
storage, _, fakeClient := newStorage(t)
......
......@@ -86,6 +86,34 @@ func TestCreate(t *testing.T) {
)
}
func TestUpdate(t *testing.T) {
storage, _, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError)
test.TestUpdate(
// valid
validNewPersistentVolumeClaim("foo", api.NamespaceDefault),
func(ctx api.Context, obj runtime.Object) error {
return registrytest.SetObject(fakeClient, storage.KeyFunc, ctx, obj)
},
func(resourceVersion uint64) {
registrytest.SetResourceVersion(fakeClient, resourceVersion)
},
func(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
return registrytest.GetObject(fakeClient, storage.KeyFunc, storage.NewFunc, ctx, obj)
},
// updateFunc
func(obj runtime.Object) runtime.Object {
object := obj.(*api.PersistentVolumeClaim)
object.Spec.Resources = api.ResourceRequirements{
Requests: api.ResourceList{
api.ResourceName(api.ResourceStorage): resource.MustParse("20G"),
},
}
return object
},
)
}
func TestDelete(t *testing.T) {
ctx := api.NewDefaultContext()
storage, _, fakeClient := newStorage(t)
......
......@@ -112,6 +112,30 @@ func TestCreate(t *testing.T) {
)
}
func TestUpdate(t *testing.T) {
storage, _, _, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError)
test.TestUpdate(
// valid
validNewPod(),
func(ctx api.Context, obj runtime.Object) error {
return registrytest.SetObject(fakeClient, storage.KeyFunc, ctx, obj)
},
func(resourceVersion uint64) {
registrytest.SetResourceVersion(fakeClient, resourceVersion)
},
func(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
return registrytest.GetObject(fakeClient, storage.KeyFunc, storage.NewFunc, ctx, obj)
},
// updateFunc
func(obj runtime.Object) runtime.Object {
object := obj.(*api.Pod)
object.Labels = map[string]string{"a": "b"}
return object
},
)
}
func TestDelete(t *testing.T) {
storage, _, _, fakeClient := newStorage(t)
ctx := api.NewDefaultContext()
......@@ -199,37 +223,6 @@ func TestPodDecode(t *testing.T) {
}
}
func TestUpdateWithConflictingNamespace(t *testing.T) {
storage, _, _, fakeClient := newStorage(t)
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: "default"},
Spec: api.PodSpec{NodeName: "machine"},
}),
ModifiedIndex: 1,
},
},
}
pod := validChangedPod()
pod.Namespace = "not-default"
obj, created, err := storage.Update(api.NewDefaultContext(), pod)
if obj != nil || created {
t.Error("Expected a nil channel, but we got a value or created")
}
if err == nil {
t.Errorf("Expected an error, but we didn't get one")
} else if strings.Index(err.Error(), "the namespace of the provided object does not match the namespace sent on the request") == -1 {
t.Errorf("Expected 'Pod.Namespace does not match the provided context' error, got '%v'", err.Error())
}
}
func TestResourceLocation(t *testing.T) {
expectedIP := "1.2.3.4"
testCases := []struct {
......@@ -691,33 +684,6 @@ func TestEtcdCreateBinding(t *testing.T) {
}
}
func TestEtcdUpdateNotFound(t *testing.T) {
storage, _, _, fakeClient := newStorage(t)
ctx := api.NewDefaultContext()
fakeClient.TestIndex = true
key, _ := storage.KeyFunc(ctx, "foo")
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{},
E: tools.EtcdErrorNotFound,
}
podIn := api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "foo",
ResourceVersion: "1",
Labels: map[string]string{
"foo": "bar",
},
},
}
_, _, err := storage.Update(ctx, &podIn)
if err == nil {
t.Errorf("unexpected non-error")
}
}
func TestEtcdUpdateNotScheduled(t *testing.T) {
storage, _, _, fakeClient := newStorage(t)
ctx := api.NewDefaultContext()
......
......@@ -24,7 +24,6 @@ import (
"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) {
......@@ -83,27 +82,23 @@ func TestCreate(t *testing.T) {
func TestUpdate(t *testing.T) {
storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError)
key, err := storage.KeyFunc(test.TestContext(), "foo")
if err != nil {
t.Fatal(err)
}
key = etcdtest.AddPrefix(key)
fakeClient.ExpectNotFoundGet(key)
fakeClient.ChangeIndex = 2
pod := validNewPodTemplate("foo")
existing := validNewPodTemplate("exists")
existing.Namespace = test.TestNamespace()
obj, err := storage.Create(test.TestContext(), existing)
if err != nil {
t.Fatalf("unable to create object: %v", err)
}
older := obj.(*api.PodTemplate)
older.ResourceVersion = "1"
test.TestUpdate(
pod,
existing,
older,
//valid
validNewPodTemplate("foo"),
func(ctx api.Context, obj runtime.Object) error {
return registrytest.SetObject(fakeClient, storage.KeyFunc, ctx, obj)
},
func(resourceVersion uint64) {
registrytest.SetResourceVersion(fakeClient, resourceVersion)
},
func(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
return registrytest.GetObject(fakeClient, storage.KeyFunc, storage.NewFunc, ctx, obj)
},
// updateFunc
func(obj runtime.Object) runtime.Object {
object := obj.(*api.PodTemplate)
object.Template.Spec.NodeSelector = map[string]string{"a": "b"}
return object
},
)
}
......@@ -24,7 +24,6 @@ import (
"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) {
......@@ -74,27 +73,23 @@ func TestCreate(t *testing.T) {
func TestUpdate(t *testing.T) {
storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError)
key, err := storage.KeyFunc(test.TestContext(), "foo")
if err != nil {
t.Fatal(err)
}
key = etcdtest.AddPrefix(key)
fakeClient.ExpectNotFoundGet(key)
fakeClient.ChangeIndex = 2
secret := validNewSecret("foo")
existing := validNewSecret("exists")
existing.Namespace = test.TestNamespace()
obj, err := storage.Create(test.TestContext(), existing)
if err != nil {
t.Fatalf("unable to create object: %v", err)
}
older := obj.(*api.Secret)
older.ResourceVersion = "1"
test.TestUpdate(
secret,
existing,
older,
// valid
validNewSecret("foo"),
func(ctx api.Context, obj runtime.Object) error {
return registrytest.SetObject(fakeClient, storage.KeyFunc, ctx, obj)
},
func(resourceVersion uint64) {
registrytest.SetResourceVersion(fakeClient, resourceVersion)
},
func(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
return registrytest.GetObject(fakeClient, storage.KeyFunc, storage.NewFunc, ctx, obj)
},
// updateFunc
func(obj runtime.Object) runtime.Object {
object := obj.(*api.Secret)
object.Data["othertest"] = []byte("otherdata")
return object
},
)
}
......@@ -86,3 +86,36 @@ func TestCreate(t *testing.T) {
},
)
}
func TestUpdate(t *testing.T) {
storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError).AllowCreateOnUpdate()
test.TestUpdate(
// valid
validService(),
func(ctx api.Context, obj runtime.Object) error {
return registrytest.SetObject(fakeClient, storage.KeyFunc, ctx, obj)
},
func(resourceVersion uint64) {
registrytest.SetResourceVersion(fakeClient, resourceVersion)
},
func(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
return registrytest.GetObject(fakeClient, storage.KeyFunc, storage.NewFunc, ctx, obj)
},
// updateFunc
func(obj runtime.Object) runtime.Object {
object := obj.(*api.Service)
object.Spec = api.ServiceSpec{
Selector: map[string]string{"bar": "baz2"},
SessionAffinity: api.ServiceAffinityNone,
Type: api.ServiceTypeClusterIP,
Ports: []api.ServicePort{{
Port: 6502,
Protocol: api.ProtocolTCP,
TargetPort: util.NewIntOrStringFromInt(6502),
}},
}
return object
},
)
}
......@@ -24,7 +24,6 @@ import (
"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) {
......@@ -67,27 +66,23 @@ func TestCreate(t *testing.T) {
func TestUpdate(t *testing.T) {
storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError)
key, err := storage.KeyFunc(test.TestContext(), "foo")
if err != nil {
t.Fatal(err)
}
key = etcdtest.AddPrefix(key)
fakeClient.ExpectNotFoundGet(key)
fakeClient.ChangeIndex = 2
serviceAccount := validNewServiceAccount("foo")
existing := validNewServiceAccount("exists")
existing.Namespace = test.TestNamespace()
obj, err := storage.Create(test.TestContext(), existing)
if err != nil {
t.Fatalf("unable to create object: %v", err)
}
older := obj.(*api.ServiceAccount)
older.ResourceVersion = "1"
test.TestUpdate(
serviceAccount,
existing,
older,
// valid
validNewServiceAccount("foo"),
func(ctx api.Context, obj runtime.Object) error {
return registrytest.SetObject(fakeClient, storage.KeyFunc, ctx, obj)
},
func(resourceVersion uint64) {
registrytest.SetResourceVersion(fakeClient, resourceVersion)
},
func(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
return registrytest.GetObject(fakeClient, storage.KeyFunc, storage.NewFunc, ctx, obj)
},
// updateFunc
func(obj runtime.Object) runtime.Object {
object := obj.(*api.ServiceAccount)
// TODO: Update this serviceAccount
return object
},
)
}
......@@ -80,26 +80,24 @@ func TestCreate(t *testing.T) {
func TestUpdate(t *testing.T) {
storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError)
key, err := storage.KeyFunc(test.TestContext(), "foo")
if err != nil {
t.Fatal(err)
}
key = etcdtest.AddPrefix(key)
fakeClient.ExpectNotFoundGet(key)
fakeClient.ChangeIndex = 2
rsrc := validNewThirdPartyResource("foo")
existing := validNewThirdPartyResource("exists")
existing.Namespace = test.TestNamespace()
obj, err := storage.Create(test.TestContext(), existing)
if err != nil {
t.Fatalf("unable to create object: %v", err)
}
older := obj.(*expapi.ThirdPartyResource)
older.ResourceVersion = "1"
test.TestUpdate(
rsrc,
existing,
older,
// valid
validNewThirdPartyResource("foo"),
func(ctx api.Context, obj runtime.Object) error {
return registrytest.SetObject(fakeClient, storage.KeyFunc, ctx, obj)
},
func(resourceVersion uint64) {
registrytest.SetResourceVersion(fakeClient, resourceVersion)
},
func(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
return registrytest.GetObject(fakeClient, storage.KeyFunc, storage.NewFunc, ctx, obj)
},
// updateFunc
func(obj runtime.Object) runtime.Object {
object := obj.(*expapi.ThirdPartyResource)
object.Description = "new description"
return object
},
)
}
......
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