sigs.k8s.io/cluster-api@v1.6.3/cmd/clusterctl/client/repository/repository_local_test.go (about) 1 /* 2 Copyright 2019 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package repository 18 19 import ( 20 "context" 21 "os" 22 "path/filepath" 23 "testing" 24 25 . "github.com/onsi/gomega" 26 27 clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" 28 "sigs.k8s.io/cluster-api/cmd/clusterctl/client/config" 29 "sigs.k8s.io/cluster-api/cmd/clusterctl/internal/test" 30 ) 31 32 func Test_localRepository_newLocalRepository(t *testing.T) { 33 type fields struct { 34 provider config.Provider 35 configVariablesClient config.VariablesClient 36 } 37 type want struct { 38 basepath string 39 providerLabel string 40 defaultVersion string 41 rootPath string 42 componentsPath string 43 } 44 tests := []struct { 45 name string 46 fields fields 47 want want 48 wantErr bool 49 }{ 50 { 51 name: "successfully creates new local repository object with a single version", 52 fields: fields{ 53 provider: config.NewProvider("foo", "/base/path/bootstrap-foo/v1.0.0/bootstrap-components.yaml", clusterctlv1.BootstrapProviderType), 54 configVariablesClient: test.NewFakeVariableClient(), 55 }, 56 want: want{ 57 basepath: "/base/path", 58 providerLabel: "bootstrap-foo", 59 defaultVersion: "v1.0.0", 60 rootPath: "", 61 componentsPath: "bootstrap-components.yaml", 62 }, 63 wantErr: false, 64 }, 65 { 66 name: "successfully creates new local repository object with a single version and no basepath", 67 fields: fields{ 68 provider: config.NewProvider("foo", "/bootstrap-foo/v1.0.0/bootstrap-components.yaml", clusterctlv1.BootstrapProviderType), 69 configVariablesClient: test.NewFakeVariableClient(), 70 }, 71 want: want{ 72 basepath: "/", 73 providerLabel: "bootstrap-foo", 74 defaultVersion: "v1.0.0", 75 rootPath: "", 76 componentsPath: "bootstrap-components.yaml", 77 }, 78 wantErr: false, 79 }, 80 { 81 name: "fails if an absolute path not specified", 82 fields: fields{ 83 provider: config.NewProvider("foo", "./bootstrap-foo/v1/bootstrap-components.yaml", clusterctlv1.BootstrapProviderType), 84 configVariablesClient: test.NewFakeVariableClient(), 85 }, 86 want: want{}, 87 wantErr: true, 88 }, 89 { 90 name: "fails if provider id does not match in the path", 91 fields: fields{ 92 provider: config.NewProvider("foo", "/foo/bar/bootstrap-bar/v1/bootstrap-components.yaml", clusterctlv1.BootstrapProviderType), 93 configVariablesClient: test.NewFakeVariableClient(), 94 }, 95 want: want{}, 96 wantErr: true, 97 }, 98 { 99 name: "fails if malformed path: invalid version directory", 100 fields: fields{ 101 provider: config.NewProvider("foo", "/foo/bar/bootstrap-foo/v.a.b.c/bootstrap-components.yaml", clusterctlv1.BootstrapProviderType), 102 configVariablesClient: test.NewFakeVariableClient(), 103 }, 104 want: want{}, 105 wantErr: true, 106 }, 107 } 108 for _, tt := range tests { 109 t.Run(tt.name, func(t *testing.T) { 110 g := NewWithT(t) 111 112 got, err := newLocalRepository(context.Background(), tt.fields.provider, tt.fields.configVariablesClient) 113 if tt.wantErr { 114 g.Expect(err).To(HaveOccurred()) 115 return 116 } 117 g.Expect(err).ToNot(HaveOccurred()) 118 119 g.Expect(got.basepath).To(Equal(tt.want.basepath)) 120 g.Expect(got.providerLabel).To(Equal(tt.want.providerLabel)) 121 g.Expect(got.DefaultVersion()).To(Equal(tt.want.defaultVersion)) 122 g.Expect(got.RootPath()).To(Equal(tt.want.rootPath)) 123 g.Expect(got.ComponentsPath()).To(Equal(tt.want.componentsPath)) 124 }) 125 } 126 } 127 128 func createTempDir(t *testing.T) string { 129 t.Helper() 130 131 dir, err := os.MkdirTemp("", "cc") 132 if err != nil { 133 t.Fatalf("err: %s", err) 134 } 135 return dir 136 } 137 138 func createLocalTestProviderFile(t *testing.T, tmpDir, path, msg string) string { 139 t.Helper() 140 141 g := NewWithT(t) 142 143 dst := filepath.Join(tmpDir, path) 144 // Create all directories in the standard layout 145 g.Expect(os.MkdirAll(filepath.Dir(dst), 0750)).To(Succeed()) 146 g.Expect(os.WriteFile(dst, []byte(msg), 0600)).To(Succeed()) 147 148 return dst 149 } 150 151 func Test_localRepository_newLocalRepository_Latest(t *testing.T) { 152 g := NewWithT(t) 153 154 tmpDir := createTempDir(t) 155 defer os.RemoveAll(tmpDir) 156 157 // Create several release directories 158 createLocalTestProviderFile(t, tmpDir, "bootstrap-foo/v1.0.0/bootstrap-components.yaml", "foo: bar") 159 createLocalTestProviderFile(t, tmpDir, "bootstrap-foo/v1.0.1/bootstrap-components.yaml", "foo: bar") 160 createLocalTestProviderFile(t, tmpDir, "bootstrap-foo/v2.0.0-alpha.0/bootstrap-components.yaml", "foo: bar") 161 createLocalTestProviderFile(t, tmpDir, "bootstrap-foo/Foo.Bar/bootstrap-components.yaml", "foo: bar") 162 createLocalTestProviderFile(t, tmpDir, "bootstrap-foo/foo.file", "foo: bar") 163 164 // Provider URL for the latest release 165 p2URLLatest := "bootstrap-foo/latest/bootstrap-components.yaml" 166 p2URLLatestAbs := filepath.Join(tmpDir, p2URLLatest) 167 p2 := config.NewProvider("foo", p2URLLatestAbs, clusterctlv1.BootstrapProviderType) 168 169 got, err := newLocalRepository(context.Background(), p2, test.NewFakeVariableClient()) 170 g.Expect(err).ToNot(HaveOccurred()) 171 172 g.Expect(got.basepath).To(Equal(tmpDir)) 173 g.Expect(got.providerLabel).To(Equal("bootstrap-foo")) 174 g.Expect(got.DefaultVersion()).To(Equal("v1.0.1")) 175 g.Expect(got.RootPath()).To(BeEmpty()) 176 g.Expect(got.ComponentsPath()).To(Equal("bootstrap-components.yaml")) 177 } 178 179 func Test_localRepository_GetFile(t *testing.T) { 180 tmpDir := createTempDir(t) 181 defer os.RemoveAll(tmpDir) 182 183 // Provider 1: URL is for the only release available 184 dst1 := createLocalTestProviderFile(t, tmpDir, "bootstrap-foo/v1.0.0/bootstrap-components.yaml", "foo: bar") 185 p1 := config.NewProvider("foo", dst1, clusterctlv1.BootstrapProviderType) 186 187 // Provider 2: URL is for the latest release 188 createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/v1.0.0/bootstrap-components.yaml", "version: v1.0.0") 189 createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/v1.0.1/bootstrap-components.yaml", "version: v1.0.1") 190 createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/v2.0.0-alpha.0/bootstrap-components.yaml", "version: v2.0.0-alpha.0") 191 createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/Foo.Bar/bootstrap-components.yaml", "version: Foo.Bar") 192 createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/foo.file", "foo: bar") 193 p2URLLatest := "bootstrap-bar/latest/bootstrap-components.yaml" 194 p2URLLatestAbs := filepath.Join(tmpDir, p2URLLatest) 195 p2 := config.NewProvider("bar", p2URLLatestAbs, clusterctlv1.BootstrapProviderType) 196 197 // Provider 3: URL is for only prerelease available 198 dst3 := createLocalTestProviderFile(t, tmpDir, "bootstrap-baz/v1.0.0-alpha.0/bootstrap-components.yaml", "version: v1.0.0-alpha.0") 199 p3 := config.NewProvider("baz", dst3, clusterctlv1.BootstrapProviderType) 200 201 type fields struct { 202 provider config.Provider 203 configVariablesClient config.VariablesClient 204 } 205 type args struct { 206 version string 207 fileName string 208 } 209 type want struct { 210 contents string 211 } 212 tests := []struct { 213 name string 214 fields fields 215 args args 216 want want 217 wantErr bool 218 }{ 219 { 220 name: "Get file from release directory", 221 fields: fields{ 222 provider: p1, 223 configVariablesClient: test.NewFakeVariableClient(), 224 }, 225 args: args{ 226 version: "v1.0.0", 227 fileName: "bootstrap-components.yaml", 228 }, 229 want: want{ 230 contents: "foo: bar", 231 }, 232 wantErr: false, 233 }, 234 { 235 name: "Get file from latest release directory", 236 fields: fields{ 237 provider: p2, 238 configVariablesClient: test.NewFakeVariableClient(), 239 }, 240 args: args{ 241 version: "latest", 242 fileName: "bootstrap-components.yaml", 243 }, 244 want: want{ 245 contents: "version: v1.0.1", // We use the file contents to determine data was read from latest release 246 }, 247 wantErr: false, 248 }, 249 { 250 name: "Get file from default version release directory", 251 fields: fields{ 252 provider: p2, 253 configVariablesClient: test.NewFakeVariableClient(), 254 }, 255 args: args{ 256 version: "", 257 fileName: "bootstrap-components.yaml", 258 }, 259 want: want{ 260 contents: "version: v1.0.1", // We use the file contents to determine data was read from latest release 261 }, 262 wantErr: false, 263 }, 264 { 265 name: "Get file from pre-release version release directory", 266 fields: fields{ 267 provider: p2, 268 configVariablesClient: test.NewFakeVariableClient(), 269 }, 270 args: args{ 271 version: "v2.0.0-alpha.0", 272 fileName: "bootstrap-components.yaml", 273 }, 274 want: want{ 275 contents: "version: v2.0.0-alpha.0", // We use the file contents to determine data was read from latest release 276 }, 277 wantErr: false, 278 }, 279 { 280 name: "Get file from latest prerelease directory if no releases", 281 fields: fields{ 282 provider: p3, 283 configVariablesClient: test.NewFakeVariableClient(), 284 }, 285 args: args{ 286 version: "latest", 287 fileName: "bootstrap-components.yaml", 288 }, 289 want: want{ 290 contents: "version: v1.0.0-alpha.0", // We use the file contents to determine data was read from latest prerelease 291 }, 292 wantErr: false, 293 }, 294 } 295 for _, tt := range tests { 296 t.Run(tt.name, func(t *testing.T) { 297 g := NewWithT(t) 298 299 r, err := newLocalRepository(context.Background(), tt.fields.provider, tt.fields.configVariablesClient) 300 g.Expect(err).ToNot(HaveOccurred()) 301 302 got, err := r.GetFile(context.Background(), tt.args.version, tt.args.fileName) 303 if tt.wantErr { 304 g.Expect(err).To(HaveOccurred()) 305 return 306 } 307 308 g.Expect(err).ToNot(HaveOccurred()) 309 g.Expect(string(got)).To(Equal(tt.want.contents)) 310 }) 311 } 312 } 313 314 func Test_localRepository_GetVersions(t *testing.T) { 315 tmpDir := createTempDir(t) 316 defer os.RemoveAll(tmpDir) 317 318 // Provider 1: has a single release available 319 dst1 := createLocalTestProviderFile(t, tmpDir, "bootstrap-foo/v1.0.0/bootstrap-components.yaml", "foo: bar") 320 p1 := config.NewProvider("foo", dst1, clusterctlv1.BootstrapProviderType) 321 322 // Provider 2: Has multiple releases available 323 createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/v1.0.0/bootstrap-components.yaml", "version: v1.0.0") 324 createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/v1.0.1/bootstrap-components.yaml", "version: v1.0.1") 325 createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/v2.0.1/bootstrap-components.yaml", "version: v2.0.1") 326 createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/v2.0.2+exp.sha.5114f85/bootstrap-components.yaml", "version: v2.0.2+exp.sha.5114f85") 327 createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/v2.0.3-alpha/bootstrap-components.yaml", "version: v2.0.3-alpha") 328 createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/Foo.Bar/bootstrap-components.yaml", "version: Foo.Bar") 329 createLocalTestProviderFile(t, tmpDir, "bootstrap-bar/foo.file", "foo: bar") 330 p2URLLatest := "bootstrap-bar/latest/bootstrap-components.yaml" 331 p2URLLatestAbs := filepath.Join(tmpDir, p2URLLatest) 332 p2 := config.NewProvider("bar", p2URLLatestAbs, clusterctlv1.BootstrapProviderType) 333 334 type fields struct { 335 provider config.Provider 336 configVariablesClient config.VariablesClient 337 } 338 type want struct { 339 versions []string 340 } 341 tests := []struct { 342 name string 343 fields fields 344 want want 345 wantErr bool 346 }{ 347 { 348 name: "Get the only release available from release directory", 349 fields: fields{ 350 provider: p1, 351 configVariablesClient: test.NewFakeVariableClient(), 352 }, 353 want: want{ 354 versions: []string{"v1.0.0"}, 355 }, 356 wantErr: false, 357 }, 358 { 359 name: "Get all valid releases available from release directory", 360 fields: fields{ 361 provider: p2, 362 configVariablesClient: test.NewFakeVariableClient(), 363 }, 364 want: want{ 365 versions: []string{"v1.0.0", "v1.0.1", "v2.0.1", "v2.0.2+exp.sha.5114f85", "v2.0.3-alpha"}, 366 }, 367 wantErr: false, 368 }, 369 } 370 for _, tt := range tests { 371 t.Run(tt.name, func(t *testing.T) { 372 g := NewWithT(t) 373 374 ctx := context.Background() 375 376 r, err := newLocalRepository(ctx, tt.fields.provider, tt.fields.configVariablesClient) 377 g.Expect(err).ToNot(HaveOccurred()) 378 379 got, err := r.GetVersions(ctx) 380 if tt.wantErr { 381 g.Expect(err).To(HaveOccurred()) 382 return 383 } 384 g.Expect(err).ToNot(HaveOccurred()) 385 386 g.Expect(got).To(ConsistOf(tt.want.versions)) 387 }) 388 } 389 }