github.com/danielqsj/helm@v2.0.0-alpha.4.0.20160908204436-976e0ba5199b+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", 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  
   255  pequod:
   256    global:
   257      name: Stinky
   258      harpooner: Tashtego
   259    ahab:
   260      scope: whale
   261  `
   262  
   263  func TestCoalesceValues(t *testing.T) {
   264  	tchart := "testdata/moby"
   265  	c, err := LoadDir(tchart)
   266  	if err != nil {
   267  		t.Fatal(err)
   268  	}
   269  
   270  	tvals := &chart.Config{Raw: testCoalesceValuesYaml}
   271  
   272  	v, err := CoalesceValues(c, tvals)
   273  	j, _ := json.MarshalIndent(v, "", "  ")
   274  	t.Logf("Coalesced Values: %s", string(j))
   275  
   276  	tests := []struct {
   277  		tpl    string
   278  		expect string
   279  	}{
   280  		{"{{.top}}", "yup"},
   281  		{"{{.name}}", "moby"},
   282  		{"{{.global.name}}", "Ishmael"},
   283  		{"{{.global.subject}}", "Queequeg"},
   284  		{"{{.global.harpooner}}", "<no value>"},
   285  		{"{{.pequod.name}}", "pequod"},
   286  		{"{{.pequod.ahab.name}}", "ahab"},
   287  		{"{{.pequod.ahab.scope}}", "whale"},
   288  		{"{{.pequod.ahab.global.name}}", "Ishmael"},
   289  		{"{{.pequod.ahab.global.subject}}", "Queequeg"},
   290  		{"{{.pequod.ahab.global.harpooner}}", "Tashtego"},
   291  		{"{{.pequod.global.name}}", "Ishmael"},
   292  		{"{{.pequod.global.subject}}", "Queequeg"},
   293  		{"{{.spouter.global.name}}", "Ishmael"},
   294  		{"{{.spouter.global.harpooner}}", "<no value>"},
   295  	}
   296  
   297  	for _, tt := range tests {
   298  		if o, err := ttpl(tt.tpl, v); err != nil || o != tt.expect {
   299  			t.Errorf("Expected %q to expand to %q, got %q", tt.tpl, tt.expect, o)
   300  		}
   301  	}
   302  }
   303  
   304  func TestCoalesceTables(t *testing.T) {
   305  	dst := map[string]interface{}{
   306  		"name": "Ishmael",
   307  		"address": map[string]interface{}{
   308  			"street": "123 Spouter Inn Ct.",
   309  			"city":   "Nantucket",
   310  		},
   311  		"details": map[string]interface{}{
   312  			"friends": []string{"Tashtego"},
   313  		},
   314  		"boat": "pequod",
   315  	}
   316  	src := map[string]interface{}{
   317  		"occupation": "whaler",
   318  		"address": map[string]interface{}{
   319  			"state":  "MA",
   320  			"street": "234 Spouter Inn Ct.",
   321  		},
   322  		"details": "empty",
   323  		"boat": map[string]interface{}{
   324  			"mast": true,
   325  		},
   326  	}
   327  
   328  	// What we expect is that anything in dst overrides anything in src, but that
   329  	// otherwise the values are coalesced.
   330  	coalesceTables(dst, src)
   331  
   332  	if dst["name"] != "Ishmael" {
   333  		t.Errorf("Unexpected name: %s", dst["name"])
   334  	}
   335  	if dst["occupation"] != "whaler" {
   336  		t.Errorf("Unexpected occupation: %s", dst["occupation"])
   337  	}
   338  
   339  	addr, ok := dst["address"].(map[string]interface{})
   340  	if !ok {
   341  		t.Fatal("Address went away.")
   342  	}
   343  
   344  	if addr["street"].(string) != "123 Spouter Inn Ct." {
   345  		t.Errorf("Unexpected address: %v", addr["street"])
   346  	}
   347  
   348  	if addr["city"].(string) != "Nantucket" {
   349  		t.Errorf("Unexpected city: %v", addr["city"])
   350  	}
   351  
   352  	if addr["state"].(string) != "MA" {
   353  		t.Errorf("Unexpected state: %v", addr["state"])
   354  	}
   355  
   356  	if det, ok := dst["details"].(map[string]interface{}); !ok {
   357  		t.Fatalf("Details is the wrong type: %v", dst["details"])
   358  	} else if _, ok := det["friends"]; !ok {
   359  		t.Error("Could not find your friends. Maybe you don't have any. :-(")
   360  	}
   361  
   362  	if dst["boat"].(string) != "pequod" {
   363  		t.Errorf("Expected boat string, got %v", dst["boat"])
   364  	}
   365  }