From 0faadb890edc2f1e4afc0cb6f087ae2aac933a49 Mon Sep 17 00:00:00 2001 From: wu8685 Date: Wed, 15 Nov 2023 17:21:21 +0800 Subject: [PATCH] test: add some tests for expectation --- .../expectations/active_expectation_test.go | 74 +++++++++--- .../utils/expectations/expectation_test.go | 107 ++++++++++++++++++ .../resourceversion_expectation_test.go | 20 ++-- .../collaset_mutating_handler_test.go | 49 ++++++++ 4 files changed, 225 insertions(+), 25 deletions(-) create mode 100644 pkg/controllers/utils/expectations/expectation_test.go create mode 100644 pkg/webhook/server/generic/collaset/collaset_mutating_handler_test.go diff --git a/pkg/controllers/utils/expectations/active_expectation_test.go b/pkg/controllers/utils/expectations/active_expectation_test.go index c995fca9..d8947b1f 100644 --- a/pkg/controllers/utils/expectations/active_expectation_test.go +++ b/pkg/controllers/utils/expectations/active_expectation_test.go @@ -17,6 +17,7 @@ limitations under the License. package expectations import ( + "fmt" "testing" "time" @@ -95,11 +96,18 @@ func TestActiveExpectations(t *testing.T) { }, } g.Expect(client.Create(context.TODO(), podB)).Should(gomega.BeNil()) - time.Sleep(3 * time.Second) - - sa, err = exp.IsSatisfied(pod) - g.Expect(err).Should(gomega.BeNil()) - g.Expect(sa).Should(gomega.BeTrue()) + g.Eventually(func() error { + sa, err = exp.IsSatisfied(pod) + if err != nil { + return err + } + + if !sa { + return fmt.Errorf("expectation unsatisfied") + } + + return nil + }, 5*time.Second, 1*time.Second).Should(gomega.BeNil()) expectation, err = exp.GetExpectation(pod.Namespace, pod.Name) g.Expect(err).Should(gomega.BeNil()) g.Expect(expectation).Should(gomega.BeNil()) @@ -109,12 +117,25 @@ func TestActiveExpectations(t *testing.T) { "test": "test", } g.Expect(client.Update(context.TODO(), podB)).Should(gomega.BeNil()) - exp.ExpectUpdate(pod, Pod, pod.Name, pod.ResourceVersion) - time.Sleep(3 * time.Second) - - sa, err = exp.IsSatisfied(pod) - g.Expect(err).Should(gomega.BeNil()) - g.Expect(sa).Should(gomega.BeTrue()) + g.Expect(exp.ExpectUpdate(pod, Pod, pod.Name, pod.ResourceVersion)).Should(gomega.BeNil()) + // update twice + podB.Labels = map[string]string{ + "test": "foo", + } + g.Expect(client.Update(context.TODO(), podB)).Should(gomega.BeNil()) + g.Expect(exp.ExpectUpdate(pod, Pod, pod.Name, pod.ResourceVersion)).Should(gomega.BeNil()) + g.Eventually(func() error { + sa, err = exp.IsSatisfied(pod) + if err != nil { + return err + } + + if !sa { + return fmt.Errorf("expectation unsatisfied") + } + + return nil + }, 5*time.Second, 1*time.Second).Should(gomega.BeNil()) expectation, err = exp.GetExpectation(pod.Namespace, pod.Name) g.Expect(err).Should(gomega.BeNil()) g.Expect(expectation).Should(gomega.BeNil()) @@ -136,11 +157,18 @@ func TestActiveExpectations(t *testing.T) { g.Expect(len(expectation.items.List())).Should(gomega.BeEquivalentTo(1)) g.Expect(client.Delete(context.TODO(), podB)).Should(gomega.BeNil()) - time.Sleep(3 * time.Second) - - sa, err = exp.IsSatisfied(pod) - g.Expect(err).Should(gomega.BeNil()) - g.Expect(sa).Should(gomega.BeTrue()) + g.Eventually(func() error { + sa, err = exp.IsSatisfied(pod) + if err != nil { + return err + } + + if !sa { + return fmt.Errorf("expectation unsatisfied") + } + + return nil + }, 5*time.Second, 1*time.Second).Should(gomega.BeNil()) expectation, err = exp.GetExpectation(pod.Namespace, pod.Name) g.Expect(err).Should(gomega.BeNil()) g.Expect(expectation).Should(gomega.BeNil()) @@ -150,4 +178,18 @@ func TestActiveExpectations(t *testing.T) { expectation, err = exp.GetExpectation(pod.Namespace, pod.Name) g.Expect(err).Should(gomega.BeNil()) g.Expect(expectation).Should(gomega.BeNil()) + + g.Expect(exp.ExpectCreate(pod, Pod, podA.Name)).Should(gomega.BeNil()) + g.Expect(exp.IsSatisfied(pod)).Should(gomega.BeFalse()) + g.Expect(exp.DeleteItem(pod, Pod, podA.Name)).Should(gomega.BeNil()) + g.Expect(exp.IsSatisfied(pod)).Should(gomega.BeTrue()) + // delete no existing item should not get error + g.Expect(exp.DeleteItem(pod, Pod, podA.Name)).Should(gomega.BeNil()) +} + +func TestActiveExpectationsForAllKinds(t *testing.T) { + g := gomega.NewGomegaWithT(t) + for kind, newFn := range ResourceInitializers { + g.Expect(newFn()).ShouldNot(gomega.BeNil(), fmt.Sprintf("check initializer for kind %s", kind)) + } } diff --git a/pkg/controllers/utils/expectations/expectation_test.go b/pkg/controllers/utils/expectations/expectation_test.go new file mode 100644 index 00000000..8faa6290 --- /dev/null +++ b/pkg/controllers/utils/expectations/expectation_test.go @@ -0,0 +1,107 @@ +/* +Copyright 2023 The KusionStack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package expectations + +import ( + "testing" + + "github.com/onsi/gomega" +) + +func TestExpectation(t *testing.T) { + g := gomega.NewGomegaWithT(t) + key := "test/foo" + exp := NewControllerExpectations("test") + ex, exist, err := exp.GetExpectations(key) + g.Expect(err).Should(gomega.BeNil()) + g.Expect(exist).Should(gomega.BeFalse()) + g.Expect(ex).Should(gomega.BeNil()) + + g.Expect(exp.InitExpectations(key)).Should(gomega.BeNil()) + ex, exist, err = exp.GetExpectations(key) + g.Expect(err).Should(gomega.BeNil()) + g.Expect(exist).Should(gomega.BeTrue()) + g.Expect(ex).ShouldNot(gomega.BeNil()) + add, del := ex.GetExpectations() + g.Expect(add).Should(gomega.BeEquivalentTo(0)) + g.Expect(del).Should(gomega.BeEquivalentTo(0)) + + testcases := []struct { + add int + del int + expectedAdd int + expectedDel int + }{ + { + add: 1, + del: 1, + expectedAdd: 1, + expectedDel: 1, + }, + { + add: -1, + del: -1, + expectedAdd: 0, + expectedDel: 0, + }, + { + add: -1, + del: -1, + expectedAdd: -1, + expectedDel: -1, + }, + } + + for _, testcase := range testcases { + exp.RaiseExpectations(key, testcase.add, testcase.del) + ex, exist, err = exp.GetExpectations(key) + g.Expect(err).Should(gomega.BeNil()) + g.Expect(exist).Should(gomega.BeTrue()) + g.Expect(ex).ShouldNot(gomega.BeNil()) + add, del = ex.GetExpectations() + g.Expect(add).Should(gomega.BeEquivalentTo(testcase.expectedAdd)) + g.Expect(del).Should(gomega.BeEquivalentTo(testcase.expectedDel)) + } + + exp.DeleteExpectations(key) + ex, exist, err = exp.GetExpectations(key) + g.Expect(err).Should(gomega.BeNil()) + g.Expect(exist).Should(gomega.BeFalse()) + g.Expect(ex).Should(gomega.BeNil()) + g.Expect(exp.SatisfiedExpectations(key)).Should(gomega.BeTrue()) +} + +func TestExpectationSatisfied(t *testing.T) { + g := gomega.NewGomegaWithT(t) + key := "test/foo" + exp := NewControllerExpectations("test") + g.Expect(exp.InitExpectations(key)).Should(gomega.BeNil()) + + g.Expect(exp.ExpectCreations(key, 2)).Should(gomega.BeNil()) + exp.CreationObserved(key) + g.Expect(exp.SatisfiedExpectations(key)).Should(gomega.BeFalse()) + exp.CreationObserved(key) + g.Expect(exp.SatisfiedExpectations(key)).Should(gomega.BeTrue()) + + g.Expect(exp.ExpectDeletions(key, 2)).Should(gomega.BeNil()) + exp.CreationObserved(key) + g.Expect(exp.SatisfiedExpectations(key)).Should(gomega.BeFalse()) + exp.DeletionObserved(key) + g.Expect(exp.SatisfiedExpectations(key)).Should(gomega.BeFalse()) + exp.DeletionObserved(key) + g.Expect(exp.SatisfiedExpectations(key)).Should(gomega.BeTrue()) +} diff --git a/pkg/controllers/utils/expectations/resourceversion_expectation_test.go b/pkg/controllers/utils/expectations/resourceversion_expectation_test.go index 297a3078..f997dba9 100644 --- a/pkg/controllers/utils/expectations/resourceversion_expectation_test.go +++ b/pkg/controllers/utils/expectations/resourceversion_expectation_test.go @@ -24,30 +24,32 @@ import ( func TestResourceVersionExpectation(t *testing.T) { g := gomega.NewGomegaWithT(t) + key := "test" exp := NewResourceVersionExpectation() - exp.SetExpectations("test", "1") - item, ok, err := exp.GetExpectations("test") + exp.SetExpectations(key, "1") + item, ok, err := exp.GetExpectations(key) g.Expect(err).Should(gomega.BeNil()) g.Expect(ok).Should(gomega.BeTrue()) g.Expect(item.resourceVersion).Should(gomega.Equal(int64(1))) - exp.ExpectUpdate("test", "2") - item, ok, err = exp.GetExpectations("test") + exp.ExpectUpdate(key, "2") + item, ok, err = exp.GetExpectations(key) g.Expect(err).Should(gomega.BeNil()) g.Expect(ok).Should(gomega.BeTrue()) g.Expect(item.resourceVersion).Should(gomega.Equal(int64(2))) - ok = exp.SatisfiedExpectations("test", "1") + ok = exp.SatisfiedExpectations(key, "1") g.Expect(ok).Should(gomega.BeFalse()) - ok = exp.SatisfiedExpectations("test", "2") + ok = exp.SatisfiedExpectations(key, "2") g.Expect(ok).Should(gomega.BeFalse()) - ok = exp.SatisfiedExpectations("test", "3") + ok = exp.SatisfiedExpectations(key, "3") g.Expect(ok).Should(gomega.BeTrue()) - exp.DeleteExpectations("test") - item, ok, err = exp.GetExpectations("test") + exp.DeleteExpectations(key) + item, ok, err = exp.GetExpectations(key) g.Expect(err).Should(gomega.BeNil()) g.Expect(ok).Should(gomega.BeFalse()) g.Expect(item).Should(gomega.BeNil()) + g.Expect(exp.SatisfiedExpectations(key, "1")).Should(gomega.BeTrue()) } diff --git a/pkg/webhook/server/generic/collaset/collaset_mutating_handler_test.go b/pkg/webhook/server/generic/collaset/collaset_mutating_handler_test.go new file mode 100644 index 00000000..888fe2a0 --- /dev/null +++ b/pkg/webhook/server/generic/collaset/collaset_mutating_handler_test.go @@ -0,0 +1,49 @@ +/* +Copyright 2023 The KusionStack Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package collaset + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + appsv1alpha1 "kusionstack.io/operating/apis/apps/v1alpha1" +) + +func TestMutatingCollaSet(t *testing.T) { + cls := &appsv1alpha1.CollaSet{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "default", + }, + Spec: appsv1alpha1.CollaSetSpec{}, + } + + appsv1alpha1.SetDetaultCollaSet(cls) + + if cls.Spec.UpdateStrategy.PodUpdatePolicy != appsv1alpha1.CollaSetInPlaceIfPossiblePodUpdateStrategyType { + t.Fatalf("expected default value is %s, got %s", appsv1alpha1.CollaSetInPlaceIfPossiblePodUpdateStrategyType, + cls.Spec.UpdateStrategy.PodUpdatePolicy) + } + + if cls.Spec.UpdateStrategy.RollingUpdate == nil { + t.Fatalf("expected default rollingUpdate, got nil") + } + + if cls.Spec.UpdateStrategy.RollingUpdate.ByPartition == nil { + t.Fatalf("expected default byPartition, got nil") + } +}