github.com/IBM-Blockchain/fabric-operator@v1.0.4/controllers/ibporderer/predicate_test.go (about) 1 /* 2 * Copyright contributors to the Hyperledger Fabric Operator project 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at: 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package ibporderer 20 21 import ( 22 "context" 23 "encoding/json" 24 "fmt" 25 "sync" 26 27 . "github.com/onsi/ginkgo/v2" 28 . "github.com/onsi/gomega" 29 30 current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1" 31 orderermocks "github.com/IBM-Blockchain/fabric-operator/controllers/ibporderer/mocks" 32 "github.com/IBM-Blockchain/fabric-operator/controllers/mocks" 33 v1 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/orderer/v1" 34 config "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/orderer/config/v1" 35 corev1 "k8s.io/api/core/v1" 36 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 37 "k8s.io/apimachinery/pkg/runtime" 38 "k8s.io/apimachinery/pkg/types" 39 "sigs.k8s.io/controller-runtime/pkg/client" 40 "sigs.k8s.io/controller-runtime/pkg/event" 41 yaml "sigs.k8s.io/yaml" 42 ) 43 44 var _ = Describe("predicate", func() { 45 var ( 46 reconciler *ReconcileIBPOrderer 47 instance *current.IBPOrderer 48 mockKubeClient *mocks.Client 49 mockOrdererReconcile *orderermocks.OrdererReconcile 50 ) 51 52 BeforeEach(func() { 53 mockKubeClient = &mocks.Client{ 54 ListStub: func(ctx context.Context, obj client.ObjectList, opts ...client.ListOption) error { 55 switch obj.(type) { 56 case *corev1.NodeList: 57 nodeList := obj.(*corev1.NodeList) 58 node := corev1.Node{} 59 node.Labels = map[string]string{} 60 node.Labels["topology.kubernetes.io/zone"] = "dal" 61 node.Labels["topology.kubernetes.io/region"] = "us-south" 62 nodeList.Items = append(nodeList.Items, node) 63 case *current.IBPOrdererList: 64 ordererList := obj.(*current.IBPOrdererList) 65 o1 := current.IBPOrderer{} 66 o1.Name = "test-orderer1" 67 o2 := current.IBPOrderer{} 68 o2.Name = "test-orderer2" 69 o3 := current.IBPOrderer{} 70 o3.Name = "test-orderer2" 71 ordererList.Items = []current.IBPOrderer{o1, o2, o3} 72 } 73 return nil 74 }, 75 } 76 77 mockOrdererReconcile = &orderermocks.OrdererReconcile{} 78 nodeNumber := 1 79 instance = ¤t.IBPOrderer{ 80 Spec: current.IBPOrdererSpec{ 81 ClusterSize: 3, 82 NodeNumber: &nodeNumber, 83 }, 84 } 85 86 reconciler = &ReconcileIBPOrderer{ 87 Offering: mockOrdererReconcile, 88 client: mockKubeClient, 89 scheme: &runtime.Scheme{}, 90 update: map[string][]Update{}, 91 mutex: &sync.Mutex{}, 92 } 93 }) 94 95 Context("create func predicate", func() { 96 var ( 97 orderer *current.IBPOrderer 98 e event.CreateEvent 99 ) 100 101 BeforeEach(func() { 102 orderer = ¤t.IBPOrderer{ 103 ObjectMeta: metav1.ObjectMeta{ 104 Name: instance.GetName(), 105 }, 106 Status: current.IBPOrdererStatus{ 107 CRStatus: current.CRStatus{ 108 Type: current.Deployed, 109 }, 110 }, 111 } 112 e = event.CreateEvent{ 113 Object: orderer, 114 } 115 }) 116 117 It("sets update flags to false if instance has status type and a create event is detected but no spec changes are detected", func() { 118 create := reconciler.CreateFunc(e) 119 Expect(create).To(Equal(true)) 120 121 Expect(reconciler.GetUpdateStatus(instance)).To(Equal(&Update{ 122 specUpdated: false, 123 overridesUpdated: false, 124 })) 125 }) 126 127 It("sets update flags to true if instance has status type and a create event is detected and spec changes detected", func() { 128 configOverride := &config.Orderer{ 129 Orderer: v1.Orderer{ 130 General: v1.General{ 131 LedgerType: "type1", 132 }, 133 }, 134 } 135 configBytes, err := json.Marshal(configOverride) 136 Expect(err).NotTo(HaveOccurred()) 137 spec := current.IBPOrdererSpec{ 138 ImagePullSecrets: []string{"pullsecret1"}, 139 ConfigOverride: &runtime.RawExtension{Raw: configBytes}, 140 } 141 binaryData, err := yaml.Marshal(spec) 142 Expect(err).NotTo(HaveOccurred()) 143 144 mockKubeClient.GetStub = func(ctx context.Context, types types.NamespacedName, obj client.Object) error { 145 switch obj.(type) { 146 case *corev1.ConfigMap: 147 o := obj.(*corev1.ConfigMap) 148 o.BinaryData = map[string][]byte{ 149 "spec": binaryData, 150 } 151 } 152 return nil 153 } 154 create := reconciler.CreateFunc(e) 155 Expect(create).To(Equal(true)) 156 157 Expect(reconciler.GetUpdateStatus(instance)).To(Equal(&Update{ 158 specUpdated: true, 159 overridesUpdated: true, 160 })) 161 }) 162 163 It("does not trigger update if instance does not have status type and a create event is detected", func() { 164 orderer.Status.Type = "" 165 166 create := reconciler.CreateFunc(e) 167 Expect(create).To(Equal(true)) 168 169 Expect(reconciler.GetUpdateStatus(instance)).To(Equal(&Update{})) 170 }) 171 172 It("returns true but does not trigger update if new instance's name is unique to one IBPOrderer in list of IBPOrderers", func() { 173 orderer.Status.Type = "" 174 orderer.Name = "test-orderer1" 175 176 create := reconciler.CreateFunc(e) 177 Expect(create).To(Equal(true)) 178 Expect(reconciler.GetUpdateStatus(instance)).To(Equal(&Update{})) 179 }) 180 181 It("returns false if new instance's name already exists for another IBPOrderer custom resource", func() { 182 orderer.Status.Type = "" 183 orderer.Name = "test-orderer2" 184 185 create := reconciler.CreateFunc(e) 186 Expect(create).To(Equal(false)) 187 Expect(orderer.Status.Type).To(Equal(current.Error)) 188 }) 189 190 Context("secret created", func() { 191 var ( 192 cert *corev1.Secret 193 e event.CreateEvent 194 ) 195 196 BeforeEach(func() { 197 cert = &corev1.Secret{ 198 ObjectMeta: metav1.ObjectMeta{ 199 OwnerReferences: []metav1.OwnerReference{ 200 {Name: instance.Name, 201 Kind: "IBPOrderer"}, 202 }, 203 }, 204 } 205 e = event.CreateEvent{} 206 }) 207 208 It("sets update flags to true if create event is detected for secret and secret is a TLS signcert", func() { 209 cert.Name = fmt.Sprintf("tls-%s-signcert", instance.Name) 210 e.Object = cert 211 create := reconciler.CreateFunc(e) 212 Expect(create).To(Equal(true)) 213 214 Expect(reconciler.GetUpdateStatus(instance)).To(Equal(&Update{ 215 tlsCertCreated: true, 216 })) 217 }) 218 219 It("sets update flags to true if create event is detected for secret and secret is an ecert signcert", func() { 220 cert.Name = fmt.Sprintf("ecert-%s-signcert", instance.Name) 221 e.Object = cert 222 create := reconciler.CreateFunc(e) 223 Expect(create).To(Equal(true)) 224 225 Expect(reconciler.GetUpdateStatus(instance)).To(Equal(&Update{ 226 ecertCreated: true, 227 })) 228 }) 229 230 It("does not set update flags and doesn't trigger create event if create event is detected for secret and secret is not a signcert", func() { 231 cert.Name = fmt.Sprintf("tls-%s-admincert", instance.Name) 232 e.Object = cert 233 create := reconciler.CreateFunc(e) 234 Expect(create).To(Equal(false)) 235 236 Expect(reconciler.GetUpdateStatus(instance)).To(Equal(&Update{})) 237 }) 238 239 It("does not set update flags and doesn't trigger create event if create event is detected for non-orderer secret", func() { 240 cert.Name = "tls-peer1-signcert" 241 cert.OwnerReferences = nil 242 e.Object = cert 243 create := reconciler.CreateFunc(e) 244 Expect(create).To(Equal(false)) 245 246 Expect(reconciler.GetUpdateStatus(instance)).To(Equal(&Update{})) 247 }) 248 249 It("does not set update flags if create event is detected for secret with non-orderer owner", func() { 250 cert.Name = "tls-peer1-signcert" 251 cert.OwnerReferences[0].Kind = "IBPPeer" 252 e.Object = cert 253 create := reconciler.CreateFunc(e) 254 Expect(create).To(Equal(true)) 255 256 Expect(reconciler.GetUpdateStatus(instance)).To(Equal(&Update{ 257 tlsCertCreated: false, 258 })) 259 }) 260 }) 261 262 Context("remove element", func() { 263 BeforeEach(func() { 264 reconciler.PushUpdate(instance.Name, Update{ 265 overridesUpdated: true, 266 }) 267 268 reconciler.PushUpdate(instance.Name, Update{ 269 specUpdated: true, 270 }) 271 272 Expect(reconciler.GetUpdateStatus(instance).ConfigOverridesUpdated()).To(Equal(true)) 273 Expect(reconciler.GetUpdateStatusAtElement(instance, 1).SpecUpdated()).To(Equal(true)) 274 }) 275 276 It("removes top element", func() { 277 reconciler.PopUpdate(instance.Name) 278 Expect(reconciler.GetUpdateStatus(instance).ConfigOverridesUpdated()).To(Equal(false)) 279 Expect(reconciler.GetUpdateStatus(instance).SpecUpdated()).To(Equal(true)) 280 }) 281 282 It("removing more elements than in slice should not panic", func() { 283 reconciler.PopUpdate(instance.Name) 284 reconciler.PopUpdate(instance.Name) 285 reconciler.PopUpdate(instance.Name) 286 Expect(reconciler.GetUpdateStatus(instance).SpecUpdated()).To(Equal(false)) 287 Expect(reconciler.GetUpdateStatus(instance).ConfigOverridesUpdated()).To(Equal(false)) 288 }) 289 }) 290 }) 291 })