github.com/Beeketing/helm@v2.12.1+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: "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 179 func verifyRequirementsEnabled(t *testing.T, c *chart.Chart, v *chart.Config, e []string) { 180 out := []*chart.Chart{} 181 err := ProcessRequirementsEnabled(c, v) 182 if err != nil { 183 t.Errorf("Error processing enabled requirements %v", err) 184 } 185 out = extractCharts(c, out) 186 // build list of chart names 187 p := []string{} 188 for _, r := range out { 189 p = append(p, r.Metadata.Name) 190 } 191 //sort alphanumeric and compare to expectations 192 sort.Strings(p) 193 if len(p) != len(e) { 194 t.Errorf("Error slice lengths do not match got %v, expected %v", len(p), len(e)) 195 return 196 } 197 for i := range p { 198 if p[i] != e[i] { 199 t.Errorf("Error slice values do not match got %v, expected %v", p[i], e[i]) 200 } 201 } 202 } 203 204 // extractCharts recursively searches chart dependencies returning all charts found 205 func extractCharts(c *chart.Chart, out []*chart.Chart) []*chart.Chart { 206 207 if len(c.Metadata.Name) > 0 { 208 out = append(out, c) 209 } 210 for _, d := range c.Dependencies { 211 out = extractCharts(d, out) 212 } 213 return out 214 } 215 func TestProcessRequirementsImportValues(t *testing.T) { 216 c, err := Load("testdata/subpop") 217 if err != nil { 218 t.Fatalf("Failed to load testdata: %s", err) 219 } 220 221 v := &chart.Config{Raw: ""} 222 223 e := make(map[string]string) 224 225 e["imported-chart1.SC1bool"] = "true" 226 e["imported-chart1.SC1float"] = "3.14" 227 e["imported-chart1.SC1int"] = "100" 228 e["imported-chart1.SC1string"] = "dollywood" 229 e["imported-chart1.SC1extra1"] = "11" 230 e["imported-chart1.SPextra1"] = "helm rocks" 231 e["imported-chart1.SC1extra1"] = "11" 232 233 e["imported-chartA.SCAbool"] = "false" 234 e["imported-chartA.SCAfloat"] = "3.1" 235 e["imported-chartA.SCAint"] = "55" 236 e["imported-chartA.SCAstring"] = "jabba" 237 e["imported-chartA.SPextra3"] = "1.337" 238 e["imported-chartA.SC1extra2"] = "1.337" 239 e["imported-chartA.SCAnested1.SCAnested2"] = "true" 240 241 e["imported-chartA-B.SCAbool"] = "false" 242 e["imported-chartA-B.SCAfloat"] = "3.1" 243 e["imported-chartA-B.SCAint"] = "55" 244 e["imported-chartA-B.SCAstring"] = "jabba" 245 246 e["imported-chartA-B.SCBbool"] = "true" 247 e["imported-chartA-B.SCBfloat"] = "7.77" 248 e["imported-chartA-B.SCBint"] = "33" 249 e["imported-chartA-B.SCBstring"] = "boba" 250 e["imported-chartA-B.SPextra5"] = "k8s" 251 e["imported-chartA-B.SC1extra5"] = "tiller" 252 253 e["overridden-chart1.SC1bool"] = "false" 254 e["overridden-chart1.SC1float"] = "3.141592" 255 e["overridden-chart1.SC1int"] = "99" 256 e["overridden-chart1.SC1string"] = "pollywog" 257 e["overridden-chart1.SPextra2"] = "42" 258 259 e["overridden-chartA.SCAbool"] = "true" 260 e["overridden-chartA.SCAfloat"] = "41.3" 261 e["overridden-chartA.SCAint"] = "808" 262 e["overridden-chartA.SCAstring"] = "jaberwocky" 263 e["overridden-chartA.SPextra4"] = "true" 264 265 e["overridden-chartA-B.SCAbool"] = "true" 266 e["overridden-chartA-B.SCAfloat"] = "41.3" 267 e["overridden-chartA-B.SCAint"] = "808" 268 e["overridden-chartA-B.SCAstring"] = "jaberwocky" 269 e["overridden-chartA-B.SCBbool"] = "false" 270 e["overridden-chartA-B.SCBfloat"] = "1.99" 271 e["overridden-chartA-B.SCBint"] = "77" 272 e["overridden-chartA-B.SCBstring"] = "jango" 273 e["overridden-chartA-B.SPextra6"] = "111" 274 e["overridden-chartA-B.SCAextra1"] = "23" 275 e["overridden-chartA-B.SCBextra1"] = "13" 276 e["overridden-chartA-B.SC1extra6"] = "77" 277 278 // `exports` style 279 e["SCBexported1B"] = "1965" 280 e["SC1extra7"] = "true" 281 e["SCBexported2A"] = "blaster" 282 e["global.SC1exported2.all.SC1exported3"] = "SC1expstr" 283 284 verifyRequirementsImportValues(t, c, v, e) 285 } 286 func verifyRequirementsImportValues(t *testing.T, c *chart.Chart, v *chart.Config, e map[string]string) { 287 288 err := ProcessRequirementsImportValues(c) 289 if err != nil { 290 t.Errorf("Error processing import values requirements %v", err) 291 } 292 cv := c.GetValues() 293 cc, err := ReadValues([]byte(cv.Raw)) 294 if err != nil { 295 t.Errorf("Error reading import values %v", err) 296 } 297 for kk, vv := range e { 298 pv, err := cc.PathValue(kk) 299 if err != nil { 300 t.Fatalf("Error retrieving import values table %v %v", kk, err) 301 return 302 } 303 304 switch pv.(type) { 305 case float64: 306 s := strconv.FormatFloat(pv.(float64), 'f', -1, 64) 307 if s != vv { 308 t.Errorf("Failed to match imported float value %v with expected %v", s, vv) 309 return 310 } 311 case bool: 312 b := strconv.FormatBool(pv.(bool)) 313 if b != vv { 314 t.Errorf("Failed to match imported bool value %v with expected %v", b, vv) 315 return 316 } 317 default: 318 if pv.(string) != vv { 319 t.Errorf("Failed to match imported string value %v with expected %v", pv, vv) 320 return 321 } 322 } 323 324 } 325 } 326 327 func TestGetAliasDependency(t *testing.T) { 328 c, err := Load("testdata/frobnitz") 329 if err != nil { 330 t.Fatalf("Failed to load testdata: %s", err) 331 } 332 req, err := LoadRequirements(c) 333 if err != nil { 334 t.Fatalf("Failed to load requirement for testdata: %s", err) 335 } 336 if len(req.Dependencies) == 0 { 337 t.Fatalf("There are no requirements to test") 338 } 339 340 // Success case 341 aliasChart := getAliasDependency(c.Dependencies, req.Dependencies[0]) 342 if aliasChart == nil { 343 t.Fatalf("Failed to get dependency chart for alias %s", req.Dependencies[0].Name) 344 } 345 if req.Dependencies[0].Alias != "" { 346 if aliasChart.Metadata.Name != req.Dependencies[0].Alias { 347 t.Fatalf("Dependency chart name should be %s but got %s", req.Dependencies[0].Alias, aliasChart.Metadata.Name) 348 } 349 } else if aliasChart.Metadata.Name != req.Dependencies[0].Name { 350 t.Fatalf("Dependency chart name should be %s but got %s", req.Dependencies[0].Name, aliasChart.Metadata.Name) 351 } 352 353 if req.Dependencies[0].Version != "" { 354 if !version.IsCompatibleRange(req.Dependencies[0].Version, aliasChart.Metadata.Version) { 355 t.Fatalf("Dependency chart version is not in the compatible range") 356 } 357 358 } 359 360 // Failure case 361 req.Dependencies[0].Name = "something-else" 362 if aliasChart := getAliasDependency(c.Dependencies, req.Dependencies[0]); aliasChart != nil { 363 t.Fatalf("expected no chart but got %s", aliasChart.Metadata.Name) 364 } 365 366 req.Dependencies[0].Version = "something else which is not in the compatible range" 367 if version.IsCompatibleRange(req.Dependencies[0].Version, aliasChart.Metadata.Version) { 368 t.Fatalf("Dependency chart version which is not in the compatible range should cause a failure other than a success ") 369 } 370 371 } 372 373 func TestDependentChartAliases(t *testing.T) { 374 c, err := Load("testdata/dependent-chart-alias") 375 if err != nil { 376 t.Fatalf("Failed to load testdata: %s", err) 377 } 378 379 if len(c.Dependencies) == 0 { 380 t.Fatal("There are no dependencies to run this test") 381 } 382 383 origLength := len(c.Dependencies) 384 if err := ProcessRequirementsEnabled(c, c.Values); err != nil { 385 t.Fatalf("Expected no errors but got %q", err) 386 } 387 388 if len(c.Dependencies) == origLength { 389 t.Fatal("Expected alias dependencies to be added, but did not got that") 390 } 391 392 reqmts, err := LoadRequirements(c) 393 if err != nil { 394 t.Fatalf("Cannot load requirements for test chart, %v", err) 395 } 396 397 if len(c.Dependencies) != len(reqmts.Dependencies) { 398 t.Fatalf("Expected number of chart dependencies %d, but got %d", len(reqmts.Dependencies), len(c.Dependencies)) 399 } 400 401 } 402 403 func TestDependentChartWithSubChartsAbsentInRequirements(t *testing.T) { 404 c, err := Load("testdata/dependent-chart-no-requirements-yaml") 405 if err != nil { 406 t.Fatalf("Failed to load testdata: %s", err) 407 } 408 409 if len(c.Dependencies) != 2 { 410 t.Fatalf("Expected 2 dependencies for this chart, but got %d", len(c.Dependencies)) 411 } 412 413 origLength := len(c.Dependencies) 414 if err := ProcessRequirementsEnabled(c, c.Values); err != nil { 415 t.Fatalf("Expected no errors but got %q", err) 416 } 417 418 if len(c.Dependencies) != origLength { 419 t.Fatal("Expected no changes in dependencies to be, but did something got changed") 420 } 421 422 } 423 424 func TestDependentChartWithSubChartsHelmignore(t *testing.T) { 425 if _, err := Load("testdata/dependent-chart-helmignore"); err != nil { 426 t.Fatalf("Failed to load testdata: %s", err) 427 } 428 } 429 430 func TestDependentChartsWithSubChartsSymlink(t *testing.T) { 431 joonix := "testdata/joonix" 432 if err := os.Symlink(filepath.Join("..", "..", "frobnitz"), filepath.Join(joonix, "charts", "frobnitz")); err != nil { 433 t.Fatal(err) 434 } 435 defer os.RemoveAll(filepath.Join(joonix, "charts", "frobnitz")) 436 c, err := Load(joonix) 437 if err != nil { 438 t.Fatalf("Failed to load testdata: %s", err) 439 } 440 if c.Metadata.Name != "joonix" { 441 t.Fatalf("Unexpected chart name: %s", c.Metadata.Name) 442 } 443 if n := len(c.Dependencies); n != 1 { 444 t.Fatalf("Expected 1 dependency for this chart, but got %d", n) 445 } 446 } 447 448 func TestDependentChartsWithSubchartsAllSpecifiedInRequirements(t *testing.T) { 449 c, err := Load("testdata/dependent-chart-with-all-in-requirements-yaml") 450 if err != nil { 451 t.Fatalf("Failed to load testdata: %s", err) 452 } 453 454 if len(c.Dependencies) == 0 { 455 t.Fatal("There are no dependencies to run this test") 456 } 457 458 origLength := len(c.Dependencies) 459 if err := ProcessRequirementsEnabled(c, c.Values); err != nil { 460 t.Fatalf("Expected no errors but got %q", err) 461 } 462 463 if len(c.Dependencies) != origLength { 464 t.Fatal("Expected no changes in dependencies to be, but did something got changed") 465 } 466 467 reqmts, err := LoadRequirements(c) 468 if err != nil { 469 t.Fatalf("Cannot load requirements for test chart, %v", err) 470 } 471 472 if len(c.Dependencies) != len(reqmts.Dependencies) { 473 t.Fatalf("Expected number of chart dependencies %d, but got %d", len(reqmts.Dependencies), len(c.Dependencies)) 474 } 475 476 } 477 478 func TestDependentChartsWithSomeSubchartsSpecifiedInRequirements(t *testing.T) { 479 c, err := Load("testdata/dependent-chart-with-mixed-requirements-yaml") 480 if err != nil { 481 t.Fatalf("Failed to load testdata: %s", err) 482 } 483 484 if len(c.Dependencies) == 0 { 485 t.Fatal("There are no dependencies to run this test") 486 } 487 488 origLength := len(c.Dependencies) 489 if err := ProcessRequirementsEnabled(c, c.Values); err != nil { 490 t.Fatalf("Expected no errors but got %q", err) 491 } 492 493 if len(c.Dependencies) != origLength { 494 t.Fatal("Expected no changes in dependencies to be, but did something got changed") 495 } 496 497 reqmts, err := LoadRequirements(c) 498 if err != nil { 499 t.Fatalf("Cannot load requirements for test chart, %v", err) 500 } 501 502 if len(c.Dependencies) <= len(reqmts.Dependencies) { 503 t.Fatalf("Expected more dependencies than specified in requirements.yaml(%d), but got %d", len(reqmts.Dependencies), len(c.Dependencies)) 504 } 505 506 }