github.com/Racer159/helm-experiment@v0.0.0-20230822001441-1eb31183f614/src/pull_test.go (about) 1 /* 2 Copyright The Helm 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 cmd 18 19 import ( 20 "fmt" 21 "net/http" 22 "net/http/httptest" 23 "os" 24 "path/filepath" 25 "testing" 26 27 "helm.sh/helm/v3/pkg/repo/repotest" 28 ) 29 30 func TestPullCmd(t *testing.T) { 31 srv, err := repotest.NewTempServerWithCleanup(t, "testdata/testcharts/*.tgz*") 32 if err != nil { 33 t.Fatal(err) 34 } 35 defer srv.Stop() 36 37 ociSrv, err := repotest.NewOCIServer(t, srv.Root()) 38 if err != nil { 39 t.Fatal(err) 40 } 41 ociSrv.Run(t) 42 43 if err := srv.LinkIndices(); err != nil { 44 t.Fatal(err) 45 } 46 47 helmTestKeyOut := "Signed by: Helm Testing (This key should only be used for testing. DO NOT TRUST.) <helm-testing@helm.sh>\n" + 48 "Using Key With Fingerprint: 5E615389B53CA37F0EE60BD3843BBF981FC18762\n" + 49 "Chart Hash Verified: " 50 51 // all flags will get "-d outdir" appended. 52 tests := []struct { 53 name string 54 args string 55 existFile string 56 existDir string 57 wantError bool 58 wantErrorMsg string 59 failExpect string 60 expectFile string 61 expectDir bool 62 expectVerify bool 63 expectSha string 64 }{ 65 { 66 name: "Basic chart fetch", 67 args: "test/signtest", 68 expectFile: "./signtest-0.1.0.tgz", 69 }, 70 { 71 name: "Chart fetch with version", 72 args: "test/signtest --version=0.1.0", 73 expectFile: "./signtest-0.1.0.tgz", 74 }, 75 { 76 name: "Fail chart fetch with non-existent version", 77 args: "test/signtest --version=99.1.0", 78 wantError: true, 79 failExpect: "no such chart", 80 }, 81 { 82 name: "Fail fetching non-existent chart", 83 args: "test/nosuchthing", 84 failExpect: "Failed to fetch", 85 wantError: true, 86 }, 87 { 88 name: "Fetch and verify", 89 args: "test/signtest --verify --keyring testdata/helm-test-key.pub", 90 expectFile: "./signtest-0.1.0.tgz", 91 expectVerify: true, 92 expectSha: "sha256:e5ef611620fb97704d8751c16bab17fedb68883bfb0edc76f78a70e9173f9b55", 93 }, 94 { 95 name: "Fetch and fail verify", 96 args: "test/reqtest --verify --keyring testdata/helm-test-key.pub", 97 failExpect: "Failed to fetch provenance", 98 wantError: true, 99 }, 100 { 101 name: "Fetch and untar", 102 args: "test/signtest --untar --untardir signtest", 103 expectFile: "./signtest", 104 expectDir: true, 105 }, 106 { 107 name: "Fetch untar when file with same name existed", 108 args: "test/test1 --untar --untardir test1", 109 existFile: "test1", 110 wantError: true, 111 wantErrorMsg: fmt.Sprintf("failed to untar: a file or directory with the name %s already exists", filepath.Join(srv.Root(), "test1")), 112 }, 113 { 114 name: "Fetch untar when dir with same name existed", 115 args: "test/test2 --untar --untardir test2", 116 existDir: "test2", 117 wantError: true, 118 wantErrorMsg: fmt.Sprintf("failed to untar: a file or directory with the name %s already exists", filepath.Join(srv.Root(), "test2")), 119 }, 120 { 121 name: "Fetch, verify, untar", 122 args: "test/signtest --verify --keyring=testdata/helm-test-key.pub --untar --untardir signtest2", 123 expectFile: "./signtest2", 124 expectDir: true, 125 expectVerify: true, 126 expectSha: "sha256:e5ef611620fb97704d8751c16bab17fedb68883bfb0edc76f78a70e9173f9b55", 127 }, 128 { 129 name: "Chart fetch using repo URL", 130 expectFile: "./signtest-0.1.0.tgz", 131 args: "signtest --repo " + srv.URL(), 132 }, 133 { 134 name: "Fail fetching non-existent chart on repo URL", 135 args: "someChart --repo " + srv.URL(), 136 failExpect: "Failed to fetch chart", 137 wantError: true, 138 }, 139 { 140 name: "Specific version chart fetch using repo URL", 141 expectFile: "./signtest-0.1.0.tgz", 142 args: "signtest --version=0.1.0 --repo " + srv.URL(), 143 }, 144 { 145 name: "Specific version chart fetch using repo URL", 146 args: "signtest --version=0.2.0 --repo " + srv.URL(), 147 failExpect: "Failed to fetch chart version", 148 wantError: true, 149 }, 150 { 151 name: "Fetch OCI Chart", 152 args: fmt.Sprintf("oci://%s/u/ocitestuser/oci-dependent-chart --version 0.1.0", ociSrv.RegistryURL), 153 expectFile: "./oci-dependent-chart-0.1.0.tgz", 154 }, 155 { 156 name: "Fetch OCI Chart with untar", 157 args: fmt.Sprintf("oci://%s/u/ocitestuser/oci-dependent-chart --version 0.1.0 --untar", ociSrv.RegistryURL), 158 expectFile: "./oci-dependent-chart", 159 expectDir: true, 160 }, 161 { 162 name: "Fetch OCI Chart with untar and untardir", 163 args: fmt.Sprintf("oci://%s/u/ocitestuser/oci-dependent-chart --version 0.1.0 --untar --untardir ocitest2", ociSrv.RegistryURL), 164 expectFile: "./ocitest2", 165 expectDir: true, 166 }, 167 { 168 name: "OCI Fetch untar when dir with same name existed", 169 args: fmt.Sprintf("oci-test-chart oci://%s/u/ocitestuser/oci-dependent-chart --version 0.1.0 --untar --untardir ocitest2 --untar --untardir ocitest2", ociSrv.RegistryURL), 170 wantError: true, 171 wantErrorMsg: fmt.Sprintf("failed to untar: a file or directory with the name %s already exists", filepath.Join(srv.Root(), "ocitest2")), 172 }, 173 { 174 name: "Fail fetching non-existent OCI chart", 175 args: fmt.Sprintf("oci://%s/u/ocitestuser/nosuchthing --version 0.1.0", ociSrv.RegistryURL), 176 failExpect: "Failed to fetch", 177 wantError: true, 178 }, 179 { 180 name: "Fail fetching OCI chart without version specified", 181 args: fmt.Sprintf("oci://%s/u/ocitestuser/nosuchthing", ociSrv.RegistryURL), 182 wantErrorMsg: "Error: --version flag is explicitly required for OCI registries", 183 wantError: true, 184 }, 185 { 186 name: "Fail fetching OCI chart without version specified", 187 args: fmt.Sprintf("oci://%s/u/ocitestuser/oci-dependent-chart:0.1.0", ociSrv.RegistryURL), 188 wantErrorMsg: "Error: --version flag is explicitly required for OCI registries", 189 wantError: true, 190 }, 191 { 192 name: "Fail fetching OCI chart without version specified", 193 args: fmt.Sprintf("oci://%s/u/ocitestuser/oci-dependent-chart:0.1.0 --version 0.1.0", ociSrv.RegistryURL), 194 wantError: true, 195 }, 196 } 197 198 for _, tt := range tests { 199 t.Run(tt.name, func(t *testing.T) { 200 outdir := srv.Root() 201 cmd := fmt.Sprintf("fetch %s -d '%s' --repository-config %s --repository-cache %s --registry-config %s", 202 tt.args, 203 outdir, 204 filepath.Join(outdir, "repositories.yaml"), 205 outdir, 206 filepath.Join(outdir, "config.json"), 207 ) 208 // Create file or Dir before helm pull --untar, see: https://github.com/helm/helm/issues/7182 209 if tt.existFile != "" { 210 file := filepath.Join(outdir, tt.existFile) 211 _, err := os.Create(file) 212 if err != nil { 213 t.Fatal(err) 214 } 215 } 216 if tt.existDir != "" { 217 file := filepath.Join(outdir, tt.existDir) 218 err := os.Mkdir(file, 0755) 219 if err != nil { 220 t.Fatal(err) 221 } 222 } 223 _, out, err := executeActionCommand(cmd) 224 if err != nil { 225 if tt.wantError { 226 if tt.wantErrorMsg != "" && tt.wantErrorMsg == err.Error() { 227 t.Fatalf("Actual error %s, not equal to expected error %s", err, tt.wantErrorMsg) 228 } 229 return 230 } 231 t.Fatalf("%q reported error: %s", tt.name, err) 232 } 233 234 if tt.expectVerify { 235 outString := helmTestKeyOut + tt.expectSha + "\n" 236 if out != outString { 237 t.Errorf("%q: expected verification output %q, got %q", tt.name, outString, out) 238 } 239 240 } 241 242 ef := filepath.Join(outdir, tt.expectFile) 243 fi, err := os.Stat(ef) 244 if err != nil { 245 t.Errorf("%q: expected a file at %s. %s", tt.name, ef, err) 246 } 247 if fi.IsDir() != tt.expectDir { 248 t.Errorf("%q: expected directory=%t, but it's not.", tt.name, tt.expectDir) 249 } 250 }) 251 } 252 } 253 254 func TestPullWithCredentialsCmd(t *testing.T) { 255 srv, err := repotest.NewTempServerWithCleanup(t, "testdata/testcharts/*.tgz*") 256 if err != nil { 257 t.Fatal(err) 258 } 259 defer srv.Stop() 260 261 srv.WithMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 262 username, password, ok := r.BasicAuth() 263 if !ok || username != "username" || password != "password" { 264 t.Errorf("Expected request to use basic auth and for username == 'username' and password == 'password', got '%v', '%s', '%s'", ok, username, password) 265 } 266 })) 267 268 srv2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 269 http.FileServer(http.Dir(srv.Root())).ServeHTTP(w, r) 270 })) 271 defer srv2.Close() 272 273 if err := srv.LinkIndices(); err != nil { 274 t.Fatal(err) 275 } 276 277 // all flags will get "-d outdir" appended. 278 tests := []struct { 279 name string 280 args string 281 existFile string 282 existDir string 283 wantError bool 284 wantErrorMsg string 285 expectFile string 286 expectDir bool 287 }{ 288 { 289 name: "Chart fetch using repo URL", 290 expectFile: "./signtest-0.1.0.tgz", 291 args: "signtest --repo " + srv.URL() + " --username username --password password", 292 }, 293 { 294 name: "Fail fetching non-existent chart on repo URL", 295 args: "someChart --repo " + srv.URL() + " --username username --password password", 296 wantError: true, 297 }, 298 { 299 name: "Specific version chart fetch using repo URL", 300 expectFile: "./signtest-0.1.0.tgz", 301 args: "signtest --version=0.1.0 --repo " + srv.URL() + " --username username --password password", 302 }, 303 { 304 name: "Specific version chart fetch using repo URL", 305 args: "signtest --version=0.2.0 --repo " + srv.URL() + " --username username --password password", 306 wantError: true, 307 }, 308 { 309 name: "Chart located on different domain with credentials passed", 310 args: "reqtest --repo " + srv2.URL + " --username username --password password --pass-credentials", 311 expectFile: "./reqtest-0.1.0.tgz", 312 }, 313 } 314 315 for _, tt := range tests { 316 t.Run(tt.name, func(t *testing.T) { 317 outdir := srv.Root() 318 cmd := fmt.Sprintf("pull %s -d '%s' --repository-config %s --repository-cache %s --registry-config %s", 319 tt.args, 320 outdir, 321 filepath.Join(outdir, "repositories.yaml"), 322 outdir, 323 filepath.Join(outdir, "config.json"), 324 ) 325 // Create file or Dir before helm pull --untar, see: https://github.com/helm/helm/issues/7182 326 if tt.existFile != "" { 327 file := filepath.Join(outdir, tt.existFile) 328 _, err := os.Create(file) 329 if err != nil { 330 t.Fatal(err) 331 } 332 } 333 if tt.existDir != "" { 334 file := filepath.Join(outdir, tt.existDir) 335 err := os.Mkdir(file, 0755) 336 if err != nil { 337 t.Fatal(err) 338 } 339 } 340 _, _, err := executeActionCommand(cmd) 341 if err != nil { 342 if tt.wantError { 343 if tt.wantErrorMsg != "" && tt.wantErrorMsg == err.Error() { 344 t.Fatalf("Actual error %s, not equal to expected error %s", err, tt.wantErrorMsg) 345 } 346 return 347 } 348 t.Fatalf("%q reported error: %s", tt.name, err) 349 } 350 351 ef := filepath.Join(outdir, tt.expectFile) 352 fi, err := os.Stat(ef) 353 if err != nil { 354 t.Errorf("%q: expected a file at %s. %s", tt.name, ef, err) 355 } 356 if fi.IsDir() != tt.expectDir { 357 t.Errorf("%q: expected directory=%t, but it's not.", tt.name, tt.expectDir) 358 } 359 }) 360 } 361 } 362 363 func TestPullVersionCompletion(t *testing.T) { 364 repoFile := "testdata/helmhome/helm/repositories.yaml" 365 repoCache := "testdata/helmhome/helm/repository" 366 367 repoSetup := fmt.Sprintf("--repository-config %s --repository-cache %s", repoFile, repoCache) 368 369 tests := []cmdTestCase{{ 370 name: "completion for pull version flag", 371 cmd: fmt.Sprintf("%s __complete pull testing/alpine --version ''", repoSetup), 372 golden: "output/version-comp.txt", 373 }, { 374 name: "completion for pull version flag, no filter", 375 cmd: fmt.Sprintf("%s __complete pull testing/alpine --version 0.3", repoSetup), 376 golden: "output/version-comp.txt", 377 }, { 378 name: "completion for pull version flag too few args", 379 cmd: fmt.Sprintf("%s __complete pull --version ''", repoSetup), 380 golden: "output/version-invalid-comp.txt", 381 }, { 382 name: "completion for pull version flag too many args", 383 cmd: fmt.Sprintf("%s __complete pull testing/alpine badarg --version ''", repoSetup), 384 golden: "output/version-invalid-comp.txt", 385 }, { 386 name: "completion for pull version flag invalid chart", 387 cmd: fmt.Sprintf("%s __complete pull invalid/invalid --version ''", repoSetup), 388 golden: "output/version-invalid-comp.txt", 389 }} 390 runTestCmd(t, tests) 391 } 392 393 func TestPullFileCompletion(t *testing.T) { 394 checkFileCompletion(t, "pull", false) 395 checkFileCompletion(t, "pull repo/chart", false) 396 }