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