github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/controller/rsm/suite_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 "testing" 25 26 . "github.com/onsi/ginkgo/v2" 27 . "github.com/onsi/gomega" 28 29 "github.com/go-logr/logr" 30 "github.com/golang/mock/gomock" 31 apps "k8s.io/api/apps/v1" 32 corev1 "k8s.io/api/core/v1" 33 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 34 "k8s.io/apimachinery/pkg/types" 35 "k8s.io/apimachinery/pkg/util/intstr" 36 logf "sigs.k8s.io/controller-runtime/pkg/log" 37 38 workloads "github.com/1aal/kubeblocks/apis/workloads/v1alpha1" 39 "github.com/1aal/kubeblocks/pkg/constant" 40 "github.com/1aal/kubeblocks/pkg/controller/builder" 41 "github.com/1aal/kubeblocks/pkg/controller/graph" 42 "github.com/1aal/kubeblocks/pkg/controller/model" 43 testutil "github.com/1aal/kubeblocks/pkg/testutil/k8s" 44 "github.com/1aal/kubeblocks/pkg/testutil/k8s/mocks" 45 ) 46 47 var ( 48 controller *gomock.Controller 49 k8sMock *mocks.MockClient 50 graphCli model.GraphClient 51 ctx context.Context 52 logger logr.Logger 53 transCtx *rsmTransformContext 54 dag *graph.DAG 55 transformer graph.Transformer 56 ) 57 58 const ( 59 namespace = "foo" 60 name = "bar" 61 oldRevision = "old-revision" 62 newRevision = "new-revision" 63 ) 64 65 var ( 66 uid = types.UID("rsm-mock-uid") 67 68 selectors = map[string]string{ 69 constant.AppInstanceLabelKey: name, 70 workloadsManagedByLabelKey: kindReplicatedStateMachine, 71 } 72 73 headlessSvcName = name + "-headless" 74 75 roles = []workloads.ReplicaRole{ 76 { 77 Name: "leader", 78 IsLeader: true, 79 CanVote: true, 80 AccessMode: workloads.ReadWriteMode, 81 }, 82 { 83 Name: "follower", 84 IsLeader: false, 85 CanVote: true, 86 AccessMode: workloads.ReadonlyMode, 87 }, 88 { 89 Name: "logger", 90 IsLeader: false, 91 CanVote: true, 92 AccessMode: workloads.NoneMode, 93 }, 94 { 95 Name: "learner", 96 IsLeader: false, 97 CanVote: false, 98 AccessMode: workloads.ReadonlyMode, 99 }, 100 } 101 102 roleProbe = &workloads.RoleProbe{ 103 CustomHandler: []workloads.Action{{Command: []string{"cmd"}}}, 104 } 105 106 reconfiguration = workloads.MembershipReconfiguration{ 107 SwitchoverAction: &workloads.Action{Command: []string{"cmd"}}, 108 MemberJoinAction: &workloads.Action{Command: []string{"cmd"}}, 109 MemberLeaveAction: &workloads.Action{Command: []string{"cmd"}}, 110 } 111 112 service = &corev1.Service{ 113 ObjectMeta: metav1.ObjectMeta{ 114 Labels: map[string]string{ 115 constant.AppManagedByLabelKey: constant.AppName, 116 constant.AppNameLabelKey: "foo-cluster-definition", 117 constant.AppInstanceLabelKey: "foo-cluster", 118 constant.KBAppComponentLabelKey: name, 119 constant.AppComponentLabelKey: name + "def", 120 }, 121 }, 122 Spec: corev1.ServiceSpec{ 123 Ports: []corev1.ServicePort{ 124 { 125 Name: "svc", 126 Protocol: corev1.ProtocolTCP, 127 Port: 12345, 128 TargetPort: intstr.FromString("my-svc"), 129 }, 130 }, 131 }, 132 } 133 134 credential = workloads.Credential{ 135 Username: workloads.CredentialVar{Value: "foo"}, 136 Password: workloads.CredentialVar{Value: "bar"}, 137 } 138 139 pod = builder.NewPodBuilder(namespace, getPodName(name, 0)). 140 AddContainer(corev1.Container{ 141 Name: "foo", 142 Image: "bar", 143 Ports: []corev1.ContainerPort{ 144 { 145 Name: "my-svc", 146 Protocol: corev1.ProtocolTCP, 147 ContainerPort: 12345, 148 }, 149 }, 150 }).GetObject() 151 template = corev1.PodTemplateSpec{ 152 ObjectMeta: pod.ObjectMeta, 153 Spec: pod.Spec, 154 } 155 156 observeActions = []workloads.Action{{Command: []string{"cmd"}}} 157 158 rsm *workloads.ReplicatedStateMachine 159 ) 160 161 func less(v1, v2 graph.Vertex) bool { 162 return model.DefaultLess(v1, v2) 163 } 164 165 func makePodUpdateReady(newRevision string, pods ...*corev1.Pod) { 166 readyCondition := corev1.PodCondition{ 167 Type: corev1.PodReady, 168 Status: corev1.ConditionTrue, 169 } 170 for _, pod := range pods { 171 pod.Labels[apps.StatefulSetRevisionLabel] = newRevision 172 if pod.Labels[roleLabelKey] == "" { 173 pod.Labels[roleLabelKey] = "learner" 174 } 175 pod.Status.Conditions = append(pod.Status.Conditions, readyCondition) 176 } 177 } 178 179 func mockUnderlyingSts(rsm workloads.ReplicatedStateMachine, generation int64) *apps.StatefulSet { 180 headLessSvc := buildHeadlessSvc(rsm) 181 envConfig := buildEnvConfigMap(rsm) 182 sts := buildSts(rsm, headLessSvc.Name, *envConfig) 183 sts.Generation = generation 184 sts.Status.ObservedGeneration = generation 185 sts.Status.Replicas = *sts.Spec.Replicas 186 sts.Status.ReadyReplicas = sts.Status.Replicas 187 sts.Status.AvailableReplicas = sts.Status.ReadyReplicas 188 sts.Status.UpdatedReplicas = sts.Status.ReadyReplicas 189 sts.Status.UpdateRevision = rsm.Status.UpdateRevision 190 return sts 191 } 192 193 func mockDAG() *graph.DAG { 194 d := graph.NewDAG() 195 graphCli.Root(d, transCtx.rsmOrig, transCtx.rsm, model.ActionStatusPtr()) 196 return d 197 } 198 199 func init() { 200 model.AddScheme(workloads.AddToScheme) 201 } 202 203 // These tests use Ginkgo (BDD-style Go testing framework). Refer to 204 // http://onsi.github.io/ginkgo/ to learn more about Ginkgo. 205 206 func TestAPIs(t *testing.T) { 207 RegisterFailHandler(Fail) 208 209 RunSpecs(t, "ReplicatedStateMachine Suite") 210 } 211 212 var _ = BeforeSuite(func() { 213 controller, k8sMock = testutil.SetupK8sMock() 214 graphCli = model.NewGraphClient(k8sMock) 215 ctx = context.Background() 216 logger = logf.FromContext(ctx).WithValues("rsm-test", namespace) 217 218 go func() { 219 defer GinkgoRecover() 220 }() 221 }) 222 223 var _ = AfterSuite(func() { 224 controller.Finish() 225 })