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