github.com/sdbaiguanghe/helm@v2.16.7+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 req.Dependencies[0].Name = "something-else" 374 if aliasChart := getAliasDependency(c.Dependencies, req.Dependencies[0]); aliasChart != nil { 375 t.Fatalf("expected no chart but got %s", aliasChart.Metadata.Name) 376 } 377 378 req.Dependencies[0].Version = "something else which is not in the compatible range" 379 if version.IsCompatibleRange(req.Dependencies[0].Version, aliasChart.Metadata.Version) { 380 t.Fatalf("Dependency chart version which is not in the compatible range should cause a failure other than a success ") 381 } 382 383 } 384 385 func TestDependentChartAliases(t *testing.T) { 386 c, err := Load("testdata/dependent-chart-alias") 387 if err != nil { 388 t.Fatalf("Failed to load testdata: %s", err) 389 } 390 391 if len(c.Dependencies) == 0 { 392 t.Fatal("There are no dependencies to run this test") 393 } 394 395 origLength := len(c.Dependencies) 396 if err := ProcessRequirementsEnabled(c, c.Values); err != nil { 397 t.Fatalf("Expected no errors but got %q", err) 398 } 399 400 if len(c.Dependencies) == origLength { 401 t.Fatal("Expected alias dependencies to be added, but did not got that") 402 } 403 404 reqmts, err := LoadRequirements(c) 405 if err != nil { 406 t.Fatalf("Cannot load requirements for test chart, %v", err) 407 } 408 409 if len(c.Dependencies) != len(reqmts.Dependencies) { 410 t.Fatalf("Expected number of chart dependencies %d, but got %d", len(reqmts.Dependencies), len(c.Dependencies)) 411 } 412 413 } 414 415 func TestDependentChartWithSubChartsAbsentInRequirements(t *testing.T) { 416 c, err := Load("testdata/dependent-chart-no-requirements-yaml") 417 if err != nil { 418 t.Fatalf("Failed to load testdata: %s", err) 419 } 420 421 if len(c.Dependencies) != 2 { 422 t.Fatalf("Expected 2 dependencies for this chart, but got %d", len(c.Dependencies)) 423 } 424 425 origLength := len(c.Dependencies) 426 if err := ProcessRequirementsEnabled(c, c.Values); err != nil { 427 t.Fatalf("Expected no errors but got %q", err) 428 } 429 430 if len(c.Dependencies) != origLength { 431 t.Fatal("Expected no changes in dependencies to be, but did something got changed") 432 } 433 434 } 435 436 func TestDependentChartWithSubChartsHelmignore(t *testing.T) { 437 if _, err := Load("testdata/dependent-chart-helmignore"); err != nil { 438 t.Fatalf("Failed to load testdata: %s", err) 439 } 440 } 441 442 func TestDependentChartsWithSubChartsSymlink(t *testing.T) { 443 joonix := "testdata/joonix" 444 if err := os.Symlink(filepath.Join("..", "..", "frobnitz"), filepath.Join(joonix, "charts", "frobnitz")); err != nil { 445 t.Fatal(err) 446 } 447 defer os.RemoveAll(filepath.Join(joonix, "charts", "frobnitz")) 448 c, err := Load(joonix) 449 if err != nil { 450 t.Fatalf("Failed to load testdata: %s", err) 451 } 452 if c.Metadata.Name != "joonix" { 453 t.Fatalf("Unexpected chart name: %s", c.Metadata.Name) 454 } 455 if n := len(c.Dependencies); n != 1 { 456 t.Fatalf("Expected 1 dependency for this chart, but got %d", n) 457 } 458 } 459 460 func TestDependentChartsWithSubchartsAllSpecifiedInRequirements(t *testing.T) { 461 c, err := Load("testdata/dependent-chart-with-all-in-requirements-yaml") 462 if err != nil { 463 t.Fatalf("Failed to load testdata: %s", err) 464 } 465 466 if len(c.Dependencies) == 0 { 467 t.Fatal("There are no dependencies to run this test") 468 } 469 470 origLength := len(c.Dependencies) 471 if err := ProcessRequirementsEnabled(c, c.Values); err != nil { 472 t.Fatalf("Expected no errors but got %q", err) 473 } 474 475 if len(c.Dependencies) != origLength { 476 t.Fatal("Expected no changes in dependencies to be, but did something got changed") 477 } 478 479 reqmts, err := LoadRequirements(c) 480 if err != nil { 481 t.Fatalf("Cannot load requirements for test chart, %v", err) 482 } 483 484 if len(c.Dependencies) != len(reqmts.Dependencies) { 485 t.Fatalf("Expected number of chart dependencies %d, but got %d", len(reqmts.Dependencies), len(c.Dependencies)) 486 } 487 488 } 489 490 func TestDependentChartsWithSomeSubchartsSpecifiedInRequirements(t *testing.T) { 491 c, err := Load("testdata/dependent-chart-with-mixed-requirements-yaml") 492 if err != nil { 493 t.Fatalf("Failed to load testdata: %s", err) 494 } 495 496 if len(c.Dependencies) == 0 { 497 t.Fatal("There are no dependencies to run this test") 498 } 499 500 origLength := len(c.Dependencies) 501 if err := ProcessRequirementsEnabled(c, c.Values); err != nil { 502 t.Fatalf("Expected no errors but got %q", err) 503 } 504 505 if len(c.Dependencies) != origLength { 506 t.Fatal("Expected no changes in dependencies to be, but did something got changed") 507 } 508 509 reqmts, err := LoadRequirements(c) 510 if err != nil { 511 t.Fatalf("Cannot load requirements for test chart, %v", err) 512 } 513 514 if len(c.Dependencies) <= len(reqmts.Dependencies) { 515 t.Fatalf("Expected more dependencies than specified in requirements.yaml(%d), but got %d", len(reqmts.Dependencies), len(c.Dependencies)) 516 } 517 518 }