github.com/verrazzano/verrazzano@v1.7.0/cluster-operator/internal/operatorinit/run_operator_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  
     4  package operatorinit
     5  
     6  import (
     7  	"context"
     8  	"os"
     9  	"strconv"
    10  	"testing"
    11  
    12  	"github.com/stretchr/testify/assert"
    13  	"go.uber.org/zap"
    14  	apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    15  	"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/fake"
    16  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    17  )
    18  
    19  // TestShouldSyncClusters tests the shouldSyncClusters function
    20  func TestShouldSyncClusters(t *testing.T) {
    21  	asserts := assert.New(t)
    22  
    23  	// when this test is done, reset the cluster sync env var
    24  	envValue, envValueExists := os.LookupEnv(syncClustersEnvVarName)
    25  	defer func() {
    26  		if envValueExists {
    27  			os.Setenv(syncClustersEnvVarName, envValue)
    28  		} else {
    29  			os.Unsetenv(syncClustersEnvVarName)
    30  		}
    31  	}()
    32  
    33  	var tests = []struct {
    34  		testName              string
    35  		enabled               bool
    36  		clusterSelectorText   string
    37  		expectedLabelSelector *metav1.LabelSelector
    38  		expectedError         bool
    39  	}{
    40  		// GIVEN cluster sync is disabled
    41  		// WHEN  shouldSyncClusters is called
    42  		// THEN  the call returns that cluster sync is disabled, a nil label selector, and no error
    43  		{
    44  			"Sync Rancher clusters is disabled",
    45  			false,
    46  			"",
    47  			nil,
    48  			false,
    49  		},
    50  		// GIVEN cluster sync is enabled and no label selector yaml is provided
    51  		// WHEN  shouldSyncClusters is called
    52  		// THEN  the call returns that cluster sync is enabled, a nil label selector, and no error
    53  		{
    54  			"Sync Rancher clusters is enabled, no label selector specified",
    55  			true,
    56  			"",
    57  			nil,
    58  			false,
    59  		},
    60  		// GIVEN cluster sync is enabled and a label selector yaml is provided
    61  		// WHEN  shouldSyncClusters is called
    62  		// THEN  the call returns that cluster sync is enabled, a populated label selector, and no error
    63  		{
    64  			"Sync Rancher clusters is enabled, simple label selector specified",
    65  			true,
    66  			"matchLabels:\n  foo: bar\n",
    67  			&metav1.LabelSelector{
    68  				MatchLabels: map[string]string{"foo": "bar"},
    69  			},
    70  			false,
    71  		},
    72  		// GIVEN cluster sync is enabled and a more complex label selector yaml is provided
    73  		// WHEN  shouldSyncClusters is called
    74  		// THEN  the call returns that cluster sync is enabled, a populated label selector, and no error
    75  		{
    76  			"Sync Rancher clusters is enabled, complex label selector specified",
    77  			true,
    78  			"matchLabels:\n  foo: bar\nmatchExpressions:\n- key: clustertype\n  operator: In\n  values: [special, reallyspecial]",
    79  			&metav1.LabelSelector{
    80  				MatchLabels: map[string]string{"foo": "bar"},
    81  				MatchExpressions: []metav1.LabelSelectorRequirement{
    82  					{
    83  						Key:      "clustertype",
    84  						Operator: metav1.LabelSelectorOpIn,
    85  						Values:   []string{"special", "reallyspecial"},
    86  					},
    87  				},
    88  			},
    89  			false,
    90  		},
    91  		// GIVEN cluster sync is enabled and malformed label selector yaml is provided
    92  		// WHEN  shouldSyncClusters is called
    93  		// THEN  the call returns that cluster sync is enabled, a nil label selector, and an error
    94  		{
    95  			"Sync Rancher clusters is enabled, invalid label selector",
    96  			true,
    97  			"matchLabels:\n  bogus\n",
    98  			nil,
    99  			true,
   100  		},
   101  	}
   102  
   103  	for _, tt := range tests {
   104  		t.Run(tt.testName, func(t *testing.T) {
   105  			// if cluster selector text is specified, write it to a temp file
   106  			var filename string
   107  			if len(tt.clusterSelectorText) > 0 {
   108  				var err error
   109  				filename, err = writeTempFile(tt.clusterSelectorText)
   110  				asserts.NoError(err)
   111  				defer os.Remove(filename)
   112  			}
   113  			os.Setenv(syncClustersEnvVarName, strconv.FormatBool(tt.enabled))
   114  
   115  			enabled, labelSelector, err := shouldSyncClusters(filename)
   116  
   117  			if tt.expectedError {
   118  				asserts.Error(err, tt.testName)
   119  			} else {
   120  				asserts.NoError(err, tt.testName)
   121  			}
   122  			asserts.Equal(tt.enabled, enabled, tt.testName)
   123  			asserts.Equal(tt.expectedLabelSelector, labelSelector, tt.testName)
   124  		})
   125  	}
   126  }
   127  
   128  // TestIsCattleClustersCRDInstalled tests the isCRDInstalled function
   129  func TestIsCattleClustersCRDInstalled(t *testing.T) {
   130  	asserts := assert.New(t)
   131  
   132  	// GIVEN a cluster that does not have the cattle clusters CRD installed
   133  	// WHEN  a call is made to isCRDInstalled
   134  	// THEN  the function returns false
   135  	client := fake.NewSimpleClientset().ApiextensionsV1()
   136  	isInstalled, err := isCRDInstalled(client, cattleClustersCRDName)
   137  	asserts.NoError(err)
   138  	asserts.False(isInstalled)
   139  
   140  	// GIVEN a cluster that does have the cattle clusters CRD installed
   141  	// WHEN  a call is made to isCRDInstalled
   142  	// THEN  the function returns true
   143  	crd := &apiextv1.CustomResourceDefinition{
   144  		ObjectMeta: metav1.ObjectMeta{
   145  			Name: cattleClustersCRDName,
   146  		},
   147  	}
   148  	client = fake.NewSimpleClientset(crd).ApiextensionsV1()
   149  	isInstalled, err = isCRDInstalled(client, cattleClustersCRDName)
   150  	asserts.NoError(err)
   151  	asserts.True(isInstalled)
   152  }
   153  
   154  // TestWatchCattleClustersCRD tests the watchCattleClustersCRD function
   155  func TestWatchCattleClustersCRD(t *testing.T) {
   156  	asserts := assert.New(t)
   157  
   158  	// GIVEN the cattle clusters CRD is installed after the cluster operator starts up
   159  	// WHEN  the watchCattleClustersCRD function is called
   160  	// THEN  the context Done channel has been closed due to the context cancel function being called
   161  	crd := &apiextv1.CustomResourceDefinition{
   162  		ObjectMeta: metav1.ObjectMeta{
   163  			Name: cattleClustersCRDName,
   164  		},
   165  	}
   166  	client := fake.NewSimpleClientset(crd).ApiextensionsV1()
   167  
   168  	ctx, cancel := context.WithCancel(context.TODO())
   169  	watchCattleClustersCRD(cancel, client, false, zap.L().Sugar())
   170  	_, open := <-ctx.Done()
   171  	asserts.False(open)
   172  
   173  	// GIVEN the cattle clusters CRD is uninstalled after the cluster operator starts up
   174  	// WHEN  the watchCattleClustersCRD function is called
   175  	// THEN  the context Done channel has been closed due to the context cancel function being called
   176  	client = fake.NewSimpleClientset().ApiextensionsV1()
   177  
   178  	ctx, cancel = context.WithCancel(context.TODO())
   179  	watchCattleClustersCRD(cancel, client, true, zap.L().Sugar())
   180  	_, open = <-ctx.Done()
   181  	asserts.False(open)
   182  }
   183  
   184  // writeTempFile creates a temp file with the specified string content. It returns the
   185  // file name.
   186  func writeTempFile(clusterSelectorText string) (string, error) {
   187  	f, err := os.CreateTemp("", "")
   188  	if err != nil {
   189  		return "", err
   190  	}
   191  	f.Write([]byte(clusterSelectorText))
   192  	f.Close()
   193  	return f.Name(), nil
   194  }