github.com/kruglovmax/helm@v3.0.0-beta.3+incompatible/cmd/helm/package_test.go (about) 1 /* 2 Copyright The Helm Authors. 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 16 package main 17 18 import ( 19 "bytes" 20 "fmt" 21 "io/ioutil" 22 "os" 23 "path/filepath" 24 "regexp" 25 "runtime" 26 "strings" 27 "testing" 28 29 "github.com/spf13/cobra" 30 31 "helm.sh/helm/internal/test/ensure" 32 "helm.sh/helm/pkg/chart" 33 "helm.sh/helm/pkg/chart/loader" 34 "helm.sh/helm/pkg/chartutil" 35 ) 36 37 func TestPackage(t *testing.T) { 38 statFileMsg := "no such file or directory" 39 if runtime.GOOS == "windows" { 40 statFileMsg = "The system cannot find the file specified." 41 } 42 43 tests := []struct { 44 name string 45 flags map[string]string 46 args []string 47 expect string 48 hasfile string 49 err bool 50 }{ 51 { 52 name: "package without chart path", 53 args: []string{}, 54 flags: map[string]string{}, 55 expect: "need at least one argument, the path to the chart", 56 err: true, 57 }, 58 { 59 name: "package --sign, no --key", 60 args: []string{"testdata/testcharts/alpine"}, 61 flags: map[string]string{"sign": "1"}, 62 expect: "key is required for signing a package", 63 err: true, 64 }, 65 { 66 name: "package --sign, no --keyring", 67 args: []string{"testdata/testcharts/alpine"}, 68 flags: map[string]string{"sign": "1", "key": "nosuchkey", "keyring": ""}, 69 expect: "keyring is required for signing a package", 70 err: true, 71 }, 72 { 73 name: "package testdata/testcharts/alpine, no save", 74 args: []string{"testdata/testcharts/alpine"}, 75 flags: map[string]string{"save": "0"}, 76 expect: "", 77 hasfile: "alpine-0.1.0.tgz", 78 }, 79 { 80 name: "package testdata/testcharts/alpine", 81 args: []string{"testdata/testcharts/alpine"}, 82 expect: "", 83 hasfile: "alpine-0.1.0.tgz", 84 }, 85 { 86 name: "package testdata/testcharts/issue1979", 87 args: []string{"testdata/testcharts/issue1979"}, 88 expect: "", 89 hasfile: "alpine-0.1.0.tgz", 90 }, 91 { 92 name: "package --destination toot", 93 args: []string{"testdata/testcharts/alpine"}, 94 flags: map[string]string{"destination": "toot"}, 95 expect: "", 96 hasfile: "toot/alpine-0.1.0.tgz", 97 }, 98 { 99 name: "package --sign --key=KEY --keyring=KEYRING testdata/testcharts/alpine", 100 args: []string{"testdata/testcharts/alpine"}, 101 flags: map[string]string{"sign": "1", "keyring": "testdata/helm-test-key.secret", "key": "helm-test"}, 102 expect: "", 103 hasfile: "alpine-0.1.0.tgz", 104 }, 105 { 106 name: "package testdata/testcharts/chart-missing-deps", 107 args: []string{"testdata/testcharts/chart-missing-deps"}, 108 hasfile: "chart-missing-deps-0.1.0.tgz", 109 err: true, 110 }, 111 { 112 name: "package --values does-not-exist", 113 args: []string{"testdata/testcharts/alpine"}, 114 flags: map[string]string{"values": "does-not-exist"}, 115 expect: fmt.Sprintf("does-not-exist: %s", statFileMsg), 116 err: true, 117 }, 118 { 119 name: "package testdata/testcharts/chart-bad-type", 120 args: []string{"testdata/testcharts/chart-bad-type"}, 121 err: true, 122 }, 123 } 124 125 origDir, err := os.Getwd() 126 if err != nil { 127 t.Fatal(err) 128 } 129 130 for _, tt := range tests { 131 t.Run(tt.name, func(t *testing.T) { 132 cachePath := ensure.TempDir(t) 133 defer testChdir(t, cachePath)() 134 135 if err := os.MkdirAll("toot", 0777); err != nil { 136 t.Fatal(err) 137 } 138 var buf bytes.Buffer 139 c := newPackageCmd(&buf) 140 141 // This is an unfortunate byproduct of the tmpdir 142 if v, ok := tt.flags["keyring"]; ok && len(v) > 0 { 143 tt.flags["keyring"] = filepath.Join(origDir, v) 144 } 145 146 setFlags(c, tt.flags) 147 re := regexp.MustCompile(tt.expect) 148 149 adjustedArgs := make([]string, len(tt.args)) 150 for i, f := range tt.args { 151 adjustedArgs[i] = filepath.Join(origDir, f) 152 } 153 154 err := c.RunE(c, adjustedArgs) 155 if err != nil { 156 if tt.err && re.MatchString(err.Error()) { 157 return 158 } 159 t.Fatalf("%q: expected error %q, got %q", tt.name, tt.expect, err) 160 } 161 162 if !re.Match(buf.Bytes()) { 163 t.Errorf("%q: expected output %q, got %q", tt.name, tt.expect, buf.String()) 164 } 165 166 if len(tt.hasfile) > 0 { 167 if fi, err := os.Stat(tt.hasfile); err != nil { 168 t.Errorf("%q: expected file %q, got err %q", tt.name, tt.hasfile, err) 169 } else if fi.Size() == 0 { 170 t.Errorf("%q: file %q has zero bytes.", tt.name, tt.hasfile) 171 } 172 } 173 174 if v, ok := tt.flags["sign"]; ok && v == "1" { 175 if fi, err := os.Stat(tt.hasfile + ".prov"); err != nil { 176 t.Errorf("%q: expected provenance file", tt.name) 177 } else if fi.Size() == 0 { 178 t.Errorf("%q: provenance file is empty", tt.name) 179 } 180 } 181 }) 182 } 183 } 184 185 func TestSetAppVersion(t *testing.T) { 186 var ch *chart.Chart 187 expectedAppVersion := "app-version-foo" 188 189 dir := ensure.TempDir(t) 190 191 c := newPackageCmd(&bytes.Buffer{}) 192 flags := map[string]string{ 193 "destination": dir, 194 "app-version": expectedAppVersion, 195 } 196 setFlags(c, flags) 197 if err := c.RunE(c, []string{"testdata/testcharts/alpine"}); err != nil { 198 t.Errorf("unexpected error %q", err) 199 } 200 201 chartPath := filepath.Join(dir, "alpine-0.1.0.tgz") 202 if fi, err := os.Stat(chartPath); err != nil { 203 t.Errorf("expected file %q, got err %q", chartPath, err) 204 } else if fi.Size() == 0 { 205 t.Errorf("file %q has zero bytes.", chartPath) 206 } 207 ch, err := loader.Load(chartPath) 208 if err != nil { 209 t.Fatalf("unexpected error loading packaged chart: %v", err) 210 } 211 if ch.Metadata.AppVersion != expectedAppVersion { 212 t.Errorf("expected app-version %q, found %q", expectedAppVersion, ch.Metadata.AppVersion) 213 } 214 } 215 216 func TestPackageValues(t *testing.T) { 217 defer resetEnv()() 218 219 repoFile := "testdata/helmhome/helm/repositories.yaml" 220 221 testCases := []struct { 222 desc string 223 args []string 224 valuefilesContents []string 225 flags map[string]string 226 expected []string 227 }{ 228 { 229 desc: "helm package, single values file", 230 args: []string{"testdata/testcharts/alpine"}, 231 flags: map[string]string{"repository-config": repoFile}, 232 valuefilesContents: []string{"Name: chart-name-foo"}, 233 expected: []string{"Name: chart-name-foo"}, 234 }, 235 { 236 desc: "helm package, multiple values files", 237 args: []string{"testdata/testcharts/alpine"}, 238 flags: map[string]string{"repository-config": repoFile}, 239 valuefilesContents: []string{"Name: chart-name-foo", "foo: bar"}, 240 expected: []string{"Name: chart-name-foo", "foo: bar"}, 241 }, 242 { 243 desc: "helm package, with set option", 244 args: []string{"testdata/testcharts/alpine"}, 245 flags: map[string]string{"set": "Name=chart-name-foo", "repository-config": repoFile}, 246 expected: []string{"Name: chart-name-foo"}, 247 }, 248 { 249 desc: "helm package, set takes precedence over value file", 250 args: []string{"testdata/testcharts/alpine"}, 251 valuefilesContents: []string{"Name: chart-name-foo"}, 252 flags: map[string]string{"set": "Name=chart-name-bar", "repository-config": repoFile}, 253 expected: []string{"Name: chart-name-bar"}, 254 }, 255 } 256 257 for _, tc := range testCases { 258 var files []string 259 for _, contents := range tc.valuefilesContents { 260 f := createValuesFile(t, contents) 261 files = append(files, f) 262 } 263 valueFiles := strings.Join(files, ",") 264 265 expected, err := chartutil.ReadValues([]byte(strings.Join(tc.expected, "\n"))) 266 if err != nil { 267 t.Errorf("unexpected error parsing values: %q", err) 268 } 269 270 outputDir := ensure.TempDir(t) 271 272 if len(tc.flags) == 0 { 273 tc.flags = make(map[string]string) 274 } 275 tc.flags["destination"] = outputDir 276 277 if len(valueFiles) > 0 { 278 tc.flags["values"] = valueFiles 279 } 280 281 cmd := newPackageCmd(&bytes.Buffer{}) 282 setFlags(cmd, tc.flags) 283 if err := cmd.RunE(cmd, tc.args); err != nil { 284 t.Fatalf("unexpected error: %q", err) 285 } 286 287 outputFile := filepath.Join(outputDir, "alpine-0.1.0.tgz") 288 verifyOutputChartExists(t, outputFile) 289 290 actual, err := getChartValues(outputFile) 291 if err != nil { 292 t.Fatalf("unexpected error extracting chart values: %q", err) 293 } 294 295 verifyValues(t, actual, expected) 296 } 297 } 298 299 func createValuesFile(t *testing.T, data string) string { 300 outputDir := ensure.TempDir(t) 301 302 outputFile := filepath.Join(outputDir, "values.yaml") 303 if err := ioutil.WriteFile(outputFile, []byte(data), 0644); err != nil { 304 t.Fatalf("err: %s", err) 305 } 306 return outputFile 307 } 308 309 func getChartValues(chartPath string) (chartutil.Values, error) { 310 chart, err := loader.Load(chartPath) 311 if err != nil { 312 return nil, err 313 } 314 return chart.Values, nil 315 } 316 317 func verifyValues(t *testing.T, actual, expected chartutil.Values) { 318 t.Helper() 319 for key, value := range expected.AsMap() { 320 if got := actual[key]; got != value { 321 t.Errorf("Expected %q, got %q (%v)", value, got, actual) 322 } 323 } 324 } 325 326 func verifyOutputChartExists(t *testing.T, chartPath string) { 327 if chartFile, err := os.Stat(chartPath); err != nil { 328 t.Errorf("expected file %q, got err %q", chartPath, err) 329 } else if chartFile.Size() == 0 { 330 t.Errorf("file %q has zero bytes.", chartPath) 331 } 332 } 333 334 func setFlags(cmd *cobra.Command, flags map[string]string) { 335 dest := cmd.Flags() 336 for f, v := range flags { 337 dest.Set(f, v) 338 } 339 }