github.com/IBM-Blockchain/fabric-operator@v1.0.4/controllers/ibporderer/ibporderer_controller_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  	"errors"
    25  	"fmt"
    26  	"sync"
    27  	"time"
    28  
    29  	. "github.com/onsi/ginkgo/v2"
    30  	. "github.com/onsi/gomega"
    31  	"k8s.io/utils/pointer"
    32  
    33  	current "github.com/IBM-Blockchain/fabric-operator/api/v1beta1"
    34  	orderermocks "github.com/IBM-Blockchain/fabric-operator/controllers/ibporderer/mocks"
    35  	"github.com/IBM-Blockchain/fabric-operator/controllers/mocks"
    36  	v1 "github.com/IBM-Blockchain/fabric-operator/pkg/apis/orderer/v1"
    37  	config "github.com/IBM-Blockchain/fabric-operator/pkg/initializer/orderer/config/v1"
    38  	"github.com/IBM-Blockchain/fabric-operator/pkg/offering/common"
    39  	"github.com/IBM-Blockchain/fabric-operator/pkg/operatorerrors"
    40  	corev1 "k8s.io/api/core/v1"
    41  	k8serror "k8s.io/apimachinery/pkg/api/errors"
    42  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    43  	"k8s.io/apimachinery/pkg/runtime"
    44  	"k8s.io/apimachinery/pkg/types"
    45  	"sigs.k8s.io/controller-runtime/pkg/client"
    46  	"sigs.k8s.io/controller-runtime/pkg/event"
    47  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    48  )
    49  
    50  var _ = Describe("ReconcileIBPOrderer", func() {
    51  	const (
    52  		testRoleBindingFile    = "../../../definitions/orderer/rolebinding.yaml"
    53  		testServiceAccountFile = "../../../definitions/orderer/serviceaccount.yaml"
    54  	)
    55  
    56  	var (
    57  		reconciler           *ReconcileIBPOrderer
    58  		request              reconcile.Request
    59  		mockKubeClient       *mocks.Client
    60  		mockOrdererReconcile *orderermocks.OrdererReconcile
    61  		instance             *current.IBPOrderer
    62  	)
    63  
    64  	BeforeEach(func() {
    65  		mockKubeClient = &mocks.Client{}
    66  		mockOrdererReconcile = &orderermocks.OrdererReconcile{}
    67  		nodeNumber := 1
    68  		instance = &current.IBPOrderer{
    69  			Spec: current.IBPOrdererSpec{
    70  				ClusterSize: 3,
    71  				NodeNumber:  &nodeNumber,
    72  			},
    73  		}
    74  		instance.Name = "test-orderer"
    75  
    76  		mockKubeClient.GetStub = func(ctx context.Context, types types.NamespacedName, obj client.Object) error {
    77  			switch obj.(type) {
    78  			case *current.IBPOrderer:
    79  				o := obj.(*current.IBPOrderer)
    80  				o.Kind = "IBPOrderer"
    81  				o.Name = instance.Name
    82  
    83  				instance.Status = o.Status
    84  			}
    85  			return nil
    86  		}
    87  
    88  		mockKubeClient.UpdateStatusStub = func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
    89  			switch obj.(type) {
    90  			case *current.IBPOrderer:
    91  				o := obj.(*current.IBPOrderer)
    92  				instance.Status = o.Status
    93  			}
    94  			return nil
    95  		}
    96  
    97  		mockKubeClient.ListStub = func(ctx context.Context, obj client.ObjectList, opts ...client.ListOption) error {
    98  			switch obj.(type) {
    99  			case *corev1.NodeList:
   100  				nodeList := obj.(*corev1.NodeList)
   101  				node := corev1.Node{}
   102  				node.Labels = map[string]string{}
   103  				node.Labels["topology.kubernetes.io/zone"] = "dal"
   104  				node.Labels["topology.kubernetes.io/region"] = "us-south"
   105  				nodeList.Items = append(nodeList.Items, node)
   106  			case *current.IBPOrdererList:
   107  				ordererList := obj.(*current.IBPOrdererList)
   108  				o1 := current.IBPOrderer{}
   109  				o1.Name = "test-orderer1"
   110  				o2 := current.IBPOrderer{}
   111  				o2.Name = "test-orderer2"
   112  				o3 := current.IBPOrderer{}
   113  				o3.Name = "test-orderer2"
   114  				ordererList.Items = []current.IBPOrderer{o1, o2, o3}
   115  			}
   116  			return nil
   117  		}
   118  
   119  		reconciler = &ReconcileIBPOrderer{
   120  			Offering: mockOrdererReconcile,
   121  			client:   mockKubeClient,
   122  			scheme:   &runtime.Scheme{},
   123  			update:   map[string][]Update{},
   124  			mutex:    &sync.Mutex{},
   125  		}
   126  		request = reconcile.Request{
   127  			NamespacedName: types.NamespacedName{
   128  				Namespace: "test-namespace",
   129  				Name:      "test",
   130  			},
   131  		}
   132  	})
   133  
   134  	Context("Reconciles", func() {
   135  		It("does not return an error if the custom resource is 'not found'", func() {
   136  			notFoundErr := &k8serror.StatusError{
   137  				ErrStatus: metav1.Status{
   138  					Reason: metav1.StatusReasonNotFound,
   139  				},
   140  			}
   141  			mockKubeClient.GetReturns(notFoundErr)
   142  			_, err := reconciler.Reconcile(context.TODO(), request)
   143  			Expect(err).NotTo(HaveOccurred())
   144  		})
   145  
   146  		It("returns an error if the request to get custom resource return any other error besides 'not found'", func() {
   147  			alreadyExistsErr := &k8serror.StatusError{
   148  				ErrStatus: metav1.Status{
   149  					Message: "already exists",
   150  					Reason:  metav1.StatusReasonAlreadyExists,
   151  				},
   152  			}
   153  			mockKubeClient.GetReturns(alreadyExistsErr)
   154  			_, err := reconciler.Reconcile(context.TODO(), request)
   155  			Expect(err).To(HaveOccurred())
   156  			Expect(err.Error()).To(Equal("already exists"))
   157  		})
   158  
   159  		It("returns an error if it encountered a non-breaking error", func() {
   160  			errMsg := "failed to reconcile deployment encountered breaking error"
   161  			mockOrdererReconcile.ReconcileReturns(common.Result{}, errors.New(errMsg))
   162  			_, err := reconciler.Reconcile(context.TODO(), request)
   163  			Expect(err).To(HaveOccurred())
   164  			Expect(err.Error()).To(Equal(fmt.Sprintf("Orderer instance '%s' encountered error: %s", instance.Name, errMsg)))
   165  		})
   166  
   167  		It("does not return an error if it encountered a breaking error", func() {
   168  			mockOrdererReconcile.ReconcileReturns(common.Result{}, operatorerrors.New(operatorerrors.InvalidDeploymentCreateRequest, "failed to reconcile deployment encountered breaking error"))
   169  			_, err := reconciler.Reconcile(context.TODO(), request)
   170  			Expect(err).NotTo(HaveOccurred())
   171  		})
   172  
   173  		Context("set status", func() {
   174  			It("sets the status to error if error occured during IBPOrderer reconciliation", func() {
   175  				reconciler.SetStatus(instance, nil, errors.New("ibporderer error"))
   176  				Expect(instance.Status.Type).To(Equal(current.Error))
   177  				Expect(instance.Status.Message).To(Equal("ibporderer error"))
   178  			})
   179  
   180  			It("sets the status to deploying if pod is not yet running", func() {
   181  				mockKubeClient.ListStub = func(ctx context.Context, obj client.ObjectList, opts ...client.ListOption) error {
   182  					switch obj.(type) {
   183  					case *corev1.PodList:
   184  						podList := obj.(*corev1.PodList)
   185  						pod := corev1.Pod{}
   186  						podList.Items = append(podList.Items, pod)
   187  						return nil
   188  					case *current.IBPOrdererList:
   189  						ordererList := obj.(*current.IBPOrdererList)
   190  						orderer := current.IBPOrderer{}
   191  						orderer.Status = current.IBPOrdererStatus{
   192  							CRStatus: current.CRStatus{
   193  								Type: current.Deploying,
   194  							},
   195  						}
   196  						ordererList.Items = append(ordererList.Items, orderer)
   197  						return nil
   198  					}
   199  					return nil
   200  				}
   201  
   202  				reconciler.SetStatus(instance, nil, nil)
   203  				Expect(instance.Status.Type).To(Equal(current.Deploying))
   204  			})
   205  
   206  			It("sets the status to deployed if pod is running", func() {
   207  				mockKubeClient.ListStub = func(ctx context.Context, obj client.ObjectList, opts ...client.ListOption) error {
   208  					switch obj.(type) {
   209  					case *corev1.PodList:
   210  						podList := obj.(*corev1.PodList)
   211  						pod := corev1.Pod{
   212  							Status: corev1.PodStatus{
   213  								Phase: corev1.PodRunning,
   214  							},
   215  						}
   216  						podList.Items = append(podList.Items, pod)
   217  
   218  						return nil
   219  					case *current.IBPOrdererList:
   220  						ordererList := obj.(*current.IBPOrdererList)
   221  						orderer := current.IBPOrderer{}
   222  						orderer.Status = current.IBPOrdererStatus{
   223  							CRStatus: current.CRStatus{
   224  								Type: current.Deployed,
   225  							},
   226  						}
   227  						ordererList.Items = append(ordererList.Items, orderer)
   228  						return nil
   229  					}
   230  					return nil
   231  				}
   232  
   233  				instance.Spec.ClusterSize = 1
   234  				reconciler.SetStatus(instance, nil, nil)
   235  				Expect(instance.Status.Type).To(Equal(current.Deployed))
   236  			})
   237  
   238  			It("sets the status to warning if the reconcile loop returns a warning status", func() {
   239  				mockKubeClient.ListStub = func(ctx context.Context, obj client.ObjectList, opts ...client.ListOption) error {
   240  					switch obj.(type) {
   241  					case *corev1.PodList:
   242  						podList := obj.(*corev1.PodList)
   243  						pod := corev1.Pod{
   244  							Status: corev1.PodStatus{
   245  								Phase: corev1.PodRunning,
   246  							},
   247  						}
   248  						podList.Items = append(podList.Items, pod)
   249  
   250  						return nil
   251  					case *current.IBPOrdererList:
   252  						ordererList := obj.(*current.IBPOrdererList)
   253  						orderer := current.IBPOrderer{}
   254  						orderer.Status = current.IBPOrdererStatus{
   255  							CRStatus: current.CRStatus{
   256  								Type: current.Deployed,
   257  							},
   258  						}
   259  						ordererList.Items = append(ordererList.Items, orderer)
   260  						return nil
   261  					}
   262  					return nil
   263  				}
   264  
   265  				result := &common.Result{
   266  					Status: &current.CRStatus{
   267  						Type: current.Warning,
   268  					},
   269  				}
   270  
   271  				instance.Spec.ClusterSize = 1
   272  				reconciler.SetStatus(instance, result, nil)
   273  				Expect(instance.Status.Type).To(Equal(current.Warning))
   274  			})
   275  
   276  			It("persists warning status if the instance is already in warning state and reconcile loop returns a warning status", func() {
   277  				mockKubeClient.ListStub = func(ctx context.Context, obj client.ObjectList, opts ...client.ListOption) error {
   278  					switch obj.(type) {
   279  					case *corev1.PodList:
   280  						podList := obj.(*corev1.PodList)
   281  						pod := corev1.Pod{
   282  							Status: corev1.PodStatus{
   283  								Phase: corev1.PodRunning,
   284  							},
   285  						}
   286  						podList.Items = append(podList.Items, pod)
   287  
   288  						return nil
   289  					case *current.IBPOrdererList:
   290  						ordererList := obj.(*current.IBPOrdererList)
   291  						orderer := current.IBPOrderer{}
   292  						orderer.Status = current.IBPOrdererStatus{
   293  							CRStatus: current.CRStatus{
   294  								Type: current.Deployed,
   295  							},
   296  						}
   297  						ordererList.Items = append(ordererList.Items, orderer)
   298  						return nil
   299  					}
   300  					return nil
   301  				}
   302  
   303  				result := &common.Result{
   304  					Status: &current.CRStatus{
   305  						Type: current.Warning,
   306  					},
   307  				}
   308  
   309  				instance.Spec.ClusterSize = 1
   310  				instance.Status.Type = current.Warning
   311  				reconciler.SetStatus(instance, result, nil)
   312  				Expect(instance.Status.Type).To(Equal(current.Warning))
   313  			})
   314  		})
   315  	})
   316  
   317  	Context("update reconcile", func() {
   318  		var (
   319  			oldOrderer *current.IBPOrderer
   320  			newOrderer *current.IBPOrderer
   321  			oldSecret  *corev1.Secret
   322  			newSecret  *corev1.Secret
   323  			e          event.UpdateEvent
   324  		)
   325  
   326  		BeforeEach(func() {
   327  			configOverride := &config.Orderer{
   328  				Orderer: v1.Orderer{
   329  					General: v1.General{
   330  						LedgerType: "type1",
   331  					},
   332  				},
   333  			}
   334  			configBytes, err := json.Marshal(configOverride)
   335  			Expect(err).NotTo(HaveOccurred())
   336  
   337  			oldOrderer = &current.IBPOrderer{
   338  				ObjectMeta: metav1.ObjectMeta{
   339  					Name: instance.Name,
   340  				},
   341  				Spec: current.IBPOrdererSpec{
   342  					Images: &current.OrdererImages{
   343  						OrdererTag: "1.4.6-20200101",
   344  					},
   345  					ConfigOverride: &runtime.RawExtension{Raw: configBytes},
   346  				},
   347  			}
   348  
   349  			configOverride2 := &config.Orderer{
   350  				Orderer: v1.Orderer{
   351  					General: v1.General{
   352  						LedgerType: "type2",
   353  					},
   354  				},
   355  			}
   356  			configBytes2, err := json.Marshal(configOverride2)
   357  			Expect(err).NotTo(HaveOccurred())
   358  			newOrderer = &current.IBPOrderer{
   359  				ObjectMeta: metav1.ObjectMeta{
   360  					Name: instance.Name,
   361  				},
   362  				Spec: current.IBPOrdererSpec{
   363  					Images: &current.OrdererImages{
   364  						OrdererTag: "1.4.9-2511004",
   365  					},
   366  					ConfigOverride: &runtime.RawExtension{Raw: configBytes2},
   367  				},
   368  			}
   369  
   370  			e = event.UpdateEvent{
   371  				ObjectOld: oldOrderer,
   372  				ObjectNew: newOrderer,
   373  			}
   374  
   375  			Expect(reconciler.UpdateFunc(e)).To(Equal(true))
   376  
   377  			oldOrderer = &current.IBPOrderer{
   378  				ObjectMeta: metav1.ObjectMeta{
   379  					Name: instance.Name,
   380  				},
   381  				Spec: current.IBPOrdererSpec{
   382  					Images: &current.OrdererImages{
   383  						OrdererTag: "1.4.9-2511004",
   384  					},
   385  					MSPID: "old-mspid",
   386  				},
   387  			}
   388  
   389  			newOrderer = &current.IBPOrderer{
   390  				ObjectMeta: metav1.ObjectMeta{
   391  					Name: instance.Name,
   392  				},
   393  				Spec: current.IBPOrdererSpec{
   394  					Images: &current.OrdererImages{
   395  						OrdererTag: "1.4.9-2511004",
   396  					},
   397  					MSPID: "new-mspid",
   398  				},
   399  			}
   400  
   401  			e = event.UpdateEvent{
   402  				ObjectOld: oldOrderer,
   403  				ObjectNew: newOrderer,
   404  			}
   405  
   406  			Expect(reconciler.UpdateFunc(e)).To(Equal(true))
   407  
   408  			oldSecret = &corev1.Secret{
   409  				ObjectMeta: metav1.ObjectMeta{
   410  					Name: fmt.Sprintf("tls-%s-signcert", instance.Name),
   411  					OwnerReferences: []metav1.OwnerReference{
   412  						{
   413  							Name: instance.Name,
   414  							Kind: "IBPOrderer",
   415  						},
   416  					},
   417  				},
   418  			}
   419  
   420  			newSecret = &corev1.Secret{
   421  				ObjectMeta: metav1.ObjectMeta{
   422  					Name: fmt.Sprintf("tls-%s-signcert", instance.Name),
   423  					OwnerReferences: []metav1.OwnerReference{
   424  						{
   425  							Name: instance.Name,
   426  							Kind: "IBPOrderer",
   427  						},
   428  					},
   429  				},
   430  			}
   431  			e = event.UpdateEvent{
   432  				ObjectOld: oldSecret,
   433  				ObjectNew: newSecret,
   434  			}
   435  
   436  			Expect(reconciler.UpdateFunc(e)).To(Equal(false))
   437  
   438  			oldSecret = &corev1.Secret{
   439  				ObjectMeta: metav1.ObjectMeta{
   440  					Name: fmt.Sprintf("ecert-%s-signcert", instance.Name),
   441  					OwnerReferences: []metav1.OwnerReference{
   442  						{
   443  							Name: instance.Name,
   444  							Kind: "IBPOrderer",
   445  						},
   446  					},
   447  				},
   448  				Data: map[string][]byte{
   449  					"test": []byte("data"),
   450  				},
   451  			}
   452  			newSecret = &corev1.Secret{
   453  				ObjectMeta: metav1.ObjectMeta{
   454  					Name: fmt.Sprintf("ecert-%s-signcert", instance.Name),
   455  					OwnerReferences: []metav1.OwnerReference{
   456  						{Name: instance.Name},
   457  					},
   458  				},
   459  				Data: map[string][]byte{
   460  					"test": []byte("newdata"),
   461  				},
   462  			}
   463  			e = event.UpdateEvent{
   464  				ObjectOld: oldSecret,
   465  				ObjectNew: newSecret,
   466  			}
   467  
   468  			Expect(reconciler.UpdateFunc(e)).To(Equal(true))
   469  
   470  			oldSecret = &corev1.Secret{
   471  				ObjectMeta: metav1.ObjectMeta{
   472  					Name: fmt.Sprintf("tls-%s-admincert", instance.Name),
   473  					OwnerReferences: []metav1.OwnerReference{
   474  						{
   475  							Name: instance.Name,
   476  							Kind: "IBPOrderer",
   477  						},
   478  					},
   479  				},
   480  			}
   481  			newSecret = &corev1.Secret{
   482  				ObjectMeta: metav1.ObjectMeta{
   483  					Name: fmt.Sprintf("tls-%s-admincert", instance.Name),
   484  					OwnerReferences: []metav1.OwnerReference{
   485  						{
   486  							Name: instance.Name,
   487  							Kind: "IBPOrderer",
   488  						},
   489  					},
   490  				},
   491  			}
   492  			e = event.UpdateEvent{
   493  				ObjectOld: oldSecret,
   494  				ObjectNew: newSecret,
   495  			}
   496  
   497  			Expect(reconciler.UpdateFunc(e)).To(Equal(false))
   498  
   499  			oldOrderer = &current.IBPOrderer{
   500  				ObjectMeta: metav1.ObjectMeta{
   501  					Name: instance.Name,
   502  				},
   503  				Spec: current.IBPOrdererSpec{
   504  					Images: &current.OrdererImages{},
   505  					Secret: &current.SecretSpec{
   506  						MSP: &current.MSPSpec{
   507  							Component: &current.MSP{
   508  								SignCerts: "testcert",
   509  							},
   510  						},
   511  					},
   512  				},
   513  			}
   514  
   515  			newOrderer = &current.IBPOrderer{
   516  				ObjectMeta: metav1.ObjectMeta{
   517  					Name: instance.Name,
   518  				},
   519  				Spec: current.IBPOrdererSpec{
   520  					Images: &current.OrdererImages{},
   521  					Secret: &current.SecretSpec{
   522  						MSP: &current.MSPSpec{
   523  							TLS: &current.MSP{
   524  								SignCerts: "testcert",
   525  							},
   526  						},
   527  					},
   528  				},
   529  			}
   530  
   531  			e = event.UpdateEvent{
   532  				ObjectOld: oldOrderer,
   533  				ObjectNew: newOrderer,
   534  			}
   535  
   536  			Expect(reconciler.UpdateFunc(e)).To(Equal(true))
   537  		})
   538  
   539  		It("properly pops update flags from stack", func() {
   540  			By("popping first update - config overrides", func() {
   541  				Expect(reconciler.GetUpdateStatus(instance).ConfigOverridesUpdated()).To(Equal(true))
   542  				Expect(reconciler.GetUpdateStatus(instance).OrdererTagUpdated()).To(Equal(true))
   543  
   544  				_, err := reconciler.Reconcile(context.TODO(), request)
   545  				Expect(err).NotTo(HaveOccurred())
   546  			})
   547  
   548  			By("popping second update - spec updated", func() {
   549  				Expect(reconciler.GetUpdateStatus(instance).ConfigOverridesUpdated()).To(Equal(false))
   550  				Expect(reconciler.GetUpdateStatus(instance).SpecUpdated()).To(Equal(true))
   551  
   552  				_, err := reconciler.Reconcile(context.TODO(), request)
   553  				Expect(err).NotTo(HaveOccurred())
   554  			})
   555  
   556  			By("popping third update - ecert updated", func() {
   557  				Expect(reconciler.GetUpdateStatus(instance).TLSCertUpdated()).To(Equal(false))
   558  				Expect(reconciler.GetUpdateStatus(instance).EcertUpdated()).To(Equal(true))
   559  
   560  				_, err := reconciler.Reconcile(context.TODO(), request)
   561  				Expect(err).NotTo(HaveOccurred())
   562  			})
   563  
   564  			By("popping fourth update - msp spec updated", func() {
   565  				Expect(reconciler.GetUpdateStatus(instance).TLSCertUpdated()).To(Equal(false))
   566  				Expect(reconciler.GetUpdateStatus(instance).EcertUpdated()).To(Equal(false))
   567  
   568  				Expect(reconciler.GetUpdateStatus(instance).MSPUpdated()).To(Equal(true))
   569  
   570  				_, err := reconciler.Reconcile(context.TODO(), request)
   571  				Expect(err).NotTo(HaveOccurred())
   572  
   573  				Expect(reconciler.GetUpdateStatus(instance).MSPUpdated()).To(Equal(false))
   574  			})
   575  
   576  		})
   577  
   578  		Context("enrollment information changes detection", func() {
   579  			BeforeEach(func() {
   580  				oldOrderer = &current.IBPOrderer{
   581  					ObjectMeta: metav1.ObjectMeta{
   582  						Name: instance.Name,
   583  					},
   584  				}
   585  
   586  				newOrderer = &current.IBPOrderer{
   587  					ObjectMeta: metav1.ObjectMeta{
   588  						Name: instance.Name,
   589  					},
   590  				}
   591  
   592  				e = event.UpdateEvent{
   593  					ObjectOld: oldOrderer,
   594  					ObjectNew: newOrderer,
   595  				}
   596  			})
   597  
   598  			It("returns false if new secret is nil", func() {
   599  				Expect(reconciler.UpdateFunc(e)).To(Equal(false))
   600  				Expect(reconciler.GetUpdateStatus(instance).EcertEnroll()).To(Equal(false))
   601  			})
   602  
   603  			It("returns false if new secret has ecert msp set along with enrollment inforamtion", func() {
   604  				oldOrderer.Spec.Secret = &current.SecretSpec{
   605  					Enrollment: &current.EnrollmentSpec{
   606  						Component: &current.Enrollment{
   607  							EnrollID: "id1",
   608  						},
   609  					},
   610  				}
   611  				newOrderer.Spec.Secret = &current.SecretSpec{
   612  					MSP: &current.MSPSpec{
   613  						Component: &current.MSP{},
   614  					},
   615  					Enrollment: &current.EnrollmentSpec{
   616  						Component: &current.Enrollment{
   617  							EnrollID: "id2",
   618  						},
   619  					},
   620  				}
   621  
   622  				newOrderer.Spec.Action = current.OrdererAction{
   623  					Restart: true,
   624  				}
   625  
   626  				reconciler.UpdateFunc(e)
   627  				Expect(reconciler.GetUpdateStatusAtElement(instance, 4).EcertEnroll()).To(Equal(false))
   628  			})
   629  		})
   630  
   631  		Context("update node OU", func() {
   632  			BeforeEach(func() {
   633  				oldOrderer = &current.IBPOrderer{
   634  					ObjectMeta: metav1.ObjectMeta{
   635  						Name: instance.Name,
   636  					},
   637  				}
   638  
   639  				newOrderer = &current.IBPOrderer{
   640  					ObjectMeta: metav1.ObjectMeta{
   641  						Name: instance.Name,
   642  					},
   643  				}
   644  				newOrderer.Spec.DisableNodeOU = pointer.Bool(true)
   645  
   646  				e = event.UpdateEvent{
   647  					ObjectOld: oldOrderer,
   648  					ObjectNew: newOrderer,
   649  				}
   650  			})
   651  
   652  			It("returns true if node ou updated in spec", func() {
   653  				reconciler.UpdateFunc(e)
   654  				Expect(reconciler.GetUpdateStatusAtElement(instance, 4).NodeOUUpdated()).To(Equal(true))
   655  			})
   656  		})
   657  	})
   658  
   659  	Context("status updated", func() {
   660  		var (
   661  			oldOrderer *current.IBPOrderer
   662  			newOrderer *current.IBPOrderer
   663  			e          event.UpdateEvent
   664  		)
   665  
   666  		BeforeEach(func() {
   667  			oldOrderer = &current.IBPOrderer{
   668  				ObjectMeta: metav1.ObjectMeta{
   669  					Name: instance.Name,
   670  				},
   671  				Spec: current.IBPOrdererSpec{
   672  					Images: &current.OrdererImages{},
   673  				},
   674  			}
   675  			newOrderer = &current.IBPOrderer{
   676  				ObjectMeta: metav1.ObjectMeta{
   677  					Name: instance.Name,
   678  				},
   679  				Spec: current.IBPOrdererSpec{
   680  					Images: &current.OrdererImages{},
   681  				},
   682  			}
   683  			e = event.UpdateEvent{
   684  				ObjectOld: oldOrderer,
   685  				ObjectNew: newOrderer,
   686  			}
   687  		})
   688  
   689  		It("does not set StatusUpdate flag if only heartbeat has changed", func() {
   690  			oldOrderer.Status.LastHeartbeatTime = time.Now().String()
   691  			newOrderer.Status.LastHeartbeatTime = time.Now().String()
   692  
   693  			Expect(reconciler.UpdateFunc(e)).To(Equal(false))
   694  			Expect(reconciler.GetUpdateStatus(instance).StatusUpdated()).To(Equal(false))
   695  		})
   696  
   697  		It("sets StatusUpdated flag to true if status type has changed", func() {
   698  			oldOrderer.Status.Type = "old"
   699  			newOrderer.Status.Type = "new"
   700  
   701  			Expect(reconciler.UpdateFunc(e)).To(Equal(true))
   702  			Expect(reconciler.GetUpdateStatus(instance).StatusUpdated()).To(Equal(true))
   703  		})
   704  
   705  		It("sets StatusUpdated flag to true if status reason has changed", func() {
   706  			oldOrderer.Status.Reason = "oldreason"
   707  			newOrderer.Status.Reason = "newreason"
   708  
   709  			Expect(reconciler.UpdateFunc(e)).To(Equal(true))
   710  			Expect(reconciler.GetUpdateStatus(instance).StatusUpdated()).To(Equal(true))
   711  		})
   712  
   713  		It("sets StatusUpdated flag to true if status message has changed", func() {
   714  			oldOrderer.Status.Message = "oldmessage"
   715  			newOrderer.Status.Message = "newmessage"
   716  
   717  			Expect(reconciler.UpdateFunc(e)).To(Equal(true))
   718  			Expect(reconciler.GetUpdateStatus(instance).StatusUpdated()).To(Equal(true))
   719  		})
   720  	})
   721  
   722  	Context("append update if missing", func() {
   723  		It("appends update", func() {
   724  			updates := []Update{{tlsCertUpdated: true}}
   725  			updates = reconciler.AppendUpdateIfMissing(updates, Update{ecertUpdated: true})
   726  			Expect(len(updates)).To(Equal(2))
   727  		})
   728  
   729  		It("doesn't append update that is already in stack", func() {
   730  			updates := []Update{{tlsCertUpdated: true}}
   731  			updates = reconciler.AppendUpdateIfMissing(updates, Update{tlsCertUpdated: true})
   732  			Expect(len(updates)).To(Equal(1))
   733  		})
   734  	})
   735  
   736  	Context("push update", func() {
   737  		It("pushes update only if missing for certificate update", func() {
   738  			reconciler.PushUpdate(instance.Name, Update{specUpdated: true})
   739  			Expect(len(reconciler.update[instance.Name])).To(Equal(1))
   740  			reconciler.PushUpdate(instance.Name, Update{tlsCertUpdated: true})
   741  			Expect(len(reconciler.update[instance.Name])).To(Equal(2))
   742  			reconciler.PushUpdate(instance.Name, Update{ecertUpdated: true})
   743  			Expect(len(reconciler.update[instance.Name])).To(Equal(3))
   744  			reconciler.PushUpdate(instance.Name, Update{tlsCertUpdated: true})
   745  			Expect(len(reconciler.update[instance.Name])).To(Equal(3))
   746  			reconciler.PushUpdate(instance.Name, Update{tlsCertUpdated: true, specUpdated: true})
   747  			Expect(len(reconciler.update[instance.Name])).To(Equal(4))
   748  		})
   749  	})
   750  
   751  	Context("add owner reference to secret", func() {
   752  		var (
   753  			secret *corev1.Secret
   754  		)
   755  
   756  		BeforeEach(func() {
   757  			secret = &corev1.Secret{}
   758  			secret.Name = "ecert-test-orderer1-signcert"
   759  		})
   760  
   761  		It("returns error if fails to get list of orderers", func() {
   762  			mockKubeClient.ListReturns(errors.New("list error"))
   763  			_, err := reconciler.AddOwnerReferenceToSecret(secret)
   764  			Expect(err).To(HaveOccurred())
   765  			Expect(err.Error()).To(ContainSubstring("list error"))
   766  		})
   767  
   768  		It("returns false if secret doesn't belong to any orderers in list", func() {
   769  			secret.Name = "tls-peer1-signcert"
   770  			added, err := reconciler.AddOwnerReferenceToSecret(secret)
   771  			Expect(err).NotTo(HaveOccurred())
   772  			Expect(added).To(Equal(false))
   773  		})
   774  
   775  		It("returns false if secret's name doesn't match expected format", func() {
   776  			secret.Name = "orderersecret"
   777  			added, err := reconciler.AddOwnerReferenceToSecret(secret)
   778  			Expect(err).NotTo(HaveOccurred())
   779  			Expect(added).To(Equal(false))
   780  		})
   781  
   782  		It("returns true if owner references added to secret", func() {
   783  			added, err := reconciler.AddOwnerReferenceToSecret(secret)
   784  			Expect(err).NotTo(HaveOccurred())
   785  			Expect(added).To(Equal(true))
   786  		})
   787  
   788  		It("returns true if owner references added to init-rootcert secret", func() {
   789  			secret.Name = "test-orderer1-init-rootcert"
   790  			added, err := reconciler.AddOwnerReferenceToSecret(secret)
   791  			Expect(err).NotTo(HaveOccurred())
   792  			Expect(added).To(Equal(true))
   793  		})
   794  	})
   795  })