github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/controller/rsm/transformer_status_test.go (about) 1 /* 2 Copyright (C) 2022-2023 ApeCloud Co., Ltd 3 4 This file is part of KubeBlocks project 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU Affero General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU Affero General Public License for more details. 15 16 You should have received a copy of the GNU Affero General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 package rsm 21 22 import ( 23 "context" 24 "time" 25 26 . "github.com/onsi/ginkgo/v2" 27 . "github.com/onsi/gomega" 28 29 "github.com/golang/mock/gomock" 30 apps "k8s.io/api/apps/v1" 31 corev1 "k8s.io/api/core/v1" 32 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 33 "sigs.k8s.io/controller-runtime/pkg/client" 34 35 workloads "github.com/1aal/kubeblocks/apis/workloads/v1alpha1" 36 "github.com/1aal/kubeblocks/pkg/controller/builder" 37 "github.com/1aal/kubeblocks/pkg/controller/model" 38 ) 39 40 var _ = Describe("object status transformer test.", func() { 41 BeforeEach(func() { 42 rsm = builder.NewReplicatedStateMachineBuilder(namespace, name). 43 SetUID(uid). 44 AddMatchLabelsInMap(selectors). 45 SetServiceName(headlessSvcName). 46 SetReplicas(3). 47 SetRoles(roles). 48 SetMembershipReconfiguration(&reconfiguration). 49 SetService(service). 50 GetObject() 51 52 transCtx = &rsmTransformContext{ 53 Context: ctx, 54 Client: graphCli, 55 EventRecorder: nil, 56 Logger: logger, 57 rsmOrig: rsm.DeepCopy(), 58 rsm: rsm, 59 } 60 61 dag = mockDAG() 62 transformer = &ObjectStatusTransformer{} 63 }) 64 65 Context("rsm deletion", func() { 66 It("should return directly", func() { 67 ts := metav1.NewTime(time.Now()) 68 transCtx.rsmOrig.DeletionTimestamp = &ts 69 transCtx.rsm.DeletionTimestamp = &ts 70 Expect(transformer.Transform(transCtx, dag)).Should(Succeed()) 71 dagExpected := mockDAG() 72 Expect(dag.Equals(dagExpected, less)).Should(BeTrue()) 73 }) 74 }) 75 76 Context("rsm update", func() { 77 It("should work well", func() { 78 generation := int64(2) 79 rsm.Generation = generation 80 rsm.Status.ObservedGeneration = generation - 1 81 transCtx.rsmOrig = rsm.DeepCopy() 82 Expect(transformer.Transform(transCtx, dag)).Should(Succeed()) 83 dagExpected := mockDAG() 84 Expect(dag.Equals(dagExpected, less)).Should(BeTrue()) 85 root, err := model.FindRootVertex(dag) 86 Expect(err).Should(BeNil()) 87 Expect(root.Action).ShouldNot(BeNil()) 88 Expect(*root.Action).Should(Equal(model.STATUS)) 89 rsmNew, ok := root.Obj.(*workloads.ReplicatedStateMachine) 90 Expect(ok).Should(BeTrue()) 91 Expect(rsmNew.Generation).Should(Equal(generation)) 92 Expect(rsmNew.Status.ObservedGeneration).Should(Equal(generation)) 93 }) 94 }) 95 96 Context("rsm status update", func() { 97 It("should work well", func() { 98 generation := int64(2) 99 rsm.Generation = generation 100 rsm.Status.ObservedGeneration = generation 101 rsm.Status.UpdateRevision = newRevision 102 transCtx.rsmOrig = rsm.DeepCopy() 103 sts := mockUnderlyingSts(*rsm, 1) 104 k8sMock.EXPECT(). 105 Get(gomock.Any(), gomock.Any(), &apps.StatefulSet{}, gomock.Any()). 106 DoAndReturn(func(_ context.Context, objKey client.ObjectKey, obj *apps.StatefulSet, _ ...client.GetOption) error { 107 Expect(obj).ShouldNot(BeNil()) 108 *obj = *sts 109 return nil 110 }).Times(1) 111 pod0 := builder.NewPodBuilder(namespace, getPodName(rsm.Name, 0)). 112 AddLabels(roleLabelKey, "follower"). 113 GetObject() 114 pod1 := builder.NewPodBuilder(namespace, getPodName(name, 1)). 115 AddLabels(roleLabelKey, "leader"). 116 GetObject() 117 pod2 := builder.NewPodBuilder(namespace, getPodName(name, 2)). 118 AddLabels(roleLabelKey, "follower"). 119 GetObject() 120 makePodUpdateReady(newRevision, pod0, pod1, pod2) 121 k8sMock.EXPECT(). 122 List(gomock.Any(), &corev1.PodList{}, gomock.Any()). 123 DoAndReturn(func(_ context.Context, list *corev1.PodList, _ ...client.ListOption) error { 124 Expect(list).ShouldNot(BeNil()) 125 list.Items = []corev1.Pod{*pod0, *pod1, *pod2} 126 return nil 127 }).Times(1) 128 Expect(transformer.Transform(transCtx, dag)).Should(Succeed()) 129 dagExpected := mockDAG() 130 Expect(dag.Equals(dagExpected, less)).Should(BeTrue()) 131 root, err := model.FindRootVertex(dag) 132 Expect(err).Should(BeNil()) 133 Expect(root.Action).ShouldNot(BeNil()) 134 Expect(*root.Action).Should(Equal(model.STATUS)) 135 rsmNew, ok := root.Obj.(*workloads.ReplicatedStateMachine) 136 Expect(ok).Should(BeTrue()) 137 Expect(rsmNew.Status.ObservedGeneration).Should(Equal(generation)) 138 // the only difference between rsm.status.StatefulSetStatus and sts.status is ObservedGeneration 139 // for less coding 140 rsmNew.Status.ObservedGeneration = sts.Status.ObservedGeneration 141 Expect(rsmNew.Status.StatefulSetStatus).Should(Equal(sts.Status)) 142 pods := []*corev1.Pod{pod0, pod1, pod2} 143 for _, pod := range pods { 144 matched := false 145 for _, status := range rsmNew.Status.MembersStatus { 146 if status.PodName == pod.Name && status.ReplicaRole.Name == pod.Labels[roleLabelKey] { 147 matched = true 148 } 149 } 150 Expect(matched).Should(BeTrue()) 151 } 152 }) 153 }) 154 })