github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/testutil/k8s/rsm_util.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 testutil 21 22 import ( 23 "fmt" 24 "reflect" 25 "strings" 26 27 "github.com/onsi/gomega" 28 appsv1 "k8s.io/api/apps/v1" 29 corev1 "k8s.io/api/core/v1" 30 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 31 "k8s.io/apimachinery/pkg/types" 32 "sigs.k8s.io/controller-runtime/pkg/client" 33 34 workloads "github.com/1aal/kubeblocks/apis/workloads/v1alpha1" 35 "github.com/1aal/kubeblocks/pkg/constant" 36 "github.com/1aal/kubeblocks/pkg/testutil" 37 testapps "github.com/1aal/kubeblocks/pkg/testutil/apps" 38 ) 39 40 // NewFakeRSM creates a fake RSM workload object for testing. 41 func NewFakeRSM(name string, replicas int) *workloads.ReplicatedStateMachine { 42 template := corev1.PodTemplateSpec{ 43 Spec: corev1.PodSpec{ 44 Containers: []corev1.Container{ 45 { 46 Name: "nginx", 47 Image: "nginx", 48 }, 49 }, 50 }, 51 } 52 53 template.Labels = map[string]string{"foo": "bar"} 54 rsmReplicas := int32(replicas) 55 Revision := name + "-d5df5b8d6" 56 return &workloads.ReplicatedStateMachine{ 57 ObjectMeta: metav1.ObjectMeta{ 58 Name: name, 59 Namespace: corev1.NamespaceDefault, 60 }, 61 Spec: workloads.ReplicatedStateMachineSpec{ 62 Selector: &metav1.LabelSelector{ 63 MatchLabels: map[string]string{"foo": "bar"}, 64 }, 65 Replicas: &rsmReplicas, 66 Template: template, 67 ServiceName: "governingsvc", 68 }, 69 Status: workloads.ReplicatedStateMachineStatus{ 70 InitReplicas: rsmReplicas, 71 StatefulSetStatus: appsv1.StatefulSetStatus{ 72 AvailableReplicas: rsmReplicas, 73 ObservedGeneration: 0, 74 ReadyReplicas: rsmReplicas, 75 UpdatedReplicas: rsmReplicas, 76 CurrentRevision: Revision, 77 UpdateRevision: Revision, 78 }, 79 }, 80 } 81 } 82 83 // NewFakeRSMPod creates a fake pod of the RSM workload for testing. 84 func NewFakeRSMPod(rsm *workloads.ReplicatedStateMachine, ordinal int) *corev1.Pod { 85 pod := &corev1.Pod{} 86 pod.Name = fmt.Sprintf("%s-%d", rsm.Name, ordinal) 87 return pod 88 } 89 90 // MockRSMReady mocks the RSM workload to ready state. 91 func MockRSMReady(rsm *workloads.ReplicatedStateMachine, pods ...*corev1.Pod) { 92 rsm.Status.InitReplicas = *rsm.Spec.Replicas 93 rsm.Status.ReadyInitReplicas = *rsm.Spec.Replicas 94 rsm.Status.AvailableReplicas = *rsm.Spec.Replicas 95 rsm.Status.ObservedGeneration = rsm.Generation 96 rsm.Status.CurrentGeneration = rsm.Generation 97 rsm.Status.Replicas = *rsm.Spec.Replicas 98 rsm.Status.ReadyReplicas = *rsm.Spec.Replicas 99 rsm.Status.CurrentRevision = rsm.Status.UpdateRevision 100 rsm.Status.UpdatedReplicas = rsm.Status.Replicas 101 102 composeRoleMap := func(rsm workloads.ReplicatedStateMachine) map[string]workloads.ReplicaRole { 103 roleMap := make(map[string]workloads.ReplicaRole, 0) 104 for _, role := range rsm.Spec.Roles { 105 roleMap[strings.ToLower(role.Name)] = role 106 } 107 return roleMap 108 } 109 var membersStatus []workloads.MemberStatus 110 roleMap := composeRoleMap(*rsm) 111 for _, pod := range pods { 112 roleName := strings.ToLower(pod.Labels[constant.RoleLabelKey]) 113 role, ok := roleMap[roleName] 114 if !ok { 115 continue 116 } 117 memberStatus := workloads.MemberStatus{ 118 PodName: pod.Name, 119 ReplicaRole: role, 120 } 121 membersStatus = append(membersStatus, memberStatus) 122 } 123 rsm.Status.MembersStatus = membersStatus 124 } 125 126 func ListAndCheckRSM(testCtx *testutil.TestContext, key types.NamespacedName) *workloads.ReplicatedStateMachineList { 127 rsmList := &workloads.ReplicatedStateMachineList{} 128 gomega.Eventually(func(g gomega.Gomega) { 129 g.Expect(testCtx.Cli.List(testCtx.Ctx, rsmList, client.MatchingLabels{ 130 constant.AppInstanceLabelKey: key.Name, 131 }, client.InNamespace(key.Namespace))).Should(gomega.Succeed()) 132 g.Expect(rsmList.Items).ShouldNot(gomega.BeNil()) 133 g.Expect(rsmList.Items).ShouldNot(gomega.BeEmpty()) 134 }).Should(gomega.Succeed()) 135 return rsmList 136 } 137 138 func ListAndCheckRSMItemsCount(testCtx *testutil.TestContext, key types.NamespacedName, cnt int) *workloads.ReplicatedStateMachineList { 139 rsmList := &workloads.ReplicatedStateMachineList{} 140 gomega.Eventually(func(g gomega.Gomega) { 141 g.Expect(testCtx.Cli.List(testCtx.Ctx, rsmList, client.MatchingLabels{ 142 constant.AppInstanceLabelKey: key.Name, 143 }, client.InNamespace(key.Namespace))).Should(gomega.Succeed()) 144 g.Expect(len(rsmList.Items)).Should(gomega.Equal(cnt)) 145 }).Should(gomega.Succeed()) 146 return rsmList 147 } 148 149 func ListAndCheckRSMWithComponent(testCtx *testutil.TestContext, key types.NamespacedName, componentName string) *workloads.ReplicatedStateMachineList { 150 rsmList := &workloads.ReplicatedStateMachineList{} 151 gomega.Eventually(func(g gomega.Gomega) { 152 g.Expect(testCtx.Cli.List(testCtx.Ctx, rsmList, client.MatchingLabels{ 153 constant.AppInstanceLabelKey: key.Name, 154 constant.KBAppComponentLabelKey: componentName, 155 }, client.InNamespace(key.Namespace))).Should(gomega.Succeed()) 156 g.Expect(rsmList.Items).ShouldNot(gomega.BeNil()) 157 g.Expect(rsmList.Items).ShouldNot(gomega.BeEmpty()) 158 }).Should(gomega.Succeed()) 159 return rsmList 160 } 161 162 func PatchRSMStatus(testCtx *testutil.TestContext, stsName string, status workloads.ReplicatedStateMachineStatus) { 163 objectKey := client.ObjectKey{Name: stsName, Namespace: testCtx.DefaultNamespace} 164 gomega.Expect(testapps.GetAndChangeObjStatus(testCtx, objectKey, func(newRSM *workloads.ReplicatedStateMachine) { 165 newRSM.Status = status 166 })()).Should(gomega.Succeed()) 167 gomega.Eventually(testapps.CheckObj(testCtx, objectKey, func(g gomega.Gomega, newRSM *workloads.ReplicatedStateMachine) { 168 g.Expect(reflect.DeepEqual(newRSM.Status, status)).Should(gomega.BeTrue()) 169 })).Should(gomega.Succeed()) 170 } 171 172 func InitRSMStatus(testCtx testutil.TestContext, rsm *workloads.ReplicatedStateMachine, controllerRevision string) { 173 gomega.Expect(testapps.ChangeObjStatus(&testCtx, rsm, func() { 174 rsm.Status.InitReplicas = *rsm.Spec.Replicas 175 rsm.Status.Replicas = *rsm.Spec.Replicas 176 rsm.Status.UpdateRevision = controllerRevision 177 rsm.Status.CurrentRevision = controllerRevision 178 rsm.Status.ObservedGeneration = rsm.Generation 179 rsm.Status.CurrentGeneration = rsm.Generation 180 })).Should(gomega.Succeed()) 181 }