Refactoring of update etcd tests.

pull/6/head
Wojciech Tyczynski 2015-08-28 15:45:38 +02:00
parent e21bcb8e7a
commit 836be0c432
15 changed files with 592 additions and 686 deletions

View File

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

View File

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

View File

@ -22,7 +22,6 @@ import (
"github.com/coreos/go-etcd/etcd"
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/errors"
"k8s.io/kubernetes/pkg/api/latest"
"k8s.io/kubernetes/pkg/api/rest/resttest"
"k8s.io/kubernetes/pkg/expapi"
@ -57,228 +56,133 @@ func createController(storage *REST, dc expapi.Daemon, t *testing.T) (expapi.Dae
return *newDc, nil
}
var validPodTemplate = api.PodTemplate{
Template: api.PodTemplateSpec{
func validNewDaemon() *expapi.Daemon {
return &expapi.Daemon{
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: expapi.DaemonSpec{
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 = expapi.DaemonSpec{
Selector: validPodTemplate.Template.Labels,
Template: &validPodTemplate.Template,
}
var validController = expapi.Daemon{
ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "default"},
Spec: validControllerSpec,
}
var validDaemon = *validNewDaemon()
func TestCreate(t *testing.T) {
storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError)
controller := validNewDaemon()
controller.ObjectMeta = api.ObjectMeta{}
test.TestCreate(
// valid
&expapi.Daemon{
Spec: expapi.DaemonSpec{
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)
&expapi.Daemon{
Spec: expapi.DaemonSpec{
Selector: map[string]string{},
Template: &validPodTemplate.Template,
Template: validDaemon.Spec.Template,
},
},
)
}
// makeControllerKey constructs etcd paths to controller items enforcing namespace rules.
func makeControllerKey(ctx api.Context, id string) (string, error) {
return etcdgeneric.NamespaceKeyFunc(ctx, daemonPrefix, id)
}
// makeControllerListKey constructs etcd paths to the root of the resource,
// not a specific controller resource
func makeControllerListKey(ctx api.Context) string {
return etcdgeneric.NamespaceKeyRootFunc(ctx, daemonPrefix)
func TestUpdate(t *testing.T) {
storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError)
test.TestUpdate(
// valid
validNewDaemon(),
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.Daemon)
object.Spec.Template.Spec.NodeSelector = map[string]string{"c": "d"}
return object
},
// invalid updateFunc
func(obj runtime.Object) runtime.Object {
object := obj.(*expapi.Daemon)
object.UID = "newUID"
return object
},
func(obj runtime.Object) runtime.Object {
object := obj.(*expapi.Daemon)
object.Name = ""
return object
},
func(obj runtime.Object) runtime.Object {
object := obj.(*expapi.Daemon)
object.Spec.Template.Spec.RestartPolicy = api.RestartPolicyOnFailure
return object
},
func(obj runtime.Object) runtime.Object {
object := obj.(*expapi.Daemon)
object.Spec.Selector = map[string]string{}
return object
},
)
}
func TestEtcdGetController(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t)
key, _ := makeControllerKey(ctx, validController.Name)
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, &validController), 0)
ctrl, err := storage.Get(ctx, validController.Name)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
controller, ok := ctrl.(*expapi.Daemon)
if !ok {
t.Errorf("Expected a controller, got %#v", ctrl)
}
if controller.Name != validController.Name {
t.Errorf("Unexpected controller: %#v", controller)
}
test := resttest.New(t, storage, fakeClient.SetError)
test.TestGet(validNewDaemon())
}
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(dc expapi.Daemon) (runtime.Object, bool, error){
func(dc expapi.Daemon) (runtime.Object, bool, error) {
dc.UID = "newUID"
return storage.Update(ctx, &dc)
},
func(dc expapi.Daemon) (runtime.Object, bool, error) {
dc.Name = ""
return storage.Update(ctx, &dc)
},
func(dc expapi.Daemon) (runtime.Object, bool, error) {
dc.Spec.Template.Spec.RestartPolicy = api.RestartPolicyOnFailure
return storage.Update(ctx, &dc)
},
func(dc expapi.Daemon) (runtime.Object, bool, error) {
dc.Spec.Selector = map[string]string{}
return storage.Update(ctx, &dc)
},
}
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")
}
}
// TestEtcdGetControllerDifferentNamespace ensures same-name controllers in different namespaces do not clash
func TestEtcdGetControllerDifferentNamespace(t *testing.T) {
func TestEtcdListControllers(t *testing.T) {
storage, fakeClient := newStorage(t)
otherNs := "other"
ctx1 := api.NewDefaultContext()
ctx2 := api.WithNamespace(api.NewContext(), otherNs)
key1, _ := makeControllerKey(ctx1, validController.Name)
key2, _ := makeControllerKey(ctx2, validController.Name)
key1 = etcdtest.AddPrefix(key1)
key2 = etcdtest.AddPrefix(key2)
fakeClient.Set(key1, runtime.EncodeOrDie(latest.Codec, &validController), 0)
otherNsController := validController
otherNsController.Namespace = otherNs
fakeClient.Set(key2, runtime.EncodeOrDie(latest.Codec, &otherNsController), 0)
obj, err := storage.Get(ctx1, validController.Name)
ctrl1, _ := obj.(*expapi.Daemon)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if ctrl1.Name != "foo" {
t.Errorf("Unexpected controller: %#v", ctrl1)
}
if ctrl1.Namespace != "default" {
t.Errorf("Unexpected controller: %#v", ctrl1)
}
obj, err = storage.Get(ctx2, validController.Name)
ctrl2, _ := obj.(*expapi.Daemon)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if ctrl2.Name != "foo" {
t.Errorf("Unexpected controller: %#v", ctrl2)
}
if ctrl2.Namespace != "other" {
t.Errorf("Unexpected controller: %#v", ctrl2)
}
}
func TestEtcdGetControllerNotFound(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t)
key, _ := makeControllerKey(ctx, validController.Name)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: nil,
test := resttest.New(t, storage, fakeClient.SetError)
key := etcdtest.AddPrefix(storage.KeyRootFunc(test.TestContext()))
test.TestList(
validNewDaemon(),
func(objects []runtime.Object) []runtime.Object {
return registrytest.SetObjectsForKey(fakeClient, key, objects)
},
E: tools.EtcdErrorNotFound,
}
ctrl, err := storage.Get(ctx, validController.Name)
if ctrl != nil {
t.Errorf("Unexpected non-nil controller: %#v", ctrl)
}
if !errors.IsNotFound(err) {
t.Errorf("Unexpected error returned: %#v", err)
}
func(resourceVersion uint64) {
registrytest.SetResourceVersion(fakeClient, resourceVersion)
})
}
func TestEtcdDeleteController(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t)
key, _ := makeControllerKey(ctx, validController.Name)
key, err := storage.KeyFunc(ctx, validDaemon.Name)
key = etcdtest.AddPrefix(key)
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, &validController), 0)
obj, err := storage.Delete(ctx, validController.Name, nil)
fakeClient.Set(key, runtime.EncodeOrDie(latest.Codec, validNewDaemon()), 0)
obj, err := storage.Delete(ctx, validDaemon.Name, nil)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
@ -295,96 +199,6 @@ func TestEtcdDeleteController(t *testing.T) {
}
}
func TestEtcdListControllers(t *testing.T) {
storage, fakeClient := newStorage(t)
ctx := api.NewDefaultContext()
key := makeControllerListKey(ctx)
key = etcdtest.AddPrefix(key)
controller := validController
controller.Name = "bar"
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Nodes: []*etcd.Node{
{
Value: runtime.EncodeOrDie(latest.Codec, &validController),
},
{
Value: runtime.EncodeOrDie(latest.Codec, &controller),
},
},
},
},
E: nil,
}
objList, err := storage.List(ctx, labels.Everything(), fields.Everything())
if err != nil {
t.Errorf("unexpected error: %v", err)
}
controllers, _ := objList.(*expapi.DaemonList)
if len(controllers.Items) != 2 || controllers.Items[0].Name != validController.Name || controllers.Items[1].Name != controller.Name {
t.Errorf("Unexpected controller list: %#v", controllers)
}
}
func TestEtcdListControllersNotFound(t *testing.T) {
storage, fakeClient := newStorage(t)
ctx := api.NewDefaultContext()
key := makeControllerListKey(ctx)
key = etcdtest.AddPrefix(key)
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{},
E: tools.EtcdErrorNotFound,
}
objList, err := storage.List(ctx, labels.Everything(), fields.Everything())
if err != nil {
t.Errorf("unexpected error: %v", err)
}
controllers, _ := objList.(*expapi.DaemonList)
if len(controllers.Items) != 0 {
t.Errorf("Unexpected controller list: %#v", controllers)
}
}
func TestEtcdListControllersLabelsMatch(t *testing.T) {
storage, fakeClient := newStorage(t)
ctx := api.NewDefaultContext()
key := makeControllerListKey(ctx)
key = etcdtest.AddPrefix(key)
controller := validController
controller.Labels = map[string]string{"k": "v"}
controller.Name = "bar"
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Nodes: []*etcd.Node{
{
Value: runtime.EncodeOrDie(latest.Codec, &validController),
},
{
Value: runtime.EncodeOrDie(latest.Codec, &controller),
},
},
},
},
E: nil,
}
testLabels := labels.SelectorFromSet(labels.Set(controller.Labels))
objList, err := storage.List(ctx, testLabels, fields.Everything())
if err != nil {
t.Errorf("unexpected error: %v", err)
}
controllers, _ := objList.(*expapi.DaemonList)
if len(controllers.Items) != 1 || controllers.Items[0].Name != controller.Name ||
!testLabels.Matches(labels.Set(controllers.Items[0].Labels)) {
t.Errorf("Unexpected controller list: %#v for query with labels %#v",
controllers, testLabels)
}
}
func TestEtcdWatchController(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t)
@ -414,12 +228,12 @@ func TestEtcdWatchController(t *testing.T) {
// Tests that we can watch for the creation of daemon controllers with specified labels.
func TestEtcdWatchControllersMatch(t *testing.T) {
ctx := api.WithNamespace(api.NewDefaultContext(), validController.Namespace)
ctx := api.WithNamespace(api.NewDefaultContext(), validDaemon.Namespace)
storage, fakeClient := newStorage(t)
fakeClient.ExpectNotFoundGet(etcdgeneric.NamespaceKeyRootFunc(ctx, "/registry/pods"))
watching, err := storage.Watch(ctx,
labels.SelectorFromSet(validController.Spec.Selector),
labels.SelectorFromSet(validDaemon.Spec.Selector),
fields.Everything(),
"1",
)
@ -434,7 +248,7 @@ func TestEtcdWatchControllersMatch(t *testing.T) {
controller := &expapi.Daemon{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: validController.Spec.Selector,
Labels: validDaemon.Spec.Selector,
Namespace: "default",
},
}
@ -458,7 +272,7 @@ func TestEtcdWatchControllersMatch(t *testing.T) {
// Tests that we can watch for daemon controllers with specified fields.
func TestEtcdWatchControllersFields(t *testing.T) {
ctx := api.WithNamespace(api.NewDefaultContext(), validController.Namespace)
ctx := api.WithNamespace(api.NewDefaultContext(), validDaemon.Namespace)
storage, fakeClient := newStorage(t)
fakeClient.ExpectNotFoundGet(etcdgeneric.NamespaceKeyRootFunc(ctx, "/registry/pods"))
@ -480,7 +294,7 @@ func TestEtcdWatchControllersFields(t *testing.T) {
controller := &expapi.Daemon{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: validController.Spec.Selector,
Labels: validDaemon.Spec.Selector,
Namespace: "default",
},
Status: expapi.DaemonStatus{
@ -578,21 +392,21 @@ func TestDelete(t *testing.T) {
ctx := api.NewDefaultContext()
storage, fakeClient := newStorage(t)
test := resttest.New(t, storage, fakeClient.SetError)
key, _ := makeControllerKey(ctx, validController.Name)
key, _ := storage.KeyFunc(ctx, validDaemon.Name)
key = etcdtest.AddPrefix(key)
createFn := func() runtime.Object {
dc := validController
dc := validNewDaemon()
dc.ResourceVersion = "1"
fakeClient.Data[key] = tools.EtcdResponseWithError{
R: &etcd.Response{
Node: &etcd.Node{
Value: runtime.EncodeOrDie(latest.Codec, &dc),
Value: runtime.EncodeOrDie(latest.Codec, dc),
ModifiedIndex: 1,
},
},
}
return &dc
return dc
}
gracefulSetFn := func() bool {
// If the controller is still around after trying to delete either the delete

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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