diff --git a/pkg/registry/apps/replicaset/storage/storage_test.go b/pkg/registry/apps/replicaset/storage/storage_test.go index 670cede929..9ce94fcfce 100644 --- a/pkg/registry/apps/replicaset/storage/storage_test.go +++ b/pkg/registry/apps/replicaset/storage/storage_test.go @@ -158,6 +158,9 @@ func TestGenerationNumber(t *testing.T) { modifiedSno.Status.ObservedGeneration = 10 ctx := genericapirequest.NewDefaultContext() rs, err := createReplicaSet(storage.ReplicaSet, modifiedSno, t) + if err != nil { + t.Errorf("unexpected error: %v", err) + } etcdRS, err := storage.ReplicaSet.Get(ctx, rs.Name, &metav1.GetOptions{}) if err != nil { t.Errorf("unexpected error: %v", err) @@ -165,14 +168,13 @@ func TestGenerationNumber(t *testing.T) { storedRS, _ := etcdRS.(*extensions.ReplicaSet) // Generation initialization - if storedRS.Generation != 1 && storedRS.Status.ObservedGeneration != 0 { + if storedRS.Generation != 1 || storedRS.Status.ObservedGeneration != 0 { t.Fatalf("Unexpected generation number %v, status generation %v", storedRS.Generation, storedRS.Status.ObservedGeneration) } // Updates to spec should increment the generation number storedRS.Spec.Replicas += 1 - storage.ReplicaSet.Update(ctx, storedRS.Name, rest.DefaultUpdatedObjectInfo(storedRS), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc) - if err != nil { + if _, _, err := storage.ReplicaSet.Update(ctx, storedRS.Name, rest.DefaultUpdatedObjectInfo(storedRS), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil { t.Errorf("unexpected error: %v", err) } etcdRS, err = storage.ReplicaSet.Get(ctx, rs.Name, &metav1.GetOptions{}) @@ -186,8 +188,7 @@ func TestGenerationNumber(t *testing.T) { // Updates to status should not increment either spec or status generation numbers storedRS.Status.Replicas += 1 - storage.ReplicaSet.Update(ctx, storedRS.Name, rest.DefaultUpdatedObjectInfo(storedRS), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc) - if err != nil { + if _, _, err := storage.ReplicaSet.Update(ctx, storedRS.Name, rest.DefaultUpdatedObjectInfo(storedRS), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil { t.Errorf("unexpected error: %v", err) } etcdRS, err = storage.ReplicaSet.Get(ctx, rs.Name, &metav1.GetOptions{}) diff --git a/pkg/registry/core/replicationcontroller/storage/storage_test.go b/pkg/registry/core/replicationcontroller/storage/storage_test.go index fc468337ac..1d5e37dc51 100644 --- a/pkg/registry/core/replicationcontroller/storage/storage_test.go +++ b/pkg/registry/core/replicationcontroller/storage/storage_test.go @@ -161,6 +161,9 @@ func TestGenerationNumber(t *testing.T) { modifiedSno.Status.ObservedGeneration = 10 ctx := genericapirequest.NewDefaultContext() rc, err := createController(storage.Controller, modifiedSno, t) + if err != nil { + t.Errorf("unexpected error: %v", err) + } ctrl, err := storage.Controller.Get(ctx, rc.Name, &metav1.GetOptions{}) if err != nil { t.Errorf("unexpected error: %v", err) @@ -168,7 +171,7 @@ func TestGenerationNumber(t *testing.T) { controller, _ := ctrl.(*api.ReplicationController) // Generation initialization - if controller.Generation != 1 && controller.Status.ObservedGeneration != 0 { + if controller.Generation != 1 || controller.Status.ObservedGeneration != 0 { t.Fatalf("Unexpected generation number %v, status generation %v", controller.Generation, controller.Status.ObservedGeneration) } diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/BUILD b/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/BUILD index 73ac1009ee..1650919915 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/BUILD +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/BUILD @@ -68,6 +68,7 @@ go_test( "//vendor/k8s.io/api/autoscaling/v1:go_default_library", "//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library", "//vendor/k8s.io/apiextensions-apiserver/pkg/apiserver:go_default_library", + "//vendor/k8s.io/apiextensions-apiserver/pkg/features:go_default_library", "//vendor/k8s.io/apiextensions-apiserver/pkg/registry/customresource:go_default_library", "//vendor/k8s.io/apiextensions-apiserver/pkg/registry/customresource/tableconvertor:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/equality:go_default_library", @@ -82,6 +83,8 @@ go_test( "//vendor/k8s.io/apiserver/pkg/registry/generic/testing:go_default_library", "//vendor/k8s.io/apiserver/pkg/registry/rest:go_default_library", "//vendor/k8s.io/apiserver/pkg/storage/etcd/testing:go_default_library", + "//vendor/k8s.io/apiserver/pkg/util/feature:go_default_library", + "//vendor/k8s.io/apiserver/pkg/util/feature/testing:go_default_library", "//vendor/k8s.io/client-go/discovery:go_default_library", ], ) diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/etcd_test.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/etcd_test.go index 8bee3396c9..79fc7e83d0 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/etcd_test.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/registry/customresource/etcd_test.go @@ -35,10 +35,13 @@ import ( registrytest "k8s.io/apiserver/pkg/registry/generic/testing" "k8s.io/apiserver/pkg/registry/rest" etcdtesting "k8s.io/apiserver/pkg/storage/etcd/testing" + utilfeature "k8s.io/apiserver/pkg/util/feature" + utilfeaturetesting "k8s.io/apiserver/pkg/util/feature/testing" "k8s.io/client-go/discovery" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" "k8s.io/apiextensions-apiserver/pkg/apiserver" + "k8s.io/apiextensions-apiserver/pkg/features" "k8s.io/apiextensions-apiserver/pkg/registry/customresource" "k8s.io/apiextensions-apiserver/pkg/registry/customresource/tableconvertor" ) @@ -160,6 +163,61 @@ func TestDelete(t *testing.T) { test.TestDelete(validNewCustomResource()) } +func TestGenerationNumber(t *testing.T) { + // enable alpha feature CustomResourceSubresources + defer utilfeaturetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CustomResourceSubresources, true)() + + storage, server := newStorage(t) + defer server.Terminate(t) + defer storage.CustomResource.Store.DestroyFunc() + modifiedRno := *validNewCustomResource() + modifiedRno.SetGeneration(10) + ctx := genericapirequest.NewDefaultContext() + cr, err := createCustomResource(storage.CustomResource, modifiedRno, t) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + etcdCR, err := storage.CustomResource.Get(ctx, cr.GetName(), &metav1.GetOptions{}) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + storedCR, _ := etcdCR.(*unstructured.Unstructured) + + // Generation initialization + if storedCR.GetGeneration() != 1 { + t.Fatalf("Unexpected generation number %v", storedCR.GetGeneration()) + } + + // Updates to spec should increment the generation number + setSpecReplicas(storedCR, getSpecReplicas(storedCR)+1) + if _, _, err := storage.CustomResource.Update(ctx, storedCR.GetName(), rest.DefaultUpdatedObjectInfo(storedCR), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil { + t.Errorf("unexpected error: %v", err) + } + etcdCR, err = storage.CustomResource.Get(ctx, cr.GetName(), &metav1.GetOptions{}) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + storedCR, _ = etcdCR.(*unstructured.Unstructured) + if storedCR.GetGeneration() != 2 { + t.Fatalf("Unexpected generation, spec: %v", storedCR.GetGeneration()) + } + + // Updates to status should not increment the generation number + setStatusReplicas(storedCR, getStatusReplicas(storedCR)+1) + if _, _, err := storage.CustomResource.Update(ctx, storedCR.GetName(), rest.DefaultUpdatedObjectInfo(storedCR), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc); err != nil { + t.Errorf("unexpected error: %v", err) + } + etcdCR, err = storage.CustomResource.Get(ctx, cr.GetName(), &metav1.GetOptions{}) + if err != nil { + t.Errorf("unexpected error: %v", err) + } + storedCR, _ = etcdCR.(*unstructured.Unstructured) + if storedCR.GetGeneration() != 2 { + t.Fatalf("Unexpected generation, spec: %v", storedCR.GetGeneration()) + } + +} + func TestCategories(t *testing.T) { storage, server := newStorage(t) defer server.Terminate(t) @@ -398,3 +456,34 @@ func (c unstructuredJsonCodec) Encode(obj runtime.Object, w io.Writer) error { w.Write(bs) return nil } + +func setSpecReplicas(u *unstructured.Unstructured, replicas int64) { + setNestedField(u, replicas, "spec", "replicas") +} + +func getSpecReplicas(u *unstructured.Unstructured) int64 { + val, found, err := unstructured.NestedInt64(u.Object, "spec", "replicas") + if !found || err != nil { + return 0 + } + return val +} + +func setStatusReplicas(u *unstructured.Unstructured, replicas int64) { + setNestedField(u, replicas, "status", "replicas") +} + +func getStatusReplicas(u *unstructured.Unstructured) int64 { + val, found, err := unstructured.NestedInt64(u.Object, "status", "replicas") + if !found || err != nil { + return 0 + } + return val +} + +func setNestedField(u *unstructured.Unstructured, value interface{}, fields ...string) { + if u.Object == nil { + u.Object = make(map[string]interface{}) + } + unstructured.SetNestedField(u.Object, value, fields...) +}