github.com/verrazzano/verrazzano@v1.7.0/cluster-operator/controllers/vmc/rancher_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 vmc 5 6 import ( 7 "bytes" 8 "encoding/json" 9 "fmt" 10 "io" 11 "net/http" 12 "testing" 13 "time" 14 15 "github.com/Jeffail/gabs/v2" 16 "github.com/golang/mock/gomock" 17 asserts "github.com/stretchr/testify/assert" 18 "github.com/verrazzano/verrazzano/pkg/log/vzlog" 19 "github.com/verrazzano/verrazzano/pkg/rancherutil" 20 "github.com/verrazzano/verrazzano/pkg/test/mockmatchers" 21 "github.com/verrazzano/verrazzano/platform-operator/mocks" 22 corev1 "k8s.io/api/core/v1" 23 v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 24 "k8s.io/apimachinery/pkg/util/wait" 25 "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" 26 ) 27 28 // TestCreateOrUpdateSecretRancherProxy tests the create or update simulation through the Rancher proxy 29 // GIVEN a new secret for the managed cluster 30 // 31 // WHEN the createOrUpdateSecretRancherProxy is called 32 // THEN the managed cluster has a version of the new secret spec that is generated 33 func TestCreateOrUpdateSecretRancherProxy(t *testing.T) { 34 a := asserts.New(t) 35 36 savedRetry := rancherutil.DefaultRetry 37 defer func() { 38 rancherutil.DefaultRetry = savedRetry 39 }() 40 rancherutil.DefaultRetry = wait.Backoff{ 41 Steps: 1, 42 Duration: 1 * time.Millisecond, 43 Factor: 1.0, 44 Jitter: 0.1, 45 } 46 47 savedRancherHTTPClient := rancherutil.RancherHTTPClient 48 defer func() { 49 rancherutil.RancherHTTPClient = savedRancherHTTPClient 50 }() 51 52 secret := corev1.Secret{ 53 ObjectMeta: v1.ObjectMeta{ 54 Namespace: "test-ns", 55 Name: "test-name", 56 }, 57 } 58 clusterID := "cluster-id" 59 60 mocker := gomock.NewController(t) 61 62 tests := []struct { 63 name string 64 f controllerutil.MutateFn 65 mock *mocks.MockRequestSender 66 result controllerutil.OperationResult 67 }{ 68 { 69 name: "test secret not found", 70 f: func() error { return nil }, 71 mock: addNotFoundMock(mocks.NewMockRequestSender(mocker), &secret, clusterID), 72 result: controllerutil.OperationResultCreated, 73 }, 74 { 75 name: "test secret found", 76 f: func() error { return nil }, 77 mock: addFoundMock(mocks.NewMockRequestSender(mocker), a, &secret, clusterID), 78 result: controllerutil.OperationResultNone, 79 }, 80 { 81 name: "test secret mutated", 82 f: func() error { 83 secret.Data = make(map[string][]byte) 84 secret.Data["test"] = []byte("newVal") 85 return nil 86 }, 87 mock: addMutatedMock(mocks.NewMockRequestSender(mocker), a, &secret, clusterID), 88 result: controllerutil.OperationResultUpdated, 89 }, 90 } 91 for _, tt := range tests { 92 t.Run(tt.name, func(t *testing.T) { 93 rancherutil.RancherHTTPClient = tt.mock 94 result, err := createOrUpdateSecretRancherProxy(&secret, &rancherutil.RancherConfig{}, clusterID, tt.f, vzlog.DefaultLogger()) 95 a.Nil(err) 96 a.Equal(tt.result, result) 97 }) 98 } 99 mocker.Finish() 100 } 101 102 func Test_makeClusterPayload(t *testing.T) { 103 // a := asserts.New(t) 104 105 tests := []struct { 106 name string 107 clusterName string 108 labels map[string]string 109 }{ 110 { 111 name: "test nil labels", 112 clusterName: "nilLabelsCluster", 113 labels: nil, 114 }, 115 { 116 name: "test empty labels map", 117 clusterName: "nilLabelsCluster", 118 labels: map[string]string{}, 119 }, 120 { 121 name: "test one label", 122 clusterName: "cluster1", 123 labels: map[string]string{ 124 "label1": "val1", 125 }, 126 }, 127 { 128 name: "test two labels", 129 clusterName: "cluster2", 130 labels: map[string]string{ 131 "label1": "val1", 132 "rancherLbl2": "val2", 133 }, 134 }, 135 { 136 name: "test 3 labels", 137 clusterName: "cluster3", 138 labels: map[string]string{ 139 "label1": "val1", 140 "rancherLbl2": "val2", 141 "rancherLbl3": "val3", 142 }, 143 }, 144 } 145 for _, tt := range tests { 146 t.Run(tt.name, func(t *testing.T) { 147 payload, err := makeClusterPayload(tt.clusterName, tt.labels) 148 asserts.NoError(t, err) 149 payloadParsed, err := gabs.ParseJSON([]byte(payload)) 150 asserts.NoError(t, err) 151 asserts.Equal(t, tt.clusterName, payloadParsed.Path("name").Data()) 152 asserts.Equal(t, "cluster", payloadParsed.Path("type").Data()) 153 labels := payloadParsed.Path("labels") 154 if tt.labels == nil || len(tt.labels) == 0 { 155 asserts.Nil(t, labels) 156 } 157 for key, val := range tt.labels { 158 asserts.Equal(t, val, labels.Path(key).Data()) 159 } 160 }) 161 } 162 } 163 164 func addNotFoundMock(httpMock *mocks.MockRequestSender, secret *corev1.Secret, clusterID string) *mocks.MockRequestSender { 165 httpMock.EXPECT().Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURIMethod(http.MethodGet, getTestPath(secret, clusterID, false))). 166 Return(&http.Response{StatusCode: 404, Body: io.NopCloser(bytes.NewReader([]byte("")))}, fmt.Errorf("not found")).AnyTimes() 167 httpMock.EXPECT().Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURIMethod(http.MethodPost, getTestPath(secret, clusterID, true))). 168 Return(&http.Response{StatusCode: 201, Body: io.NopCloser(bytes.NewReader([]byte("")))}, nil) 169 return httpMock 170 } 171 172 func addFoundMock(httpMock *mocks.MockRequestSender, a *asserts.Assertions, secret *corev1.Secret, clusterID string) *mocks.MockRequestSender { 173 secretData, err := json.Marshal(secret) 174 a.NoError(err) 175 httpMock.EXPECT().Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURIMethod(http.MethodGet, getTestPath(secret, clusterID, false))). 176 Return(&http.Response{StatusCode: 200, Body: io.NopCloser(bytes.NewReader(secretData))}, nil) 177 return httpMock 178 } 179 180 func addMutatedMock(httpMock *mocks.MockRequestSender, a *asserts.Assertions, secret *corev1.Secret, clusterID string) *mocks.MockRequestSender { 181 secretData, err := json.Marshal(secret) 182 a.NoError(err) 183 httpMock.EXPECT().Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURIMethod(http.MethodGet, getTestPath(secret, clusterID, false))). 184 Return(&http.Response{StatusCode: 200, Body: io.NopCloser(bytes.NewReader(secretData))}, nil) 185 httpMock.EXPECT().Do(gomock.Not(gomock.Nil()), mockmatchers.MatchesURIMethod(http.MethodPut, getTestPath(secret, clusterID, false))). 186 Return(&http.Response{StatusCode: 200, Body: io.NopCloser(bytes.NewReader([]byte("")))}, nil) 187 return httpMock 188 } 189 190 func getTestPath(secret *corev1.Secret, clusterID string, create bool) string { 191 if create { 192 return k8sClustersPath + clusterID + fmt.Sprintf(secretCreateTemplate, secret.GetNamespace()) 193 } 194 return k8sClustersPath + clusterID + fmt.Sprintf(secretPathTemplate, secret.GetNamespace(), secret.GetName()) 195 }