github.com/amtisyAts/helm@v2.17.0+incompatible/pkg/chartutil/requirements_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 package chartutil 16 17 import ( 18 "os" 19 "path/filepath" 20 "sort" 21 "testing" 22 23 "strconv" 24 25 "k8s.io/helm/pkg/proto/hapi/chart" 26 "k8s.io/helm/pkg/version" 27 ) 28 29 func TestLoadRequirements(t *testing.T) { 30 c, err := Load("testdata/frobnitz") 31 if err != nil { 32 t.Fatalf("Failed to load testdata: %s", err) 33 } 34 verifyRequirements(t, c) 35 } 36 37 func TestLoadRequirementsLock(t *testing.T) { 38 c, err := Load("testdata/frobnitz") 39 if err != nil { 40 t.Fatalf("Failed to load testdata: %s", err) 41 } 42 verifyRequirementsLock(t, c) 43 } 44 func TestRequirementsTagsNonValue(t *testing.T) { 45 c, err := Load("testdata/subpop") 46 if err != nil { 47 t.Fatalf("Failed to load testdata: %s", err) 48 } 49 // tags with no effect 50 v := &chart.Config{Raw: "tags:\n nothinguseful: false\n\n"} 51 // expected charts including duplicates in alphanumeric order 52 e := []string{"parentchart", "subchart1", "subcharta", "subchartb"} 53 54 verifyRequirementsEnabled(t, c, v, e) 55 } 56 func TestRequirementsTagsDisabledL1(t *testing.T) { 57 c, err := Load("testdata/subpop") 58 if err != nil { 59 t.Fatalf("Failed to load testdata: %s", err) 60 } 61 // tags disabling a group 62 v := &chart.Config{Raw: "tags:\n front-end: false\n\n"} 63 // expected charts including duplicates in alphanumeric order 64 e := []string{"parentchart"} 65 66 verifyRequirementsEnabled(t, c, v, e) 67 } 68 func TestRequirementsTagsEnabledL1(t *testing.T) { 69 c, err := Load("testdata/subpop") 70 if err != nil { 71 t.Fatalf("Failed to load testdata: %s", err) 72 } 73 // tags disabling a group and enabling a different group 74 v := &chart.Config{Raw: "tags:\n front-end: false\n\n back-end: true\n"} 75 // expected charts including duplicates in alphanumeric order 76 e := []string{"parentchart", "subchart2", "subchartb", "subchartc"} 77 78 verifyRequirementsEnabled(t, c, v, e) 79 } 80 81 func TestRequirementsTagsDisabledL2(t *testing.T) { 82 c, err := Load("testdata/subpop") 83 if err != nil { 84 t.Fatalf("Failed to load testdata: %s", err) 85 } 86 // tags disabling only children, children still enabled since tag front-end=true in values.yaml 87 v := &chart.Config{Raw: "tags:\n subcharta: false\n\n subchartb: false\n"} 88 // expected charts including duplicates in alphanumeric order 89 e := []string{"parentchart", "subchart1", "subcharta", "subchartb"} 90 91 verifyRequirementsEnabled(t, c, v, e) 92 } 93 func TestRequirementsTagsDisabledL1Mixed(t *testing.T) { 94 c, err := Load("testdata/subpop") 95 if err != nil { 96 t.Fatalf("Failed to load testdata: %s", err) 97 } 98 // tags disabling all parents/children with additional tag re-enabling a parent 99 v := &chart.Config{Raw: "tags:\n front-end: false\n\n subchart1: true\n\n back-end: false\n"} 100 // expected charts including duplicates in alphanumeric order 101 e := []string{"parentchart", "subchart1"} 102 103 verifyRequirementsEnabled(t, c, v, e) 104 } 105 func TestRequirementsConditionsNonValue(t *testing.T) { 106 c, err := Load("testdata/subpop") 107 if err != nil { 108 t.Fatalf("Failed to load testdata: %s", err) 109 } 110 // tags with no effect 111 v := &chart.Config{Raw: "subchart1:\n nothinguseful: false\n\n"} 112 // expected charts including duplicates in alphanumeric order 113 e := []string{"parentchart", "subchart1", "subcharta", "subchartb"} 114 115 verifyRequirementsEnabled(t, c, v, e) 116 } 117 func TestRequirementsConditionsEnabledL1Both(t *testing.T) { 118 c, err := Load("testdata/subpop") 119 if err != nil { 120 t.Fatalf("Failed to load testdata: %s", err) 121 } 122 // conditions enabling the parent charts, but back-end (b, c) is still disabled via values.yaml 123 v := &chart.Config{Raw: "subchart1:\n enabled: true\nsubchart2:\n enabled: true\n"} 124 // expected charts including duplicates in alphanumeric order 125 e := []string{"parentchart", "subchart1", "subchart2", "subcharta", "subchartb"} 126 127 verifyRequirementsEnabled(t, c, v, e) 128 } 129 func TestRequirementsConditionsDisabledL1Both(t *testing.T) { 130 c, err := Load("testdata/subpop") 131 if err != nil { 132 t.Fatalf("Failed to load testdata: %s", err) 133 } 134 // conditions disabling the parent charts, effectively disabling children 135 v := &chart.Config{Raw: "subchart1:\n enabled: false\nsubchart2:\n enabled: false\n"} 136 // expected charts including duplicates in alphanumeric order 137 e := []string{"parentchart"} 138 139 verifyRequirementsEnabled(t, c, v, e) 140 } 141 142 func TestRequirementsConditionsSecond(t *testing.T) { 143 c, err := Load("testdata/subpop") 144 if err != nil { 145 t.Fatalf("Failed to load testdata: %s", err) 146 } 147 // conditions a child using the second condition path of child's condition 148 v := &chart.Config{Raw: "subchart1:\n subcharta:\n enabled: false\n"} 149 // expected charts including duplicates in alphanumeric order 150 e := []string{"parentchart", "subchart1", "subchartb"} 151 152 verifyRequirementsEnabled(t, c, v, e) 153 } 154 func TestRequirementsCombinedDisabledL2(t *testing.T) { 155 c, err := Load("testdata/subpop") 156 if err != nil { 157 t.Fatalf("Failed to load testdata: %s", err) 158 } 159 // tags enabling a parent/child group with condition disabling one child 160 v := &chart.Config{Raw: "subchart2:\n subchartc:\n enabled: false\ntags:\n back-end: true\n"} 161 // expected charts including duplicates in alphanumeric order 162 e := []string{"parentchart", "subchart1", "subchart2", "subcharta", "subchartb", "subchartb"} 163 164 verifyRequirementsEnabled(t, c, v, e) 165 } 166 func TestRequirementsCombinedDisabledL1(t *testing.T) { 167 c, err := Load("testdata/subpop") 168 if err != nil { 169 t.Fatalf("Failed to load testdata: %s", err) 170 } 171 // tags will not enable a child if parent is explicitly disabled with condition 172 v := &chart.Config{Raw: "subchart1:\n enabled: false\ntags:\n front-end: true\n"} 173 // expected charts including duplicates in alphanumeric order 174 e := []string{"parentchart"} 175 176 verifyRequirementsEnabled(t, c, v, e) 177 } 178 func TestRequirementsAliasCondition(t *testing.T) { 179 c, err := Load("testdata/subpop") 180 if err != nil { 181 t.Fatalf("Failed to load testdata: %s", err) 182 } 183 v := &chart.Config{Raw: "subchart1:\n enabled: false\nsubchart2alias:\n enabled: true\n subchartb:\n enabled: true\n"} 184 e := []string{"parentchart", "subchart2alias", "subchartb"} 185 verifyRequirementsEnabled(t, c, v, e) 186 } 187 188 func verifyRequirementsEnabled(t *testing.T, c *chart.Chart, v *chart.Config, e []string) { 189 out := []*chart.Chart{} 190 err := ProcessRequirementsEnabled(c, v) 191 if err != nil { 192 t.Errorf("Error processing enabled requirements %v", err) 193 } 194 out = extractCharts(c, out) 195 // build list of chart names 196 p := []string{} 197 for _, r := range out { 198 p = append(p, r.Metadata.Name) 199 } 200 //sort alphanumeric and compare to expectations 201 sort.Strings(p) 202 if len(p) != len(e) { 203 t.Errorf("Error slice lengths do not match got %v, expected %v", len(p), len(e)) 204 return 205 } 206 for i := range p { 207 if p[i] != e[i] { 208 t.Errorf("Error slice values do not match got %v, expected %v", p[i], e[i]) 209 } 210 } 211 } 212 213 // extractCharts recursively searches chart dependencies returning all charts found 214 func extractCharts(c *chart.Chart, out []*chart.Chart) []*chart.Chart { 215 216 if len(c.Metadata.Name) > 0 { 217 out = append(out, c) 218 } 219 for _, d := range c.Dependencies { 220 out = extractCharts(d, out) 221 } 222 return out 223 } 224 func TestProcessRequirementsImportValues(t *testing.T) { 225 c, err := Load("testdata/subpop") 226 if err != nil { 227 t.Fatalf("Failed to load testdata: %s", err) 228 } 229 230 v := &chart.Config{Raw: ""} 231 232 e := make(map[string]string) 233 234 e["imported-chart1.SC1bool"] = "true" 235 e["imported-chart1.SC1float"] = "3.14" 236 e["imported-chart1.SC1int"] = "100" 237 e["imported-chart1.SC1string"] = "dollywood" 238 e["imported-chart1.SC1extra1"] = "11" 239 e["imported-chart1.SPextra1"] = "helm rocks" 240 e["imported-chart1.SC1extra1"] = "11" 241 242 e["imported-chartA.SCAbool"] = "false" 243 e["imported-chartA.SCAfloat"] = "3.1" 244 e["imported-chartA.SCAint"] = "55" 245 e["imported-chartA.SCAstring"] = "jabba" 246 e["imported-chartA.SPextra3"] = "1.337" 247 e["imported-chartA.SC1extra2"] = "1.337" 248 e["imported-chartA.SCAnested1.SCAnested2"] = "true" 249 250 e["imported-chartA-B.SCAbool"] = "false" 251 e["imported-chartA-B.SCAfloat"] = "3.1" 252 e["imported-chartA-B.SCAint"] = "55" 253 e["imported-chartA-B.SCAstring"] = "jabba" 254 255 e["imported-chartA-B.SCBbool"] = "true" 256 e["imported-chartA-B.SCBfloat"] = "7.77" 257 e["imported-chartA-B.SCBint"] = "33" 258 e["imported-chartA-B.SCBstring"] = "boba" 259 e["imported-chartA-B.SPextra5"] = "k8s" 260 e["imported-chartA-B.SC1extra5"] = "tiller" 261 262 e["overridden-chart1.SC1bool"] = "true" 263 e["overridden-chart1.SC1float"] = "3.14" 264 e["overridden-chart1.SC1int"] = "100" 265 e["overridden-chart1.SC1string"] = "dollywood" 266 e["overridden-chart1.SPextra2"] = "42" 267 268 e["overridden-chartA.SCAbool"] = "true" 269 e["overridden-chartA.SCAfloat"] = "41.3" 270 e["overridden-chartA.SCAint"] = "808" 271 e["overridden-chartA.SCAstring"] = "jaberwocky" 272 e["overridden-chartA.SPextra4"] = "true" 273 274 e["overridden-chartA-B.SCAbool"] = "true" 275 e["overridden-chartA-B.SCAfloat"] = "3.33" 276 e["overridden-chartA-B.SCAint"] = "555" 277 e["overridden-chartA-B.SCAstring"] = "wormwood" 278 e["overridden-chartA-B.SCBbool"] = "true" 279 e["overridden-chartA-B.SCBfloat"] = "0.25" 280 e["overridden-chartA-B.SCBint"] = "98" 281 e["overridden-chartA-B.SCBstring"] = "murkwood" 282 e["overridden-chartA-B.SPextra6"] = "111" 283 e["overridden-chartA-B.SCAextra1"] = "23" 284 e["overridden-chartA-B.SCBextra1"] = "13" 285 e["overridden-chartA-B.SC1extra6"] = "77" 286 287 // `exports` style 288 e["SCBexported1B"] = "1965" 289 e["SC1extra7"] = "true" 290 e["SCBexported2A"] = "blaster" 291 e["global.SC1exported2.all.SC1exported3"] = "SC1expstr" 292 293 e["SCCdata.SCCstring"] = "mugwort" 294 e["SCCdata.SCCint"] = "42" 295 296 verifyRequirementsImportValues(t, c, v, e) 297 } 298 func verifyRequirementsImportValues(t *testing.T, c *chart.Chart, v *chart.Config, e map[string]string) { 299 300 err := ProcessRequirementsImportValues(c) 301 if err != nil { 302 t.Errorf("Error processing import values requirements %v", err) 303 } 304 cv := c.GetValues() 305 cc, err := ReadValues([]byte(cv.Raw)) 306 if err != nil { 307 t.Errorf("Error reading import values %v", err) 308 } 309 for kk, vv := range e { 310 pv, err := cc.PathValue(kk) 311 if err != nil { 312 t.Fatalf("Error retrieving import values table %v %v", kk, err) 313 return 314 } 315 316 switch pv.(type) { 317 case float64: 318 s := strconv.FormatFloat(pv.(float64), 'f', -1, 64) 319 if s != vv { 320 t.Errorf("Failed to match imported float field %v with value %v with expected %v", kk, s, vv) 321 return 322 } 323 case bool: 324 b := strconv.FormatBool(pv.(bool)) 325 if b != vv { 326 t.Errorf("Failed to match imported bool field %v with value %v with expected %v", kk, b, vv) 327 return 328 } 329 default: 330 if pv.(string) != vv { 331 t.Errorf("Failed to match imported string field %v with value %v with expected %v", kk, pv, vv) 332 return 333 } 334 } 335 336 } 337 } 338 339 func TestGetAliasDependency(t *testing.T) { 340 c, err := Load("testdata/frobnitz") 341 if err != nil { 342 t.Fatalf("Failed to load testdata: %s", err) 343 } 344 req, err := LoadRequirements(c) 345 if err != nil { 346 t.Fatalf("Failed to load requirement for testdata: %s", err) 347 } 348 if len(req.Dependencies) == 0 { 349 t.Fatalf("There are no requirements to test") 350 } 351 352 // Success case 353 aliasChart := getAliasDependency(c.Dependencies, req.Dependencies[0]) 354 if aliasChart == nil { 355 t.Fatalf("Failed to get dependency chart for alias %s", req.Dependencies[0].Name) 356 } 357 if req.Dependencies[0].Alias != "" { 358 if aliasChart.Metadata.Name != req.Dependencies[0].Alias { 359 t.Fatalf("Dependency chart name should be %s but got %s", req.Dependencies[0].Alias, aliasChart.Metadata.Name) 360 } 361 } else if aliasChart.Metadata.Name != req.Dependencies[0].Name { 362 t.Fatalf("Dependency chart name should be %s but got %s", req.Dependencies[0].Name, aliasChart.Metadata.Name) 363 } 364 365 if req.Dependencies[0].Version != "" { 366 if !version.IsCompatibleRange(req.Dependencies[0].Version, aliasChart.Metadata.Version) { 367 t.Fatalf("Dependency chart version is not in the compatible range") 368 } 369 370 } 371 372 // Failure case 373 resetName := req.Dependencies[0].Name 374 req.Dependencies[0].Name = "something-else" 375 if aliasChart := getAliasDependency(c.Dependencies, req.Dependencies[0]); aliasChart != nil { 376 t.Fatalf("expected no chart but got %s", aliasChart.Metadata.Name) 377 } 378 379 // Add a bad alias name 380 req.Dependencies[0].Name = resetName 381 req.Dependencies[0].Alias = "$foobar" 382 if aliasChart := getAliasDependency(c.Dependencies, req.Dependencies[0]); aliasChart != nil { 383 t.Fatalf("expected no chart but got %s", aliasChart.Metadata.Name) 384 } 385 386 req.Dependencies[0].Version = "something else which is not in the compatible range" 387 if version.IsCompatibleRange(req.Dependencies[0].Version, aliasChart.Metadata.Version) { 388 t.Fatalf("Dependency chart version which is not in the compatible range should cause a failure other than a success ") 389 } 390 391 } 392 393 func TestDependentChartAliases(t *testing.T) { 394 c, err := Load("testdata/dependent-chart-alias") 395 if err != nil { 396 t.Fatalf("Failed to load testdata: %s", err) 397 } 398 399 if len(c.Dependencies) == 0 { 400 t.Fatal("There are no dependencies to run this test") 401 } 402 403 origLength := len(c.Dependencies) 404 if err := ProcessRequirementsEnabled(c, c.Values); err != nil { 405 t.Fatalf("Expected no errors but got %q", err) 406 } 407 408 if len(c.Dependencies) == origLength { 409 t.Fatal("Expected alias dependencies to be added, but did not got that") 410 } 411 412 reqmts, err := LoadRequirements(c) 413 if err != nil { 414 t.Fatalf("Cannot load requirements for test chart, %v", err) 415 } 416 417 if len(c.Dependencies) != len(reqmts.Dependencies) { 418 t.Fatalf("Expected number of chart dependencies %d, but got %d", len(reqmts.Dependencies), len(c.Dependencies)) 419 } 420 421 } 422 423 func TestDependentChartWithSubChartsAbsentInRequirements(t *testing.T) { 424 c, err := Load("testdata/dependent-chart-no-requirements-yaml") 425 if err != nil { 426 t.Fatalf("Failed to load testdata: %s", err) 427 } 428 429 if len(c.Dependencies) != 2 { 430 t.Fatalf("Expected 2 dependencies for this chart, but got %d", len(c.Dependencies)) 431 } 432 433 origLength := len(c.Dependencies) 434 if err := ProcessRequirementsEnabled(c, c.Values); err != nil { 435 t.Fatalf("Expected no errors but got %q", err) 436 } 437 438 if len(c.Dependencies) != origLength { 439 t.Fatal("Expected no changes in dependencies to be, but did something got changed") 440 } 441 442 } 443 444 func TestDependentChartWithSubChartsHelmignore(t *testing.T) { 445 if _, err := Load("testdata/dependent-chart-helmignore"); err != nil { 446 t.Fatalf("Failed to load testdata: %s", err) 447 } 448 } 449 450 func TestDependentChartsWithSubChartsSymlink(t *testing.T) { 451 joonix := "testdata/joonix" 452 if err := os.Symlink(filepath.Join("..", "..", "frobnitz"), filepath.Join(joonix, "charts", "frobnitz")); err != nil { 453 t.Fatal(err) 454 } 455 defer os.RemoveAll(filepath.Join(joonix, "charts", "frobnitz")) 456 c, err := Load(joonix) 457 if err != nil { 458 t.Fatalf("Failed to load testdata: %s", err) 459 } 460 if c.Metadata.Name != "joonix" { 461 t.Fatalf("Unexpected chart name: %s", c.Metadata.Name) 462 } 463 if n := len(c.Dependencies); n != 1 { 464 t.Fatalf("Expected 1 dependency for this chart, but got %d", n) 465 } 466 } 467 468 func TestDependentChartsWithSubchartsAllSpecifiedInRequirements(t *testing.T) { 469 c, err := Load("testdata/dependent-chart-with-all-in-requirements-yaml") 470 if err != nil { 471 t.Fatalf("Failed to load testdata: %s", err) 472 } 473 474 if len(c.Dependencies) == 0 { 475 t.Fatal("There are no dependencies to run this test") 476 } 477 478 origLength := len(c.Dependencies) 479 if err := ProcessRequirementsEnabled(c, c.Values); err != nil { 480 t.Fatalf("Expected no errors but got %q", err) 481 } 482 483 if len(c.Dependencies) != origLength { 484 t.Fatal("Expected no changes in dependencies to be, but did something got changed") 485 } 486 487 reqmts, err := LoadRequirements(c) 488 if err != nil { 489 t.Fatalf("Cannot load requirements for test chart, %v", err) 490 } 491 492 if len(c.Dependencies) != len(reqmts.Dependencies) { 493 t.Fatalf("Expected number of chart dependencies %d, but got %d", len(reqmts.Dependencies), len(c.Dependencies)) 494 } 495 496 } 497 498 func TestDependentChartsWithSomeSubchartsSpecifiedInRequirements(t *testing.T) { 499 c, err := Load("testdata/dependent-chart-with-mixed-requirements-yaml") 500 if err != nil { 501 t.Fatalf("Failed to load testdata: %s", err) 502 } 503 504 if len(c.Dependencies) == 0 { 505 t.Fatal("There are no dependencies to run this test") 506 } 507 508 origLength := len(c.Dependencies) 509 if err := ProcessRequirementsEnabled(c, c.Values); err != nil { 510 t.Fatalf("Expected no errors but got %q", err) 511 } 512 513 if len(c.Dependencies) != origLength { 514 t.Fatal("Expected no changes in dependencies to be, but did something got changed") 515 } 516 517 reqmts, err := LoadRequirements(c) 518 if err != nil { 519 t.Fatalf("Cannot load requirements for test chart, %v", err) 520 } 521 522 if len(c.Dependencies) <= len(reqmts.Dependencies) { 523 t.Fatalf("Expected more dependencies than specified in requirements.yaml(%d), but got %d", len(reqmts.Dependencies), len(c.Dependencies)) 524 } 525 526 } 527 528 func TestAliasRegexp(t *testing.T) { 529 for name, shouldPass := range map[string]bool{ 530 "abcdefghijklmnopqrstuvwxyzABCDEFG0987654321_-": true, 531 "$foo": false, 532 "bar$": false, 533 "foo\nbar": false, 534 } { 535 if aliasRegexp.MatchString(name) != shouldPass { 536 t.Errorf("name %q failed to pass its test", name) 537 } 538 } 539 }