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 = &current.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 = &current.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  })