github.com/verrazzano/verrazzano@v1.7.0/tools/vz/cmd/helpers/vpo_test.go (about)

     1  // Copyright (c) 2022, 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  package helpers
     4  
     5  import (
     6  	"bytes"
     7  	"context"
     8  	"fmt"
     9  	"io/fs"
    10  	"os"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/stretchr/testify/assert"
    15  	vzconstants "github.com/verrazzano/verrazzano/pkg/constants"
    16  	vzos "github.com/verrazzano/verrazzano/pkg/os"
    17  	"github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1alpha1"
    18  	"github.com/verrazzano/verrazzano/platform-operator/apis/verrazzano/v1beta1"
    19  	vpoconst "github.com/verrazzano/verrazzano/platform-operator/constants"
    20  	"github.com/verrazzano/verrazzano/tools/vz/pkg/constants"
    21  	"github.com/verrazzano/verrazzano/tools/vz/pkg/helpers"
    22  	testhelpers "github.com/verrazzano/verrazzano/tools/vz/test/helpers"
    23  	appsv1 "k8s.io/api/apps/v1"
    24  	corev1 "k8s.io/api/core/v1"
    25  	"k8s.io/apimachinery/pkg/api/errors"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/apimachinery/pkg/types"
    28  	"k8s.io/cli-runtime/pkg/genericclioptions"
    29  	fakek8s "k8s.io/client-go/kubernetes/fake"
    30  	k8scheme "k8s.io/client-go/kubernetes/scheme"
    31  	"sigs.k8s.io/controller-runtime/pkg/client"
    32  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    33  )
    34  
    35  const (
    36  	podTemplateHashLabel         = "pod-template-hash"
    37  	deploymentRevisionAnnotation = "deployment.kubernetes.io/revision"
    38  	defaultTimeout               = time.Duration(1) * time.Second
    39  	vpoPodName                   = "verrazzano-platform-operator-95d8c5d96-m6mbr"
    40  	testRegistry                 = "myreg.example.io"
    41  	testImagePrefix              = "myprefix"
    42  )
    43  
    44  var (
    45  	testVZNamespacedName = types.NamespacedName{
    46  		Name:      "myverrazzano",
    47  		Namespace: "default",
    48  	}
    49  	vpoDeployNamespacedName = types.NamespacedName{
    50  		Namespace: vzconstants.VerrazzanoInstallNamespace,
    51  		Name:      constants.VerrazzanoPlatformOperator,
    52  	}
    53  )
    54  
    55  // TestGetVpoLogStream tests the functionality that returns the right log stream of the VPO pod.
    56  func TestGetVpoLogStream(t *testing.T) {
    57  	// GIVEN a k8s cluster with no VPO installed,
    58  	// WHEN get log stream is called,
    59  	// THEN no error is returned and a default no op log stream is returned.
    60  	fakeClient := fakek8s.NewSimpleClientset()
    61  	reader, err := GetVpoLogStream(fakeClient, "verrazzano-platform-operator-xyz")
    62  	assert.NoError(t, err)
    63  	assert.NotNil(t, reader)
    64  
    65  }
    66  
    67  // TestGetVerrazzanoPlatformOperatorPodName tests the functionality that returns the right VPO pod name.
    68  func TestGetVerrazzanoPlatformOperatorPodName(t *testing.T) {
    69  	// GIVEN a k8s cluster with no VPO installed,
    70  	// WHEN GetVerrazzanoPlatformOperatorPodName is invoked,
    71  	// THEN no error is returned and a default no op log stream is returned.
    72  	fakeClient := fake.NewClientBuilder().Build()
    73  	podName, err := GetVerrazzanoPlatformOperatorPodName(fakeClient)
    74  	assert.Error(t, err)
    75  	assert.Equal(t, "", podName)
    76  
    77  	// GIVEN a k8s cluster with no VPO installed,
    78  	// WHEN GetVerrazzanoPlatformOperatorPodName is invoked,
    79  	// THEN no error is returned and a default no op log stream is returned.
    80  	fakeClient = fake.NewClientBuilder().WithObjects(&corev1.Pod{
    81  		ObjectMeta: metav1.ObjectMeta{
    82  			Namespace: vpoconst.VerrazzanoInstallNamespace,
    83  			Name:      vpoPodName,
    84  			Labels: map[string]string{
    85  				podTemplateHashLabel: "95d8c5d96",
    86  				"app":                constants.VerrazzanoPlatformOperator,
    87  			},
    88  		},
    89  	}).Build()
    90  	podName, err = GetVerrazzanoPlatformOperatorPodName(fakeClient)
    91  	assert.NoError(t, err)
    92  	assert.Equal(t, vpoPodName, podName)
    93  }
    94  
    95  // TestGetVerrazzanoPlatformOperatorPodName tests the functionality that waits still the Verrazzano resource reaches the given state.
    96  func TestWaitForPlatformOperator(t *testing.T) {
    97  	// GIVEN a k8s cluster with VPO installed,
    98  	// WHEN WaitForPlatformOperator is invoked,
    99  	// THEN no error is returned and the expected pod name is returned.
   100  	fakeClient := fake.NewClientBuilder().WithObjects(
   101  		getAllVpoObjects()...).Build()
   102  	buf := new(bytes.Buffer)
   103  	errBuf := new(bytes.Buffer)
   104  	rc := testhelpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
   105  	podName, err := WaitForPlatformOperator(fakeClient, rc, v1beta1.CondInstallComplete, time.Duration(1)*time.Second)
   106  	assert.NoError(t, err)
   107  	assert.Equal(t, vpoPodName, podName)
   108  
   109  	// GIVEN a k8s cluster with no VPO installed,
   110  	// WHEN WaitForPlatformOperator is invoked,
   111  	// THEN an error is returned as there is no VPO pod object.
   112  	fakeClient = fake.NewClientBuilder().Build()
   113  	_, err = WaitForPlatformOperator(fakeClient, rc, v1beta1.CondInstallComplete, time.Duration(1)*time.Second)
   114  	assert.Error(t, err)
   115  }
   116  
   117  // TestWaitForOperationToComplete tests the functionality to wait till the given operation completes
   118  func TestWaitForOperationToComplete(t *testing.T) {
   119  	scheme := k8scheme.Scheme
   120  	_ = v1beta1.AddToScheme(scheme)
   121  	_ = v1alpha1.AddToScheme(scheme)
   122  	k8sClient := fakek8s.NewSimpleClientset()
   123  	buf := new(bytes.Buffer)
   124  	errBuf := new(bytes.Buffer)
   125  	rc := testhelpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
   126  
   127  	// GIVEN a k8s cluster with VPO installed,
   128  	// WHEN WaitForOperationToComplete is invoked,
   129  	// THEN an error is returned as the VZ resource is not in InstallComplete state.
   130  	fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(append(getAllVpoObjects(), getVZObject())...).Build()
   131  	err := WaitForOperationToComplete(fakeClient, k8sClient, rc, testVZNamespacedName, defaultTimeout, defaultTimeout, LogFormatSimple, v1beta1.CondInstallComplete)
   132  	assert.Error(t, err)
   133  }
   134  
   135  // TestApplyPlatformOperatorYaml tests the functionality to apply VPO operator yaml
   136  func TestApplyPlatformOperatorYaml(t *testing.T) {
   137  	vpoDeployment := &appsv1.Deployment{
   138  		ObjectMeta: metav1.ObjectMeta{
   139  			Namespace: vpoDeployNamespacedName.Namespace,
   140  			Name:      vpoDeployNamespacedName.Name,
   141  		},
   142  		Spec: appsv1.DeploymentSpec{
   143  			Selector: &metav1.LabelSelector{
   144  				MatchLabels: map[string]string{"app": constants.VerrazzanoPlatformOperator},
   145  			},
   146  		},
   147  	}
   148  	fakeClient := fake.NewClientBuilder().WithScheme(helpers.NewScheme()).WithObjects(vpoDeployment).Build()
   149  	buf := new(bytes.Buffer)
   150  	errBuf := new(bytes.Buffer)
   151  
   152  	// GIVEN a k8s cluster with VPO installed,
   153  	// WHEN ApplyPlatformOperatorYaml is invoked without the operator manifest flag set,
   154  	// THEN an error is returned and the existing VPO deployment is not deleted
   155  	rc := testhelpers.NewFakeRootCmdContext(genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: errBuf})
   156  	err := ApplyPlatformOperatorYaml(getCommandWithoutFlags(), fakeClient, rc, "1.5.0")
   157  	assert.Error(t, err)
   158  	// VPO deployment should not have been deleted, since the platform operator would not be applied
   159  	var vpo2 appsv1.Deployment
   160  	err = fakeClient.Get(context.TODO(), vpoDeployNamespacedName, &vpo2)
   161  	assert.NoError(t, err)
   162  	assertVPO(t, fakeClient, true)
   163  
   164  	// GIVEN a k8s cluster with VPO installed,
   165  	// WHEN ApplyPlatformOperatorYaml is invoked with a non-existent operator file
   166  	// THEN a path error is returned and the existing VPO deployment is not deleted
   167  	cmdWithOperatorYaml := getCommandWithoutFlags()
   168  	cmdWithOperatorYaml.PersistentFlags().String(constants.ManifestsFlag, "operator.yaml", "")
   169  	err = ApplyPlatformOperatorYaml(cmdWithOperatorYaml, fakeClient, rc, "1.5.0")
   170  	assert.Error(t, err)
   171  	assert.IsType(t, &fs.PathError{}, err)
   172  	assertVPO(t, fakeClient, true)
   173  
   174  	// GIVEN a k8s cluster with VPO installed,
   175  	// WHEN ApplyPlatformOperatorYaml is invoked with an existing operator file
   176  	// THEN the existing VPO deployment should be deleted
   177  	cmdWithOperatorYaml2 := getCommandWithoutFlags()
   178  	var tempFile *os.File
   179  	tempFile, err = vzos.CreateTempFile("operator", nil)
   180  	assert.NoError(t, err)
   181  	SetApplyYAMLFunc(func(filename string, client client.Client, vzHelper helpers.VZHelper) error {
   182  		return nil
   183  	})
   184  	cmdWithOperatorYaml2.PersistentFlags().String(constants.ManifestsFlag, tempFile.Name(), "")
   185  	err = ApplyPlatformOperatorYaml(cmdWithOperatorYaml2, fakeClient, rc, "1.5.0")
   186  	assert.NoError(t, err)
   187  	assertVPO(t, fakeClient, false)
   188  }
   189  
   190  // assertVPO asserts that the VPO deployment exists (if expectExist is true) otherwise that it
   191  // does not exist
   192  func assertVPO(t *testing.T, fakeClient client.WithWatch, expectExist bool) {
   193  	var vpoDeploy appsv1.Deployment
   194  	err := fakeClient.Get(context.TODO(), vpoDeployNamespacedName, &vpoDeploy)
   195  	if expectExist {
   196  		assert.NoError(t, err)
   197  	} else {
   198  		assert.True(t, errors.IsNotFound(err))
   199  	}
   200  }
   201  
   202  // TestUsePlatformOperatorUninstallJob tests the functionality of VPO Uninstall job for different versions.
   203  func TestUsePlatformOperatorUninstallJob(t *testing.T) {
   204  	upgradeFlag, err := UsePlatformOperatorUninstallJob(fake.NewClientBuilder().Build())
   205  	assert.Error(t, err)
   206  	assert.False(t, upgradeFlag)
   207  
   208  	deploy := getVpoDeployment("", 1, 1)
   209  	deploy.SetLabels(map[string]string{})
   210  	fakeClient := fake.NewClientBuilder().WithObjects(deploy).Build()
   211  	upgradeFlag, err = UsePlatformOperatorUninstallJob(fakeClient)
   212  	assert.NoError(t, err)
   213  	assert.True(t, upgradeFlag)
   214  
   215  	// GIVEN a k8s cluster with VPO installed,
   216  	// WHEN UsePlatformOperatorUninstallJob is invoked for an invalid vpo version which does not match the semversion pattern,
   217  	// THEN an error is returned.
   218  	fakeClient = fake.NewClientBuilder().WithObjects(getVpoDeployment("1.f", 1, 1)).Build()
   219  	upgradeFlag, err = UsePlatformOperatorUninstallJob(fakeClient)
   220  	assert.Error(t, err)
   221  	assert.False(t, upgradeFlag)
   222  
   223  	// GIVEN a k8s cluster with VPO installed,
   224  	// WHEN UsePlatformOperatorUninstallJob is invoked for an invalid vpo version which does not match the semversion pattern,
   225  	// THEN an error is returned.
   226  	fakeClient = fake.NewClientBuilder().WithObjects(getVpoDeployment("1.4.0", 1, 1)).Build()
   227  	upgradeFlag, err = UsePlatformOperatorUninstallJob(fakeClient)
   228  	assert.NoError(t, err)
   229  	assert.False(t, upgradeFlag)
   230  
   231  	// GIVEN a k8s cluster with VPO installed,
   232  	// WHEN UsePlatformOperatorUninstallJob is invoked for a valid sem version lesser than 1.4.0,
   233  	// THEN no error is returned and the upgrade flag is set to true.
   234  	fakeClient = fake.NewClientBuilder().WithObjects(getVpoDeployment("1.3.0", 1, 1)).Build()
   235  	upgradeFlag, err = UsePlatformOperatorUninstallJob(fakeClient)
   236  	assert.NoError(t, err)
   237  	assert.True(t, upgradeFlag)
   238  
   239  	// GIVEN a k8s cluster with VPO installed,
   240  	// WHEN UsePlatformOperatorUninstallJob is invoked for a valid sem version greater than 1.4.0,
   241  	// THEN no error is returned and upgrade flag is set to false.
   242  	fakeClient = fake.NewClientBuilder().WithObjects(getVpoDeployment("1.5.0", 1, 1)).Build()
   243  	upgradeFlag, err = UsePlatformOperatorUninstallJob(fakeClient)
   244  	assert.NoError(t, err)
   245  	assert.False(t, upgradeFlag)
   246  }
   247  
   248  // TestVpoIsReady tests the functionality to check if VPO deployment is ready based on the VPO pods that are available
   249  func TestVpoIsReady(t *testing.T) {
   250  	// GIVEN a k8s cluster with all VPO deployment with 1 updated replicas, and 1 available replicas
   251  	// WHEN vpoIsReady is invoked,
   252  	// THEN it returns false .
   253  	fakeClient := fake.NewClientBuilder().WithObjects(getVpoDeployment("1.4.0", 1, 1)).Build()
   254  	isReady, err := vpoIsReady(fakeClient)
   255  	assert.NoError(t, err)
   256  	assert.False(t, isReady)
   257  
   258  	// GIVEN a k8s cluster with all VPO deployment with 0 updated replicas, and 0 available replicas
   259  	// WHEN vpoIsReady is invoked,
   260  	// THEN it returns false .
   261  	fakeClient = fake.NewClientBuilder().WithObjects(getVpoDeployment("1.4.0", 0, 0)).Build()
   262  	isReady, err = vpoIsReady(fakeClient)
   263  	assert.NoError(t, err)
   264  	assert.False(t, isReady)
   265  
   266  	// GIVEN a k8s cluster with all VPO deployment with 0 updated replicas, and 1 available replicas
   267  	// WHEN vpoIsReady is invoked,
   268  	// THEN it returns false .
   269  	fakeClient = fake.NewClientBuilder().WithObjects(getVpoDeployment("1.4.0", 0, 1)).Build()
   270  	isReady, err = vpoIsReady(fakeClient)
   271  	assert.NoError(t, err)
   272  	assert.False(t, isReady)
   273  
   274  	// GIVEN a k8s cluster with all VPO deployment with no available replicas
   275  	// WHEN vpoIsReady is invoked,
   276  	// THEN it returns false .
   277  	fakeClient = fake.NewClientBuilder().WithObjects(getVpoDeployment("1.4.0", 1, 0)).Build()
   278  	isReady, err = vpoIsReady(fakeClient)
   279  	assert.NoError(t, err)
   280  	assert.False(t, isReady)
   281  
   282  }
   283  
   284  // TestGetScanner tests the functionality of returning the right scanner object
   285  func TestGetScanner(t *testing.T) {
   286  	// GIVEN a k8s cluster with all VPO specific objects,
   287  	// WHEN getScanner is invoked,
   288  	// THEN no error is returned and the scanner returned is the default no-op scanner .
   289  	fakeClient := fake.NewClientBuilder().WithObjects(getAllVpoObjects()...).Build()
   290  	k8sClient := fakek8s.NewSimpleClientset()
   291  	scanner, err := getScanner(fakeClient, k8sClient)
   292  	assert.NoError(t, err)
   293  	assert.NotNil(t, scanner)
   294  }
   295  
   296  // TestDeleteLeftoverPlatformOperator tests the functionality of deleting the left over VPO pod.
   297  func TestDeleteLeftoverPlatformOperator(t *testing.T) {
   298  	// GIVEN a k8s cluster,
   299  	// WHEN deleteLeftoverPlatformOperator is invoked,
   300  	// THEN no error is returned.
   301  	err := deleteLeftoverPlatformOperator(fake.NewClientBuilder().Build())
   302  	assert.NoError(t, err)
   303  }
   304  
   305  // TestSetDeleteFunc tests the functionality where user can provide a custom delete function, and it gets invoked when
   306  // calling the delete operation.
   307  func TestSetDeleteFunc(t *testing.T) {
   308  	// GIVEN a k8s cluster,
   309  	// WHEN delete function is overridden to a custom function using SetDeleteFunc
   310  	// THEN the expected error is returned with the string 'dummy error'.
   311  	SetDeleteFunc(func(client client.Client) error {
   312  		return fmt.Errorf("dummy error")
   313  	})
   314  	err := DeleteFunc(fake.NewClientBuilder().Build())
   315  	assert.Error(t, err)
   316  	assert.Equal(t, "dummy error", err.Error())
   317  }
   318  
   319  // TestSetDefaultDeleteFunc tests the functionality where a custom delete function can be provided by the user and invoked.
   320  func TestSetDefaultDeleteFunc(t *testing.T) {
   321  	// GIVEN a k8s cluster,
   322  	// WHEN SetDefaultDeleteFunc is set and DeleteFunc invoked,
   323  	// THEN no error is returned.
   324  	SetDefaultDeleteFunc()
   325  	err := DeleteFunc(fake.NewClientBuilder().Build())
   326  	assert.NoError(t, err)
   327  }
   328  
   329  // TestFakeDeleteFunc tests the fake delete function.
   330  func TestFakeDeleteFunc(t *testing.T) {
   331  	// When FakeDeleteFunc it should return nil
   332  	err := FakeDeleteFunc(fake.NewClientBuilder().Build())
   333  	assert.NoError(t, err)
   334  }
   335  
   336  // TestGetOperationString tests the functionality that returns the right operation string - install or upgrade
   337  func TestGetOperationString(t *testing.T) {
   338  	// GIVEN a k8s cluster with VPO installed,
   339  	// WHEN getOperationString is invoked for install complete state,
   340  	// THEN it returns a string install.
   341  	operation := getOperationString(v1beta1.CondInstallComplete)
   342  	assert.Equal(t, "install", operation)
   343  
   344  	// GIVEN a k8s cluster with VPO installed,
   345  	// WHEN getOperationString is invoked for upgrade complete state,
   346  	// THEN it returns a string upgrade.
   347  	operation = getOperationString(v1beta1.CondUpgradeComplete)
   348  	assert.Equal(t, "upgrade", operation)
   349  }
   350  
   351  // TestGetExistingVPODeployment
   352  // GIVEN a K8S client
   353  //
   354  //	WHEN I call GetExistingVPODeployment
   355  //	THEN expect it to return the Verrazzano Platform operator deployment if it exists, nil if it doesn't
   356  func TestGetExistingVPODeployment(t *testing.T) {
   357  	var tests = []struct {
   358  		name      string
   359  		vpoExists bool
   360  	}{
   361  		{
   362  			"VPO exists",
   363  			true,
   364  		},
   365  		{
   366  			"VPO does not exist",
   367  			false,
   368  		},
   369  	}
   370  	for _, tt := range tests {
   371  		clientBuilder := fake.NewClientBuilder()
   372  		if tt.vpoExists {
   373  			clientBuilder = clientBuilder.WithObjects(
   374  				&appsv1.Deployment{
   375  					ObjectMeta: metav1.ObjectMeta{
   376  						Namespace: vpoconst.VerrazzanoInstallNamespace,
   377  						Name:      constants.VerrazzanoPlatformOperator,
   378  					},
   379  				})
   380  		}
   381  		fakeClient := clientBuilder.Build()
   382  		vpo, err := GetExistingVPODeployment(fakeClient)
   383  		assert.NoError(t, err)
   384  		if tt.vpoExists {
   385  			assert.Equal(t, vpoconst.VerrazzanoInstallNamespace, vpo.Namespace)
   386  			assert.Equal(t, constants.VerrazzanoPlatformOperator, vpo.Name)
   387  		} else {
   388  			assert.Nil(t, vpo)
   389  		}
   390  	}
   391  }
   392  
   393  // TestGetExistingPrivateRegistrySettings
   394  // GIVEN a K8S client
   395  //
   396  //	WHEN I call getExistingPrivateRegistrySettings
   397  //	THEN expect it to return the Verrazzano Platform operator deployment's REGISTRY and IMAGE_REPO
   398  //	environment variables from the verrazzano-platform-operator container, empty strings for missing
   399  //	 values
   400  func TestGetExistingPrivateRegistrySettings(t *testing.T) {
   401  	var tests = []struct {
   402  		name             string
   403  		envVarsMap       map[string]string
   404  		expectedRegistry string
   405  		expectedPrefix   string
   406  	}{
   407  		{
   408  			"no env vars",
   409  			map[string]string{},
   410  			"",
   411  			"",
   412  		},
   413  		{
   414  			"no private registry env vars",
   415  			map[string]string{"someEnv": "someValue"},
   416  			"",
   417  			"",
   418  		},
   419  		{
   420  			"only registry env var",
   421  			map[string]string{vpoconst.RegistryOverrideEnvVar: testRegistry},
   422  			testRegistry,
   423  			"",
   424  		},
   425  		{
   426  			"only prefix env var",
   427  			map[string]string{vpoconst.ImageRepoOverrideEnvVar: "myImagePrefix/morestuff"},
   428  			"",
   429  			"myImagePrefix/morestuff",
   430  		},
   431  		{
   432  			"registry and prefix env vars",
   433  			map[string]string{
   434  				vpoconst.RegistryOverrideEnvVar:  testRegistry,
   435  				vpoconst.ImageRepoOverrideEnvVar: testImagePrefix,
   436  			},
   437  			testRegistry,
   438  			testImagePrefix,
   439  		},
   440  	}
   441  	for _, tt := range tests {
   442  		vpoDeploy := getVpoDeploymentWithEnvVars(tt.envVarsMap)
   443  		reg, prefix := getExistingPrivateRegistrySettings(vpoDeploy)
   444  		assert.Equal(t, tt.expectedRegistry, reg)
   445  		assert.Equal(t, tt.expectedPrefix, prefix)
   446  	}
   447  }
   448  
   449  // TestValidatePrivateRegistry
   450  // GIVEN a VZ command with/without private registry settings
   451  //
   452  //	WHEN I call ValidatePrivateRegistry
   453  //	THEN expect it to return an error if the settings in the command don't match existing
   454  //	VPO deployment env vars, nil if they match
   455  func TestValidatePrivateRegistry(t *testing.T) {
   456  	var tests = []struct {
   457  		name            string
   458  		existingEnvVars map[string]string
   459  		newRegistry     string
   460  		newPrefix       string
   461  		expectErr       bool
   462  		expectMsg       string
   463  	}{
   464  		{
   465  			"no private registry existing or new",
   466  			map[string]string{},
   467  			"",
   468  			"",
   469  			false,
   470  			"",
   471  		},
   472  		{
   473  			"no private registry existing VPO, but supplied in new command",
   474  			map[string]string{},
   475  			testRegistry,
   476  			testImagePrefix,
   477  			true,
   478  			imageRegistryMismatchError("", "", testRegistry, testImagePrefix),
   479  		},
   480  		{
   481  			"private registry existing VPO, but NOT supplied in new command",
   482  			map[string]string{vpoconst.RegistryOverrideEnvVar: testRegistry, vpoconst.ImageRepoOverrideEnvVar: testImagePrefix},
   483  			"",
   484  			"",
   485  			true,
   486  			imageRegistryMismatchError(testRegistry, testImagePrefix, "", ""),
   487  		},
   488  		{
   489  			"private registry settings in existing VPO and new command match",
   490  			map[string]string{vpoconst.RegistryOverrideEnvVar: testRegistry, vpoconst.ImageRepoOverrideEnvVar: testImagePrefix},
   491  			testRegistry,
   492  			testImagePrefix,
   493  			false,
   494  			"",
   495  		},
   496  	}
   497  	for _, tt := range tests {
   498  		vpoDeploy := getVpoDeploymentWithEnvVars(tt.existingEnvVars)
   499  		fakeClient := fake.NewClientBuilder().WithObjects(vpoDeploy).Build()
   500  		myCmd := getCommandWithoutFlags()
   501  		myCmd.PersistentFlags().String(constants.ImageRegistryFlag, tt.newRegistry, "")
   502  		myCmd.PersistentFlags().String(constants.ImagePrefixFlag, tt.newPrefix, "")
   503  		err := ValidatePrivateRegistry(myCmd, fakeClient)
   504  		if tt.expectErr {
   505  			assert.Error(t, err)
   506  			assert.Equal(t, tt.expectMsg, err.Error())
   507  		} else {
   508  			assert.NoError(t, err)
   509  		}
   510  	}
   511  }
   512  
   513  func getVpoDeploymentWithEnvVars(envVarsMap map[string]string) *appsv1.Deployment {
   514  	vpoDeploy := getVpoDeployment("1.5.0", 1, 1)
   515  	for idx := range vpoDeploy.Spec.Template.Spec.Containers {
   516  		container := &vpoDeploy.Spec.Template.Spec.Containers[idx]
   517  		if container.Name == constants.VerrazzanoPlatformOperator {
   518  			for envName, envValue := range envVarsMap {
   519  				container.Env = append(container.Env, corev1.EnvVar{Name: envName, Value: envValue})
   520  			}
   521  		}
   522  	}
   523  	return vpoDeploy
   524  }
   525  
   526  // getVpoDeployment returns just the deployment object simulating a Verrazzano Platform Operator deployment.
   527  func getVpoDeployment(vpoVersion string, updatedReplicas, availableReplicas int32) *appsv1.Deployment {
   528  	return &appsv1.Deployment{
   529  		ObjectMeta: metav1.ObjectMeta{
   530  			Namespace: vpoconst.VerrazzanoInstallNamespace,
   531  			Name:      constants.VerrazzanoPlatformOperator,
   532  			Labels: map[string]string{
   533  				"app":                       constants.VerrazzanoPlatformOperator,
   534  				"app.kubernetes.io/version": vpoVersion},
   535  		},
   536  		Spec: appsv1.DeploymentSpec{
   537  			Selector: &metav1.LabelSelector{
   538  				MatchLabels: map[string]string{"app": constants.VerrazzanoPlatformOperator},
   539  			},
   540  			Template: corev1.PodTemplateSpec{
   541  				Spec: corev1.PodSpec{
   542  					Containers: []corev1.Container{
   543  						{Name: constants.VerrazzanoPlatformOperator},
   544  					},
   545  				},
   546  			},
   547  		},
   548  		Status: appsv1.DeploymentStatus{
   549  			AvailableReplicas: availableReplicas,
   550  			ReadyReplicas:     1,
   551  			Replicas:          1,
   552  			UpdatedReplicas:   updatedReplicas,
   553  		},
   554  	}
   555  }
   556  
   557  // getAllVpoObjects returns the deployment, pod and replica set objects simulating a Verrazzano Platform Operator deployment.
   558  func getAllVpoObjects() []client.Object {
   559  	return []client.Object{
   560  		&appsv1.Deployment{
   561  			ObjectMeta: metav1.ObjectMeta{
   562  				Namespace: vpoconst.VerrazzanoInstallNamespace,
   563  				Name:      constants.VerrazzanoPlatformOperator,
   564  				Labels:    map[string]string{"app": constants.VerrazzanoPlatformOperator},
   565  			},
   566  			Spec: appsv1.DeploymentSpec{
   567  				Selector: &metav1.LabelSelector{
   568  					MatchLabels: map[string]string{"app": constants.VerrazzanoPlatformOperator},
   569  				},
   570  			},
   571  			Status: appsv1.DeploymentStatus{
   572  				AvailableReplicas: 1,
   573  				ReadyReplicas:     1,
   574  				Replicas:          1,
   575  				UpdatedReplicas:   1,
   576  			},
   577  		},
   578  		&corev1.Pod{
   579  			ObjectMeta: metav1.ObjectMeta{
   580  				Namespace: vpoconst.VerrazzanoInstallNamespace,
   581  				Name:      constants.VerrazzanoPlatformOperator + "-95d8c5d96-m6mbr",
   582  				Labels: map[string]string{
   583  					podTemplateHashLabel: "95d8c5d96",
   584  					"app":                constants.VerrazzanoPlatformOperator,
   585  				},
   586  			},
   587  		},
   588  		&appsv1.ReplicaSet{
   589  			ObjectMeta: metav1.ObjectMeta{
   590  				Namespace:   vpoconst.VerrazzanoInstallNamespace,
   591  				Name:        constants.VerrazzanoPlatformOperator + "-95d8c5d96",
   592  				Annotations: map[string]string{deploymentRevisionAnnotation: "1"},
   593  			},
   594  		},
   595  	}
   596  }
   597  
   598  // getVZObject returns the Verrazzano CR object configured by the user.
   599  func getVZObject() client.Object {
   600  	return &v1beta1.Verrazzano{
   601  		ObjectMeta: metav1.ObjectMeta{
   602  			Namespace: testVZNamespacedName.Namespace,
   603  			Name:      testVZNamespacedName.Name,
   604  		},
   605  		Spec: v1beta1.VerrazzanoSpec{
   606  			Profile: "dev",
   607  		},
   608  		Status: v1beta1.VerrazzanoStatus{
   609  			Conditions: []v1beta1.Condition{
   610  				{
   611  					LastTransitionTime: time.Now().Add(time.Duration(-1) * time.Hour).Format(time.RFC3339),
   612  					Type:               "InstallComplete",
   613  					Message:            "Verrazzano install completed successfully",
   614  					Status:             corev1.ConditionTrue,
   615  				},
   616  			},
   617  		},
   618  	}
   619  }