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