github.com/caicloud/helm@v2.5.0+incompatible/pkg/chartutil/requirements_test.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors All rights reserved.
     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  	"sort"
    19  	"testing"
    20  
    21  	"strconv"
    22  
    23  	"k8s.io/helm/pkg/proto/hapi/chart"
    24  )
    25  
    26  func TestLoadRequirements(t *testing.T) {
    27  	c, err := Load("testdata/frobnitz")
    28  	if err != nil {
    29  		t.Fatalf("Failed to load testdata: %s", err)
    30  	}
    31  	verifyRequirements(t, c)
    32  }
    33  
    34  func TestLoadRequirementsLock(t *testing.T) {
    35  	c, err := Load("testdata/frobnitz")
    36  	if err != nil {
    37  		t.Fatalf("Failed to load testdata: %s", err)
    38  	}
    39  	verifyRequirementsLock(t, c)
    40  }
    41  func TestRequirementsTagsNonValue(t *testing.T) {
    42  	c, err := Load("testdata/subpop")
    43  	if err != nil {
    44  		t.Fatalf("Failed to load testdata: %s", err)
    45  	}
    46  	// tags with no effect
    47  	v := &chart.Config{Raw: "tags:\n  nothinguseful: false\n\n"}
    48  	// expected charts including duplicates in alphanumeric order
    49  	e := []string{"parentchart", "subchart1", "subcharta", "subchartb"}
    50  
    51  	verifyRequirementsEnabled(t, c, v, e)
    52  }
    53  func TestRequirementsTagsDisabledL1(t *testing.T) {
    54  	c, err := Load("testdata/subpop")
    55  	if err != nil {
    56  		t.Fatalf("Failed to load testdata: %s", err)
    57  	}
    58  	// tags disabling a group
    59  	v := &chart.Config{Raw: "tags:\n  front-end: false\n\n"}
    60  	// expected charts including duplicates in alphanumeric order
    61  	e := []string{"parentchart"}
    62  
    63  	verifyRequirementsEnabled(t, c, v, e)
    64  }
    65  func TestRequirementsTagsEnabledL1(t *testing.T) {
    66  	c, err := Load("testdata/subpop")
    67  	if err != nil {
    68  		t.Fatalf("Failed to load testdata: %s", err)
    69  	}
    70  	// tags disabling a group and enabling a different group
    71  	v := &chart.Config{Raw: "tags:\n  front-end: false\n\n  back-end: true\n"}
    72  	// expected charts including duplicates in alphanumeric order
    73  	e := []string{"parentchart", "subchart2", "subchartb", "subchartc"}
    74  
    75  	verifyRequirementsEnabled(t, c, v, e)
    76  }
    77  
    78  func TestRequirementsTagsDisabledL2(t *testing.T) {
    79  	c, err := Load("testdata/subpop")
    80  	if err != nil {
    81  		t.Fatalf("Failed to load testdata: %s", err)
    82  	}
    83  	// tags disabling only children, children still enabled since tag front-end=true in values.yaml
    84  	v := &chart.Config{Raw: "tags:\n  subcharta: false\n\n  subchartb: false\n"}
    85  	// expected charts including duplicates in alphanumeric order
    86  	e := []string{"parentchart", "subchart1", "subcharta", "subchartb"}
    87  
    88  	verifyRequirementsEnabled(t, c, v, e)
    89  }
    90  func TestRequirementsTagsDisabledL1Mixed(t *testing.T) {
    91  	c, err := Load("testdata/subpop")
    92  	if err != nil {
    93  		t.Fatalf("Failed to load testdata: %s", err)
    94  	}
    95  	// tags disabling all parents/children with additional tag re-enabling a parent
    96  	v := &chart.Config{Raw: "tags:\n  front-end: false\n\n  subchart1: true\n\n  back-end: false\n"}
    97  	// expected charts including duplicates in alphanumeric order
    98  	e := []string{"parentchart", "subchart1"}
    99  
   100  	verifyRequirementsEnabled(t, c, v, e)
   101  }
   102  func TestRequirementsConditionsNonValue(t *testing.T) {
   103  	c, err := Load("testdata/subpop")
   104  	if err != nil {
   105  		t.Fatalf("Failed to load testdata: %s", err)
   106  	}
   107  	// tags with no effect
   108  	v := &chart.Config{Raw: "subchart1:\n  nothinguseful: false\n\n"}
   109  	// expected charts including duplicates in alphanumeric order
   110  	e := []string{"parentchart", "subchart1", "subcharta", "subchartb"}
   111  
   112  	verifyRequirementsEnabled(t, c, v, e)
   113  }
   114  func TestRequirementsConditionsEnabledL1Both(t *testing.T) {
   115  	c, err := Load("testdata/subpop")
   116  	if err != nil {
   117  		t.Fatalf("Failed to load testdata: %s", err)
   118  	}
   119  	// conditions enabling the parent charts, but back-end (b, c) is still disabled via values.yaml
   120  	v := &chart.Config{Raw: "subchart1:\n  enabled: true\nsubchart2:\n  enabled: true\n"}
   121  	// expected charts including duplicates in alphanumeric order
   122  	e := []string{"parentchart", "subchart1", "subchart2", "subcharta", "subchartb"}
   123  
   124  	verifyRequirementsEnabled(t, c, v, e)
   125  }
   126  func TestRequirementsConditionsDisabledL1Both(t *testing.T) {
   127  	c, err := Load("testdata/subpop")
   128  	if err != nil {
   129  		t.Fatalf("Failed to load testdata: %s", err)
   130  	}
   131  	// conditions disabling the parent charts, effectively disabling children
   132  	v := &chart.Config{Raw: "subchart1:\n  enabled: false\nsubchart2:\n  enabled: false\n"}
   133  	// expected charts including duplicates in alphanumeric order
   134  	e := []string{"parentchart"}
   135  
   136  	verifyRequirementsEnabled(t, c, v, e)
   137  }
   138  
   139  func TestRequirementsConditionsSecond(t *testing.T) {
   140  	c, err := Load("testdata/subpop")
   141  	if err != nil {
   142  		t.Fatalf("Failed to load testdata: %s", err)
   143  	}
   144  	// conditions a child using the second condition path of child's condition
   145  	v := &chart.Config{Raw: "subchart1:\n  subcharta:\n    enabled: false\n"}
   146  	// expected charts including duplicates in alphanumeric order
   147  	e := []string{"parentchart", "subchart1", "subchartb"}
   148  
   149  	verifyRequirementsEnabled(t, c, v, e)
   150  }
   151  func TestRequirementsCombinedDisabledL2(t *testing.T) {
   152  	c, err := Load("testdata/subpop")
   153  	if err != nil {
   154  		t.Fatalf("Failed to load testdata: %s", err)
   155  	}
   156  	// tags enabling a parent/child group with condition disabling one child
   157  	v := &chart.Config{Raw: "subchartc:\n  enabled: false\ntags:\n  back-end: true\n"}
   158  	// expected charts including duplicates in alphanumeric order
   159  	e := []string{"parentchart", "subchart1", "subchart2", "subcharta", "subchartb", "subchartb"}
   160  
   161  	verifyRequirementsEnabled(t, c, v, e)
   162  }
   163  func TestRequirementsCombinedDisabledL1(t *testing.T) {
   164  	c, err := Load("testdata/subpop")
   165  	if err != nil {
   166  		t.Fatalf("Failed to load testdata: %s", err)
   167  	}
   168  	// tags will not enable a child if parent is explicitly disabled with condition
   169  	v := &chart.Config{Raw: "subchart1:\n  enabled: false\ntags:\n  front-end: true\n"}
   170  	// expected charts including duplicates in alphanumeric order
   171  	e := []string{"parentchart"}
   172  
   173  	verifyRequirementsEnabled(t, c, v, e)
   174  }
   175  
   176  func verifyRequirementsEnabled(t *testing.T, c *chart.Chart, v *chart.Config, e []string) {
   177  	out := []*chart.Chart{}
   178  	err := ProcessRequirementsEnabled(c, v)
   179  	if err != nil {
   180  		t.Errorf("Error processing enabled requirements %v", err)
   181  	}
   182  	out = extractCharts(c, out)
   183  	// build list of chart names
   184  	p := []string{}
   185  	for _, r := range out {
   186  		p = append(p, r.Metadata.Name)
   187  	}
   188  	//sort alphanumeric and compare to expectations
   189  	sort.Strings(p)
   190  	if len(p) != len(e) {
   191  		t.Errorf("Error slice lengths do not match got %v, expected %v", len(p), len(e))
   192  		return
   193  	}
   194  	for i := range p {
   195  		if p[i] != e[i] {
   196  			t.Errorf("Error slice values do not match got %v, expected %v", p[i], e[i])
   197  		}
   198  	}
   199  }
   200  
   201  // extractCharts recursively searches chart dependencies returning all charts found
   202  func extractCharts(c *chart.Chart, out []*chart.Chart) []*chart.Chart {
   203  
   204  	if len(c.Metadata.Name) > 0 {
   205  		out = append(out, c)
   206  	}
   207  	for _, d := range c.Dependencies {
   208  		out = extractCharts(d, out)
   209  	}
   210  	return out
   211  }
   212  func TestProcessRequirementsImportValues(t *testing.T) {
   213  	c, err := Load("testdata/subpop")
   214  	if err != nil {
   215  		t.Fatalf("Failed to load testdata: %s", err)
   216  	}
   217  
   218  	v := &chart.Config{Raw: ""}
   219  
   220  	e := make(map[string]string)
   221  
   222  	e["imported-chart1.SC1bool"] = "true"
   223  	e["imported-chart1.SC1float"] = "3.14"
   224  	e["imported-chart1.SC1int"] = "100"
   225  	e["imported-chart1.SC1string"] = "dollywood"
   226  	e["imported-chart1.SC1extra1"] = "11"
   227  	e["imported-chart1.SPextra1"] = "helm rocks"
   228  	e["imported-chart1.SC1extra1"] = "11"
   229  
   230  	e["imported-chartA.SCAbool"] = "false"
   231  	e["imported-chartA.SCAfloat"] = "3.1"
   232  	e["imported-chartA.SCAint"] = "55"
   233  	e["imported-chartA.SCAstring"] = "jabba"
   234  	e["imported-chartA.SPextra3"] = "1.337"
   235  	e["imported-chartA.SC1extra2"] = "1.337"
   236  	e["imported-chartA.SCAnested1.SCAnested2"] = "true"
   237  
   238  	e["imported-chartA-B.SCAbool"] = "false"
   239  	e["imported-chartA-B.SCAfloat"] = "3.1"
   240  	e["imported-chartA-B.SCAint"] = "55"
   241  	e["imported-chartA-B.SCAstring"] = "jabba"
   242  
   243  	e["imported-chartA-B.SCBbool"] = "true"
   244  	e["imported-chartA-B.SCBfloat"] = "7.77"
   245  	e["imported-chartA-B.SCBint"] = "33"
   246  	e["imported-chartA-B.SCBstring"] = "boba"
   247  	e["imported-chartA-B.SPextra5"] = "k8s"
   248  	e["imported-chartA-B.SC1extra5"] = "tiller"
   249  
   250  	e["overridden-chart1.SC1bool"] = "false"
   251  	e["overridden-chart1.SC1float"] = "3.141592"
   252  	e["overridden-chart1.SC1int"] = "99"
   253  	e["overridden-chart1.SC1string"] = "pollywog"
   254  	e["overridden-chart1.SPextra2"] = "42"
   255  
   256  	e["overridden-chartA.SCAbool"] = "true"
   257  	e["overridden-chartA.SCAfloat"] = "41.3"
   258  	e["overridden-chartA.SCAint"] = "808"
   259  	e["overridden-chartA.SCAstring"] = "jaberwocky"
   260  	e["overridden-chartA.SPextra4"] = "true"
   261  
   262  	e["overridden-chartA-B.SCAbool"] = "true"
   263  	e["overridden-chartA-B.SCAfloat"] = "41.3"
   264  	e["overridden-chartA-B.SCAint"] = "808"
   265  	e["overridden-chartA-B.SCAstring"] = "jaberwocky"
   266  	e["overridden-chartA-B.SCBbool"] = "false"
   267  	e["overridden-chartA-B.SCBfloat"] = "1.99"
   268  	e["overridden-chartA-B.SCBint"] = "77"
   269  	e["overridden-chartA-B.SCBstring"] = "jango"
   270  	e["overridden-chartA-B.SPextra6"] = "111"
   271  	e["overridden-chartA-B.SCAextra1"] = "23"
   272  	e["overridden-chartA-B.SCBextra1"] = "13"
   273  	e["overridden-chartA-B.SC1extra6"] = "77"
   274  
   275  	// `exports` style
   276  	e["SCBexported1B"] = "1965"
   277  	e["SC1extra7"] = "true"
   278  	e["SCBexported2A"] = "blaster"
   279  	e["global.SC1exported2.all.SC1exported3"] = "SC1expstr"
   280  
   281  	verifyRequirementsImportValues(t, c, v, e)
   282  }
   283  func verifyRequirementsImportValues(t *testing.T, c *chart.Chart, v *chart.Config, e map[string]string) {
   284  
   285  	err := ProcessRequirementsImportValues(c)
   286  	if err != nil {
   287  		t.Errorf("Error processing import values requirements %v", err)
   288  	}
   289  	cv := c.GetValues()
   290  	cc, err := ReadValues([]byte(cv.Raw))
   291  	if err != nil {
   292  		t.Errorf("Error reading import values %v", err)
   293  	}
   294  	for kk, vv := range e {
   295  		pv, err := cc.PathValue(kk)
   296  		if err != nil {
   297  			t.Fatalf("Error retrieving import values table %v %v", kk, err)
   298  			return
   299  		}
   300  
   301  		switch pv.(type) {
   302  		case float64:
   303  			s := strconv.FormatFloat(pv.(float64), 'f', -1, 64)
   304  			if s != vv {
   305  				t.Errorf("Failed to match imported float value %v with expected %v", s, vv)
   306  				return
   307  			}
   308  		case bool:
   309  			b := strconv.FormatBool(pv.(bool))
   310  			if b != vv {
   311  				t.Errorf("Failed to match imported bool value %v with expected %v", b, vv)
   312  				return
   313  			}
   314  		default:
   315  			if pv.(string) != vv {
   316  				t.Errorf("Failed to match imported string value %v with expected %v", pv, vv)
   317  				return
   318  			}
   319  		}
   320  
   321  	}
   322  }
   323  
   324  func TestGetAliasDependency(t *testing.T) {
   325  	c, err := Load("testdata/frobnitz")
   326  	if err != nil {
   327  		t.Fatalf("Failed to load testdata: %s", err)
   328  	}
   329  	req, err := LoadRequirements(c)
   330  	if err != nil {
   331  		t.Fatalf("Failed to load requirement for testdata: %s", err)
   332  	}
   333  	if len(req.Dependencies) == 0 {
   334  		t.Fatalf("There are no requirements to test")
   335  	}
   336  
   337  	// Success case
   338  	aliasChart := getAliasDependency(c.Dependencies, req.Dependencies[0])
   339  	if aliasChart == nil {
   340  		t.Fatalf("Failed to get dependency chart for alias %s", req.Dependencies[0].Name)
   341  	}
   342  	if req.Dependencies[0].Alias != "" {
   343  		if aliasChart.Metadata.Name != req.Dependencies[0].Alias {
   344  			t.Fatalf("Dependency chart name should be %s but got %s", req.Dependencies[0].Alias, aliasChart.Metadata.Name)
   345  		}
   346  	} else if aliasChart.Metadata.Name != req.Dependencies[0].Name {
   347  		t.Fatalf("Dependency chart name should be %s but got %s", req.Dependencies[0].Name, aliasChart.Metadata.Name)
   348  	}
   349  
   350  	// Failure case
   351  	req.Dependencies[0].Name = "something-else"
   352  	if aliasChart := getAliasDependency(c.Dependencies, req.Dependencies[0]); aliasChart != nil {
   353  		t.Fatalf("expected no chart but got %s", aliasChart.Metadata.Name)
   354  	}
   355  }
   356  
   357  func TestDependentChartAliases(t *testing.T) {
   358  	c, err := Load("testdata/dependent-chart-alias")
   359  	if err != nil {
   360  		t.Fatalf("Failed to load testdata: %s", err)
   361  	}
   362  
   363  	if len(c.Dependencies) == 0 {
   364  		t.Fatal("There are no dependencies to run this test")
   365  	}
   366  
   367  	origLength := len(c.Dependencies)
   368  	if err := ProcessRequirementsEnabled(c, c.Values); err != nil {
   369  		t.Fatalf("Expected no errors but got %q", err)
   370  	}
   371  
   372  	if len(c.Dependencies) == origLength {
   373  		t.Fatal("Expected alias dependencies to be added, but did not got that")
   374  	}
   375  
   376  	reqmts, err := LoadRequirements(c)
   377  	if err != nil {
   378  		t.Fatalf("Cannot load requirements for test chart, %v", err)
   379  	}
   380  
   381  	// var expectedDependencyCharts int
   382  	// for _, reqmt := range reqmts.Dependencies {
   383  	// 	expectedDependencyCharts++
   384  	// 	if len(reqmt.Alias) >= 0 {
   385  	// 		expectedDependencyCharts += len(reqmt.Alias)
   386  	// 	}
   387  	// }
   388  	if len(c.Dependencies) != len(reqmts.Dependencies) {
   389  		t.Fatalf("Expected number of chart dependencies %d, but got %d", len(reqmts.Dependencies), len(c.Dependencies))
   390  	}
   391  
   392  }