github.com/verrazzano/verrazzano@v1.7.1/pkg/vzchecks/precheck_test.go (about) 1 // Copyright (c) 2022, 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 vzchecks 5 6 import ( 7 "fmt" 8 "github.com/stretchr/testify/assert" 9 v1 "k8s.io/api/core/v1" 10 "k8s.io/apimachinery/pkg/api/resource" 11 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 12 k8scheme "k8s.io/client-go/kubernetes/scheme" 13 client2 "sigs.k8s.io/controller-runtime/pkg/client" 14 "sigs.k8s.io/controller-runtime/pkg/client/fake" 15 "testing" 16 ) 17 18 var ( 19 allNotMet = []string{nodeCountReqMsg, cpuReqMsg, memoryReqMsg, storageReqMsg} 20 onlyStorageMet = []string{nodeCountReqMsg, cpuReqMsg, memoryReqMsg} 21 onlyMemoryMet = []string{nodeCountReqMsg, cpuReqMsg, storageReqMsg} 22 onlyCPUMet = []string{nodeCountReqMsg, memoryReqMsg, storageReqMsg} 23 onlyNodeCountMet = []string{cpuReqMsg, memoryReqMsg, storageReqMsg} 24 storageAndMemoryMet = []string{nodeCountReqMsg, cpuReqMsg} 25 storageAndCPUMet = []string{nodeCountReqMsg, memoryReqMsg} 26 storageAndNodeCountMet = []string{memoryReqMsg, cpuReqMsg} 27 memoryAndCPUMet = []string{nodeCountReqMsg, storageReqMsg} 28 memoryAndNodeCountMet = []string{cpuReqMsg, storageReqMsg} 29 nodeCountAndCPUMet = []string{memoryReqMsg, storageReqMsg} 30 memoryNotMet = []string{memoryReqMsg} 31 nodeNotMet = []string{nodeCountReqMsg} 32 allMet = []string{} 33 ) 34 35 type testData = struct { 36 profile ProfileType 37 nodeCount int 38 cpu string 39 memory string 40 storage string 41 } 42 43 // TestPrerequisiteCheck tests prerequisite checks for various profiles 44 func TestPrerequisiteCheck(t *testing.T) { 45 var tests = []struct { 46 data testData 47 errCount int 48 errTypes []string 49 }{ 50 {testData{Prod, 2, "1", "423Ki", "50G"}, 7, allNotMet}, 51 {testData{Prod, 3, "1", "12G", "50G"}, 9, onlyNodeCountMet}, 52 {testData{Prod, 2, "1", "12G", "100G"}, 5, onlyStorageMet}, 53 {testData{Prod, 2, "4", "12G", "50G"}, 5, onlyCPUMet}, 54 {testData{Prod, 2, "1", "32G", "50G"}, 5, onlyMemoryMet}, 55 {testData{Prod, 1, "6", "35G", "50G"}, 2, memoryAndCPUMet}, 56 {testData{Prod, 2, "5", "12G", "100G"}, 3, storageAndCPUMet}, 57 {testData{Prod, 2, "3", "32G", "100G"}, 3, storageAndMemoryMet}, 58 {testData{Prod, 5, "6", "32G", "500G"}, 0, allMet}, 59 {testData{Dev, 0, "1", "10G", "50G"}, 1, allNotMet}, 60 {testData{Dev, 1, "1", "12G", "50G"}, 3, onlyNodeCountMet}, 61 {testData{ManagedCluster, 2, "1", "12G", "100G"}, 4, storageAndNodeCountMet}, 62 {testData{ManagedCluster, 2, "4", "12G", "50G"}, 4, nodeCountAndCPUMet}, 63 {testData{Dev, 2, "2", "2G", "50G"}, 4, nodeCountAndCPUMet}, 64 {testData{Dev, 1, "1", "5G", "100G"}, 2, storageAndNodeCountMet}, 65 {testData{ManagedCluster, 2, "5", "12G", "100G"}, 2, memoryNotMet}, 66 {testData{Dev, 1, "1", "32G", "10G"}, 2, memoryAndNodeCountMet}, 67 {testData{Dev, 0, "", "", ""}, 1, nodeNotMet}, 68 {testData{"unspecified", 1, "2", "24G", "50G"}, 0, allMet}, 69 } 70 71 for _, tt := range tests { 72 t.Run(string(tt.data.profile), func(t *testing.T) { 73 client := fake.NewClientBuilder().WithScheme(k8scheme.Scheme).WithObjects( 74 getNodes(tt.data)...).Build() 75 errs := PrerequisiteCheck(client, tt.data.profile) 76 assert.Equal(t, tt.errCount, len(errs)) 77 vzReq := getVZRequirement(tt.data.profile) 78 for _, errMsg := range tt.errTypes { 79 for i := 1; i <= tt.data.nodeCount; i++ { 80 nodeName := fmt.Sprintf("node%d", i) 81 expectedMsg := getExpectedMessage(errMsg, nodeName, vzReq, tt.data) 82 assert.Equal(t, true, errorSliceContainsMessage(errs, expectedMsg), 83 "Expected error message \"%s\" not found", expectedMsg) 84 } 85 } 86 }) 87 } 88 } 89 90 // errorSliceContainsMessage checks for a error message in a slice of errors 91 // errs is the error slice to search. May be nil. 92 // msg is the string to search for in the errs. 93 // Returns true if the string is found in the slice and false otherwise. 94 func errorSliceContainsMessage(errs []error, msg string) bool { 95 for _, err := range errs { 96 if err.Error() == msg { 97 return true 98 } 99 } 100 return false 101 } 102 103 func getNodes(data testData) []client2.Object { 104 var nodes []client2.Object 105 for i := 1; i <= data.nodeCount; i++ { 106 nodes = append(nodes, &v1.Node{ 107 TypeMeta: metav1.TypeMeta{ 108 Kind: "Node", 109 APIVersion: "v1", 110 }, 111 ObjectMeta: metav1.ObjectMeta{ 112 Name: fmt.Sprintf("node%d", i), 113 }, 114 Status: v1.NodeStatus{ 115 Allocatable: v1.ResourceList{ 116 "cpu": resource.MustParse(data.cpu), 117 "memory": resource.MustParse(data.memory), 118 "ephemeral-storage": resource.MustParse(data.storage), 119 }, 120 }, 121 }) 122 } 123 return nodes 124 } 125 126 func getExpectedMessage(errMsg string, nodeName string, vzReq VZRequirement, data testData) string { 127 expectedMsg := "" 128 switch errMsg { 129 case nodeCountReqMsg: 130 expectedMsg = fmt.Sprintf(errMsg, vzReq.nodeCount, data.nodeCount) 131 case cpuReqMsg: 132 expectedMsg = fmt.Sprintf(errMsg, vzReq.cpu.allocatable.Value(), 133 nodeName, data.cpu) 134 case memoryReqMsg: 135 expectedMsg = fmt.Sprintf(errMsg, convertQuantityToString(vzReq.memory.allocatable), 136 nodeName, convertQuantityToString(resource.MustParse(data.memory))) 137 case storageReqMsg: 138 expectedMsg = fmt.Sprintf(errMsg, convertQuantityToString(vzReq.ephemeralStorage.allocatable), 139 nodeName, convertQuantityToString(resource.MustParse(data.storage))) 140 } 141 return expectedMsg 142 }