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  }