github.com/verrazzano/verrazzano@v1.7.0/cluster-operator/controllers/vmc/vmc_controller_test.go (about)

     1  // Copyright (c) 2021, 2023, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  
     4  package vmc
     5  
     6  import (
     7  	"bytes"
     8  	"context"
     9  	"fmt"
    10  	"io"
    11  	"net/http"
    12  	"strings"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/Jeffail/gabs/v2"
    17  	"github.com/golang/mock/gomock"
    18  	"github.com/prometheus/client_golang/prometheus/testutil"
    19  	"github.com/stretchr/testify/assert"
    20  	"github.com/verrazzano/verrazzano/cluster-operator/apis/clusters/v1alpha1"
    21  	"github.com/verrazzano/verrazzano/pkg/constants"
    22  	"github.com/verrazzano/verrazzano/pkg/log/vzlog"
    23  	"github.com/verrazzano/verrazzano/pkg/mcconstants"
    24  	"github.com/verrazzano/verrazzano/pkg/metricsutils"
    25  	"github.com/verrazzano/verrazzano/pkg/rancherutil"
    26  	"github.com/verrazzano/verrazzano/pkg/test/mockmatchers"
    27  	"github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1beta1"
    28  	vpoconstants "github.com/verrazzano/verrazzano/platform-operator/constants"
    29  	"github.com/verrazzano/verrazzano/platform-operator/mocks"
    30  	corev1 "k8s.io/api/core/v1"
    31  	networkingv1 "k8s.io/api/networking/v1"
    32  	rbacv1 "k8s.io/api/rbac/v1"
    33  	apiv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    34  	"k8s.io/apimachinery/pkg/api/errors"
    35  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    36  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    37  	"k8s.io/apimachinery/pkg/runtime"
    38  	"k8s.io/apimachinery/pkg/runtime/schema"
    39  	"k8s.io/apimachinery/pkg/types"
    40  	"k8s.io/apimachinery/pkg/util/wait"
    41  	"k8s.io/client-go/rest"
    42  	ctrl "sigs.k8s.io/controller-runtime"
    43  	"sigs.k8s.io/controller-runtime/pkg/client"
    44  )
    45  
    46  const apiVersion = "clusters.verrazzano.io/v1alpha1"
    47  const kind = "VerrazzanoManagedCluster"
    48  
    49  const (
    50  	token                    = "tokenData"
    51  	testManagedCluster       = "test"
    52  	rancherAgentRegistry     = "ghcr.io"
    53  	rancherAgentImage        = rancherAgentRegistry + "/verrazzano/rancher-agent:v1.0.0"
    54  	rancherAdminSecret       = "rancher-admin-secret"
    55  	unitTestRancherClusterID = "unit-test-rancher-cluster-id"
    56  )
    57  
    58  var (
    59  	loginURLParts    = strings.Split(loginPath, "?")
    60  	loginURIPath     = loginURLParts[0]
    61  	loginQueryString = loginURLParts[1]
    62  )
    63  
    64  const rancherManifestYAML = `
    65  apiVersion: apps/v1
    66  kind: Deployment
    67  metadata:
    68    name: cattle-cluster-agent
    69    namespace: cattle-system
    70  spec:
    71    template:
    72      spec:
    73  	  containers:
    74  	    - name: cluster-register
    75  		  image: ` + rancherAgentImage + `
    76  		  imagePullPolicy: IfNotPresent
    77  `
    78  
    79  type AssertFn func(configMap *corev1.ConfigMap) error
    80  type secretAssertFn func(secret *corev1.Secret) error
    81  
    82  func init() {
    83  	// stub out keycloak client creation for these tests
    84  	createClient = func(r *VerrazzanoManagedClusterReconciler, vmc *v1alpha1.VerrazzanoManagedCluster) error {
    85  		return nil
    86  	}
    87  }
    88  
    89  // TestCreateVMC tests the Reconcile method for the following use case
    90  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
    91  // WHEN a VerrazzanoManagedCluster resource has been applied in a cluster where Rancher is enabled
    92  // THEN ensure all the objects are created correctly
    93  func TestCreateVMCRancherEnabled(t *testing.T) {
    94  	// with feature flag disabled (which triggers different asserts/mocks from enabled)
    95  	doTestCreateVMC(t, true)
    96  }
    97  
    98  // TestCreateVMC tests the Reconcile method for the following use case
    99  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
   100  // WHEN a VerrazzanoManagedCluster resource has been applied in a cluster where Rancher is DISABLED
   101  // THEN ensure all the objects are created correctly
   102  func TestCreateVMCRancherDisabled(t *testing.T) {
   103  	doTestCreateVMC(t, false)
   104  }
   105  
   106  func doTestCreateVMC(t *testing.T, rancherEnabled bool) {
   107  	// clear any cached user auth tokens when the test completes
   108  	defer rancherutil.DeleteStoredTokens()
   109  
   110  	namespace := constants.VerrazzanoMultiClusterNamespace
   111  	asserts := assert.New(t)
   112  	mocker := gomock.NewController(t)
   113  	mock := mocks.NewMockClient(mocker)
   114  	mockStatus := mocks.NewMockStatusWriter(mocker)
   115  	asserts.NotNil(mockStatus)
   116  
   117  	mockRequestSender := mocks.NewMockRequestSender(mocker)
   118  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   119  	defer func() {
   120  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   121  	}()
   122  	rancherutil.RancherHTTPClient = mockRequestSender
   123  
   124  	defer setConfigFunc(getConfigFunc)
   125  	setConfigFunc(fakeGetConfig)
   126  
   127  	caSecretExistsInVMC := true
   128  	expectVmcGetAndUpdate(t, mock, testManagedCluster, caSecretExistsInVMC, false)
   129  	expectSyncServiceAccount(t, mock, testManagedCluster, true)
   130  	expectSyncRoleBinding(t, mock, testManagedCluster, true)
   131  	// Agent secret sync checks depend on whether Rancher is enabled
   132  	expectSyncAgent(t, mock, testManagedCluster, rancherEnabled, false)
   133  	expectMockCallsForListingRancherUsers(mock)
   134  	expectSyncRegistration(t, mock, testManagedCluster, false)
   135  	expectSyncManifest(t, mock, mockStatus, mockRequestSender, testManagedCluster, false, rancherManifestYAML)
   136  	expectRancherConfigK8sCalls(t, mock, false)
   137  	expectMockCallsForCreateClusterRoleBindingTemplate(mock, unitTestRancherClusterID)
   138  	expectPushManifestRequests(t, mockRequestSender, mock)
   139  	expectSyncCACertRancherK8sCalls(t, mock, mockRequestSender, false)
   140  	expectThanosDelete(t, mock)
   141  	expectSyncPrometheusScraper(mock, testManagedCluster, "", "", true, getCaCrt(), func(configMap *corev1.ConfigMap) error {
   142  		asserts.Len(configMap.Data, 2, "no data found")
   143  		asserts.NotEmpty(configMap.Data["ca-test"], "No cert entry found")
   144  		prometheusYaml := configMap.Data["prometheus.yml"]
   145  		asserts.NotEmpty(prometheusYaml, "No prometheus config yaml found")
   146  
   147  		scrapeConfig, err := getScrapeConfig(prometheusYaml, testManagedCluster)
   148  		if err != nil {
   149  			asserts.Fail("failed due to error %v", err)
   150  		}
   151  		validateScrapeConfig(t, scrapeConfig, prometheusConfigBasePath, true)
   152  		return nil
   153  	}, func(secret *corev1.Secret) error {
   154  		scrapeConfigYaml := secret.Data[constants.PromAdditionalScrapeConfigsSecretKey]
   155  		scrapeConfigs, err := metricsutils.ParseScrapeConfig(string(scrapeConfigYaml))
   156  		if err != nil {
   157  			asserts.Fail("failed due to error %v", err)
   158  		}
   159  		scrapeConfig := getJob(scrapeConfigs.Children(), testManagedCluster)
   160  		validateScrapeConfig(t, scrapeConfig, managedCertsBasePath, true)
   161  		return nil
   162  	}, func(secret *corev1.Secret) error {
   163  		asserts.NotEmpty(secret.Data["ca-test"], "Expected to find a managed cluster TLS cert")
   164  		return nil
   165  	})
   166  
   167  	// expect status updated with condition Ready=true
   168  	expectStatusUpdateReadyCondition(asserts, mock, mockStatus, corev1.ConditionTrue, "", false)
   169  
   170  	// Create and make the request
   171  	request := newRequest(namespace, testManagedCluster)
   172  	reconciler := newVMCReconciler(mock)
   173  	result, err := reconciler.Reconcile(context.TODO(), request)
   174  
   175  	// Validate the results
   176  	mocker.Finish()
   177  	asserts.NoError(err)
   178  	asserts.Equal(true, result.Requeue)
   179  	asserts.Equal(time.Duration(vpoconstants.ReconcileLoopRequeueInterval), result.RequeueAfter)
   180  }
   181  
   182  // TestCreateVMC tests the Reconcile method for the following use case
   183  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
   184  // WHEN a VerrazzanoManagedCluster resource has been applied on a Verrazzano install configured with external ES
   185  // THEN ensure all the objects are created
   186  func TestCreateVMCWithExternalES(t *testing.T) {
   187  	// clear any cached user auth tokens when the test completes
   188  	defer rancherutil.DeleteStoredTokens()
   189  
   190  	namespace := constants.VerrazzanoMultiClusterNamespace
   191  	asserts := assert.New(t)
   192  	mocker := gomock.NewController(t)
   193  	mock := mocks.NewMockClient(mocker)
   194  	mockStatus := mocks.NewMockStatusWriter(mocker)
   195  	asserts.NotNil(mockStatus)
   196  
   197  	mockRequestSender := mocks.NewMockRequestSender(mocker)
   198  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   199  	defer func() {
   200  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   201  	}()
   202  	rancherutil.RancherHTTPClient = mockRequestSender
   203  
   204  	defer setConfigFunc(getConfigFunc)
   205  	setConfigFunc(fakeGetConfig)
   206  
   207  	expectVmcGetAndUpdate(t, mock, testManagedCluster, true, false)
   208  	expectSyncServiceAccount(t, mock, testManagedCluster, true)
   209  	expectSyncRoleBinding(t, mock, testManagedCluster, true)
   210  	expectSyncAgent(t, mock, testManagedCluster, false, true)
   211  	expectMockCallsForListingRancherUsers(mock)
   212  	expectSyncRegistration(t, mock, testManagedCluster, true)
   213  	expectSyncManifest(t, mock, mockStatus, mockRequestSender, testManagedCluster, false, rancherManifestYAML)
   214  	expectRancherConfigK8sCalls(t, mock, false)
   215  	expectMockCallsForCreateClusterRoleBindingTemplate(mock, unitTestRancherClusterID)
   216  	expectPushManifestRequests(t, mockRequestSender, mock)
   217  	expectSyncCACertRancherK8sCalls(t, mock, mockRequestSender, false)
   218  	expectThanosDelete(t, mock)
   219  	expectSyncPrometheusScraper(mock, testManagedCluster, "", "", true, getCaCrt(), func(configMap *corev1.ConfigMap) error {
   220  		asserts.Len(configMap.Data, 2, "no data found")
   221  		asserts.NotEmpty(configMap.Data["ca-test"], "No cert entry found")
   222  		prometheusYaml := configMap.Data["prometheus.yml"]
   223  		asserts.NotEmpty(prometheusYaml, "No prometheus config yaml found")
   224  
   225  		scrapeConfig, err := getScrapeConfig(prometheusYaml, testManagedCluster)
   226  		if err != nil {
   227  			asserts.Fail("failed due to error %v", err)
   228  		}
   229  		validateScrapeConfig(t, scrapeConfig, prometheusConfigBasePath, true)
   230  		return nil
   231  	}, func(secret *corev1.Secret) error {
   232  		scrapeConfigYaml := secret.Data[constants.PromAdditionalScrapeConfigsSecretKey]
   233  		scrapeConfigs, err := metricsutils.ParseScrapeConfig(string(scrapeConfigYaml))
   234  		if err != nil {
   235  			asserts.Fail("failed due to error %v", err)
   236  		}
   237  		scrapeConfig := getJob(scrapeConfigs.Children(), testManagedCluster)
   238  		validateScrapeConfig(t, scrapeConfig, managedCertsBasePath, true)
   239  		return nil
   240  	}, func(secret *corev1.Secret) error {
   241  		asserts.NotEmpty(secret.Data["ca-test"], "Expected to find a managed cluster TLS cert")
   242  		return nil
   243  	})
   244  
   245  	// expect status updated with condition Ready=true
   246  	expectStatusUpdateReadyCondition(asserts, mock, mockStatus, corev1.ConditionTrue, "", false)
   247  
   248  	// Create and make the request
   249  	request := newRequest(namespace, testManagedCluster)
   250  	reconciler := newVMCReconciler(mock)
   251  	result, err := reconciler.Reconcile(context.TODO(), request)
   252  
   253  	// Validate the results
   254  	mocker.Finish()
   255  	asserts.NoError(err)
   256  	asserts.Equal(true, result.Requeue)
   257  	asserts.Equal(time.Duration(vpoconstants.ReconcileLoopRequeueInterval), result.RequeueAfter)
   258  }
   259  
   260  // TestCreateVMC tests the Reconcile method for the following use case
   261  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource for an OCI DNS cluster
   262  // WHEN a VerrazzanoManagedCluster resource has been applied
   263  // THEN ensure all the objects are created
   264  func TestCreateVMCOCIDNS(t *testing.T) {
   265  	// clear any cached user auth tokens when the test completes
   266  	defer rancherutil.DeleteStoredTokens()
   267  
   268  	namespace := "verrazzano-mc"
   269  	asserts := assert.New(t)
   270  	mocker := gomock.NewController(t)
   271  	mock := mocks.NewMockClient(mocker)
   272  	mockStatus := mocks.NewMockStatusWriter(mocker)
   273  	asserts.NotNil(mockStatus)
   274  
   275  	mockRequestSender := mocks.NewMockRequestSender(mocker)
   276  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   277  	defer func() {
   278  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   279  	}()
   280  	rancherutil.RancherHTTPClient = mockRequestSender
   281  
   282  	defer setConfigFunc(getConfigFunc)
   283  	setConfigFunc(fakeGetConfig)
   284  
   285  	expectVmcGetAndUpdate(t, mock, testManagedCluster, true, false)
   286  	expectSyncServiceAccount(t, mock, testManagedCluster, true)
   287  	expectSyncRoleBinding(t, mock, testManagedCluster, true)
   288  	expectSyncAgent(t, mock, testManagedCluster, false, true)
   289  	expectMockCallsForListingRancherUsers(mock)
   290  	expectSyncRegistration(t, mock, testManagedCluster, false)
   291  	expectSyncManifest(t, mock, mockStatus, mockRequestSender, testManagedCluster, false, rancherManifestYAML)
   292  	expectRancherConfigK8sCalls(t, mock, false)
   293  	expectMockCallsForCreateClusterRoleBindingTemplate(mock, unitTestRancherClusterID)
   294  	expectPushManifestRequests(t, mockRequestSender, mock)
   295  	expectSyncCACertRancherK8sCalls(t, mock, mockRequestSender, false)
   296  	expectThanosDelete(t, mock)
   297  	expectSyncPrometheusScraper(mock, testManagedCluster, "", "", true, "", func(configMap *corev1.ConfigMap) error {
   298  		asserts.Len(configMap.Data, 2, "no data found")
   299  		asserts.Empty(configMap.Data["ca-test"], "Cert entry found")
   300  		prometheusYaml := configMap.Data["prometheus.yml"]
   301  		asserts.NotEmpty(prometheusYaml, "No prometheus config yaml found")
   302  
   303  		scrapeConfig, err := getScrapeConfig(prometheusYaml, testManagedCluster)
   304  		if err != nil {
   305  			asserts.Fail("failed due to error %v", err)
   306  		}
   307  		validateScrapeConfig(t, scrapeConfig, prometheusConfigBasePath, false)
   308  		return nil
   309  	}, func(secret *corev1.Secret) error {
   310  		scrapeConfigYaml := secret.Data[constants.PromAdditionalScrapeConfigsSecretKey]
   311  		scrapeConfigs, err := metricsutils.ParseScrapeConfig(string(scrapeConfigYaml))
   312  		if err != nil {
   313  			asserts.Fail("failed due to error %v", err)
   314  		}
   315  		scrapeConfig := getJob(scrapeConfigs.Children(), testManagedCluster)
   316  		validateScrapeConfig(t, scrapeConfig, managedCertsBasePath, false)
   317  		return nil
   318  	}, func(secret *corev1.Secret) error {
   319  		asserts.Empty(secret.Data["ca-test"])
   320  		return nil
   321  	})
   322  
   323  	// expect status updated with condition Ready=true
   324  	expectStatusUpdateReadyCondition(asserts, mock, mockStatus, corev1.ConditionTrue, "", false)
   325  
   326  	// Create and make the request
   327  	request := newRequest(namespace, testManagedCluster)
   328  	reconciler := newVMCReconciler(mock)
   329  	result, err := reconciler.Reconcile(context.TODO(), request)
   330  
   331  	// Validate the results
   332  	mocker.Finish()
   333  	asserts.NoError(err)
   334  	asserts.Equal(true, result.Requeue)
   335  	asserts.Equal(time.Duration(vpoconstants.ReconcileLoopRequeueInterval), result.RequeueAfter)
   336  }
   337  
   338  // TestCreateVMCNoCACert tests the Reconcile method for the following use case
   339  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
   340  // WHEN a VerrazzanoManagedCluster resource has been applied with no CA Cert
   341  // THEN ensure all the objects are created
   342  func TestCreateVMCNoCACert(t *testing.T) {
   343  	// clear any cached user auth tokens when the test completes
   344  	defer rancherutil.DeleteStoredTokens()
   345  
   346  	namespace := constants.VerrazzanoMultiClusterNamespace
   347  	asserts := assert.New(t)
   348  	mocker := gomock.NewController(t)
   349  	mock := mocks.NewMockClient(mocker)
   350  	mockStatus := mocks.NewMockStatusWriter(mocker)
   351  	asserts.NotNil(mockStatus)
   352  
   353  	mockRequestSender := mocks.NewMockRequestSender(mocker)
   354  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   355  	defer func() {
   356  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   357  	}()
   358  	rancherutil.RancherHTTPClient = mockRequestSender
   359  
   360  	defer setConfigFunc(getConfigFunc)
   361  	setConfigFunc(fakeGetConfig)
   362  
   363  	expectVmcGetAndUpdate(t, mock, testManagedCluster, false, false)
   364  	expectSyncServiceAccount(t, mock, testManagedCluster, true)
   365  	expectSyncRoleBinding(t, mock, testManagedCluster, true)
   366  	expectSyncAgent(t, mock, testManagedCluster, false, true)
   367  	expectMockCallsForListingRancherUsers(mock)
   368  	expectSyncRegistration(t, mock, testManagedCluster, true)
   369  	expectSyncManifest(t, mock, mockStatus, mockRequestSender, testManagedCluster, false, rancherManifestYAML)
   370  	expectRancherConfigK8sCalls(t, mock, true)
   371  	expectSyncCACertRancherHTTPCalls(t, mockRequestSender, "")
   372  	expectRancherConfigK8sCalls(t, mock, false)
   373  	expectMockCallsForCreateClusterRoleBindingTemplate(mock, unitTestRancherClusterID)
   374  	expectPushManifestRequests(t, mockRequestSender, mock)
   375  	expectThanosDelete(t, mock)
   376  	expectSyncPrometheusScraper(mock, testManagedCluster, "", "", false, getCaCrt(), func(configMap *corev1.ConfigMap) error {
   377  		asserts.Len(configMap.Data, 2, "no data found")
   378  		prometheusYaml := configMap.Data["prometheus.yml"]
   379  		asserts.NotEmpty(prometheusYaml, "No prometheus config yaml found")
   380  
   381  		scrapeConfig, err := getScrapeConfig(prometheusYaml, testManagedCluster)
   382  		if err != nil {
   383  			asserts.Fail("failed due to error %v", err)
   384  		}
   385  		validateScrapeConfig(t, scrapeConfig, prometheusConfigBasePath, false)
   386  		return nil
   387  	}, func(secret *corev1.Secret) error {
   388  		scrapeConfigYaml := secret.Data[constants.PromAdditionalScrapeConfigsSecretKey]
   389  		scrapeConfigs, err := metricsutils.ParseScrapeConfig(string(scrapeConfigYaml))
   390  		if err != nil {
   391  			asserts.Fail("failed due to error %v", err)
   392  		}
   393  		scrapeConfig := getJob(scrapeConfigs.Children(), testManagedCluster)
   394  		validateScrapeConfig(t, scrapeConfig, managedCertsBasePath, false)
   395  		return nil
   396  	}, func(secret *corev1.Secret) error {
   397  		asserts.Empty(secret.Data["ca-test"])
   398  		return nil
   399  	})
   400  
   401  	// expect status updated with condition Ready=true and ManagedCARetrieved condition is not set because we don't provide
   402  	// a non-zero length managed ca cert
   403  	expectStatusUpdateReadyCondition(asserts, mock, mockStatus, corev1.ConditionTrue, "", false)
   404  
   405  	// Create and make the request
   406  	request := newRequest(namespace, testManagedCluster)
   407  	reconciler := newVMCReconciler(mock)
   408  	result, err := reconciler.Reconcile(context.TODO(), request)
   409  
   410  	// Validate the results
   411  	mocker.Finish()
   412  	asserts.NoError(err)
   413  	asserts.Equal(true, result.Requeue)
   414  	asserts.Equal(time.Duration(vpoconstants.ReconcileLoopRequeueInterval), result.RequeueAfter)
   415  }
   416  
   417  // TestCreateVMCFetchCACertFromManagedCluster tests the Reconcile method for the following use case
   418  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
   419  // WHEN a VerrazzanoManagedCluster resource has been applied and the caSecret field is NOT empty
   420  // THEN ensure that we fetch the CA cert secret from the managed cluster and populate the caSecret field
   421  func TestCreateVMCFetchCACertFromManagedCluster(t *testing.T) {
   422  	// clear any cached user auth tokens when the test completes
   423  	defer rancherutil.DeleteStoredTokens()
   424  
   425  	namespace := constants.VerrazzanoMultiClusterNamespace
   426  	asserts := assert.New(t)
   427  	mocker := gomock.NewController(t)
   428  	mock := mocks.NewMockClient(mocker)
   429  	mockStatus := mocks.NewMockStatusWriter(mocker)
   430  	asserts.NotNil(mockStatus)
   431  
   432  	mockRequestSender := mocks.NewMockRequestSender(mocker)
   433  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   434  	defer func() {
   435  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   436  	}()
   437  	rancherutil.RancherHTTPClient = mockRequestSender
   438  
   439  	defer setConfigFunc(getConfigFunc)
   440  	setConfigFunc(fakeGetConfig)
   441  
   442  	expectVmcGetAndUpdate(t, mock, testManagedCluster, false, false)
   443  	expectSyncServiceAccount(t, mock, testManagedCluster, true)
   444  	expectSyncRoleBinding(t, mock, testManagedCluster, true)
   445  	expectSyncAgent(t, mock, testManagedCluster, true, false)
   446  	expectMockCallsForListingRancherUsers(mock)
   447  	expectSyncRegistration(t, mock, testManagedCluster, true)
   448  	expectSyncManifest(t, mock, mockStatus, mockRequestSender, testManagedCluster, false, rancherManifestYAML)
   449  	expectSyncCACertRancherHTTPCalls(t, mockRequestSender, `{"data":{"ca.crt":"base64-ca-cert"}}`)
   450  	expectSyncCACertRancherK8sCalls(t, mock, mockRequestSender, true)
   451  	expectRancherConfigK8sCalls(t, mock, false)
   452  	expectMockCallsForCreateClusterRoleBindingTemplate(mock, unitTestRancherClusterID)
   453  	expectPushManifestRequests(t, mockRequestSender, mock)
   454  	expectThanosDelete(t, mock)
   455  	expectSyncPrometheusScraper(mock, testManagedCluster, "", "", true, getCaCrt(), func(configMap *corev1.ConfigMap) error {
   456  		asserts.Len(configMap.Data, 2, "no data found")
   457  		prometheusYaml := configMap.Data["prometheus.yml"]
   458  		asserts.NotEmpty(prometheusYaml, "No prometheus config yaml found")
   459  
   460  		scrapeConfig, err := getScrapeConfig(prometheusYaml, testManagedCluster)
   461  		if err != nil {
   462  			asserts.Fail("failed due to error %v", err)
   463  		}
   464  		validateScrapeConfig(t, scrapeConfig, prometheusConfigBasePath, true)
   465  		return nil
   466  	}, func(secret *corev1.Secret) error {
   467  		scrapeConfigYaml := secret.Data[constants.PromAdditionalScrapeConfigsSecretKey]
   468  		scrapeConfigs, err := metricsutils.ParseScrapeConfig(string(scrapeConfigYaml))
   469  		if err != nil {
   470  			asserts.Fail("failed due to error %v", err)
   471  		}
   472  		scrapeConfig := getJob(scrapeConfigs.Children(), testManagedCluster)
   473  		validateScrapeConfig(t, scrapeConfig, managedCertsBasePath, true)
   474  		return nil
   475  	}, func(secret *corev1.Secret) error {
   476  		asserts.NotEmpty(secret.Data["ca-test"], "Expected to find a managed cluster TLS cert")
   477  		return nil
   478  	})
   479  
   480  	// expect status updated with condition Ready=true and ManagedCARetrieved
   481  	expectStatusUpdateReadyCondition(asserts, mock, mockStatus, corev1.ConditionTrue, "", true)
   482  
   483  	// Create and make the request
   484  	request := newRequest(namespace, testManagedCluster)
   485  	reconciler := newVMCReconciler(mock)
   486  	result, err := reconciler.Reconcile(context.TODO(), request)
   487  
   488  	// Validate the results
   489  	mocker.Finish()
   490  	asserts.NoError(err)
   491  	asserts.Equal(true, result.Requeue)
   492  	asserts.Equal(time.Duration(vpoconstants.ReconcileLoopRequeueInterval), result.RequeueAfter)
   493  }
   494  
   495  // TestCreateVMCWithExistingScrapeConfiguration tests the Reconcile method for the following use case
   496  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
   497  // WHEN a VerrazzanoManagedCluster resource has been applied and prometheus is already configured with a scrape config for the cluster
   498  // THEN ensure all the objects are created
   499  func TestCreateVMCWithExistingScrapeConfiguration(t *testing.T) {
   500  	// clear any cached user auth tokens when the test completes
   501  	defer rancherutil.DeleteStoredTokens()
   502  
   503  	namespace := "verrazzano-mc"
   504  	jobs := `  - ` + constants.PrometheusJobNameKey + `: cluster1
   505      scrape_interval: 20s
   506      scrape_timeout: 15s
   507      scheme: http`
   508  	prometheusYaml := `global:
   509    scrape_interval: 20s
   510    scrape_timeout: 10s
   511    evaluation_interval: 30s
   512  scrape_configs:
   513  ` + jobs
   514  	asserts := assert.New(t)
   515  	mocker := gomock.NewController(t)
   516  	mock := mocks.NewMockClient(mocker)
   517  	mockStatus := mocks.NewMockStatusWriter(mocker)
   518  	asserts.NotNil(mockStatus)
   519  
   520  	mockRequestSender := mocks.NewMockRequestSender(mocker)
   521  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   522  	defer func() {
   523  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   524  	}()
   525  	rancherutil.RancherHTTPClient = mockRequestSender
   526  
   527  	defer setConfigFunc(getConfigFunc)
   528  	setConfigFunc(fakeGetConfig)
   529  
   530  	expectVmcGetAndUpdate(t, mock, testManagedCluster, true, false)
   531  	expectSyncServiceAccount(t, mock, testManagedCluster, true)
   532  	expectSyncRoleBinding(t, mock, testManagedCluster, true)
   533  	expectSyncAgent(t, mock, testManagedCluster, false, false)
   534  	expectMockCallsForListingRancherUsers(mock)
   535  	expectSyncRegistration(t, mock, testManagedCluster, false)
   536  	expectSyncManifest(t, mock, mockStatus, mockRequestSender, testManagedCluster, false, rancherManifestYAML)
   537  	expectRancherConfigK8sCalls(t, mock, false)
   538  	expectMockCallsForCreateClusterRoleBindingTemplate(mock, unitTestRancherClusterID)
   539  	expectPushManifestRequests(t, mockRequestSender, mock)
   540  	expectSyncCACertRancherK8sCalls(t, mock, mockRequestSender, false)
   541  	expectThanosDelete(t, mock)
   542  	expectSyncPrometheusScraper(mock, testManagedCluster, prometheusYaml, jobs, true, getCaCrt(), func(configMap *corev1.ConfigMap) error {
   543  
   544  		// check for the modified entry
   545  		asserts.Len(configMap.Data, 2, "no data found")
   546  		asserts.NotEmpty(configMap.Data["ca-test"], "No cert entry found")
   547  		prometheusYaml := configMap.Data["prometheus.yml"]
   548  		asserts.NotEmpty(prometheusYaml, "No prometheus config yaml found")
   549  
   550  		scrapeConfig, err := getScrapeConfig(prometheusYaml, testManagedCluster)
   551  		if err != nil {
   552  			asserts.Fail("failed due to error %v", err)
   553  		}
   554  		validateScrapeConfig(t, scrapeConfig, prometheusConfigBasePath, true)
   555  		return nil
   556  	}, func(secret *corev1.Secret) error {
   557  		scrapeConfigYaml := secret.Data[constants.PromAdditionalScrapeConfigsSecretKey]
   558  		scrapeConfigs, err := metricsutils.ParseScrapeConfig(string(scrapeConfigYaml))
   559  		if err != nil {
   560  			asserts.Fail("failed due to error %v", err)
   561  		}
   562  		scrapeConfig := getJob(scrapeConfigs.Children(), testManagedCluster)
   563  		validateScrapeConfig(t, scrapeConfig, managedCertsBasePath, true)
   564  		return nil
   565  	}, func(secret *corev1.Secret) error {
   566  		asserts.NotEmpty(secret.Data["ca-test"], "Expected to find a managed cluster TLS cert")
   567  		return nil
   568  	})
   569  
   570  	// expect status updated with condition Ready=true
   571  	expectStatusUpdateReadyCondition(asserts, mock, mockStatus, corev1.ConditionTrue, "", false)
   572  
   573  	// Create and make the request
   574  	request := newRequest(namespace, testManagedCluster)
   575  	reconciler := newVMCReconciler(mock)
   576  	result, err := reconciler.Reconcile(context.TODO(), request)
   577  
   578  	// Validate the results
   579  	mocker.Finish()
   580  	asserts.NoError(err)
   581  	asserts.Equal(true, result.Requeue)
   582  	asserts.Equal(time.Duration(vpoconstants.ReconcileLoopRequeueInterval), result.RequeueAfter)
   583  }
   584  
   585  // TestReplaceExistingScrapeConfiguration tests the Reconcile method for the following use case
   586  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
   587  // WHEN a VerrazzanoManagedCluster resource has been applied and prometheus is already configured with a scrape configuration for the same cluster
   588  // THEN ensure all the objects are created (existing configuration is replaced)
   589  func TestReplaceExistingScrapeConfiguration(t *testing.T) {
   590  	// clear any cached user auth tokens when the test completes
   591  	defer rancherutil.DeleteStoredTokens()
   592  
   593  	namespace := "verrazzano-mc"
   594  	jobs := `  - ` + constants.PrometheusJobNameKey + `: test
   595      scrape_interval: 20s
   596      scrape_timeout: 15s
   597      scheme: http`
   598  	prometheusYaml := `global:
   599    scrape_interval: 20s
   600    scrape_timeout: 10s
   601    evaluation_interval: 30s
   602  scrape_configs:
   603  ` + jobs
   604  	asserts := assert.New(t)
   605  	mocker := gomock.NewController(t)
   606  	mock := mocks.NewMockClient(mocker)
   607  	mockStatus := mocks.NewMockStatusWriter(mocker)
   608  	asserts.NotNil(mockStatus)
   609  
   610  	mockRequestSender := mocks.NewMockRequestSender(mocker)
   611  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   612  	defer func() {
   613  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   614  	}()
   615  	rancherutil.RancherHTTPClient = mockRequestSender
   616  
   617  	defer setConfigFunc(getConfigFunc)
   618  	setConfigFunc(fakeGetConfig)
   619  
   620  	expectVmcGetAndUpdate(t, mock, testManagedCluster, true, false)
   621  	expectSyncServiceAccount(t, mock, testManagedCluster, true)
   622  	expectSyncRoleBinding(t, mock, testManagedCluster, true)
   623  	expectSyncAgent(t, mock, testManagedCluster, false, true)
   624  	expectMockCallsForListingRancherUsers(mock)
   625  	expectSyncRegistration(t, mock, testManagedCluster, false)
   626  	expectSyncManifest(t, mock, mockStatus, mockRequestSender, testManagedCluster, false, rancherManifestYAML)
   627  	expectRancherConfigK8sCalls(t, mock, false)
   628  	expectMockCallsForCreateClusterRoleBindingTemplate(mock, unitTestRancherClusterID)
   629  	expectPushManifestRequests(t, mockRequestSender, mock)
   630  	expectSyncCACertRancherK8sCalls(t, mock, mockRequestSender, false)
   631  	expectThanosDelete(t, mock)
   632  	expectSyncPrometheusScraper(mock, testManagedCluster, prometheusYaml, jobs, true, getCaCrt(), func(configMap *corev1.ConfigMap) error {
   633  
   634  		asserts.Len(configMap.Data, 2, "no data found")
   635  		asserts.NotNil(configMap.Data["ca-test"], "No cert entry found")
   636  		prometheusYaml := configMap.Data["prometheus.yml"]
   637  		asserts.NotEmpty(prometheusYaml, "No prometheus config yaml found")
   638  
   639  		scrapeConfig, err := getScrapeConfig(prometheusYaml, testManagedCluster)
   640  		if err != nil {
   641  			asserts.Fail("failed due to error %v", err)
   642  		}
   643  		validateScrapeConfig(t, scrapeConfig, prometheusConfigBasePath, true)
   644  		return nil
   645  	}, func(secret *corev1.Secret) error {
   646  		scrapeConfigYaml := secret.Data[constants.PromAdditionalScrapeConfigsSecretKey]
   647  		scrapeConfigs, err := metricsutils.ParseScrapeConfig(string(scrapeConfigYaml))
   648  		if err != nil {
   649  			asserts.Fail("failed due to error %v", err)
   650  		}
   651  		scrapeConfig := getJob(scrapeConfigs.Children(), testManagedCluster)
   652  		validateScrapeConfig(t, scrapeConfig, managedCertsBasePath, true)
   653  		return nil
   654  	}, func(secret *corev1.Secret) error {
   655  		asserts.NotEmpty(secret.Data["ca-test"], "Expected to find a managed cluster TLS cert")
   656  		return nil
   657  	})
   658  
   659  	// expect status updated with condition Ready=true
   660  	expectStatusUpdateReadyCondition(asserts, mock, mockStatus, corev1.ConditionTrue, "", false)
   661  
   662  	// Create and make the request
   663  	request := newRequest(namespace, testManagedCluster)
   664  	reconciler := newVMCReconciler(mock)
   665  	result, err := reconciler.Reconcile(context.TODO(), request)
   666  
   667  	// Validate the results
   668  	mocker.Finish()
   669  	asserts.NoError(err)
   670  	asserts.Equal(true, result.Requeue)
   671  	asserts.Equal(time.Duration(vpoconstants.ReconcileLoopRequeueInterval), result.RequeueAfter)
   672  }
   673  
   674  // TestCreateVMC tests the Reconcile method for the following use case
   675  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
   676  // WHEN a VerrazzanoManagedCluster resource has been applied
   677  // AND the cluster has already been registered with Rancher
   678  // THEN ensure all the objects are created
   679  func TestCreateVMCClusterAlreadyRegistered(t *testing.T) {
   680  	// clear any cached user auth tokens when the test completes
   681  	defer rancherutil.DeleteStoredTokens()
   682  
   683  	namespace := constants.VerrazzanoMultiClusterNamespace
   684  	asserts := assert.New(t)
   685  	mocker := gomock.NewController(t)
   686  	mock := mocks.NewMockClient(mocker)
   687  	mockStatus := mocks.NewMockStatusWriter(mocker)
   688  	asserts.NotNil(mockStatus)
   689  
   690  	mockRequestSender := mocks.NewMockRequestSender(mocker)
   691  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   692  	defer func() {
   693  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   694  	}()
   695  	rancherutil.RancherHTTPClient = mockRequestSender
   696  
   697  	defer setConfigFunc(getConfigFunc)
   698  	setConfigFunc(fakeGetConfig)
   699  
   700  	expectVmcGetAndUpdate(t, mock, testManagedCluster, true, true)
   701  	expectSyncServiceAccount(t, mock, testManagedCluster, true)
   702  	expectSyncRoleBinding(t, mock, testManagedCluster, true)
   703  	expectSyncAgent(t, mock, testManagedCluster, false, true)
   704  	expectMockCallsForListingRancherUsers(mock)
   705  	expectSyncRegistration(t, mock, testManagedCluster, false)
   706  	expectSyncManifest(t, mock, mockStatus, mockRequestSender, testManagedCluster, true, rancherManifestYAML)
   707  	expectRancherConfigK8sCalls(t, mock, false)
   708  	expectMockCallsForCreateClusterRoleBindingTemplate(mock, unitTestRancherClusterID)
   709  	expectPushManifestRequests(t, mockRequestSender, mock)
   710  	expectSyncCACertRancherK8sCalls(t, mock, mockRequestSender, false)
   711  	expectThanosDelete(t, mock)
   712  	expectSyncPrometheusScraper(mock, testManagedCluster, "", "", true, getCaCrt(), func(configMap *corev1.ConfigMap) error {
   713  		asserts.Len(configMap.Data, 2, "no data found")
   714  		asserts.NotEmpty(configMap.Data["ca-test"], "No cert entry found")
   715  		prometheusYaml := configMap.Data["prometheus.yml"]
   716  		asserts.NotEmpty(prometheusYaml, "No prometheus config yaml found")
   717  
   718  		scrapeConfig, err := getScrapeConfig(prometheusYaml, testManagedCluster)
   719  		if err != nil {
   720  			asserts.Fail("failed due to error %v", err)
   721  		}
   722  		validateScrapeConfig(t, scrapeConfig, prometheusConfigBasePath, true)
   723  		return nil
   724  	}, func(secret *corev1.Secret) error {
   725  		scrapeConfigYaml := secret.Data[constants.PromAdditionalScrapeConfigsSecretKey]
   726  		scrapeConfigs, err := metricsutils.ParseScrapeConfig(string(scrapeConfigYaml))
   727  		if err != nil {
   728  			asserts.Fail("failed due to error %v", err)
   729  		}
   730  		scrapeConfig := getJob(scrapeConfigs.Children(), testManagedCluster)
   731  		validateScrapeConfig(t, scrapeConfig, managedCertsBasePath, true)
   732  		return nil
   733  	}, func(secret *corev1.Secret) error {
   734  		asserts.NotEmpty(secret.Data["ca-test"], "Expected to find a managed cluster TLS cert")
   735  		return nil
   736  	})
   737  
   738  	// expect status updated with condition Ready=true
   739  	expectStatusUpdateReadyCondition(asserts, mock, mockStatus, corev1.ConditionTrue, "", false)
   740  
   741  	// Create and make the request
   742  	request := newRequest(namespace, testManagedCluster)
   743  	reconciler := newVMCReconciler(mock)
   744  	result, err := reconciler.Reconcile(context.TODO(), request)
   745  
   746  	// Validate the results
   747  	mocker.Finish()
   748  	asserts.NoError(err)
   749  	asserts.Equal(true, result.Requeue)
   750  	asserts.Equal(time.Duration(vpoconstants.ReconcileLoopRequeueInterval), result.RequeueAfter)
   751  }
   752  
   753  // TestCreateVMCSyncSvcAccountFailed tests the Reconcile method for the following use case
   754  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
   755  // WHEN syncing of service account fails
   756  // THEN ensure that the VMC status is updated to Ready=false with an appropriate message
   757  func TestCreateVMCSyncSvcAccountFailed(t *testing.T) {
   758  	// clear any cached user auth tokens when the test completes
   759  	defer rancherutil.DeleteStoredTokens()
   760  
   761  	namespace := constants.VerrazzanoMultiClusterNamespace
   762  	asserts := assert.New(t)
   763  	mocker := gomock.NewController(t)
   764  	mock := mocks.NewMockClient(mocker)
   765  	mockStatus := mocks.NewMockStatusWriter(mocker)
   766  	asserts.NotNil(mockStatus)
   767  
   768  	defer setConfigFunc(getConfigFunc)
   769  	setConfigFunc(fakeGetConfig)
   770  
   771  	expectVmcGetAndUpdate(t, mock, testManagedCluster, true, false)
   772  	expectSyncServiceAccount(t, mock, testManagedCluster, false)
   773  
   774  	// expect status updated with condition Ready=true
   775  	expectStatusUpdateReadyCondition(asserts, mock, mockStatus, corev1.ConditionFalse, "failing syncServiceAccount", false)
   776  
   777  	errCount := testutil.ToFloat64(reconcileErrorCount)
   778  
   779  	// Create and make the request
   780  	request := newRequest(namespace, testManagedCluster)
   781  	reconciler := newVMCReconciler(mock)
   782  	result, err := reconciler.Reconcile(context.TODO(), request)
   783  
   784  	// Validate the results - there should have been no error returned for failing to sync svc account, but the reconcile
   785  	// error metric should have been incremented and the request should be requeued
   786  	mocker.Finish()
   787  	asserts.NoError(err)
   788  	asserts.Equal(true, result.Requeue)
   789  	asserts.NotEqual(time.Duration(0), result.RequeueAfter)
   790  	asserts.Equal(errCount+1, testutil.ToFloat64(reconcileErrorCount))
   791  }
   792  
   793  // TestCreateVMCSyncRoleBindingFailed tests the Reconcile method for the following use case
   794  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
   795  // WHEN syncing of role binding fails
   796  // THEN ensure that the VMC status is updated to Ready=false with an appropriate message
   797  func TestCreateVMCSyncRoleBindingFailed(t *testing.T) {
   798  	// clear any cached user auth tokens when the test completes
   799  	defer rancherutil.DeleteStoredTokens()
   800  
   801  	namespace := constants.VerrazzanoMultiClusterNamespace
   802  	name := "test"
   803  
   804  	asserts := assert.New(t)
   805  	mocker := gomock.NewController(t)
   806  	mock := mocks.NewMockClient(mocker)
   807  	mockStatus := mocks.NewMockStatusWriter(mocker)
   808  	asserts.NotNil(mockStatus)
   809  
   810  	defer setConfigFunc(getConfigFunc)
   811  	setConfigFunc(fakeGetConfig)
   812  
   813  	expectVmcGetAndUpdate(t, mock, name, true, false)
   814  	expectSyncServiceAccount(t, mock, name, true)
   815  	expectSyncRoleBinding(t, mock, name, false)
   816  
   817  	// expect status updated with condition Ready=true
   818  	expectStatusUpdateReadyCondition(asserts, mock, mockStatus, corev1.ConditionFalse, "failing syncRoleBinding", false)
   819  
   820  	// Create and make the request
   821  	request := newRequest(namespace, name)
   822  	reconciler := newVMCReconciler(mock)
   823  	result, err := reconciler.Reconcile(context.TODO(), request)
   824  
   825  	// Validate the results - there should have been an error returned
   826  	mocker.Finish()
   827  	asserts.Nil(err)
   828  	asserts.Equal(true, result.Requeue)
   829  	asserts.NotEqual(time.Duration(0), result.RequeueAfter)
   830  }
   831  
   832  // TestDeleteVMC tests the Reconcile method for the following use case
   833  // GIVEN a request to reconcile an VerrazzanoManagedCluster resource
   834  // WHEN a VerrazzanoManagedCluster resource has been deleted
   835  // THEN ensure the object is not processed
   836  func TestDeleteVMC(t *testing.T) {
   837  	// clear any cached user auth tokens when the test completes
   838  	defer rancherutil.DeleteStoredTokens()
   839  
   840  	namespace := "verrazzano-install"
   841  	asserts := assert.New(t)
   842  	mocker := gomock.NewController(t)
   843  	mock := mocks.NewMockClient(mocker)
   844  
   845  	mockRequestSender := mocks.NewMockRequestSender(mocker)
   846  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   847  	defer func() {
   848  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   849  	}()
   850  	rancherutil.RancherHTTPClient = mockRequestSender
   851  
   852  	// Expect all of the calls when deleting a VMC
   853  	expectMockCallsForDelete(t, mock, namespace)
   854  	expectRancherGetAuthTokenHTTPCall(t, mockRequestSender)
   855  	expectThanosDelete(t, mock)
   856  
   857  	// Expect an API call to delete the Rancher cluster
   858  	mockRequestSender.EXPECT().
   859  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURIMethod("DELETE", clustersPath+"/"+unitTestRancherClusterID)).
   860  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
   861  			r := io.NopCloser(bytes.NewReader([]byte("")))
   862  			resp := &http.Response{
   863  				StatusCode: http.StatusOK,
   864  				Body:       r,
   865  			}
   866  			return resp, nil
   867  		})
   868  
   869  	// Expect a call to update the VerrazzanoManagedCluster finalizer
   870  	mock.EXPECT().
   871  		Update(gomock.Any(), gomock.Any(), gomock.Any()).
   872  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
   873  			asserts.True(len(vmc.ObjectMeta.Finalizers) == 0, "Wrong number of finalizers")
   874  			return nil
   875  		})
   876  
   877  	mock.EXPECT().
   878  		List(gomock.Any(), &v1beta1.VerrazzanoList{}, gomock.Not(gomock.Nil())).
   879  		DoAndReturn(func(ctx context.Context, list *v1beta1.VerrazzanoList, opts ...client.ListOption) error {
   880  			vz := v1beta1.Verrazzano{}
   881  			list.Items = append(list.Items, vz)
   882  			return nil
   883  		})
   884  
   885  	// Create and make the request
   886  	request := newRequest(namespace, testManagedCluster)
   887  	reconciler := newVMCReconciler(mock)
   888  	result, err := reconciler.Reconcile(context.TODO(), request)
   889  
   890  	// Validate the results
   891  	mocker.Finish()
   892  	asserts.NoError(err)
   893  	asserts.Equal(false, result.Requeue)
   894  	asserts.Equal(time.Duration(0), result.RequeueAfter)
   895  }
   896  
   897  // TestDeleteVMCFailedDeletingRancherCluster tests deleting a VMC when there are errors attempting to
   898  // delete the Rancher cluster.
   899  func TestDeleteVMCFailedDeletingRancherCluster(t *testing.T) {
   900  	// clear any cached user auth tokens when the test completes
   901  	defer rancherutil.DeleteStoredTokens()
   902  
   903  	namespace := "verrazzano-install"
   904  	asserts := assert.New(t)
   905  	mocker := gomock.NewController(t)
   906  	mock := mocks.NewMockClient(mocker)
   907  	mockStatus := mocks.NewMockStatusWriter(mocker)
   908  	asserts.NotNil(mockStatus)
   909  
   910  	mockRequestSender := mocks.NewMockRequestSender(mocker)
   911  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
   912  	defer func() {
   913  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
   914  	}()
   915  	rancherutil.RancherHTTPClient = mockRequestSender
   916  
   917  	// GIVEN a VMC is being deleted
   918  	//  WHEN we fail creating a Rancher API client that will be used to delete the cluster in Rancher
   919  	//  THEN the appropriate status is set on the VMC and the finalizer is not removed
   920  
   921  	// Expect all of the calls when deleting a VMC
   922  	expectMockCallsForDelete(t, mock, namespace)
   923  	expectThanosDelete(t, mock)
   924  
   925  	// Expect an HTTP request to fetch the admin token from Rancher - return an error
   926  	mockRequestSender.EXPECT().
   927  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(loginURIPath)).
   928  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
   929  			asserts.Equal(loginQueryString, req.URL.RawQuery)
   930  
   931  			r := io.NopCloser(bytes.NewReader([]byte("")))
   932  			resp := &http.Response{
   933  				StatusCode: http.StatusBadRequest,
   934  				Body:       r,
   935  				Request:    &http.Request{Method: http.MethodDelete},
   936  			}
   937  			return resp, nil
   938  		})
   939  
   940  	mock.EXPECT().Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: testManagedCluster}, gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
   941  		DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
   942  			return nil
   943  		})
   944  
   945  	mock.EXPECT().Status().Return(mockStatus)
   946  	mockStatus.EXPECT().
   947  		Update(gomock.Any(), gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
   948  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
   949  			asserts.Equal(v1alpha1.DeleteFailed, vmc.Status.RancherRegistration.Status)
   950  			asserts.Equal("Failed to create Rancher API client", vmc.Status.RancherRegistration.Message)
   951  			return nil
   952  		})
   953  
   954  	mock.EXPECT().
   955  		List(gomock.Any(), gomock.Any(), gomock.Not(gomock.Nil())).
   956  		DoAndReturn(func(ctx context.Context, list *v1beta1.VerrazzanoList, opts ...client.ListOption) error {
   957  			vz := v1beta1.Verrazzano{}
   958  			list.Items = append(list.Items, vz)
   959  			return nil
   960  		})
   961  
   962  	// Create and make the request
   963  	request := newRequest(namespace, testManagedCluster)
   964  	reconciler := newVMCReconciler(mock)
   965  	result, err := reconciler.Reconcile(context.TODO(), request)
   966  
   967  	// Validate the results
   968  	mocker.Finish()
   969  	asserts.NoError(err)
   970  	asserts.Equal(true, result.Requeue)
   971  
   972  	// GIVEN a VMC is being deleted
   973  	//  WHEN we fail attempting to delete the cluster in Rancher
   974  	//  THEN the appropriate status is set on the VMC and the finalizer is not removed
   975  
   976  	mock = mocks.NewMockClient(mocker)
   977  	mockStatus = mocks.NewMockStatusWriter(mocker)
   978  	mockRequestSender = mocks.NewMockRequestSender(mocker)
   979  	rancherutil.RancherHTTPClient = mockRequestSender
   980  
   981  	// Expect all of the calls when deleting a VMC
   982  	expectMockCallsForDelete(t, mock, namespace)
   983  	expectRancherGetAuthTokenHTTPCall(t, mockRequestSender)
   984  	expectThanosDelete(t, mock)
   985  
   986  	// Expect an API call to delete the Rancher cluster - return an error
   987  	mockRequestSender.EXPECT().
   988  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURIMethod("DELETE", clustersPath+"/"+unitTestRancherClusterID)).
   989  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
   990  			r := io.NopCloser(bytes.NewReader([]byte("")))
   991  			resp := &http.Response{
   992  				StatusCode: http.StatusConflict,
   993  				Body:       r,
   994  				Request:    &http.Request{Method: http.MethodDelete},
   995  			}
   996  			return resp, nil
   997  		})
   998  
   999  	mock.EXPECT().Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: testManagedCluster}, gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  1000  		DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
  1001  			return nil
  1002  		})
  1003  
  1004  	mock.EXPECT().Status().Return(mockStatus)
  1005  	mockStatus.EXPECT().
  1006  		Update(gomock.Any(), gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  1007  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  1008  			asserts.Equal(v1alpha1.DeleteFailed, vmc.Status.RancherRegistration.Status)
  1009  			asserts.Equal("Failed deleting cluster", vmc.Status.RancherRegistration.Message)
  1010  			return nil
  1011  		})
  1012  
  1013  	mock.EXPECT().
  1014  		List(gomock.Any(), gomock.Any(), gomock.Not(gomock.Nil())).
  1015  		DoAndReturn(func(ctx context.Context, list *v1beta1.VerrazzanoList, opts ...client.ListOption) error {
  1016  			vz := v1beta1.Verrazzano{}
  1017  			list.Items = append(list.Items, vz)
  1018  			return nil
  1019  		})
  1020  
  1021  	// Create and make the request
  1022  	request = newRequest(namespace, testManagedCluster)
  1023  	reconciler = newVMCReconciler(mock)
  1024  	result, err = reconciler.Reconcile(context.TODO(), request)
  1025  
  1026  	// Validate the results
  1027  	mocker.Finish()
  1028  	asserts.NoError(err)
  1029  	asserts.Equal(true, result.Requeue)
  1030  }
  1031  
  1032  // TestSyncManifestSecretFailRancherRegistration tests syncing the manifest secret
  1033  // when Rancher registration fails
  1034  // GIVEN a call to sync the manifest secret
  1035  // WHEN Rancher registration fails
  1036  // THEN the manifest secret is still created and syncManifestSecret returns no error
  1037  func TestSyncManifestSecretFailRancherRegistration(t *testing.T) {
  1038  	// clear any cached user auth tokens when the test completes
  1039  	defer rancherutil.DeleteStoredTokens()
  1040  
  1041  	asserts := assert.New(t)
  1042  	mocker := gomock.NewController(t)
  1043  	mock := mocks.NewMockClient(mocker)
  1044  	mockStatus := mocks.NewMockStatusWriter(mocker)
  1045  	asserts.NotNil(mockStatus)
  1046  
  1047  	clusterName := "cluster1"
  1048  	caData := "ca"
  1049  	userData := "user"
  1050  	passwordData := "pw"
  1051  	kubeconfigData := "fakekubeconfig"
  1052  	urlData := "https://testhost:443"
  1053  
  1054  	// Expect a call to get the Agent secret
  1055  	mock.EXPECT().
  1056  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: GetAgentSecretName(clusterName)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1057  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1058  			secret.Data = map[string][]byte{
  1059  				mcconstants.KubeconfigKey: []byte(kubeconfigData),
  1060  			}
  1061  			return nil
  1062  		})
  1063  
  1064  	// Expect a call to get the registration secret
  1065  	mock.EXPECT().
  1066  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: GetRegistrationSecretName(clusterName)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1067  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1068  			secret.Data = map[string][]byte{
  1069  				mcconstants.ManagedClusterNameKey:   []byte(clusterName),
  1070  				mcconstants.CaCrtKey:                []byte(caData),
  1071  				mcconstants.RegistrationUsernameKey: []byte(userData),
  1072  				mcconstants.RegistrationPasswordKey: []byte(passwordData),
  1073  				mcconstants.ESURLKey:                []byte(urlData),
  1074  			}
  1075  			return nil
  1076  		})
  1077  
  1078  	// Expect a call to get the manifest secret - return that it does not exist
  1079  	mock.EXPECT().
  1080  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: GetManifestSecretName(clusterName)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1081  		Return(errors.NewNotFound(schema.GroupResource{Group: constants.VerrazzanoMultiClusterNamespace, Resource: "Secret"}, GetManifestSecretName(clusterName)))
  1082  
  1083  	// Expect a call to get the Rancher ingress and return no spec rules, which will cause registration to fail
  1084  	mock.EXPECT().
  1085  		Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: rancherNamespace, Name: rancherIngressName}), gomock.Not(gomock.Nil()), gomock.Any()).
  1086  		DoAndReturn(func(ctx context.Context, nsName types.NamespacedName, ingress *networkingv1.Ingress, opts ...client.GetOption) error {
  1087  			return nil
  1088  		})
  1089  
  1090  	// Expect to get existing VMC for status update
  1091  	mock.EXPECT().Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: clusterName}, gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  1092  		DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
  1093  			return nil
  1094  		})
  1095  
  1096  	mock.EXPECT().Get(gomock.Any(), types.NamespacedName{Namespace: constants.RancherSystemNamespace, Name: rancherAdminSecret}, gomock.AssignableToTypeOf(&corev1.Secret{}), gomock.Any()).
  1097  		DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1098  			secret.Data = map[string][]byte{
  1099  				"password": []byte("super-secret"),
  1100  			}
  1101  			return nil
  1102  		})
  1103  
  1104  	mock.EXPECT().Status().Return(mockStatus)
  1105  	mockStatus.EXPECT().
  1106  		Update(gomock.Any(), gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  1107  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  1108  			asserts.Equal(v1alpha1.RegistrationFailed, vmc.Status.RancherRegistration.Status)
  1109  			asserts.Contains(vmc.Status.RancherRegistration.Message, "Failed to create Rancher API client")
  1110  			return nil
  1111  		})
  1112  
  1113  	// Expect a call to create the manifest secret
  1114  	mock.EXPECT().
  1115  		Create(gomock.Any(), gomock.AssignableToTypeOf(&corev1.Secret{}), gomock.Any()).
  1116  		DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.CreateOption) error {
  1117  			data := secret.Data[mcconstants.YamlKey]
  1118  			asserts.NotZero(len(data), "Expected yaml data in manifest secret")
  1119  			return nil
  1120  		})
  1121  
  1122  	// Expect a call to update the VerrazzanoManagedCluster kubeconfig secret testManagedCluster - return success
  1123  	mock.EXPECT().
  1124  		Update(gomock.Any(), gomock.Any(), gomock.Any()).
  1125  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  1126  			asserts.Equal(vmc.Spec.ManagedClusterManifestSecret, GetManifestSecretName(clusterName), "Manifest secret testManagedCluster did not match")
  1127  			return nil
  1128  		})
  1129  
  1130  	// Create a reconciler and call the function to sync the manifest secret - the call to register the cluster with Rancher will
  1131  	// fail but the result of syncManifestSecret should be success
  1132  	vmc := v1alpha1.VerrazzanoManagedCluster{ObjectMeta: metav1.ObjectMeta{Name: clusterName, Namespace: constants.VerrazzanoMultiClusterNamespace}}
  1133  	reconciler := newVMCReconciler(mock)
  1134  	reconciler.log = vzlog.DefaultLogger()
  1135  
  1136  	vzVMCWaitingForClusterID, err := reconciler.syncManifestSecret(context.TODO(), &vmc)
  1137  
  1138  	// Validate the results
  1139  	mocker.Finish()
  1140  	asserts.NoError(err)
  1141  	asserts.False(vzVMCWaitingForClusterID)
  1142  }
  1143  
  1144  // TestSyncManifestSecretEmptyRancherManifest tests syncing the manifest secret
  1145  // when Rancher returns an empty registration manifest YAML string.
  1146  // GIVEN a call to sync the manifest secret
  1147  // WHEN Rancher returns an empty manifest
  1148  // THEN the status is set to failed on the VMC with an appropriate message and the syncManifestSecret call returns an error
  1149  func TestSyncManifestSecretEmptyRancherManifest(t *testing.T) {
  1150  	// clear any cached user auth tokens when the test completes
  1151  	defer rancherutil.DeleteStoredTokens()
  1152  
  1153  	asserts := assert.New(t)
  1154  	mocker := gomock.NewController(t)
  1155  	mock := mocks.NewMockClient(mocker)
  1156  	mockStatus := mocks.NewMockStatusWriter(mocker)
  1157  	asserts.NotNil(mockStatus)
  1158  
  1159  	mockRequestSender := mocks.NewMockRequestSender(mocker)
  1160  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
  1161  	defer func() {
  1162  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
  1163  	}()
  1164  	rancherutil.RancherHTTPClient = mockRequestSender
  1165  
  1166  	defer setConfigFunc(getConfigFunc)
  1167  	setConfigFunc(fakeGetConfig)
  1168  
  1169  	caData := "ca"
  1170  	userData := "user"
  1171  	passwordData := "pw"
  1172  	kubeconfigData := "fakekubeconfig"
  1173  	urlData := "https://testhost:443"
  1174  
  1175  	mock.EXPECT().
  1176  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: GetAgentSecretName(testManagedCluster)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1177  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1178  			secret.Data = map[string][]byte{
  1179  				mcconstants.KubeconfigKey: []byte(kubeconfigData),
  1180  			}
  1181  			return nil
  1182  		})
  1183  
  1184  	// Expect a call to get the registration secret
  1185  	mock.EXPECT().
  1186  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: GetRegistrationSecretName(testManagedCluster)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1187  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1188  			secret.Data = map[string][]byte{
  1189  				mcconstants.ManagedClusterNameKey:   []byte(testManagedCluster),
  1190  				mcconstants.CaCrtKey:                []byte(caData),
  1191  				mcconstants.RegistrationUsernameKey: []byte(userData),
  1192  				mcconstants.RegistrationPasswordKey: []byte(passwordData),
  1193  				mcconstants.ESURLKey:                []byte(urlData),
  1194  			}
  1195  			return nil
  1196  		})
  1197  
  1198  	// Expect all the calls needed to register the cluster with Rancher - note we are passing an empty string for the Rancher manifest YAML
  1199  	// that will be returned when calling the Rancher API
  1200  	expectRegisterClusterWithRancher(t, mock, mockRequestSender, testManagedCluster, false, "")
  1201  
  1202  	// Expect to get existing VMC for status update
  1203  	mock.EXPECT().Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: testManagedCluster}, gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  1204  		DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
  1205  			return nil
  1206  		})
  1207  
  1208  	// Expect the Rancher registration status to be set appropriately
  1209  	mock.EXPECT().Status().Return(mockStatus)
  1210  	mockStatus.EXPECT().
  1211  		Update(gomock.Any(), gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  1212  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  1213  			asserts.Equal(v1alpha1.RegistrationFailed, vmc.Status.RancherRegistration.Status)
  1214  			asserts.Equal(unitTestRancherClusterID, vmc.Status.RancherRegistration.ClusterID)
  1215  			asserts.Equal("Empty Rancher manifest YAML", vmc.Status.RancherRegistration.Message)
  1216  			return nil
  1217  		})
  1218  
  1219  	// Create a reconciler and call the function to sync the manifest secret
  1220  	vmc := v1alpha1.VerrazzanoManagedCluster{ObjectMeta: metav1.ObjectMeta{Name: testManagedCluster, Namespace: constants.VerrazzanoMultiClusterNamespace}}
  1221  	reconciler := newVMCReconciler(mock)
  1222  	reconciler.log = vzlog.DefaultLogger()
  1223  
  1224  	vzVMCWaitingForClusterID, err := reconciler.syncManifestSecret(context.TODO(), &vmc)
  1225  
  1226  	// Validate the results
  1227  	mocker.Finish()
  1228  	asserts.ErrorContains(err, "Failed retrieving Rancher manifest, YAML is an empty string")
  1229  	asserts.False(vzVMCWaitingForClusterID)
  1230  }
  1231  
  1232  // TestRegisterClusterWithRancherK8sErrorCases tests errors cases using the Kubernetes
  1233  // client when registering with Rancher.
  1234  func TestRegisterClusterWithRancherK8sErrorCases(t *testing.T) {
  1235  	// clear any cached user auth tokens when the test completes
  1236  	defer rancherutil.DeleteStoredTokens()
  1237  
  1238  	asserts := assert.New(t)
  1239  	mocker := gomock.NewController(t)
  1240  	mock := mocks.NewMockClient(mocker)
  1241  
  1242  	// GIVEN a call to register a managed cluster with Rancher
  1243  	// WHEN the call to get the ingress host name returns no ingress rules
  1244  	// THEN the registration call returns an error
  1245  
  1246  	// Expect a call to get the ingress host name but there are no ingress rules
  1247  	mock.EXPECT().
  1248  		Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: rancherNamespace, Name: rancherIngressName}), gomock.Not(gomock.Nil()), gomock.Any()).
  1249  		DoAndReturn(func(ctx context.Context, nsName types.NamespacedName, ingress *networkingv1.Ingress, opts ...client.GetOption) error {
  1250  			return nil
  1251  		})
  1252  
  1253  	// Expect a call for the verrazzano cluser user secret
  1254  	mock.EXPECT().
  1255  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: constants.VerrazzanoClusterRancherName}, gomock.AssignableToTypeOf(&corev1.Secret{}), gomock.Any()).
  1256  		DoAndReturn(func(ctx context.Context, nsName types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1257  			secret.Data = map[string][]byte{
  1258  				"password": []byte("super-secret"),
  1259  			}
  1260  			return nil
  1261  		})
  1262  
  1263  	rc, err := rancherutil.NewVerrazzanoClusterRancherConfig(mock, rancherutil.RancherIngressServiceHost(), vzlog.DefaultLogger())
  1264  
  1265  	mocker.Finish()
  1266  	asserts.Error(err)
  1267  	asserts.Nil(rc)
  1268  
  1269  	// GIVEN a call to register a managed cluster with Rancher
  1270  	// WHEN the call to get the Rancher root CA cert secret fails
  1271  	// THEN the registration call returns an error
  1272  	mocker = gomock.NewController(t)
  1273  	mock = mocks.NewMockClient(mocker)
  1274  
  1275  	// Expect a call to get the ingress host name
  1276  	mock.EXPECT().
  1277  		Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: rancherNamespace, Name: rancherIngressName}), gomock.Not(gomock.Nil()), gomock.Any()).
  1278  		DoAndReturn(func(ctx context.Context, nsName types.NamespacedName, ingress *networkingv1.Ingress, opts ...client.GetOption) error {
  1279  			rule := networkingv1.IngressRule{Host: "rancher.unit-test.com"}
  1280  			ingress.Spec.Rules = append(ingress.Spec.Rules, rule)
  1281  			return nil
  1282  		})
  1283  
  1284  	// Expect a call to get the secret with the Rancher root CA cert but the call fails
  1285  	mock.EXPECT().
  1286  		Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: rancherNamespace, Name: rancherTLSSecret}), gomock.Not(gomock.Nil()), gomock.Any()).
  1287  		DoAndReturn(func(ctx context.Context, nsName types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1288  			return errors.NewResourceExpired("something bad happened")
  1289  		})
  1290  
  1291  	// Expect a call for the verrazzano cluser user secret
  1292  	mock.EXPECT().
  1293  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: constants.VerrazzanoClusterRancherName}, gomock.AssignableToTypeOf(&corev1.Secret{}), gomock.Any()).
  1294  		DoAndReturn(func(ctx context.Context, nsName types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1295  			secret.Data = map[string][]byte{
  1296  				"password": []byte("super-secret"),
  1297  			}
  1298  			return nil
  1299  		})
  1300  
  1301  	rc, err = rancherutil.NewVerrazzanoClusterRancherConfig(mock, rancherutil.RancherIngressServiceHost(), vzlog.DefaultLogger())
  1302  
  1303  	mocker.Finish()
  1304  	asserts.Error(err)
  1305  	asserts.Nil(rc)
  1306  }
  1307  
  1308  // TestRegisterClusterWithRancherHTTPErrorCases tests errors cases using the HTTP
  1309  // client when registering with Rancher.
  1310  func TestRegisterClusterWithRancherHTTPErrorCases(t *testing.T) {
  1311  	// clear any cached user auth tokens when the test completes
  1312  	defer rancherutil.DeleteStoredTokens()
  1313  
  1314  	asserts := assert.New(t)
  1315  	mocker := gomock.NewController(t)
  1316  	mock := mocks.NewMockClient(mocker)
  1317  	mockRequestSender := mocks.NewMockRequestSender(mocker)
  1318  
  1319  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
  1320  	defer func() {
  1321  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
  1322  	}()
  1323  	rancherutil.RancherHTTPClient = mockRequestSender
  1324  
  1325  	// GIVEN a call to register a managed cluster with Rancher
  1326  	// WHEN the call to get the Rancher admin token fails
  1327  	// THEN the registration call returns an error
  1328  
  1329  	// Expect all of the Kubernetes calls
  1330  	expectRancherConfigK8sCalls(t, mock, false)
  1331  
  1332  	// Expect an HTTP request to fetch the admin token from Rancher but the call fails
  1333  	mockRequestSender.EXPECT().
  1334  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(loginURIPath)).
  1335  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1336  			r := io.NopCloser(bytes.NewReader([]byte{}))
  1337  			resp := &http.Response{
  1338  				StatusCode: http.StatusUnauthorized,
  1339  				Body:       r,
  1340  				Request:    &http.Request{Method: http.MethodPost},
  1341  			}
  1342  			return resp, nil
  1343  		})
  1344  
  1345  	rc, err := rancherutil.NewVerrazzanoClusterRancherConfig(mock, rancherutil.RancherIngressServiceHost(), vzlog.DefaultLogger())
  1346  
  1347  	mocker.Finish()
  1348  	asserts.Error(err)
  1349  	asserts.Nil(rc)
  1350  	rancherutil.DeleteStoredTokens()
  1351  
  1352  	// GIVEN a call to register a managed cluster with Rancher
  1353  	// WHEN the call to import the cluster into Rancher fails
  1354  	// THEN the registration call returns an error
  1355  	mocker = gomock.NewController(t)
  1356  	mock = mocks.NewMockClient(mocker)
  1357  	mockRequestSender = mocks.NewMockRequestSender(mocker)
  1358  	rancherutil.RancherHTTPClient = mockRequestSender
  1359  
  1360  	// Expect all of the Kubernetes calls
  1361  	expectRancherConfigK8sCalls(t, mock, false)
  1362  
  1363  	// Expect an HTTP request to fetch the admin token from Rancher
  1364  	mockRequestSender.EXPECT().
  1365  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(loginURIPath)).
  1366  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1367  			r := io.NopCloser(bytes.NewReader([]byte(`{"token":"unit-test-token"}`)))
  1368  			resp := &http.Response{
  1369  				StatusCode: http.StatusCreated,
  1370  				Body:       r,
  1371  				Request:    &http.Request{Method: http.MethodPost},
  1372  			}
  1373  			return resp, nil
  1374  		})
  1375  
  1376  	// Expect an HTTP request to import the cluster to Rancher but the call fails
  1377  	mockRequestSender.EXPECT().
  1378  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(clusterPath)).
  1379  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1380  			r := io.NopCloser(bytes.NewReader([]byte{}))
  1381  			resp := &http.Response{
  1382  				StatusCode: http.StatusConflict,
  1383  				Body:       r,
  1384  				Request:    &http.Request{Method: http.MethodPost},
  1385  			}
  1386  			return resp, nil
  1387  		})
  1388  
  1389  	rc, err = rancherutil.NewVerrazzanoClusterRancherConfig(mock, rancherutil.RancherIngressServiceHost(), vzlog.DefaultLogger())
  1390  	asserts.NoError(err)
  1391  
  1392  	regYAML, _, err := RegisterManagedClusterWithRancher(rc, testManagedCluster, "", vzlog.DefaultLogger())
  1393  
  1394  	mocker.Finish()
  1395  	asserts.Error(err)
  1396  	asserts.Empty(regYAML)
  1397  	rancherutil.DeleteStoredTokens()
  1398  
  1399  	// GIVEN a call to register a managed cluster with Rancher
  1400  	// WHEN the call to create the Rancher registration token fails
  1401  	// THEN the registration call returns an error
  1402  	mocker = gomock.NewController(t)
  1403  	mock = mocks.NewMockClient(mocker)
  1404  	mockRequestSender = mocks.NewMockRequestSender(mocker)
  1405  	rancherutil.RancherHTTPClient = mockRequestSender
  1406  
  1407  	// Expect all of the Kubernetes calls
  1408  	expectRancherConfigK8sCalls(t, mock, false)
  1409  
  1410  	// Expect an HTTP request to fetch the admin token from Rancher
  1411  	mockRequestSender.EXPECT().
  1412  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(loginURIPath)).
  1413  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1414  			r := io.NopCloser(bytes.NewReader([]byte(`{"token":"unit-test-token"}`)))
  1415  			resp := &http.Response{
  1416  				StatusCode: http.StatusCreated,
  1417  				Body:       r,
  1418  				Request:    &http.Request{Method: http.MethodPost},
  1419  			}
  1420  			return resp, nil
  1421  		})
  1422  
  1423  	// Expect an HTTP request to import the cluster to Rancher
  1424  	mockRequestSender.EXPECT().
  1425  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(clusterPath)).
  1426  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1427  			r := io.NopCloser(bytes.NewReader([]byte(`{"id":"some-cluster"}`)))
  1428  			resp := &http.Response{
  1429  				StatusCode: http.StatusCreated,
  1430  				Body:       r,
  1431  			}
  1432  			return resp, nil
  1433  		})
  1434  
  1435  	// Expect an HTTP request to get the registration token in Rancher for the clusterId
  1436  	mockRequestSender.EXPECT().
  1437  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(clusterRegTokenPath)).
  1438  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1439  			asserts.Contains(clusterRegTokenPath, req.URL.Path)
  1440  
  1441  			_, err := io.ReadAll(req.Body)
  1442  			asserts.NoError(err)
  1443  
  1444  			r := io.NopCloser(bytes.NewReader([]byte(`{"data":[]}`)))
  1445  			resp := &http.Response{
  1446  				StatusCode: http.StatusOK,
  1447  				Body:       r,
  1448  				Request:    &http.Request{Method: http.MethodGet},
  1449  			}
  1450  			return resp, nil
  1451  		})
  1452  
  1453  	// Expect an HTTP request to create the registration token in Rancher but the call fails
  1454  	mockRequestSender.EXPECT().
  1455  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(clusterRegTokenPath)).
  1456  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1457  			r := io.NopCloser(bytes.NewReader([]byte{}))
  1458  			resp := &http.Response{
  1459  				StatusCode: http.StatusBadRequest,
  1460  				Body:       r,
  1461  				Request:    &http.Request{Method: http.MethodPost},
  1462  			}
  1463  			return resp, nil
  1464  		})
  1465  
  1466  	rc, err = rancherutil.NewVerrazzanoClusterRancherConfig(mock, rancherutil.RancherIngressServiceHost(), vzlog.DefaultLogger())
  1467  	asserts.NoError(err)
  1468  
  1469  	regYAML, _, err = RegisterManagedClusterWithRancher(rc, testManagedCluster, "", vzlog.DefaultLogger())
  1470  
  1471  	mocker.Finish()
  1472  	asserts.Error(err)
  1473  	asserts.Empty(regYAML)
  1474  	rancherutil.DeleteStoredTokens()
  1475  
  1476  	// GIVEN a call to register a managed cluster with Rancher
  1477  	// WHEN the call to get the Rancher manifest YAML fails
  1478  	// THEN the registration call returns an error
  1479  	mocker = gomock.NewController(t)
  1480  	mock = mocks.NewMockClient(mocker)
  1481  	mockRequestSender = mocks.NewMockRequestSender(mocker)
  1482  	rancherutil.RancherHTTPClient = mockRequestSender
  1483  
  1484  	// Expect all of the Kubernetes calls
  1485  	expectRancherConfigK8sCalls(t, mock, false)
  1486  
  1487  	// Expect an HTTP request to fetch the admin token from Rancher
  1488  	mockRequestSender.EXPECT().
  1489  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(loginURIPath)).
  1490  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1491  			r := io.NopCloser(bytes.NewReader([]byte(`{"token":"unit-test-token"}`)))
  1492  			resp := &http.Response{
  1493  				StatusCode: http.StatusCreated,
  1494  				Body:       r,
  1495  				Request:    &http.Request{Method: http.MethodPost},
  1496  			}
  1497  			return resp, nil
  1498  		})
  1499  
  1500  	// Expect an HTTP request to import the cluster to Rancher
  1501  	mockRequestSender.EXPECT().
  1502  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(clusterPath)).
  1503  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1504  			r := io.NopCloser(bytes.NewReader([]byte(`{"id":"some-cluster"}`)))
  1505  			resp := &http.Response{
  1506  				StatusCode: http.StatusCreated,
  1507  				Body:       r,
  1508  			}
  1509  			return resp, nil
  1510  		})
  1511  
  1512  	// Expect an HTTP request to get the registration token in Rancher for the clusterId
  1513  	mockRequestSender.EXPECT().
  1514  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(clusterRegTokenPath)).
  1515  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1516  			asserts.Contains(clusterRegTokenPath, req.URL.Path)
  1517  
  1518  			_, err := io.ReadAll(req.Body)
  1519  			asserts.NoError(err)
  1520  
  1521  			// return a response with the CRT
  1522  			r := io.NopCloser(bytes.NewReader([]byte(`{"data":[{"token":"manifest-token","state":"active","clusterId":"some-cluster"}]}`)))
  1523  			resp := &http.Response{
  1524  				StatusCode: http.StatusOK,
  1525  				Body:       r,
  1526  				Request:    &http.Request{Method: http.MethodGet},
  1527  			}
  1528  			return resp, nil
  1529  		})
  1530  
  1531  	// Expect an HTTP request to fetch the manifest YAML from Rancher but the call fails
  1532  	mockRequestSender.EXPECT().
  1533  		Do(gomock.Not(gomock.Nil()), gomock.Not(gomock.Nil())).
  1534  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1535  			r := io.NopCloser(bytes.NewReader([]byte{}))
  1536  			resp := &http.Response{
  1537  				StatusCode: http.StatusUnsupportedMediaType,
  1538  				Body:       r,
  1539  				Request:    &http.Request{Method: http.MethodGet},
  1540  			}
  1541  			return resp, nil
  1542  		})
  1543  
  1544  	rc, err = rancherutil.NewVerrazzanoClusterRancherConfig(mock, rancherutil.RancherIngressServiceHost(), vzlog.DefaultLogger())
  1545  	asserts.NoError(err)
  1546  
  1547  	regYAML, _, err = RegisterManagedClusterWithRancher(rc, testManagedCluster, "", vzlog.DefaultLogger())
  1548  
  1549  	mocker.Finish()
  1550  	asserts.Error(err)
  1551  	asserts.Empty(regYAML)
  1552  }
  1553  
  1554  // GIVEN a call to register a managed cluster with Rancher
  1555  // WHEN the call to get the admin token from Rancher fails
  1556  // AND the error is retryable
  1557  // THEN ensure that the request is retried
  1558  func TestRegisterClusterWithRancherRetryRequest(t *testing.T) {
  1559  	// clear any cached user auth tokens when the test completes
  1560  	defer rancherutil.DeleteStoredTokens()
  1561  
  1562  	asserts := assert.New(t)
  1563  	mocker := gomock.NewController(t)
  1564  	mock := mocks.NewMockClient(mocker)
  1565  	mockRequestSender := mocks.NewMockRequestSender(mocker)
  1566  
  1567  	savedRancherHTTPClient := rancherutil.RancherHTTPClient
  1568  	defer func() {
  1569  		rancherutil.RancherHTTPClient = savedRancherHTTPClient
  1570  	}()
  1571  	rancherutil.RancherHTTPClient = mockRequestSender
  1572  
  1573  	// replace the retry configuration so all of the retries happen very quickly
  1574  	retrySteps := 3
  1575  	savedRetry := rancherutil.DefaultRetry
  1576  	defer func() {
  1577  		rancherutil.DefaultRetry = savedRetry
  1578  	}()
  1579  	rancherutil.DefaultRetry = wait.Backoff{
  1580  		Steps:    retrySteps,
  1581  		Duration: 1 * time.Millisecond,
  1582  		Factor:   1.0,
  1583  		Jitter:   0.1,
  1584  	}
  1585  
  1586  	// Expect all of the Kubernetes calls
  1587  	expectRancherConfigK8sCalls(t, mock, false)
  1588  
  1589  	// Expect an HTTP request to fetch the admin token from Rancher - return an error response and
  1590  	// the request should be retried for a total of "retrySteps" # of times
  1591  	mockRequestSender.EXPECT().
  1592  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(loginURIPath)).
  1593  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  1594  			r := io.NopCloser(bytes.NewReader([]byte{}))
  1595  			resp := &http.Response{
  1596  				StatusCode: http.StatusInternalServerError,
  1597  				Body:       r,
  1598  				Request:    &http.Request{Method: http.MethodPost},
  1599  			}
  1600  			return resp, nil
  1601  		}).Times(retrySteps)
  1602  
  1603  	_, err := rancherutil.NewVerrazzanoClusterRancherConfig(mock, rancherutil.RancherIngressServiceHost(), vzlog.DefaultLogger())
  1604  
  1605  	mocker.Finish()
  1606  	asserts.Error(err)
  1607  }
  1608  
  1609  // TestUpateStatus tests the updateStatus function
  1610  func TestUpateStatus(t *testing.T) {
  1611  	// clear any cached user auth tokens when the test completes
  1612  	defer rancherutil.DeleteStoredTokens()
  1613  
  1614  	asserts := assert.New(t)
  1615  	mocker := gomock.NewController(t)
  1616  	mock := mocks.NewMockClient(mocker)
  1617  	mockStatus := mocks.NewMockStatusWriter(mocker)
  1618  	asserts.NotNil(mockStatus)
  1619  
  1620  	// Expect the requests for the existing VMC resource
  1621  	mock.EXPECT().Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: testManagedCluster}, gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  1622  		DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
  1623  			return nil
  1624  		}).AnyTimes()
  1625  
  1626  	// GIVEN a VMC with a status state unset and the last agent connect time set
  1627  	// WHEN the updateStatus function is called
  1628  	// THEN the status state is updated to pending
  1629  	mock.EXPECT().Status().Return(mockStatus)
  1630  	mockStatus.EXPECT().
  1631  		Update(gomock.Any(), gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  1632  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  1633  			asserts.Equal(v1alpha1.StatePending, vmc.Status.State)
  1634  			return nil
  1635  		})
  1636  
  1637  	vmc := v1alpha1.VerrazzanoManagedCluster{
  1638  		ObjectMeta: metav1.ObjectMeta{
  1639  			Name:      testManagedCluster,
  1640  			Namespace: constants.VerrazzanoMultiClusterNamespace,
  1641  		},
  1642  		Status: v1alpha1.VerrazzanoManagedClusterStatus{
  1643  			LastAgentConnectTime: &metav1.Time{
  1644  				Time: time.Now(),
  1645  			},
  1646  		},
  1647  	}
  1648  	reconciler := newVMCReconciler(mock)
  1649  	reconciler.log = vzlog.DefaultLogger()
  1650  
  1651  	err := reconciler.updateStatus(context.TODO(), &vmc)
  1652  
  1653  	// Validate the results
  1654  	mocker.Finish()
  1655  	asserts.NoError(err)
  1656  
  1657  	// GIVEN a VMC with a status state of pending and the last agent connect time set
  1658  	// WHEN the updateStatus function is called
  1659  	// THEN the status state is updated to active
  1660  	mock.EXPECT().Status().Return(mockStatus)
  1661  	mockStatus.EXPECT().
  1662  		Update(gomock.Any(), gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  1663  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  1664  			asserts.Equal(v1alpha1.StateActive, vmc.Status.State)
  1665  			return nil
  1666  		})
  1667  
  1668  	err = reconciler.updateStatus(context.TODO(), &vmc)
  1669  
  1670  	// Validate the results
  1671  	mocker.Finish()
  1672  	asserts.NoError(err)
  1673  
  1674  	// GIVEN a VMC with a last agent connect time set in the past
  1675  	// WHEN the updateStatus function is called
  1676  	// THEN the status state is updated to inactive
  1677  	past := metav1.Unix(0, 0)
  1678  	vmc.Status.LastAgentConnectTime = &past
  1679  
  1680  	// Expect the Rancher registration status to be set appropriately
  1681  	mock.EXPECT().Status().Return(mockStatus)
  1682  	mockStatus.EXPECT().
  1683  		Update(gomock.Any(), gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  1684  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  1685  			asserts.Equal(v1alpha1.StateInactive, vmc.Status.State)
  1686  			return nil
  1687  		})
  1688  
  1689  	err = reconciler.updateStatus(context.TODO(), &vmc)
  1690  
  1691  	// Validate the results
  1692  	mocker.Finish()
  1693  	asserts.NoError(err)
  1694  }
  1695  
  1696  // newScheme creates a new scheme that includes this package's object to use for testing
  1697  func newScheme() *runtime.Scheme {
  1698  	scheme := runtime.NewScheme()
  1699  	_ = corev1.AddToScheme(scheme)
  1700  	_ = v1alpha1.AddToScheme(scheme)
  1701  	return scheme
  1702  }
  1703  
  1704  // newRequest creates a new reconciler request for testing
  1705  // namespace - The namespace to use in the request
  1706  // testManagedCluster - The testManagedCluster to use in the request
  1707  func newRequest(namespace string, name string) ctrl.Request {
  1708  	return ctrl.Request{
  1709  		NamespacedName: types.NamespacedName{
  1710  			Namespace: namespace,
  1711  			Name:      name}}
  1712  }
  1713  
  1714  // newVMCReconciler creates a new reconciler for testing
  1715  // c - The Kerberos client to inject into the reconciler
  1716  func newVMCReconciler(c client.Client) VerrazzanoManagedClusterReconciler {
  1717  	scheme := newScheme()
  1718  	reconciler := VerrazzanoManagedClusterReconciler{
  1719  		Client: c,
  1720  		Scheme: scheme}
  1721  	return reconciler
  1722  }
  1723  
  1724  func fakeGetConfig() (*rest.Config, error) {
  1725  	conf := rest.Config{
  1726  		TLSClientConfig: rest.TLSClientConfig{
  1727  			CAData: []byte("fakeCA"),
  1728  		},
  1729  	}
  1730  	return &conf, nil
  1731  }
  1732  
  1733  // Expect syncRoleBinding related calls
  1734  func expectSyncRoleBinding(t *testing.T, mock *mocks.MockClient, name string, succeed bool) {
  1735  	asserts := assert.New(t)
  1736  
  1737  	// Expect a call to get the RoleBinding - return that it does not exist
  1738  	mock.EXPECT().
  1739  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: generateManagedResourceName(name)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1740  		Return(errors.NewNotFound(schema.GroupResource{Group: "", Resource: "RoleBinding"}, generateManagedResourceName(name)))
  1741  
  1742  	// Expect a call to create the RoleBinding - return success or failure based on the succeed argument
  1743  	mock.EXPECT().
  1744  		Create(gomock.Any(), gomock.Any(), gomock.Any()).
  1745  		DoAndReturn(func(ctx context.Context, binding *rbacv1.RoleBinding, opts ...client.CreateOption) error {
  1746  			if succeed {
  1747  				asserts.Equalf(generateManagedResourceName(name), binding.Name, "RoleBinding testManagedCluster did not match")
  1748  				asserts.Equalf(vpoconstants.MCClusterRole, binding.RoleRef.Name, "RoleBinding roleref did not match")
  1749  				asserts.Equalf(generateManagedResourceName(name), binding.Subjects[0].Name, "Subject did not match")
  1750  				asserts.Equalf(constants.VerrazzanoMultiClusterNamespace, binding.Subjects[0].Namespace, "Subject namespace did not match")
  1751  				return nil
  1752  			}
  1753  			return errors.NewInternalError(fmt.Errorf("failing syncRoleBinding"))
  1754  		})
  1755  }
  1756  
  1757  // Expect syncServiceAccount related calls
  1758  func expectSyncServiceAccount(t *testing.T, mock *mocks.MockClient, name string, succeed bool) {
  1759  	asserts := assert.New(t)
  1760  
  1761  	// Expect a call to get the ServiceAccount - return that it does not exist
  1762  	mock.EXPECT().
  1763  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: generateManagedResourceName(name)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1764  		Return(errors.NewNotFound(schema.GroupResource{Group: "", Resource: "ServiceAccount"}, generateManagedResourceName(name)))
  1765  
  1766  	// Expect a call to create the ServiceAccount - return success
  1767  	mock.EXPECT().
  1768  		Create(gomock.Any(), gomock.Any(), gomock.Any()).
  1769  		DoAndReturn(func(ctx context.Context, serviceAccount *corev1.ServiceAccount, opts ...client.CreateOption) error {
  1770  			asserts.Equalf(constants.VerrazzanoMultiClusterNamespace, serviceAccount.Namespace, "ServiceAccount namespace did not match")
  1771  			asserts.Equalf(generateManagedResourceName(name), serviceAccount.Name, "ServiceAccount testManagedCluster did not match")
  1772  			return nil
  1773  		})
  1774  
  1775  	// Expect a call to get the Token Secret - return that it does not exist
  1776  	mock.EXPECT().
  1777  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: generateManagedResourceName(name) + "-token"}, gomock.Not(gomock.Nil()), gomock.Any()).
  1778  		Return(errors.NewNotFound(schema.GroupResource{Group: "", Resource: "Secret"}, generateManagedResourceName(name)+"-token"))
  1779  
  1780  	// Expect a call to create the Token Secret - return success
  1781  	mock.EXPECT().
  1782  		Create(gomock.Any(), gomock.Any(), gomock.Any()).
  1783  		DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.CreateOption) error {
  1784  			asserts.Equalf(constants.VerrazzanoMultiClusterNamespace, secret.Namespace, "Secret namespace did not match")
  1785  			asserts.Equalf(generateManagedResourceName(name)+"-token", secret.Name, "Secret testManagedCluster did not match")
  1786  			return nil
  1787  		})
  1788  
  1789  	// Expect a call to update the VerrazzanoManagedCluster service account name - return success or
  1790  	// failure depending on the succeed argument
  1791  	mock.EXPECT().
  1792  		Update(gomock.Any(), gomock.Any(), gomock.Any()).
  1793  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  1794  			if succeed {
  1795  				asserts.Equal(vmc.Spec.ServiceAccount, generateManagedResourceName(name), "ServiceAccount testManagedCluster did not match")
  1796  				return nil
  1797  			}
  1798  			return errors.NewInternalError(fmt.Errorf("failing syncServiceAccount"))
  1799  		})
  1800  }
  1801  
  1802  // Expect syncAgent related calls
  1803  func expectSyncAgent(t *testing.T, mock *mocks.MockClient, name string, rancherEnabled bool, noSASecret bool) {
  1804  	saSecretName := "saSecret"
  1805  	rancherURL := "http://rancher-url"
  1806  	rancherCAData := "rancherCAData"
  1807  	userAPIServerURL := "https://testurl"
  1808  	if noSASecret {
  1809  		// Expect a call to get the ServiceAccount, return without the secret set
  1810  		mock.EXPECT().
  1811  			Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: generateManagedResourceName(name)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1812  			DoAndReturn(func(ctx context.Context, name types.NamespacedName, sa *corev1.ServiceAccount, opts ...client.GetOption) error {
  1813  				sa.Name = name.Name
  1814  				return nil
  1815  			})
  1816  		// Set the secret name to the service account token created by the VMC controller
  1817  		saSecretName = generateManagedResourceName(name) + "-token"
  1818  
  1819  	} else {
  1820  		// Expect a call to get the ServiceAccount, return one with the secret testManagedCluster set
  1821  		mock.EXPECT().
  1822  			Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: generateManagedResourceName(name)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1823  			DoAndReturn(func(ctx context.Context, name types.NamespacedName, sa *corev1.ServiceAccount, opts ...client.GetOption) error {
  1824  				sa.Secrets = []corev1.ObjectReference{{
  1825  					Name: saSecretName,
  1826  				}}
  1827  				return nil
  1828  			})
  1829  	}
  1830  
  1831  	// Expect a call to list Verrazzanos and return a Verrazzano that has Rancher URL in status only
  1832  	// if rancherEnabled is true
  1833  	mock.EXPECT().
  1834  		List(gomock.Any(), &v1beta1.VerrazzanoList{}, gomock.Not(gomock.Nil())).
  1835  		DoAndReturn(func(ctx context.Context, list *v1beta1.VerrazzanoList, opts ...client.ListOption) error {
  1836  			var status v1beta1.VerrazzanoStatus
  1837  			if rancherEnabled {
  1838  				status = v1beta1.VerrazzanoStatus{
  1839  					VerrazzanoInstance: &v1beta1.InstanceInfo{RancherURL: &rancherURL},
  1840  				}
  1841  			}
  1842  			vz := v1beta1.Verrazzano{
  1843  				Spec:   v1beta1.VerrazzanoSpec{},
  1844  				Status: status,
  1845  			}
  1846  			list.Items = append(list.Items, vz)
  1847  			return nil
  1848  		})
  1849  
  1850  	// Expect a call to get the service token secret, return the secret with the token
  1851  	mock.EXPECT().
  1852  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: saSecretName}, gomock.Not(gomock.Nil()), gomock.Any()).
  1853  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1854  			secret.Data = map[string][]byte{
  1855  				mcconstants.TokenKey: []byte(token),
  1856  			}
  1857  			return nil
  1858  		})
  1859  
  1860  	if rancherEnabled {
  1861  		// Expect a call to get the tls-ca secret, return the secret as not found
  1862  		mock.EXPECT().
  1863  			Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoSystemNamespace, Name: constants.PrivateCABundle}, gomock.Not(gomock.Nil()), gomock.Any()).
  1864  			Return(errors.NewNotFound(schema.GroupResource{Group: constants.VerrazzanoSystemNamespace, Resource: "Secret"}, constants.PrivateCABundle))
  1865  
  1866  		// Expect a call to get the Rancher ingress tls secret, return the secret with the fields set
  1867  		mock.EXPECT().
  1868  			Get(gomock.Any(), types.NamespacedName{Namespace: constants.RancherSystemNamespace, Name: rancherTLSSecret}, gomock.Not(gomock.Nil()), gomock.Any()).
  1869  			DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1870  				secret.Data = map[string][]byte{
  1871  					mcconstants.CaCrtKey: []byte(rancherCAData),
  1872  				}
  1873  				return nil
  1874  			})
  1875  	} else {
  1876  		// Expect a call to get the verrazzano-admin-cluster configmap
  1877  		mock.EXPECT().
  1878  			Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: vpoconstants.AdminClusterConfigMapName}, gomock.Not(gomock.Nil()), gomock.Any()).
  1879  			DoAndReturn(func(ctx context.Context, name types.NamespacedName, cm *corev1.ConfigMap, opts ...client.GetOption) error {
  1880  				cm.Data = map[string]string{
  1881  					vpoconstants.ServerDataKey: userAPIServerURL,
  1882  				}
  1883  				return nil
  1884  			})
  1885  	}
  1886  
  1887  	// Expect a call to get the Agent secret - return that it does not exist
  1888  	mock.EXPECT().
  1889  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: GetAgentSecretName(name)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1890  		Return(errors.NewNotFound(schema.GroupResource{Group: constants.VerrazzanoMultiClusterNamespace, Resource: "Secret"}, GetAgentSecretName(name)))
  1891  
  1892  	// Expect a call to create the Agent secret
  1893  	mock.EXPECT().
  1894  		Create(gomock.Any(), gomock.Any(), gomock.Any()).
  1895  		DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.CreateOption) error {
  1896  			adminKubeconfig := string(secret.Data[mcconstants.KubeconfigKey])
  1897  			if rancherEnabled {
  1898  				assert.Contains(t, adminKubeconfig, "server: "+rancherURL)
  1899  			} else {
  1900  				assert.Contains(t, adminKubeconfig, "server: "+userAPIServerURL)
  1901  			}
  1902  			return nil
  1903  		})
  1904  }
  1905  
  1906  // Expect syncRegistration related calls
  1907  func expectSyncRegistration(t *testing.T, mock *mocks.MockClient, name string, externalES bool) {
  1908  	const vzEsURLData = "https://vz-testhost:443"
  1909  	const vzUserData = "vz-user"
  1910  	const vzPasswordData = "vz-pw"
  1911  	const vzCaData = "vz-ca"
  1912  
  1913  	const externalEsURLData = "https://external-testhost:443"
  1914  	const externalUserData = "external-user"
  1915  	const externalPasswordData = "external-pw"
  1916  	const externalCaData = "external-ca"
  1917  
  1918  	fluentdESURL := "http://verrazzano-authproxy-opensearch:8775"
  1919  	fluentdESSecret := "verrazzano"
  1920  	esSecret := constants.VerrazzanoESInternal
  1921  	if externalES {
  1922  		fluentdESURL = externalEsURLData
  1923  		fluentdESSecret = "some-external-es-secret"
  1924  		esSecret = fluentdESSecret
  1925  	}
  1926  
  1927  	asserts := assert.New(t)
  1928  
  1929  	// Expect a call to get the registration secret - return that it does not exist
  1930  	mock.EXPECT().
  1931  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: GetRegistrationSecretName(name)}, gomock.Not(gomock.Nil()), gomock.Any()).
  1932  		Return(errors.NewNotFound(schema.GroupResource{Group: constants.VerrazzanoMultiClusterNamespace, Resource: "Secret"}, GetRegistrationSecretName(name)))
  1933  
  1934  	// Expect a call to list Verrazzanos - return the Verrazzano configured with fluentd
  1935  	mock.EXPECT().
  1936  		List(gomock.Any(), &v1beta1.VerrazzanoList{}, gomock.Not(gomock.Nil())).
  1937  		DoAndReturn(func(ctx context.Context, list *v1beta1.VerrazzanoList, opts ...client.ListOption) error {
  1938  			vz := v1beta1.Verrazzano{
  1939  				Spec: v1beta1.VerrazzanoSpec{
  1940  					Components: v1beta1.ComponentSpec{
  1941  						Fluentd: &v1beta1.FluentdComponent{
  1942  							OpenSearchURL:    fluentdESURL,
  1943  							OpenSearchSecret: fluentdESSecret,
  1944  						},
  1945  					},
  1946  				},
  1947  			}
  1948  			list.Items = append(list.Items, vz)
  1949  			return nil
  1950  		}).Times(5)
  1951  
  1952  	// Expect a call to get the tls ingress and return the ingress.
  1953  	if !externalES {
  1954  		mock.EXPECT().
  1955  			Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoSystemNamespace, Name: operatorOSIngress}, gomock.Not(gomock.Nil()), gomock.Any()).
  1956  			DoAndReturn(func(ctx context.Context, name types.NamespacedName, ingress *networkingv1.Ingress, opts ...client.GetOption) error {
  1957  				ingress.TypeMeta = metav1.TypeMeta{
  1958  					APIVersion: "networking.k8s.io/v1",
  1959  					Kind:       "ingress"}
  1960  				ingress.ObjectMeta = metav1.ObjectMeta{
  1961  					Namespace: name.Namespace,
  1962  					Name:      name.Name}
  1963  				ingress.Spec.Rules = []networkingv1.IngressRule{{
  1964  					Host: "vz-testhost",
  1965  				}}
  1966  				return nil
  1967  			})
  1968  	}
  1969  
  1970  	// Expect a call to get the opensearch secret, return the secret with the fields set
  1971  	mock.EXPECT().
  1972  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoSystemNamespace, Name: esSecret}, gomock.Not(gomock.Nil()), gomock.Any()).
  1973  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1974  			if externalES {
  1975  				secret.Data = map[string][]byte{
  1976  					mcconstants.VerrazzanoUsernameKey: []byte(externalUserData),
  1977  					mcconstants.VerrazzanoPasswordKey: []byte(externalPasswordData),
  1978  					mcconstants.FluentdESCaBundleKey:  []byte(externalCaData),
  1979  				}
  1980  			} else {
  1981  				secret.Data = map[string][]byte{
  1982  					mcconstants.VerrazzanoUsernameKey: []byte(vzUserData),
  1983  					mcconstants.VerrazzanoPasswordKey: []byte(vzPasswordData),
  1984  				}
  1985  			}
  1986  			return nil
  1987  		})
  1988  
  1989  	// Expect a call to get the tls secret, return the secret with the fields set
  1990  	mock.EXPECT().
  1991  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoSystemNamespace, Name: "verrazzano-tls"}, gomock.Not(gomock.Nil()), gomock.Any()).
  1992  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  1993  			secret.Data = map[string][]byte{
  1994  				mcconstants.CaCrtKey: []byte(vzCaData),
  1995  			}
  1996  			return nil
  1997  		})
  1998  
  1999  	// Expect a call to get the tls-ca secret, return the secret as not found
  2000  	mock.EXPECT().
  2001  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoSystemNamespace, Name: constants.PrivateCABundle}, gomock.Not(gomock.Nil()), gomock.Any()).
  2002  		Return(errors.NewNotFound(schema.GroupResource{Group: constants.VerrazzanoSystemNamespace, Resource: "Secret"}, constants.PrivateCABundle))
  2003  
  2004  	// Expect a call to get the keycloak ingress and return the ingress.
  2005  	mock.EXPECT().
  2006  		Get(gomock.Any(), types.NamespacedName{Namespace: "keycloak", Name: "keycloak"}, gomock.Not(gomock.Nil()), gomock.Any()).
  2007  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, ingress *networkingv1.Ingress, opts ...client.GetOption) error {
  2008  			ingress.TypeMeta = metav1.TypeMeta{
  2009  				APIVersion: "networking.k8s.io/v1",
  2010  				Kind:       "ingress"}
  2011  			ingress.ObjectMeta = metav1.ObjectMeta{
  2012  				Namespace: name.Namespace,
  2013  				Name:      name.Name}
  2014  			ingress.Spec.Rules = []networkingv1.IngressRule{{
  2015  				Host: "keycloak",
  2016  			}}
  2017  			return nil
  2018  		})
  2019  
  2020  	// Expect a call to get the dex ingress and return the ingress.
  2021  	mock.EXPECT().
  2022  		Get(gomock.Any(), types.NamespacedName{Namespace: "verrazzano-auth", Name: "dex"}, gomock.Not(gomock.Nil()), gomock.Any()).
  2023  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, ingress *networkingv1.Ingress, opts ...client.GetOption) error {
  2024  			ingress.TypeMeta = metav1.TypeMeta{
  2025  				APIVersion: "networking.k8s.io/v1",
  2026  				Kind:       "ingress"}
  2027  			ingress.ObjectMeta = metav1.ObjectMeta{
  2028  				Namespace: name.Namespace,
  2029  				Name:      name.Name}
  2030  			ingress.Spec.Rules = []networkingv1.IngressRule{{
  2031  				Host: "auth",
  2032  			}}
  2033  			return nil
  2034  		})
  2035  
  2036  	// Expect a call to create the registration secret
  2037  	mock.EXPECT().
  2038  		Create(gomock.Any(), gomock.Any(), gomock.Any()).
  2039  		DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.CreateOption) error {
  2040  			asserts.Equalf(testManagedCluster, string(secret.Data[mcconstants.ManagedClusterNameKey]), "Incorrect cluster testManagedCluster in Registration secret ")
  2041  			asserts.Equalf("https://keycloak", string(secret.Data[mcconstants.KeycloakURLKey]), "Incorrect admin ca bundle in Registration secret ")
  2042  			asserts.Equalf(vzCaData, string(secret.Data[mcconstants.AdminCaBundleKey]), "Incorrect admin ca bundle in Registration secret ")
  2043  			if externalES {
  2044  				asserts.Equalf(externalEsURLData, string(secret.Data[mcconstants.ESURLKey]), "Incorrect ES URL in Registration secret ")
  2045  				asserts.Equalf(externalCaData, string(secret.Data[mcconstants.ESCaBundleKey]), "Incorrect ES ca bundle in Registration secret ")
  2046  				asserts.Equalf(externalUserData, string(secret.Data[mcconstants.RegistrationUsernameKey]), "Incorrect ES user in Registration secret ")
  2047  				asserts.Equalf(externalPasswordData, string(secret.Data[mcconstants.RegistrationPasswordKey]), "Incorrect ES password in Registration secret ")
  2048  			} else {
  2049  				asserts.Equalf(vzEsURLData, string(secret.Data[mcconstants.ESURLKey]), "Incorrect ES URL in Registration secret ")
  2050  				asserts.Equalf(vzCaData, string(secret.Data[mcconstants.ESCaBundleKey]), "Incorrect ES ca bundle in Registration secret ")
  2051  				asserts.Equalf(vzUserData, string(secret.Data[mcconstants.RegistrationUsernameKey]), "Incorrect ES user in Registration secret ")
  2052  				asserts.Equalf(vzPasswordData, string(secret.Data[mcconstants.RegistrationPasswordKey]), "Incorrect ES password in Registration secret ")
  2053  			}
  2054  			return nil
  2055  		})
  2056  }
  2057  
  2058  // Expect syncManifest related calls
  2059  func expectSyncManifest(t *testing.T, mock *mocks.MockClient, mockStatus *mocks.MockStatusWriter, mockRequestSender *mocks.MockRequestSender,
  2060  	name string, clusterAlreadyRegistered bool, expectedRancherYAML string) {
  2061  
  2062  	asserts := assert.New(t)
  2063  	clusterName := "cluster1"
  2064  	caData := "ca"
  2065  	userData := "user"
  2066  	passwordData := "pw"
  2067  	kubeconfigData := "fakekubeconfig"
  2068  	urlData := "https://testhost:443"
  2069  
  2070  	// Expect a call to get the Agent secret
  2071  	mock.EXPECT().
  2072  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: GetAgentSecretName(name)}, gomock.Not(gomock.Nil()), gomock.Any()).
  2073  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  2074  			secret.Data = map[string][]byte{
  2075  				mcconstants.KubeconfigKey: []byte(kubeconfigData),
  2076  			}
  2077  			return nil
  2078  		})
  2079  
  2080  	// Expect a call to get the registration secret
  2081  	mock.EXPECT().
  2082  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: GetRegistrationSecretName(name)}, gomock.Not(gomock.Nil()), gomock.Any()).
  2083  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  2084  			secret.Data = map[string][]byte{
  2085  				mcconstants.ManagedClusterNameKey:   []byte(clusterName),
  2086  				mcconstants.CaCrtKey:                []byte(caData),
  2087  				mcconstants.RegistrationUsernameKey: []byte(userData),
  2088  				mcconstants.RegistrationPasswordKey: []byte(passwordData),
  2089  				mcconstants.ESURLKey:                []byte(urlData),
  2090  			}
  2091  			return nil
  2092  		})
  2093  
  2094  	// Expect a call to get the manifest secret - return that it does not exist
  2095  	mock.EXPECT().
  2096  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: GetManifestSecretName(name)}, gomock.Not(gomock.Nil()), gomock.Any()).
  2097  		Return(errors.NewNotFound(schema.GroupResource{Group: constants.VerrazzanoMultiClusterNamespace, Resource: "Secret"}, GetManifestSecretName(name)))
  2098  
  2099  	// Expect all the calls needed to register the cluster with Rancher
  2100  	expectRegisterClusterWithRancher(t, mock, mockRequestSender, name, clusterAlreadyRegistered, expectedRancherYAML)
  2101  
  2102  	// Expect to get existing VMC for status update
  2103  	mock.EXPECT().Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: testManagedCluster}, gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  2104  		DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
  2105  			return nil
  2106  		})
  2107  
  2108  	mock.EXPECT().Status().Return(mockStatus)
  2109  	mockStatus.EXPECT().
  2110  		Update(gomock.Any(), gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  2111  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  2112  			asserts.Equal(v1alpha1.RegistrationCompleted, vmc.Status.RancherRegistration.Status)
  2113  			asserts.Equal(unitTestRancherClusterID, vmc.Status.RancherRegistration.ClusterID)
  2114  			asserts.Equal(fmt.Sprintf("Registration of managed cluster completed successfully for cluster test with ID %s", unitTestRancherClusterID),
  2115  				vmc.Status.RancherRegistration.Message)
  2116  			return nil
  2117  		})
  2118  
  2119  	// Expect a call to create the manifest secret
  2120  	mock.EXPECT().
  2121  		Create(gomock.Any(), gomock.Any(), gomock.Any()).
  2122  		DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.CreateOption) error {
  2123  			data := secret.Data[mcconstants.YamlKey]
  2124  			asserts.NotZero(len(data), "Expected yaml data in manifest secret")
  2125  
  2126  			// YAML should contain the Rancher manifest things
  2127  			yamlString := string(data)
  2128  			asserts.True(strings.Contains(yamlString, expectedRancherYAML), "Manifest YAML does not contain the correct Rancher resources")
  2129  
  2130  			return nil
  2131  		})
  2132  
  2133  	// Expect a call to update the VerrazzanoManagedCluster kubeconfig secret testManagedCluster - return success
  2134  	mock.EXPECT().
  2135  		Update(gomock.Any(), gomock.Any(), gomock.Any()).
  2136  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  2137  			asserts.Equal(vmc.Spec.ManagedClusterManifestSecret, GetManifestSecretName(name), "Manifest secret testManagedCluster did not match")
  2138  			return nil
  2139  		})
  2140  }
  2141  
  2142  func expectPushManifestRequests(t *testing.T, mockRequestSender *mocks.MockRequestSender, mock *mocks.MockClient) {
  2143  	// expect a login request for the vz-cluster-reg user
  2144  	expectRancherGetAuthTokenHTTPCall(t, mockRequestSender)
  2145  	expectRancherConfigK8sCalls(t, mock, true)
  2146  	addVerrazzanoSystemNamespaceMock(mockRequestSender, unitTestRancherClusterID, true)
  2147  
  2148  	mockRequestSender.EXPECT().
  2149  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(clustersPath+"/"+unitTestRancherClusterID)).
  2150  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  2151  			var resp *http.Response
  2152  			r := io.NopCloser(bytes.NewReader([]byte(`{"state":"inactive", "agentImage":"test"}`)))
  2153  			resp = &http.Response{
  2154  				StatusCode: http.StatusOK,
  2155  				Body:       r,
  2156  			}
  2157  			return resp, nil
  2158  		})
  2159  }
  2160  
  2161  func expectVmcGetAndUpdate(t *testing.T, mock *mocks.MockClient, name string, caSecretExists bool, rancherClusterAlreadyRegistered bool) {
  2162  	asserts := assert.New(t)
  2163  	labels := map[string]string{"label1": "test"}
  2164  
  2165  	// Expect a call to get the VerrazzanoManagedCluster resource.
  2166  	mock.EXPECT().
  2167  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: name}, gomock.Not(gomock.Nil()), gomock.Any()).
  2168  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
  2169  			vmc.TypeMeta = metav1.TypeMeta{
  2170  				APIVersion: apiVersion,
  2171  				Kind:       kind}
  2172  			vmc.ObjectMeta = metav1.ObjectMeta{
  2173  				Namespace: name.Namespace,
  2174  				Name:      name.Name,
  2175  				Labels:    labels}
  2176  			if caSecretExists {
  2177  				vmc.Spec = v1alpha1.VerrazzanoManagedClusterSpec{
  2178  					CASecret: getCASecretName(name.Name),
  2179  				}
  2180  			}
  2181  			vmc.Status = v1alpha1.VerrazzanoManagedClusterStatus{
  2182  				PrometheusHost: getPrometheusHost(),
  2183  			}
  2184  			if rancherClusterAlreadyRegistered {
  2185  				vmc.Status.RancherRegistration = v1alpha1.RancherRegistration{
  2186  					Status:    v1alpha1.RegistrationCompleted,
  2187  					ClusterID: unitTestRancherClusterID,
  2188  				}
  2189  			}
  2190  			return nil
  2191  		})
  2192  
  2193  	// Expect a call to update the VerrazzanoManagedCluster finalizer
  2194  	mock.EXPECT().
  2195  		Update(gomock.Any(), gomock.Any(), gomock.Any()).
  2196  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  2197  			asserts.True(len(vmc.ObjectMeta.Finalizers) == 1, "Wrong number of finalizers")
  2198  			asserts.Equal(finalizerName, vmc.ObjectMeta.Finalizers[0], "wrong finalizer")
  2199  			return nil
  2200  		})
  2201  
  2202  }
  2203  
  2204  func expectSyncPrometheusScraper(mock *mocks.MockClient, vmcName string, prometheusYaml string, jobs string, caSecretExists bool, cacrtSecretData string,
  2205  	f AssertFn, additionalScrapeConfigsAssertFunc secretAssertFn, managedClusterCertsAssertFunc secretAssertFn) {
  2206  	const internalSecretPassword = "nRXlxXgMwN" //nolint:gosec //#gosec G101
  2207  
  2208  	if caSecretExists {
  2209  		// Expect a call to get the prometheus secret - return it
  2210  		mock.EXPECT().
  2211  			Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: getCASecretName(vmcName)}, gomock.Not(gomock.Nil()), gomock.Any()).
  2212  			DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  2213  
  2214  				secret.Data = map[string][]byte{
  2215  					"cacrt": []byte(cacrtSecretData),
  2216  				}
  2217  				return nil
  2218  			})
  2219  	}
  2220  
  2221  	// Expect a call to get the Verrazzano Prometheus internal secret - return it
  2222  	mock.EXPECT().
  2223  		Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoSystemNamespace, Name: constants.VerrazzanoPromInternal}, gomock.Not(gomock.Nil()), gomock.Any()).
  2224  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  2225  			secret.Data = map[string][]byte{
  2226  				mcconstants.VerrazzanoPasswordKey: []byte(internalSecretPassword),
  2227  			}
  2228  			return nil
  2229  		})
  2230  
  2231  	// Expect a call to get the additional scrape config secret - return it
  2232  	mock.EXPECT().
  2233  		Get(gomock.Any(), types.NamespacedName{Namespace: vpoconstants.VerrazzanoMonitoringNamespace, Name: constants.PromAdditionalScrapeConfigsSecretName}, gomock.Not(gomock.Nil()), gomock.Any()).
  2234  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  2235  			secret.Data = map[string][]byte{
  2236  				constants.PromAdditionalScrapeConfigsSecretKey: []byte(jobs),
  2237  			}
  2238  			return nil
  2239  		})
  2240  
  2241  	// Expect a call to get the additional scrape config secret (we call controllerruntime.CreateOrUpdate so it fetches again) - return it
  2242  	mock.EXPECT().
  2243  		Get(gomock.Any(), types.NamespacedName{Namespace: vpoconstants.VerrazzanoMonitoringNamespace, Name: constants.PromAdditionalScrapeConfigsSecretName}, gomock.Not(gomock.Nil()), gomock.Any()).
  2244  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  2245  			secret.Data = map[string][]byte{
  2246  				constants.PromAdditionalScrapeConfigsSecretKey: []byte(jobs),
  2247  			}
  2248  			return nil
  2249  		})
  2250  
  2251  	// Expect a call to update the additional scrape config secret
  2252  	mock.EXPECT().
  2253  		Update(gomock.Any(), gomock.Any(), gomock.Any()).
  2254  		DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.UpdateOption) error {
  2255  			return additionalScrapeConfigsAssertFunc(secret)
  2256  		})
  2257  
  2258  	// Expect a call to get the verrazzano-monitoring namespace
  2259  	mock.EXPECT().
  2260  		Get(gomock.Any(), types.NamespacedName{Name: vpoconstants.VerrazzanoMonitoringNamespace}, gomock.Not(gomock.Nil()), gomock.Any()).
  2261  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, ns *corev1.Namespace, opts ...client.GetOption) error {
  2262  			ns.SetName(vpoconstants.VerrazzanoMonitoringNamespace)
  2263  			return nil
  2264  		})
  2265  
  2266  	// Expect a call to get the managed cluster TLS certs secret - return NotFound error
  2267  	mock.EXPECT().
  2268  		Get(gomock.Any(), types.NamespacedName{Namespace: vpoconstants.VerrazzanoMonitoringNamespace, Name: vpoconstants.PromManagedClusterCACertsSecretName}, gomock.Not(gomock.Nil()), gomock.Any()).
  2269  		Return(errors.NewNotFound(schema.GroupResource{Group: "", Resource: "Secret"}, vpoconstants.PromManagedClusterCACertsSecretName))
  2270  
  2271  	// Expect a call to update the managed cluster TLS certs secret
  2272  	mock.EXPECT().
  2273  		Create(gomock.Any(), gomock.Any(), gomock.Any()).
  2274  		DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.UpdateOption) error {
  2275  			return managedClusterCertsAssertFunc(secret)
  2276  		})
  2277  
  2278  }
  2279  
  2280  // expectRegisterClusterWithRancher asserts all of the expected calls on the Kubernetes client mock and the HTTP client mock
  2281  func expectRegisterClusterWithRancher(t *testing.T,
  2282  	k8sMock *mocks.MockClient,
  2283  	requestSenderMock *mocks.MockRequestSender,
  2284  	clusterName string,
  2285  	clusterAlreadyRegistered bool,
  2286  	expectedRancherYAML string) {
  2287  
  2288  	expectRancherConfigK8sCalls(t, k8sMock, true)
  2289  	expectRegisterClusterWithRancherHTTPCalls(t, requestSenderMock, clusterName, clusterAlreadyRegistered, expectedRancherYAML)
  2290  }
  2291  
  2292  // expectRegisterClusterWithRancherHTTPCalls asserts all of the expected calls on the HTTP client mock
  2293  func expectRegisterClusterWithRancherHTTPCalls(t *testing.T, requestSenderMock *mocks.MockRequestSender, clusterName string, clusterAlreadyRegistered bool, rancherManifestYAML string) {
  2294  	asserts := assert.New(t)
  2295  
  2296  	expectRancherGetAuthTokenHTTPCall(t, requestSenderMock)
  2297  
  2298  	if !clusterAlreadyRegistered {
  2299  		// Cluster is not already registered - we now only expect import to happen if the cluster is NOT already registered
  2300  		// Expect an HTTP request to import the cluster to Rancher
  2301  		requestSenderMock.EXPECT().
  2302  			Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(clusterPath)).
  2303  			DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  2304  				asserts.Equal(clusterPath, req.URL.Path)
  2305  
  2306  				var resp *http.Response
  2307  				r := io.NopCloser(bytes.NewReader([]byte(`{"id":"` + unitTestRancherClusterID + `"}`)))
  2308  				resp = &http.Response{
  2309  					StatusCode: http.StatusCreated,
  2310  					Body:       r,
  2311  				}
  2312  				return resp, nil
  2313  			})
  2314  	}
  2315  
  2316  	manifestToken := "unit-test-manifest-token"
  2317  
  2318  	// Expect an HTTP request to get the registration token in Rancher
  2319  	requestSenderMock.EXPECT().
  2320  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(clusterRegTokenPath)).
  2321  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  2322  			asserts.Contains(clusterRegTokenPath, req.URL.Path)
  2323  
  2324  			// assert that the cluster ID in the request body is what we expect
  2325  			_, err := io.ReadAll(req.Body)
  2326  			asserts.NoError(err)
  2327  
  2328  			// return a response with the empty data, no CRT exists for this cluster
  2329  			r := io.NopCloser(bytes.NewReader([]byte(`{"data":[]}`)))
  2330  			resp := &http.Response{
  2331  				StatusCode: http.StatusOK,
  2332  				Body:       r,
  2333  				Request:    &http.Request{Method: http.MethodGet},
  2334  			}
  2335  			return resp, nil
  2336  		})
  2337  
  2338  	// Expect an HTTP request to create the registration token in Rancher
  2339  	requestSenderMock.EXPECT().
  2340  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(clusterRegTokenPath)).
  2341  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  2342  			asserts.Equal(clusterRegTokenPath, req.URL.Path)
  2343  
  2344  			// assert that the cluster ID in the request body is what we expect
  2345  			body, err := io.ReadAll(req.Body)
  2346  			asserts.NoError(err)
  2347  			jsonString, err := gabs.ParseJSON(body)
  2348  			asserts.NoError(err)
  2349  			clusterID, ok := jsonString.Path("clusterId").Data().(string)
  2350  			asserts.True(ok)
  2351  			asserts.Equal(unitTestRancherClusterID, clusterID)
  2352  
  2353  			// return a response with the manifest token
  2354  			r := io.NopCloser(bytes.NewReader([]byte(`{"token":"` + manifestToken + `"}`)))
  2355  			resp := &http.Response{
  2356  				StatusCode: http.StatusCreated,
  2357  				Body:       r,
  2358  				Request:    &http.Request{Method: http.MethodPost},
  2359  			}
  2360  			return resp, nil
  2361  		})
  2362  
  2363  	// Expect an HTTP request to fetch the manifest YAML from Rancher
  2364  	requestSenderMock.EXPECT().
  2365  		Do(gomock.Not(gomock.Nil()), gomock.Not(gomock.Nil())).
  2366  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  2367  			asserts.Equal(manifestPath+manifestToken+"_"+unitTestRancherClusterID+".yaml", req.URL.Path)
  2368  
  2369  			r := io.NopCloser(bytes.NewReader([]byte(rancherManifestYAML)))
  2370  			resp := &http.Response{
  2371  				StatusCode: http.StatusOK,
  2372  				Body:       r,
  2373  				Request:    &http.Request{Method: http.MethodGet},
  2374  			}
  2375  			return resp, nil
  2376  		})
  2377  }
  2378  
  2379  func expectRancherGetAuthTokenHTTPCall(t *testing.T, requestSenderMock *mocks.MockRequestSender) {
  2380  	asserts := assert.New(t)
  2381  
  2382  	// Expect an HTTP request to fetch the admin token from Rancher
  2383  	requestSenderMock.EXPECT().
  2384  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(loginURIPath)).
  2385  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  2386  			asserts.Equal(loginQueryString, req.URL.RawQuery)
  2387  
  2388  			r := io.NopCloser(bytes.NewReader([]byte(`{"token":"unit-test-token"}`)))
  2389  			resp := &http.Response{
  2390  				StatusCode: http.StatusCreated,
  2391  				Body:       r,
  2392  				Request:    &http.Request{Method: http.MethodPost},
  2393  			}
  2394  			return resp, nil
  2395  		}).AnyTimes()
  2396  
  2397  }
  2398  
  2399  func expectThanosDelete(t *testing.T, mock *mocks.MockClient) {
  2400  	// Expect a call to get the Istio CRDs
  2401  	mock.EXPECT().
  2402  		Get(gomock.Any(), gomock.Eq(client.ObjectKey{Name: destinationRuleCRDName}), gomock.AssignableToTypeOf(&apiv1.CustomResourceDefinition{}), gomock.Any()).
  2403  		DoAndReturn(func(ctx context.Context, key client.ObjectKey, crd *apiv1.CustomResourceDefinition, opts ...client.GetOption) error {
  2404  			return errors.NewNotFound(schema.GroupResource{}, "not found")
  2405  		})
  2406  	mock.EXPECT().
  2407  		Get(gomock.Any(), gomock.Eq(client.ObjectKey{Name: serviceEntryCRDName}), gomock.AssignableToTypeOf(&apiv1.CustomResourceDefinition{}), gomock.Any()).
  2408  		DoAndReturn(func(ctx context.Context, key client.ObjectKey, crd *apiv1.CustomResourceDefinition, opts ...client.GetOption) error {
  2409  			return errors.NewNotFound(schema.GroupResource{}, "not found")
  2410  		})
  2411  }
  2412  
  2413  // expectSyncCACertRancherHTTPCalls asserts all of the expected calls on the HTTP client mock when sync'ing the managed cluster
  2414  // CA cert secret
  2415  func expectSyncCACertRancherHTTPCalls(t *testing.T, requestSenderMock *mocks.MockRequestSender, caCertSecretData string) {
  2416  	// Expect an HTTP request to fetch the managed cluster info from Rancher
  2417  	fetchClusterPath := fmt.Sprintf("/v3/clusters/%s", unitTestRancherClusterID)
  2418  	requestSenderMock.EXPECT().
  2419  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(fetchClusterPath)).
  2420  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  2421  
  2422  			r := io.NopCloser(bytes.NewReader([]byte(`{"state":"active","agentImage":"test-image:1.0.0"}`)))
  2423  			resp := &http.Response{
  2424  				StatusCode: http.StatusOK,
  2425  				Body:       r,
  2426  				Request:    &http.Request{Method: http.MethodGet},
  2427  			}
  2428  			return resp, nil
  2429  		})
  2430  
  2431  	// Expect an HTTP request to fetch the Rancher TLS additional CA secret from the managed cluster and return an HTTP 404
  2432  	managedClusterAdditionalTLSCAPath := fmt.Sprintf("/k8s/clusters/%s/api/v1/namespaces/cattle-system/secrets/tls-ca", unitTestRancherClusterID)
  2433  	requestSenderMock.EXPECT().
  2434  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(managedClusterAdditionalTLSCAPath)).
  2435  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  2436  			r := io.NopCloser(bytes.NewReader([]byte{}))
  2437  			resp := &http.Response{
  2438  				StatusCode: http.StatusNotFound,
  2439  				Body:       r,
  2440  				Request:    &http.Request{Method: http.MethodGet},
  2441  			}
  2442  			return resp, nil
  2443  		})
  2444  
  2445  	// Expect an HTTP request to fetch the Verrazzano system TLS CA secret from the managed cluster and return the secret
  2446  	managedClusterSystemCAPath := fmt.Sprintf("/k8s/clusters/%s/api/v1/namespaces/verrazzano-system/secrets/verrazzano-tls", unitTestRancherClusterID)
  2447  	requestSenderMock.EXPECT().
  2448  		Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURI(managedClusterSystemCAPath)).
  2449  		DoAndReturn(func(httpClient *http.Client, req *http.Request) (*http.Response, error) {
  2450  			statusCode := http.StatusOK
  2451  			if len(caCertSecretData) == 0 {
  2452  				statusCode = http.StatusNotFound
  2453  			}
  2454  			r := io.NopCloser(bytes.NewReader([]byte(caCertSecretData)))
  2455  			resp := &http.Response{
  2456  				StatusCode: statusCode,
  2457  				Body:       r,
  2458  				Request:    &http.Request{Method: http.MethodGet},
  2459  			}
  2460  			return resp, nil
  2461  		})
  2462  }
  2463  
  2464  // expectSyncCACertRancherK8sCalls asserts all of the expected calls on the Kubernetes client mock when sync'ing the managed cluster
  2465  // CA cert secret
  2466  func expectSyncCACertRancherK8sCalls(t *testing.T, k8sMock *mocks.MockClient, mockRequestSender *mocks.MockRequestSender, shouldSyncCACert bool) {
  2467  	asserts := assert.New(t)
  2468  
  2469  	if shouldSyncCACert {
  2470  		expectRancherConfigK8sCalls(t, k8sMock, true)
  2471  
  2472  		// Expect a call to get the CA cert secret for the managed cluster - return not found
  2473  		k8sMock.EXPECT().
  2474  			Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: "ca-secret-test"}), gomock.Not(gomock.Nil()), gomock.Any()).
  2475  			Return(errors.NewNotFound(schema.GroupResource{Group: constants.VerrazzanoMultiClusterNamespace, Resource: "Secret"}, "ca-secret-test"))
  2476  
  2477  		// Expect a call to create the CA cert secret for the managed cluster
  2478  		k8sMock.EXPECT().
  2479  			Create(gomock.Any(), gomock.Any(), gomock.Any()).
  2480  			DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.CreateOption) error {
  2481  				data := secret.Data[caCertSecretKey]
  2482  				asserts.NotZero(len(data), "Expected data in CA cert secret")
  2483  				return nil
  2484  			})
  2485  
  2486  		// Expect a call to update the VMC with ca secret name
  2487  		k8sMock.EXPECT().
  2488  			Update(gomock.Any(), gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  2489  			DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  2490  				asserts.Equal(vmc.Spec.CASecret, getCASecretName(vmc.Name), "CA secret name %s did not match", vmc.Spec.CASecret)
  2491  				return nil
  2492  			})
  2493  	}
  2494  }
  2495  
  2496  // getScrapeConfig gets a representation of the vmc scrape configuration from the provided yaml
  2497  func getScrapeConfig(prometheusYaml string, name string) (*gabs.Container, error) {
  2498  	cfg, err := parsePrometheusConfig(prometheusYaml)
  2499  	if err != nil {
  2500  		return nil, err
  2501  	}
  2502  	scrapeConfigs := cfg.Path(scrapeConfigsKey).Children()
  2503  	return getJob(scrapeConfigs, name), nil
  2504  }
  2505  
  2506  // getJob returns the scrape config job identified by the passed name from the slice of scrape configs
  2507  func getJob(scrapeConfigs []*gabs.Container, name string) *gabs.Container {
  2508  	var job *gabs.Container
  2509  	for _, scrapeConfig := range scrapeConfigs {
  2510  		jobName := scrapeConfig.Search(constants.PrometheusJobNameKey).Data()
  2511  		if jobName == name {
  2512  			job = scrapeConfig
  2513  			break
  2514  		}
  2515  	}
  2516  	return job
  2517  }
  2518  
  2519  // getPrometheusHost returns the prometheus host for testManagedCluster
  2520  func getPrometheusHost() string {
  2521  	return "prometheus.vmi.system.default.1.2.3.4.nip.io"
  2522  }
  2523  
  2524  // getPrometheusHost returns the prometheus host for testManagedCluster
  2525  func getCaCrt() string {
  2526  	// this is fake data
  2527  	return "    -----BEGIN CERTIFICATE-----\n" +
  2528  		"    MIIBiDCCAS6gAwIBAgIBADAKBggqhkjOPQQDAjA7MRwwGgYDVQQKExNkeW5hbWlj\n" +
  2529  		"    -----END CERTIFICATE-----"
  2530  }
  2531  
  2532  func expectStatusUpdateReadyCondition(asserts *assert.Assertions, mock *mocks.MockClient, mockStatus *mocks.MockStatusWriter, expectReady corev1.ConditionStatus, msg string, assertManagedCACondition bool) {
  2533  	mock.EXPECT().Get(gomock.Any(), types.NamespacedName{Namespace: constants.VerrazzanoMultiClusterNamespace, Name: testManagedCluster}, gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  2534  		DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
  2535  			return nil
  2536  		})
  2537  
  2538  	mock.EXPECT().Status().Return(mockStatus)
  2539  	mockStatus.EXPECT().
  2540  		Update(gomock.Any(), gomock.AssignableToTypeOf(&v1alpha1.VerrazzanoManagedCluster{}), gomock.Any()).
  2541  		DoAndReturn(func(ctx context.Context, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.UpdateOption) error {
  2542  			readyFound := false
  2543  			managedCaFound := false
  2544  			readyConditionCount := 0
  2545  			managedCaConditionCount := 0
  2546  			for _, condition := range vmc.Status.Conditions {
  2547  				if condition.Type == v1alpha1.ConditionReady {
  2548  					readyConditionCount++
  2549  					if condition.Status == expectReady {
  2550  						readyFound = true
  2551  						asserts.Contains(condition.Message, msg)
  2552  					}
  2553  				}
  2554  				if condition.Type == v1alpha1.ConditionManagedCARetrieved {
  2555  					managedCaConditionCount++
  2556  					if condition.Status == expectReady {
  2557  						managedCaFound = true
  2558  						// asserts.Contains(condition.Message, msg)
  2559  					}
  2560  				}
  2561  			}
  2562  			asserts.True(readyFound, "Expected Ready condition on VMC not found")
  2563  			asserts.Equal(1, readyConditionCount, "Found more than one Ready condition")
  2564  			if assertManagedCACondition {
  2565  				asserts.True(managedCaFound, "Expected ManagedCARetrieved condition on VMC not found")
  2566  				asserts.Equal(1, managedCaConditionCount, "Found more than one ManagedCARetrieved condition")
  2567  			}
  2568  
  2569  			return nil
  2570  		})
  2571  }
  2572  
  2573  // validateScrapeConfig validates that a scrape config job has the expected field names and values
  2574  func validateScrapeConfig(t *testing.T, scrapeConfig *gabs.Container, caBasePath string, expectTLSConfig bool) {
  2575  	asserts := assert.New(t)
  2576  	asserts.NotNil(scrapeConfig)
  2577  	asserts.Equal(getPrometheusHost(),
  2578  		scrapeConfig.Search("static_configs", "0", "targets", "0").Data(), "No host entry found")
  2579  	asserts.NotEmpty(scrapeConfig.Search("basic_auth", "password").Data(), "No password")
  2580  
  2581  	// assert that the verrazzano_cluster label is added in the static config
  2582  	asserts.Equal(testManagedCluster, scrapeConfig.Search(
  2583  		"static_configs", "0", "labels", "verrazzano_cluster").Data(),
  2584  		"Label verrazzano_cluster not set correctly in static_configs")
  2585  
  2586  	// assert that the VMC job relabels verrazzano_cluster label to the right value
  2587  	asserts.Equal("verrazzano_cluster", scrapeConfig.Search("metric_relabel_configs", "0",
  2588  		"target_label").Data(),
  2589  		"metric_relabel_configs entry to post-process verrazzano_cluster label does not have expected target_label value")
  2590  	asserts.Equal(testManagedCluster, scrapeConfig.Search("metric_relabel_configs", "0",
  2591  		"replacement").Data(),
  2592  		"metric_relabel_configs entry to post-process verrazzano_cluster label does not have right replacement value")
  2593  	schemePath := scrapeConfig.Path("scheme")
  2594  	tlsScrapeConfig := scrapeConfig.Search("tls_config", "ca_file")
  2595  	if expectTLSConfig {
  2596  		asserts.Equal("https", schemePath.Data(), "wrong scheme")
  2597  		assert.NotNil(t, tlsScrapeConfig)
  2598  		asserts.Equal(caBasePath+"ca-test", tlsScrapeConfig.Data(), "Wrong cert path")
  2599  	} else {
  2600  		assert.Nil(t, tlsScrapeConfig)
  2601  		asserts.Equal("https", schemePath.Data(), "wrong scheme")
  2602  	}
  2603  }
  2604  
  2605  // expectRancherConfigK8sCalls asserts all of the expected calls on the Kubernetes client mock
  2606  // when creating a new Rancher config for the purpose of making http calls
  2607  func expectRancherConfigK8sCalls(t *testing.T, k8sMock *mocks.MockClient, admin bool) {
  2608  	// Expect a call to get the ingress host name
  2609  	k8sMock.EXPECT().
  2610  		Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: rancherNamespace, Name: rancherIngressName}), gomock.Not(gomock.Nil()), gomock.Any()).
  2611  		DoAndReturn(func(ctx context.Context, nsName types.NamespacedName, ingress *networkingv1.Ingress, opts ...client.GetOption) error {
  2612  			rule := networkingv1.IngressRule{Host: "rancher.unit-test.com"}
  2613  			ingress.Spec.Rules = append(ingress.Spec.Rules, rule)
  2614  			return nil
  2615  		})
  2616  
  2617  	// Expect a call to get the secret with the Rancher root CA cert
  2618  	k8sMock.EXPECT().
  2619  		Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: rancherNamespace, Name: rancherTLSSecret}), gomock.Not(gomock.Nil()), gomock.Any()).
  2620  		DoAndReturn(func(ctx context.Context, nsName types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  2621  			secret.Data = map[string][]byte{
  2622  				"ca.crt": {},
  2623  			}
  2624  			return nil
  2625  		})
  2626  
  2627  	secNS := constants.VerrazzanoMultiClusterNamespace
  2628  	secName := constants.VerrazzanoClusterRancherName
  2629  	if admin {
  2630  		secNS = constants.RancherSystemNamespace
  2631  		secName = rancherAdminSecret
  2632  	}
  2633  	// Expect a call to get the admin secret
  2634  	k8sMock.EXPECT().
  2635  		Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: secNS, Name: secName}), gomock.Not(gomock.Nil()), gomock.Any()).
  2636  		DoAndReturn(func(ctx context.Context, nsName types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  2637  			secret.Data = map[string][]byte{
  2638  				"password": []byte("super-secret"),
  2639  			}
  2640  			return nil
  2641  		})
  2642  
  2643  	// Expect a call to get the Rancher additional CA secret
  2644  	k8sMock.EXPECT().
  2645  		Get(gomock.Any(), gomock.Eq(types.NamespacedName{Namespace: constants.VerrazzanoSystemNamespace, Name: constants.PrivateCABundle}), gomock.Not(gomock.Nil()), gomock.Any()).
  2646  		Return(errors.NewNotFound(schema.GroupResource{Group: constants.VerrazzanoSystemNamespace, Resource: "Secret"}, constants.PrivateCABundle))
  2647  }
  2648  
  2649  // expectMockCallsForDelete mocks expectations for the VMC deletion scenario. These are the common mock expectations across
  2650  // tests that exercise delete functionality. Individual tests add mock expectations after these to test various scenarios.
  2651  func expectMockCallsForDelete(t *testing.T, mock *mocks.MockClient, namespace string) {
  2652  	asserts := assert.New(t)
  2653  
  2654  	// Expect a call to get the VerrazzanoManagedCluster resource.
  2655  	mock.EXPECT().
  2656  		Get(gomock.Any(), types.NamespacedName{Namespace: namespace, Name: testManagedCluster}, gomock.Not(gomock.Nil()), gomock.Any()).
  2657  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, vmc *v1alpha1.VerrazzanoManagedCluster, opts ...client.GetOption) error {
  2658  			vmc.TypeMeta = metav1.TypeMeta{
  2659  				APIVersion: apiVersion,
  2660  				Kind:       kind}
  2661  			vmc.ObjectMeta = metav1.ObjectMeta{
  2662  				Namespace:         name.Namespace,
  2663  				Name:              name.Name,
  2664  				DeletionTimestamp: &metav1.Time{Time: time.Now()},
  2665  				Finalizers:        []string{finalizerName}}
  2666  			vmc.Status = v1alpha1.VerrazzanoManagedClusterStatus{
  2667  				PrometheusHost: getPrometheusHost(),
  2668  				RancherRegistration: v1alpha1.RancherRegistration{
  2669  					ClusterID: unitTestRancherClusterID,
  2670  				},
  2671  			}
  2672  
  2673  			return nil
  2674  		})
  2675  
  2676  	jobs := `  - ` + constants.PrometheusJobNameKey + `: test
  2677      scrape_interval: 20s
  2678      scrape_timeout: 15s
  2679      scheme: http
  2680    - ` + constants.PrometheusJobNameKey + `: test2
  2681      scrape_interval: 20s
  2682      scrape_timeout: 15s
  2683      scheme: http`
  2684  
  2685  	// Expect a call to get the additional scrape config secret - return it configured with the two scrape jobs
  2686  	mock.EXPECT().
  2687  		Get(gomock.Any(), types.NamespacedName{Namespace: vpoconstants.VerrazzanoMonitoringNamespace, Name: constants.PromAdditionalScrapeConfigsSecretName}, gomock.Not(gomock.Nil()), gomock.Any()).
  2688  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  2689  			secret.Data = map[string][]byte{
  2690  				constants.PromAdditionalScrapeConfigsSecretKey: []byte(jobs),
  2691  			}
  2692  			return nil
  2693  		})
  2694  
  2695  	// Expect a call to get the additional scrape config secret (we call controllerruntime.CreateOrUpdate so it fetches again) - return it
  2696  	mock.EXPECT().
  2697  		Get(gomock.Any(), types.NamespacedName{Namespace: vpoconstants.VerrazzanoMonitoringNamespace, Name: constants.PromAdditionalScrapeConfigsSecretName}, gomock.Not(gomock.Nil()), gomock.Any()).
  2698  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  2699  			secret.Data = map[string][]byte{
  2700  				constants.PromAdditionalScrapeConfigsSecretKey: []byte(jobs),
  2701  			}
  2702  			return nil
  2703  		})
  2704  
  2705  	// Expect a call to update the additional scrape config secret
  2706  	mock.EXPECT().
  2707  		Update(gomock.Any(), gomock.Any(), gomock.Any()).
  2708  		DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.UpdateOption) error {
  2709  			// validate that the scrape config for the managed cluster is no longer present
  2710  			scrapeConfigs, err := metricsutils.ParseScrapeConfig(string(secret.Data[constants.PromAdditionalScrapeConfigsSecretKey]))
  2711  			if err != nil {
  2712  				return err
  2713  			}
  2714  			asserts.Len(scrapeConfigs.Children(), 1, "Expected only one scrape config")
  2715  			scrapeJobName := scrapeConfigs.Children()[0].Search(constants.PrometheusJobNameKey).Data()
  2716  			asserts.Equal("test2", scrapeJobName)
  2717  			return nil
  2718  		})
  2719  
  2720  	// Expect a call to get the verrazzano-monitoring namespace
  2721  	mock.EXPECT().
  2722  		Get(gomock.Any(), types.NamespacedName{Name: vpoconstants.VerrazzanoMonitoringNamespace}, gomock.Not(gomock.Nil()), gomock.Any()).
  2723  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, ns *corev1.Namespace, opts ...client.GetOption) error {
  2724  			ns.SetName(vpoconstants.VerrazzanoMonitoringNamespace)
  2725  			return nil
  2726  		})
  2727  
  2728  	// Expect a call to get the managed cluster TLS certs secret - return it configured with two managed cluster certs
  2729  	mock.EXPECT().
  2730  		Get(gomock.Any(), types.NamespacedName{Namespace: vpoconstants.VerrazzanoMonitoringNamespace, Name: vpoconstants.PromManagedClusterCACertsSecretName}, gomock.Not(gomock.Nil()), gomock.Any()).
  2731  		DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *corev1.Secret, opts ...client.GetOption) error {
  2732  			secret.Data = map[string][]byte{
  2733  				"ca-test":  []byte("ca-cert-1"),
  2734  				"ca-test2": []byte("ca-cert-1"),
  2735  			}
  2736  			return nil
  2737  		})
  2738  
  2739  	// Expect a call to update the managed cluster TLS certs secret
  2740  	mock.EXPECT().
  2741  		Update(gomock.Any(), gomock.Any(), gomock.Any()).
  2742  		DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.UpdateOption) error {
  2743  			// validate that the cert for the cluster being deleted is no longer present
  2744  			asserts.Len(secret.Data, 1, "Expected only one managed cluster cert")
  2745  			asserts.Contains(secret.Data, "ca-test2", "Expected to find cert for managed cluster not being deleted")
  2746  			return nil
  2747  		})
  2748  
  2749  	// Expect a call to delete the argocd cluster secret
  2750  	mock.EXPECT().
  2751  		Delete(gomock.Any(), gomock.Any(), gomock.Any()).
  2752  		DoAndReturn(func(ctx context.Context, secret *corev1.Secret, opts ...client.UpdateOption) error {
  2753  			return nil
  2754  		})
  2755  
  2756  	// Expect Rancher k8s calls to configure the API client
  2757  	expectRancherConfigK8sCalls(t, mock, true)
  2758  }
  2759  
  2760  func expectMockCallsForCreateClusterRoleBindingTemplate(mock *mocks.MockClient, clusterID string) {
  2761  	name := fmt.Sprintf("crtb-verrazzano-cluster-%s", clusterID)
  2762  	mock.EXPECT().
  2763  		Get(gomock.Any(), gomock.Eq(types.NamespacedName{Name: name, Namespace: clusterID}), gomock.Not(gomock.Nil()), gomock.Any()).
  2764  		DoAndReturn(func(ctx context.Context, nsn types.NamespacedName, resource *unstructured.Unstructured, opts ...client.GetOption) error {
  2765  			data := resource.UnstructuredContent()
  2766  			data[ClusterRoleTemplateBindingAttributeClusterName] = clusterID
  2767  			data[ClusterRoleTemplateBindingAttributeUserName] = constants.VerrazzanoClusterRancherUsername
  2768  			data[ClusterRoleTemplateBindingAttributeRoleTemplateName] = constants.VerrazzanoClusterRancherName
  2769  			return nil
  2770  		})
  2771  }
  2772  
  2773  func expectMockCallsForListingRancherUsers(mock *mocks.MockClient) {
  2774  	usersList := unstructured.UnstructuredList{}
  2775  	usersList.SetGroupVersionKind(schema.GroupVersionKind{
  2776  		Group:   APIGroupRancherManagement,
  2777  		Version: APIGroupVersionRancherManagement,
  2778  		Kind:    UserListKind,
  2779  	})
  2780  	mock.EXPECT().
  2781  		List(gomock.Any(), &usersList, gomock.Not(gomock.Nil())).
  2782  		DoAndReturn(func(ctx context.Context, userList *unstructured.UnstructuredList, options *client.ListOptions) error {
  2783  			user := unstructured.Unstructured{}
  2784  			user.SetGroupVersionKind(schema.GroupVersionKind{
  2785  				Group:   APIGroupRancherManagement,
  2786  				Version: APIGroupVersionRancherManagement,
  2787  				Kind:    UserKind,
  2788  			})
  2789  			user.SetName(constants.VerrazzanoClusterRancherUsername)
  2790  			data := user.UnstructuredContent()
  2791  			data[UserUsernameAttribute] = constants.VerrazzanoClusterRancherUsername
  2792  			userList.Items = []unstructured.Unstructured{user}
  2793  			return nil
  2794  		})
  2795  }