github.com/Racer159/jackal@v0.32.7-0.20240401174413-0bd2339e4f2e/src/pkg/packager/common_test.go (about) 1 package packager 2 3 import ( 4 "errors" 5 "fmt" 6 "testing" 7 8 "github.com/Racer159/jackal/src/config" 9 "github.com/Racer159/jackal/src/config/lang" 10 "github.com/Racer159/jackal/src/pkg/cluster" 11 "github.com/Racer159/jackal/src/pkg/k8s" 12 "github.com/Racer159/jackal/src/types" 13 "github.com/stretchr/testify/require" 14 v1 "k8s.io/api/core/v1" 15 "k8s.io/apimachinery/pkg/runtime" 16 "k8s.io/client-go/kubernetes/fake" 17 k8sTesting "k8s.io/client-go/testing" 18 ) 19 20 // TestValidatePackageArchitecture verifies that Jackal validates package architecture against cluster architecture correctly. 21 func TestValidatePackageArchitecture(t *testing.T) { 22 t.Parallel() 23 24 type testCase struct { 25 name string 26 pkgArch string 27 clusterArchs []string 28 images []string 29 expectedError error 30 getArchError error 31 } 32 33 testCases := []testCase{ 34 { 35 name: "architecture match", 36 pkgArch: "amd64", 37 clusterArchs: []string{"amd64"}, 38 images: []string{"nginx"}, 39 expectedError: nil, 40 }, 41 { 42 name: "architecture mismatch", 43 pkgArch: "arm64", 44 clusterArchs: []string{"amd64"}, 45 images: []string{"nginx"}, 46 expectedError: fmt.Errorf(lang.CmdPackageDeployValidateArchitectureErr, "arm64", "amd64"), 47 }, 48 { 49 name: "multiple cluster architectures", 50 pkgArch: "arm64", 51 clusterArchs: []string{"amd64", "arm64"}, 52 images: []string{"nginx"}, 53 expectedError: nil, 54 }, 55 { 56 name: "ignore validation when package arch equals 'multi'", 57 pkgArch: "multi", 58 clusterArchs: []string{"not evaluated"}, 59 expectedError: nil, 60 }, 61 { 62 name: "ignore validation when a package doesn't contain images", 63 pkgArch: "amd64", 64 images: []string{}, 65 clusterArchs: []string{"not evaluated"}, 66 expectedError: nil, 67 }, 68 { 69 name: "test the error path when fetching cluster architecture fails", 70 pkgArch: "amd64", 71 images: []string{"nginx"}, 72 getArchError: errors.New("error fetching cluster architecture"), 73 expectedError: lang.ErrUnableToCheckArch, 74 }, 75 } 76 77 for _, testCase := range testCases { 78 testCase := testCase 79 80 t.Run(testCase.name, func(t *testing.T) { 81 t.Parallel() 82 83 mockClient := fake.NewSimpleClientset() 84 logger := func(string, ...interface{}) {} 85 86 // Create a Packager instance with package architecture set and a mock Kubernetes client. 87 p := &Packager{ 88 cluster: &cluster.Cluster{ 89 K8s: &k8s.K8s{ 90 Clientset: mockClient, 91 Log: logger, 92 }, 93 }, 94 cfg: &types.PackagerConfig{ 95 Pkg: types.JackalPackage{ 96 Metadata: types.JackalMetadata{Architecture: testCase.pkgArch}, 97 Components: []types.JackalComponent{ 98 { 99 Images: testCase.images, 100 }, 101 }, 102 }, 103 }, 104 } 105 106 // Set up test data for fetching cluster architecture. 107 mockClient.Fake.PrependReactor("list", "nodes", func(_ k8sTesting.Action) (bool, runtime.Object, error) { 108 // Return an error for cases that test this error path. 109 if testCase.getArchError != nil { 110 return true, nil, testCase.getArchError 111 } 112 113 nodeItems := []v1.Node{} 114 115 for _, arch := range testCase.clusterArchs { 116 nodeItems = append(nodeItems, v1.Node{ 117 Status: v1.NodeStatus{ 118 NodeInfo: v1.NodeSystemInfo{ 119 Architecture: arch, 120 }, 121 }, 122 }) 123 } 124 125 // Create a NodeList object to fetch cluster architecture with the mock client. 126 nodeList := &v1.NodeList{ 127 Items: nodeItems, 128 } 129 return true, nodeList, nil 130 }) 131 132 err := p.validatePackageArchitecture() 133 134 require.Equal(t, testCase.expectedError, err) 135 }) 136 } 137 } 138 139 // TestValidateLastNonBreakingVersion verifies that Jackal validates the lastNonBreakingVersion of packages against the CLI version correctly. 140 func TestValidateLastNonBreakingVersion(t *testing.T) { 141 t.Parallel() 142 143 type testCase struct { 144 name string 145 cliVersion string 146 lastNonBreakingVersion string 147 expectedErrorMessage string 148 expectedWarningMessage string 149 returnError bool 150 throwWarning bool 151 } 152 153 testCases := []testCase{ 154 { 155 name: "CLI version less than lastNonBreakingVersion", 156 cliVersion: "v0.26.4", 157 lastNonBreakingVersion: "v0.27.0", 158 returnError: false, 159 throwWarning: true, 160 expectedWarningMessage: fmt.Sprintf( 161 lang.CmdPackageDeployValidateLastNonBreakingVersionWarn, 162 "v0.26.4", 163 "v0.27.0", 164 "v0.27.0", 165 ), 166 }, 167 { 168 name: "invalid semantic version (CLI version)", 169 cliVersion: "invalidSemanticVersion", 170 lastNonBreakingVersion: "v0.0.1", 171 returnError: false, 172 throwWarning: true, 173 expectedWarningMessage: fmt.Sprintf(lang.CmdPackageDeployInvalidCLIVersionWarn, "invalidSemanticVersion"), 174 }, 175 { 176 name: "invalid semantic version (lastNonBreakingVersion)", 177 cliVersion: "v0.0.1", 178 lastNonBreakingVersion: "invalidSemanticVersion", 179 throwWarning: false, 180 returnError: true, 181 expectedErrorMessage: "unable to parse lastNonBreakingVersion", 182 }, 183 { 184 name: "CLI version greater than lastNonBreakingVersion", 185 cliVersion: "v0.28.2", 186 lastNonBreakingVersion: "v0.27.0", 187 returnError: false, 188 throwWarning: false, 189 }, 190 { 191 name: "CLI version equal to lastNonBreakingVersion", 192 cliVersion: "v0.27.0", 193 lastNonBreakingVersion: "v0.27.0", 194 returnError: false, 195 throwWarning: false, 196 }, 197 { 198 name: "empty lastNonBreakingVersion", 199 cliVersion: "this shouldn't get evaluated when the lastNonBreakingVersion is empty", 200 lastNonBreakingVersion: "", 201 returnError: false, 202 throwWarning: false, 203 }, 204 } 205 206 for _, testCase := range testCases { 207 testCase := testCase 208 209 t.Run(testCase.name, func(t *testing.T) { 210 config.CLIVersion = testCase.cliVersion 211 212 p := &Packager{ 213 cfg: &types.PackagerConfig{ 214 Pkg: types.JackalPackage{ 215 Build: types.JackalBuildData{ 216 LastNonBreakingVersion: testCase.lastNonBreakingVersion, 217 }, 218 }, 219 }, 220 } 221 222 err := p.validateLastNonBreakingVersion() 223 224 switch { 225 case testCase.returnError: 226 require.ErrorContains(t, err, testCase.expectedErrorMessage) 227 require.Empty(t, p.warnings, "Expected no warnings for test case: %s", testCase.name) 228 case testCase.throwWarning: 229 require.Contains(t, p.warnings, testCase.expectedWarningMessage) 230 require.NoError(t, err, "Expected no error for test case: %s", testCase.name) 231 default: 232 require.NoError(t, err, "Expected no error for test case: %s", testCase.name) 233 require.Empty(t, p.warnings, "Expected no warnings for test case: %s", testCase.name) 234 } 235 }) 236 } 237 }