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  }