github.com/verrazzano/verrazzano@v1.7.0/application-operator/controllers/clusters/test/test_utils.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 clusterstest 5 6 import ( 7 "context" 8 "encoding/json" 9 "fmt" 10 "os" 11 "sigs.k8s.io/controller-runtime/pkg/client" 12 "testing" 13 14 "github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2" 15 "github.com/golang/mock/gomock" 16 "github.com/stretchr/testify/assert" 17 "github.com/verrazzano/verrazzano/application-operator/apis/clusters/v1alpha1" 18 "github.com/verrazzano/verrazzano/application-operator/constants" 19 "github.com/verrazzano/verrazzano/application-operator/controllers/clusters" 20 "github.com/verrazzano/verrazzano/application-operator/mocks" 21 "k8s.io/api/core/v1" 22 "k8s.io/apimachinery/pkg/runtime" 23 "k8s.io/apimachinery/pkg/types" 24 ctrl "sigs.k8s.io/controller-runtime" 25 "sigs.k8s.io/yaml" 26 ) 27 28 // UnitTestClusterName - cluster name used in unit tests 29 const UnitTestClusterName = "cluster1" 30 31 // NewRequest creates a new reconciler request for testing 32 // namespace - The namespace to use in the request 33 // name - The name to use in the request 34 func NewRequest(namespace string, name string) ctrl.Request { 35 return ctrl.Request{ 36 NamespacedName: types.NamespacedName{ 37 Namespace: namespace, 38 Name: name, 39 }, 40 } 41 } 42 43 // ReadYaml2Json reads the testdata YAML file at the given path, converts it to JSON and returns 44 // a byte slice containing the JSON 45 func ReadYaml2Json(filename string) ([]byte, error) { 46 yamlBytes, err := os.ReadFile(filename) 47 if err != nil { 48 return nil, fmt.Errorf("failed to read test data file %s: %s", filename, err.Error()) 49 } 50 jsonBytes, err := yaml.YAMLToJSON(yamlBytes) 51 if err != nil { 52 return nil, fmt.Errorf("failed to unmarshall YAML to JSON in file %s: %s", filename, err.Error()) 53 } 54 return jsonBytes, nil 55 } 56 57 // ReadContainerizedWorkload reads the raw workload (typically from an OAM component) into 58 // a ContainerizedWorkload object 59 func ReadContainerizedWorkload(rawWorkload runtime.RawExtension) (v1alpha2.ContainerizedWorkload, error) { 60 ctrWorkload := v1alpha2.ContainerizedWorkload{} 61 workloadBytes, err := rawWorkload.MarshalJSON() 62 if err != nil { 63 return ctrWorkload, err 64 } 65 err = json.Unmarshal(workloadBytes, &ctrWorkload) 66 return ctrWorkload, err 67 } 68 69 // DoExpectGetMCRegistrationSecret adds an expectation to the given MockClient to expect a Get 70 // call for the managed cluster registration secret, and populate it with the cluster-name 71 func DoExpectGetMCRegistrationSecret(cli *mocks.MockClient) { 72 // expect a call to fetch the MCRegistrationSecret and return a fake one with a specific cluster name 73 mockRegistrationSecretData := map[string][]byte{constants.ClusterNameData: []byte(UnitTestClusterName)} 74 cli.EXPECT(). 75 Get(gomock.Any(), types.NamespacedName{ 76 Namespace: clusters.MCRegistrationSecretFullName.Namespace, 77 Name: clusters.MCRegistrationSecretFullName.Name}, 78 gomock.Not(gomock.Nil()), 79 gomock.Any()). 80 DoAndReturn(func(ctx context.Context, name types.NamespacedName, secret *v1.Secret, opts ...client.GetOption) error { 81 secret.Data = mockRegistrationSecretData 82 secret.ObjectMeta.Namespace = clusters.MCRegistrationSecretFullName.Namespace 83 secret.ObjectMeta.Name = clusters.MCRegistrationSecretFullName.Name 84 return nil 85 }) 86 } 87 88 // AssertMultiClusterResourceStatus asserts that the status, conditions and cluster level status 89 // on the MultiClusterResourceStatus are as expected 90 func AssertMultiClusterResourceStatus(assert *assert.Assertions, 91 actualStatus v1alpha1.MultiClusterResourceStatus, 92 expectedState v1alpha1.StateType, 93 expectedConditionType v1alpha1.ConditionType, 94 expectedConditionStatus v1.ConditionStatus) { 95 96 assert.Equal(expectedState, actualStatus.State) 97 assert.Equal(1, len(actualStatus.Conditions)) 98 assert.Equal(expectedConditionStatus, actualStatus.Conditions[0].Status) 99 assert.Equal(expectedConditionType, actualStatus.Conditions[0].Type) 100 101 assert.Equal(1, len(actualStatus.Clusters)) 102 assert.Equal(UnitTestClusterName, actualStatus.Clusters[0].Name) 103 assert.Equal(expectedState, actualStatus.Clusters[0].State) 104 } 105 106 // DoExpectUpdateState checks that the status writer was retrieved and an update of the 107 // resource's state to the given value was called 108 func DoExpectUpdateState(t *testing.T, cli *mocks.MockClient, statusWriter *mocks.MockStatusWriter, mcAppConfig clusters.MultiClusterResource, expectedState v1alpha1.StateType) { 109 // expect a call to update the status of the MultiClusterApplicationConfiguration 110 cli.EXPECT().Status().Return(statusWriter) 111 112 // the status update should be to success status/conditions on the MultiClusterApplicationConfiguration 113 statusWriter.EXPECT(). 114 Update(gomock.Any(), gomock.AssignableToTypeOf(mcAppConfig), gomock.Any()). 115 DoAndReturn(func(ctx context.Context, mcAppConfig clusters.MultiClusterResource, opts ...client.UpdateOption) error { 116 assert.Equal(t, v1alpha1.Pending, mcAppConfig.GetStatus().State) 117 return nil 118 }) 119 } 120 121 // ExpectDeleteAssociatedResource adds an expectation to the given MockClient to expect a Get 122 // call for the runtime resource and a subsequent request to delete it 123 func ExpectDeleteAssociatedResource(cli *mocks.MockClient, resource runtime.Object, name types.NamespacedName) { 124 cli.EXPECT(). 125 Get(gomock.Any(), types.NamespacedName{Namespace: name.Namespace, Name: name.Name}, gomock.Not(gomock.Nil()), gomock.Any()). 126 DoAndReturn(func(ctx context.Context, name types.NamespacedName, obj runtime.Object, opts ...client.GetOption) error { 127 return nil 128 }) 129 130 cli.EXPECT(). 131 Delete(gomock.Any(), gomock.Any(), gomock.Any()). 132 DoAndReturn(func(ctx context.Context, resource runtime.Object, opts ...client.DeleteOption) error { 133 return nil 134 }) 135 136 }