github.com/felipejfc/helm@v2.1.2+incompatible/pkg/chartutil/values_test.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors All rights reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package chartutil
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/json"
    22  	"fmt"
    23  	"testing"
    24  	"text/template"
    25  
    26  	"github.com/golang/protobuf/ptypes/any"
    27  	"k8s.io/helm/pkg/proto/hapi/chart"
    28  	"k8s.io/helm/pkg/timeconv"
    29  )
    30  
    31  func TestReadValues(t *testing.T) {
    32  	doc := `# Test YAML parse
    33  poet: "Coleridge"
    34  title: "Rime of the Ancient Mariner"
    35  stanza:
    36    - "at"
    37    - "length"
    38    - "did"
    39    - cross
    40    - an
    41    - Albatross
    42  
    43  mariner:
    44    with: "crossbow"
    45    shot: "ALBATROSS"
    46  
    47  water:
    48    water:
    49      where: "everywhere"
    50      nor: "any drop to drink"
    51  `
    52  
    53  	data, err := ReadValues([]byte(doc))
    54  	if err != nil {
    55  		t.Fatalf("Error parsing bytes: %s", err)
    56  	}
    57  	matchValues(t, data)
    58  
    59  	tests := []string{`poet: "Coleridge"`, "# Just a comment", ""}
    60  
    61  	for _, tt := range tests {
    62  		data, err = ReadValues([]byte(tt))
    63  		if err != nil {
    64  			t.Fatalf("Error parsing bytes (%s): %s", tt, err)
    65  		}
    66  		if data == nil {
    67  			t.Errorf(`YAML string "%s" gave a nil map`, tt)
    68  		}
    69  	}
    70  }
    71  
    72  func TestToRenderValues(t *testing.T) {
    73  
    74  	chartValues := `
    75  name: al Rashid
    76  where:
    77    city: Basrah
    78    title: caliph
    79  `
    80  	overideValues := `
    81  name: Haroun
    82  where:
    83    city: Baghdad
    84    date: 809 CE
    85  `
    86  
    87  	c := &chart.Chart{
    88  		Metadata:  &chart.Metadata{Name: "test"},
    89  		Templates: []*chart.Template{},
    90  		Values:    &chart.Config{Raw: chartValues},
    91  		Dependencies: []*chart.Chart{
    92  			{
    93  				Metadata: &chart.Metadata{Name: "where"},
    94  				Values:   &chart.Config{Raw: ""},
    95  			},
    96  		},
    97  		Files: []*any.Any{
    98  			{TypeUrl: "scheherazade/shahryar.txt", Value: []byte("1,001 Nights")},
    99  		},
   100  	}
   101  	v := &chart.Config{Raw: overideValues}
   102  
   103  	o := ReleaseOptions{
   104  		Name:      "Seven Voyages",
   105  		Time:      timeconv.Now(),
   106  		Namespace: "al Basrah",
   107  	}
   108  
   109  	res, err := ToRenderValues(c, v, o)
   110  	if err != nil {
   111  		t.Fatal(err)
   112  	}
   113  
   114  	// Ensure that the top-level values are all set.
   115  	if name := res["Chart"].(*chart.Metadata).Name; name != "test" {
   116  		t.Errorf("Expected chart name 'test', got %q", name)
   117  	}
   118  	if name := res["Release"].(map[string]interface{})["Name"]; fmt.Sprint(name) != "Seven Voyages" {
   119  		t.Errorf("Expected release name 'Seven Voyages', got %q", name)
   120  	}
   121  	if data := res["Files"].(Files)["scheherazade/shahryar.txt"]; string(data) != "1,001 Nights" {
   122  		t.Errorf("Expected file '1,001 Nights', got %q", string(data))
   123  	}
   124  
   125  	var vals Values
   126  	vals = res["Values"].(Values)
   127  
   128  	if vals["name"] != "Haroun" {
   129  		t.Errorf("Expected 'Haroun', got %q (%v)", vals["name"], vals)
   130  	}
   131  	where := vals["where"].(map[string]interface{})
   132  	expects := map[string]string{
   133  		"city":  "Baghdad",
   134  		"date":  "809 CE",
   135  		"title": "caliph",
   136  	}
   137  	for field, expect := range expects {
   138  		if got := where[field]; got != expect {
   139  			t.Errorf("Expected %q, got %q (%v)", expect, got, where)
   140  		}
   141  	}
   142  }
   143  
   144  func TestReadValuesFile(t *testing.T) {
   145  	data, err := ReadValuesFile("./testdata/coleridge.yaml")
   146  	if err != nil {
   147  		t.Fatalf("Error reading YAML file: %s", err)
   148  	}
   149  	matchValues(t, data)
   150  }
   151  
   152  func ExampleValues() {
   153  	doc := `
   154  title: "Moby Dick"
   155  chapter:
   156    one:
   157      title: "Loomings"
   158    two:
   159      title: "The Carpet-Bag"
   160    three:
   161      title: "The Spouter Inn"
   162  `
   163  	d, err := ReadValues([]byte(doc))
   164  	if err != nil {
   165  		panic(err)
   166  	}
   167  	ch1, err := d.Table("chapter.one")
   168  	if err != nil {
   169  		panic("could not find chapter one")
   170  	}
   171  	fmt.Print(ch1["title"])
   172  	// Output:
   173  	// Loomings
   174  }
   175  
   176  func TestTable(t *testing.T) {
   177  	doc := `
   178  title: "Moby Dick"
   179  chapter:
   180    one:
   181      title: "Loomings"
   182    two:
   183      title: "The Carpet-Bag"
   184    three:
   185      title: "The Spouter Inn"
   186  `
   187  	d, err := ReadValues([]byte(doc))
   188  	if err != nil {
   189  		t.Fatalf("Failed to parse the White Whale: %s", err)
   190  	}
   191  
   192  	if _, err := d.Table("title"); err == nil {
   193  		t.Fatalf("Title is not a table.")
   194  	}
   195  
   196  	if _, err := d.Table("chapter"); err != nil {
   197  		t.Fatalf("Failed to get the chapter table: %s\n%v", err, d)
   198  	}
   199  
   200  	if v, err := d.Table("chapter.one"); err != nil {
   201  		t.Errorf("Failed to get chapter.one: %s", err)
   202  	} else if v["title"] != "Loomings" {
   203  		t.Errorf("Unexpected title: %s", v["title"])
   204  	}
   205  
   206  	if _, err := d.Table("chapter.three"); err != nil {
   207  		t.Errorf("Chapter three is missing: %s\n%v", err, d)
   208  	}
   209  
   210  	if _, err := d.Table("chapter.OneHundredThirtySix"); err == nil {
   211  		t.Errorf("I think you mean 'Epilogue'")
   212  	}
   213  }
   214  
   215  func matchValues(t *testing.T, data map[string]interface{}) {
   216  	if data["poet"] != "Coleridge" {
   217  		t.Errorf("Unexpected poet: %s", data["poet"])
   218  	}
   219  
   220  	if o, err := ttpl("{{len .stanza}}", data); err != nil {
   221  		t.Errorf("len stanza: %s", err)
   222  	} else if o != "6" {
   223  		t.Errorf("Expected 6, got %s", o)
   224  	}
   225  
   226  	if o, err := ttpl("{{.mariner.shot}}", data); err != nil {
   227  		t.Errorf(".mariner.shot: %s", err)
   228  	} else if o != "ALBATROSS" {
   229  		t.Errorf("Expected that mariner shot ALBATROSS")
   230  	}
   231  
   232  	if o, err := ttpl("{{.water.water.where}}", data); err != nil {
   233  		t.Errorf(".water.water.where: %s", err)
   234  	} else if o != "everywhere" {
   235  		t.Errorf("Expected water water everywhere")
   236  	}
   237  }
   238  
   239  func ttpl(tpl string, v map[string]interface{}) (string, error) {
   240  	var b bytes.Buffer
   241  	tt := template.Must(template.New("t").Parse(tpl))
   242  	if err := tt.Execute(&b, v); err != nil {
   243  		return "", err
   244  	}
   245  	return b.String(), nil
   246  }
   247  
   248  var testCoalesceValuesYaml = `
   249  top: yup
   250  
   251  global:
   252    name: Ishmael
   253    subject: Queequeg
   254    nested:
   255      boat: true
   256  
   257  pequod:
   258    global:
   259      name: Stinky
   260      harpooner: Tashtego
   261      nested:
   262        boat: false
   263        sail: true
   264    ahab:
   265      scope: whale
   266  `
   267  
   268  func TestCoalesceValues(t *testing.T) {
   269  	tchart := "testdata/moby"
   270  	c, err := LoadDir(tchart)
   271  	if err != nil {
   272  		t.Fatal(err)
   273  	}
   274  
   275  	tvals := &chart.Config{Raw: testCoalesceValuesYaml}
   276  
   277  	v, err := CoalesceValues(c, tvals)
   278  	if err != nil {
   279  		t.Fatal(err)
   280  	}
   281  	j, _ := json.MarshalIndent(v, "", "  ")
   282  	t.Logf("Coalesced Values: %s", string(j))
   283  
   284  	tests := []struct {
   285  		tpl    string
   286  		expect string
   287  	}{
   288  		{"{{.top}}", "yup"},
   289  		{"{{.name}}", "moby"},
   290  		{"{{.global.name}}", "Ishmael"},
   291  		{"{{.global.subject}}", "Queequeg"},
   292  		{"{{.global.harpooner}}", "<no value>"},
   293  		{"{{.pequod.name}}", "pequod"},
   294  		{"{{.pequod.ahab.name}}", "ahab"},
   295  		{"{{.pequod.ahab.scope}}", "whale"},
   296  		{"{{.pequod.ahab.global.name}}", "Ishmael"},
   297  		{"{{.pequod.ahab.global.subject}}", "Queequeg"},
   298  		{"{{.pequod.ahab.global.harpooner}}", "Tashtego"},
   299  		{"{{.pequod.global.name}}", "Ishmael"},
   300  		{"{{.pequod.global.subject}}", "Queequeg"},
   301  		{"{{.spouter.global.name}}", "Ishmael"},
   302  		{"{{.spouter.global.harpooner}}", "<no value>"},
   303  
   304  		{"{{.global.nested.boat}}", "true"},
   305  		{"{{.pequod.global.nested.boat}}", "true"},
   306  		{"{{.spouter.global.nested.boat}}", "true"},
   307  		{"{{.pequod.global.nested.sail}}", "true"},
   308  		{"{{.spouter.global.nested.sail}}", "<no value>"},
   309  	}
   310  
   311  	for _, tt := range tests {
   312  		if o, err := ttpl(tt.tpl, v); err != nil || o != tt.expect {
   313  			t.Errorf("Expected %q to expand to %q, got %q", tt.tpl, tt.expect, o)
   314  		}
   315  	}
   316  }
   317  
   318  func TestCoalesceTables(t *testing.T) {
   319  	dst := map[string]interface{}{
   320  		"name": "Ishmael",
   321  		"address": map[string]interface{}{
   322  			"street": "123 Spouter Inn Ct.",
   323  			"city":   "Nantucket",
   324  		},
   325  		"details": map[string]interface{}{
   326  			"friends": []string{"Tashtego"},
   327  		},
   328  		"boat": "pequod",
   329  	}
   330  	src := map[string]interface{}{
   331  		"occupation": "whaler",
   332  		"address": map[string]interface{}{
   333  			"state":  "MA",
   334  			"street": "234 Spouter Inn Ct.",
   335  		},
   336  		"details": "empty",
   337  		"boat": map[string]interface{}{
   338  			"mast": true,
   339  		},
   340  	}
   341  
   342  	// What we expect is that anything in dst overrides anything in src, but that
   343  	// otherwise the values are coalesced.
   344  	coalesceTables(dst, src)
   345  
   346  	if dst["name"] != "Ishmael" {
   347  		t.Errorf("Unexpected name: %s", dst["name"])
   348  	}
   349  	if dst["occupation"] != "whaler" {
   350  		t.Errorf("Unexpected occupation: %s", dst["occupation"])
   351  	}
   352  
   353  	addr, ok := dst["address"].(map[string]interface{})
   354  	if !ok {
   355  		t.Fatal("Address went away.")
   356  	}
   357  
   358  	if addr["street"].(string) != "123 Spouter Inn Ct." {
   359  		t.Errorf("Unexpected address: %v", addr["street"])
   360  	}
   361  
   362  	if addr["city"].(string) != "Nantucket" {
   363  		t.Errorf("Unexpected city: %v", addr["city"])
   364  	}
   365  
   366  	if addr["state"].(string) != "MA" {
   367  		t.Errorf("Unexpected state: %v", addr["state"])
   368  	}
   369  
   370  	if det, ok := dst["details"].(map[string]interface{}); !ok {
   371  		t.Fatalf("Details is the wrong type: %v", dst["details"])
   372  	} else if _, ok := det["friends"]; !ok {
   373  		t.Error("Could not find your friends. Maybe you don't have any. :-(")
   374  	}
   375  
   376  	if dst["boat"].(string) != "pequod" {
   377  		t.Errorf("Expected boat string, got %v", dst["boat"])
   378  	}
   379  }