github.com/zsuzhengdu/helm@v3.0.0-beta.3+incompatible/pkg/engine/engine_test.go (about)

     1  /*
     2  Copyright The Helm Authors.
     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 engine
    18  
    19  import (
    20  	"fmt"
    21  	"strings"
    22  	"sync"
    23  	"testing"
    24  
    25  	"helm.sh/helm/pkg/chart"
    26  	"helm.sh/helm/pkg/chartutil"
    27  )
    28  
    29  func TestSortTemplates(t *testing.T) {
    30  	tpls := map[string]renderable{
    31  		"/mychart/templates/foo.tpl":                                 {},
    32  		"/mychart/templates/charts/foo/charts/bar/templates/foo.tpl": {},
    33  		"/mychart/templates/bar.tpl":                                 {},
    34  		"/mychart/templates/charts/foo/templates/bar.tpl":            {},
    35  		"/mychart/templates/_foo.tpl":                                {},
    36  		"/mychart/templates/charts/foo/templates/foo.tpl":            {},
    37  		"/mychart/templates/charts/bar/templates/foo.tpl":            {},
    38  	}
    39  	got := sortTemplates(tpls)
    40  	if len(got) != len(tpls) {
    41  		t.Fatal("Sorted results are missing templates")
    42  	}
    43  
    44  	expect := []string{
    45  		"/mychart/templates/charts/foo/charts/bar/templates/foo.tpl",
    46  		"/mychart/templates/charts/foo/templates/foo.tpl",
    47  		"/mychart/templates/charts/foo/templates/bar.tpl",
    48  		"/mychart/templates/charts/bar/templates/foo.tpl",
    49  		"/mychart/templates/foo.tpl",
    50  		"/mychart/templates/bar.tpl",
    51  		"/mychart/templates/_foo.tpl",
    52  	}
    53  	for i, e := range expect {
    54  		if got[i] != e {
    55  			t.Fatalf("\n\tExp:\n%s\n\tGot:\n%s",
    56  				strings.Join(expect, "\n"),
    57  				strings.Join(got, "\n"),
    58  			)
    59  		}
    60  	}
    61  }
    62  
    63  func TestFuncMap(t *testing.T) {
    64  	fns := funcMap()
    65  	forbidden := []string{"env", "expandenv"}
    66  	for _, f := range forbidden {
    67  		if _, ok := fns[f]; ok {
    68  			t.Errorf("Forbidden function %s exists in FuncMap.", f)
    69  		}
    70  	}
    71  
    72  	// Test for Engine-specific template functions.
    73  	expect := []string{"include", "required", "tpl", "toYaml", "fromYaml", "toToml", "toJson", "fromJson"}
    74  	for _, f := range expect {
    75  		if _, ok := fns[f]; !ok {
    76  			t.Errorf("Expected add-on function %q", f)
    77  		}
    78  	}
    79  }
    80  
    81  func TestRender(t *testing.T) {
    82  	c := &chart.Chart{
    83  		Metadata: &chart.Metadata{
    84  			Name:    "moby",
    85  			Version: "1.2.3",
    86  		},
    87  		Templates: []*chart.File{
    88  			{Name: "templates/test1", Data: []byte("{{.Values.outer | title }} {{.Values.inner | title}}")},
    89  			{Name: "templates/test2", Data: []byte("{{.Values.global.callme | lower }}")},
    90  			{Name: "templates/test3", Data: []byte("{{.noValue}}")},
    91  			{Name: "templates/test4", Data: []byte("{{toJson .Values}}")},
    92  		},
    93  		Values: map[string]interface{}{"outer": "DEFAULT", "inner": "DEFAULT"},
    94  	}
    95  
    96  	vals := map[string]interface{}{
    97  		"Values": map[string]interface{}{
    98  			"outer": "spouter",
    99  			"inner": "inn",
   100  			"global": map[string]interface{}{
   101  				"callme": "Ishmael",
   102  			},
   103  		},
   104  	}
   105  
   106  	v, err := chartutil.CoalesceValues(c, vals)
   107  	if err != nil {
   108  		t.Fatalf("Failed to coalesce values: %s", err)
   109  	}
   110  	out, err := Render(c, v)
   111  	if err != nil {
   112  		t.Errorf("Failed to render templates: %s", err)
   113  	}
   114  
   115  	expect := map[string]string{
   116  		"moby/templates/test1": "Spouter Inn",
   117  		"moby/templates/test2": "ishmael",
   118  		"moby/templates/test3": "",
   119  		"moby/templates/test4": `{"global":{"callme":"Ishmael"},"inner":"inn","outer":"spouter"}`,
   120  	}
   121  
   122  	for name, data := range expect {
   123  		if out[name] != data {
   124  			t.Errorf("Expected %q, got %q", data, out[name])
   125  		}
   126  	}
   127  }
   128  
   129  func TestRenderInternals(t *testing.T) {
   130  	// Test the internals of the rendering tool.
   131  
   132  	vals := chartutil.Values{"Name": "one", "Value": "two"}
   133  	tpls := map[string]renderable{
   134  		"one": {tpl: `Hello {{title .Name}}`, vals: vals},
   135  		"two": {tpl: `Goodbye {{upper .Value}}`, vals: vals},
   136  		// Test whether a template can reliably reference another template
   137  		// without regard for ordering.
   138  		"three": {tpl: `{{template "two" dict "Value" "three"}}`, vals: vals},
   139  	}
   140  
   141  	out, err := new(Engine).render(tpls)
   142  	if err != nil {
   143  		t.Fatalf("Failed template rendering: %s", err)
   144  	}
   145  
   146  	if len(out) != 3 {
   147  		t.Fatalf("Expected 3 templates, got %d", len(out))
   148  	}
   149  
   150  	if out["one"] != "Hello One" {
   151  		t.Errorf("Expected 'Hello One', got %q", out["one"])
   152  	}
   153  
   154  	if out["two"] != "Goodbye TWO" {
   155  		t.Errorf("Expected 'Goodbye TWO'. got %q", out["two"])
   156  	}
   157  
   158  	if out["three"] != "Goodbye THREE" {
   159  		t.Errorf("Expected 'Goodbye THREE'. got %q", out["two"])
   160  	}
   161  }
   162  
   163  func TestParallelRenderInternals(t *testing.T) {
   164  	// Make sure that we can use one Engine to run parallel template renders.
   165  	e := new(Engine)
   166  	var wg sync.WaitGroup
   167  	for i := 0; i < 20; i++ {
   168  		wg.Add(1)
   169  		go func(i int) {
   170  			tt := fmt.Sprintf("expect-%d", i)
   171  			tpls := map[string]renderable{
   172  				"t": {
   173  					tpl:  `{{.val}}`,
   174  					vals: map[string]interface{}{"val": tt},
   175  				},
   176  			}
   177  			out, err := e.render(tpls)
   178  			if err != nil {
   179  				t.Errorf("Failed to render %s: %s", tt, err)
   180  			}
   181  			if out["t"] != tt {
   182  				t.Errorf("Expected %q, got %q", tt, out["t"])
   183  			}
   184  			wg.Done()
   185  		}(i)
   186  	}
   187  	wg.Wait()
   188  }
   189  
   190  func TestParseErrors(t *testing.T) {
   191  	vals := chartutil.Values{"Values": map[string]interface{}{}}
   192  
   193  	tplsUndefinedFunction := map[string]renderable{
   194  		"undefined_function": {tpl: `{{foo}}`, vals: vals},
   195  	}
   196  	_, err := new(Engine).render(tplsUndefinedFunction)
   197  	if err == nil {
   198  		t.Fatalf("Expected failures while rendering: %s", err)
   199  	}
   200  	expected := `parse error at (undefined_function:1): function "foo" not defined`
   201  	if err.Error() != expected {
   202  		t.Errorf("Expected '%s', got %q", expected, err.Error())
   203  	}
   204  }
   205  
   206  func TestExecErrors(t *testing.T) {
   207  	vals := chartutil.Values{"Values": map[string]interface{}{}}
   208  
   209  	tplsMissingRequired := map[string]renderable{
   210  		"missing_required": {tpl: `{{required "foo is required" .Values.foo}}`, vals: vals},
   211  	}
   212  	_, err := new(Engine).render(tplsMissingRequired)
   213  	if err == nil {
   214  		t.Fatalf("Expected failures while rendering: %s", err)
   215  	}
   216  	expected := `execution error at (missing_required:1:2): foo is required`
   217  	if err.Error() != expected {
   218  		t.Errorf("Expected '%s', got %q", expected, err.Error())
   219  	}
   220  
   221  	tplsMissingRequired = map[string]renderable{
   222  		"missing_required_with_colons": {tpl: `{{required ":this: message: has many: colons:" .Values.foo}}`, vals: vals},
   223  	}
   224  	_, err = new(Engine).render(tplsMissingRequired)
   225  	if err == nil {
   226  		t.Fatalf("Expected failures while rendering: %s", err)
   227  	}
   228  	expected = `execution error at (missing_required_with_colons:1:2): :this: message: has many: colons:`
   229  	if err.Error() != expected {
   230  		t.Errorf("Expected '%s', got %q", expected, err.Error())
   231  	}
   232  
   233  	issue6044tpl := `{{ $someEmptyValue := "" }}
   234  {{ $myvar := "abc" }}
   235  {{- required (printf "%s: something is missing" $myvar) $someEmptyValue | repeat 0 }}`
   236  	tplsMissingRequired = map[string]renderable{
   237  		"issue6044": {tpl: issue6044tpl, vals: vals},
   238  	}
   239  	_, err = new(Engine).render(tplsMissingRequired)
   240  	if err == nil {
   241  		t.Fatalf("Expected failures while rendering: %s", err)
   242  	}
   243  	expected = `execution error at (issue6044:3:4): abc: something is missing`
   244  	if err.Error() != expected {
   245  		t.Errorf("Expected '%s', got %q", expected, err.Error())
   246  	}
   247  }
   248  
   249  func TestAllTemplates(t *testing.T) {
   250  	ch1 := &chart.Chart{
   251  		Metadata: &chart.Metadata{Name: "ch1"},
   252  		Templates: []*chart.File{
   253  			{Name: "templates/foo", Data: []byte("foo")},
   254  			{Name: "templates/bar", Data: []byte("bar")},
   255  		},
   256  	}
   257  	dep1 := &chart.Chart{
   258  		Metadata: &chart.Metadata{Name: "laboratory mice"},
   259  		Templates: []*chart.File{
   260  			{Name: "templates/pinky", Data: []byte("pinky")},
   261  			{Name: "templates/brain", Data: []byte("brain")},
   262  		},
   263  	}
   264  	ch1.AddDependency(dep1)
   265  
   266  	dep2 := &chart.Chart{
   267  		Metadata: &chart.Metadata{Name: "same thing we do every night"},
   268  		Templates: []*chart.File{
   269  			{Name: "templates/innermost", Data: []byte("innermost")},
   270  		},
   271  	}
   272  	dep1.AddDependency(dep2)
   273  
   274  	tpls := allTemplates(ch1, chartutil.Values{})
   275  	if len(tpls) != 5 {
   276  		t.Errorf("Expected 5 charts, got %d", len(tpls))
   277  	}
   278  }
   279  
   280  func TestRenderDependency(t *testing.T) {
   281  	deptpl := `{{define "myblock"}}World{{end}}`
   282  	toptpl := `Hello {{template "myblock"}}`
   283  	ch := &chart.Chart{
   284  		Metadata: &chart.Metadata{Name: "outerchart"},
   285  		Templates: []*chart.File{
   286  			{Name: "templates/outer", Data: []byte(toptpl)},
   287  		},
   288  	}
   289  	ch.AddDependency(&chart.Chart{
   290  		Metadata: &chart.Metadata{Name: "innerchart"},
   291  		Templates: []*chart.File{
   292  			{Name: "templates/inner", Data: []byte(deptpl)},
   293  		},
   294  	})
   295  
   296  	out, err := Render(ch, map[string]interface{}{})
   297  	if err != nil {
   298  		t.Fatalf("failed to render chart: %s", err)
   299  	}
   300  
   301  	if len(out) != 2 {
   302  		t.Errorf("Expected 2, got %d", len(out))
   303  	}
   304  
   305  	expect := "Hello World"
   306  	if out["outerchart/templates/outer"] != expect {
   307  		t.Errorf("Expected %q, got %q", expect, out["outer"])
   308  	}
   309  
   310  }
   311  
   312  func TestRenderNestedValues(t *testing.T) {
   313  	innerpath := "templates/inner.tpl"
   314  	outerpath := "templates/outer.tpl"
   315  	// Ensure namespacing rules are working.
   316  	deepestpath := "templates/inner.tpl"
   317  	checkrelease := "templates/release.tpl"
   318  
   319  	deepest := &chart.Chart{
   320  		Metadata: &chart.Metadata{Name: "deepest"},
   321  		Templates: []*chart.File{
   322  			{Name: deepestpath, Data: []byte(`And this same {{.Values.what}} that smiles {{.Values.global.when}}`)},
   323  			{Name: checkrelease, Data: []byte(`Tomorrow will be {{default "happy" .Release.Name }}`)},
   324  		},
   325  		Values: map[string]interface{}{"what": "milkshake"},
   326  	}
   327  
   328  	inner := &chart.Chart{
   329  		Metadata: &chart.Metadata{Name: "herrick"},
   330  		Templates: []*chart.File{
   331  			{Name: innerpath, Data: []byte(`Old {{.Values.who}} is still a-flyin'`)},
   332  		},
   333  		Values: map[string]interface{}{"who": "Robert"},
   334  	}
   335  	inner.AddDependency(deepest)
   336  
   337  	outer := &chart.Chart{
   338  		Metadata: &chart.Metadata{Name: "top"},
   339  		Templates: []*chart.File{
   340  			{Name: outerpath, Data: []byte(`Gather ye {{.Values.what}} while ye may`)},
   341  		},
   342  		Values: map[string]interface{}{
   343  			"what": "stinkweed",
   344  			"who":  "me",
   345  			"herrick": map[string]interface{}{
   346  				"who": "time",
   347  			},
   348  		},
   349  	}
   350  	outer.AddDependency(inner)
   351  
   352  	injValues := map[string]interface{}{
   353  		"what": "rosebuds",
   354  		"herrick": map[string]interface{}{
   355  			"deepest": map[string]interface{}{
   356  				"what": "flower",
   357  			},
   358  		},
   359  		"global": map[string]interface{}{
   360  			"when": "to-day",
   361  		},
   362  	}
   363  
   364  	tmp, err := chartutil.CoalesceValues(outer, injValues)
   365  	if err != nil {
   366  		t.Fatalf("Failed to coalesce values: %s", err)
   367  	}
   368  
   369  	inject := chartutil.Values{
   370  		"Values": tmp,
   371  		"Chart":  outer.Metadata,
   372  		"Release": chartutil.Values{
   373  			"Name": "dyin",
   374  		},
   375  	}
   376  
   377  	t.Logf("Calculated values: %v", inject)
   378  
   379  	out, err := Render(outer, inject)
   380  	if err != nil {
   381  		t.Fatalf("failed to render templates: %s", err)
   382  	}
   383  
   384  	fullouterpath := "top/" + outerpath
   385  	if out[fullouterpath] != "Gather ye rosebuds while ye may" {
   386  		t.Errorf("Unexpected outer: %q", out[fullouterpath])
   387  	}
   388  
   389  	fullinnerpath := "top/charts/herrick/" + innerpath
   390  	if out[fullinnerpath] != "Old time is still a-flyin'" {
   391  		t.Errorf("Unexpected inner: %q", out[fullinnerpath])
   392  	}
   393  
   394  	fulldeepestpath := "top/charts/herrick/charts/deepest/" + deepestpath
   395  	if out[fulldeepestpath] != "And this same flower that smiles to-day" {
   396  		t.Errorf("Unexpected deepest: %q", out[fulldeepestpath])
   397  	}
   398  
   399  	fullcheckrelease := "top/charts/herrick/charts/deepest/" + checkrelease
   400  	if out[fullcheckrelease] != "Tomorrow will be dyin" {
   401  		t.Errorf("Unexpected release: %q", out[fullcheckrelease])
   402  	}
   403  }
   404  
   405  func TestRenderBuiltinValues(t *testing.T) {
   406  	inner := &chart.Chart{
   407  		Metadata: &chart.Metadata{Name: "Latium"},
   408  		Templates: []*chart.File{
   409  			{Name: "templates/Lavinia", Data: []byte(`{{.Template.Name}}{{.Chart.Name}}{{.Release.Name}}`)},
   410  			{Name: "templates/From", Data: []byte(`{{.Files.author | printf "%s"}} {{.Files.Get "book/title.txt"}}`)},
   411  		},
   412  		Files: []*chart.File{
   413  			{Name: "author", Data: []byte("Virgil")},
   414  			{Name: "book/title.txt", Data: []byte("Aeneid")},
   415  		},
   416  	}
   417  
   418  	outer := &chart.Chart{
   419  		Metadata: &chart.Metadata{Name: "Troy"},
   420  		Templates: []*chart.File{
   421  			{Name: "templates/Aeneas", Data: []byte(`{{.Template.Name}}{{.Chart.Name}}{{.Release.Name}}`)},
   422  		},
   423  	}
   424  	outer.AddDependency(inner)
   425  
   426  	inject := chartutil.Values{
   427  		"Values": "",
   428  		"Chart":  outer.Metadata,
   429  		"Release": chartutil.Values{
   430  			"Name": "Aeneid",
   431  		},
   432  	}
   433  
   434  	t.Logf("Calculated values: %v", outer)
   435  
   436  	out, err := Render(outer, inject)
   437  	if err != nil {
   438  		t.Fatalf("failed to render templates: %s", err)
   439  	}
   440  
   441  	expects := map[string]string{
   442  		"Troy/charts/Latium/templates/Lavinia": "Troy/charts/Latium/templates/LaviniaLatiumAeneid",
   443  		"Troy/templates/Aeneas":                "Troy/templates/AeneasTroyAeneid",
   444  		"Troy/charts/Latium/templates/From":    "Virgil Aeneid",
   445  	}
   446  	for file, expect := range expects {
   447  		if out[file] != expect {
   448  			t.Errorf("Expected %q, got %q", expect, out[file])
   449  		}
   450  	}
   451  
   452  }
   453  
   454  func TestAlterFuncMap_include(t *testing.T) {
   455  	c := &chart.Chart{
   456  		Metadata: &chart.Metadata{Name: "conrad"},
   457  		Templates: []*chart.File{
   458  			{Name: "templates/quote", Data: []byte(`{{include "conrad/templates/_partial" . | indent 2}} dead.`)},
   459  			{Name: "templates/_partial", Data: []byte(`{{.Release.Name}} - he`)},
   460  		},
   461  	}
   462  
   463  	v := chartutil.Values{
   464  		"Values": "",
   465  		"Chart":  c.Metadata,
   466  		"Release": chartutil.Values{
   467  			"Name": "Mistah Kurtz",
   468  		},
   469  	}
   470  
   471  	out, err := Render(c, v)
   472  	if err != nil {
   473  		t.Fatal(err)
   474  	}
   475  
   476  	expect := "  Mistah Kurtz - he dead."
   477  	if got := out["conrad/templates/quote"]; got != expect {
   478  		t.Errorf("Expected %q, got %q (%v)", expect, got, out)
   479  	}
   480  }
   481  
   482  func TestAlterFuncMap_require(t *testing.T) {
   483  	c := &chart.Chart{
   484  		Metadata: &chart.Metadata{Name: "conan"},
   485  		Templates: []*chart.File{
   486  			{Name: "templates/quote", Data: []byte(`All your base are belong to {{ required "A valid 'who' is required" .Values.who }}`)},
   487  			{Name: "templates/bases", Data: []byte(`All {{ required "A valid 'bases' is required" .Values.bases }} of them!`)},
   488  		},
   489  	}
   490  
   491  	v := chartutil.Values{
   492  		"Values": chartutil.Values{
   493  			"who":   "us",
   494  			"bases": 2,
   495  		},
   496  		"Chart": c.Metadata,
   497  		"Release": chartutil.Values{
   498  			"Name": "That 90s meme",
   499  		},
   500  	}
   501  
   502  	out, err := Render(c, v)
   503  	if err != nil {
   504  		t.Fatal(err)
   505  	}
   506  
   507  	expectStr := "All your base are belong to us"
   508  	if gotStr := out["conan/templates/quote"]; gotStr != expectStr {
   509  		t.Errorf("Expected %q, got %q (%v)", expectStr, gotStr, out)
   510  	}
   511  	expectNum := "All 2 of them!"
   512  	if gotNum := out["conan/templates/bases"]; gotNum != expectNum {
   513  		t.Errorf("Expected %q, got %q (%v)", expectNum, gotNum, out)
   514  	}
   515  
   516  	// test required without passing in needed values with lint mode on
   517  	// verifies lint replaces required with an empty string (should not fail)
   518  	lintValues := chartutil.Values{
   519  		"Values": chartutil.Values{
   520  			"who": "us",
   521  		},
   522  		"Chart": c.Metadata,
   523  		"Release": chartutil.Values{
   524  			"Name": "That 90s meme",
   525  		},
   526  	}
   527  	var e Engine
   528  	e.LintMode = true
   529  	out, err = e.Render(c, lintValues)
   530  	if err != nil {
   531  		t.Fatal(err)
   532  	}
   533  
   534  	expectStr = "All your base are belong to us"
   535  	if gotStr := out["conan/templates/quote"]; gotStr != expectStr {
   536  		t.Errorf("Expected %q, got %q (%v)", expectStr, gotStr, out)
   537  	}
   538  	expectNum = "All  of them!"
   539  	if gotNum := out["conan/templates/bases"]; gotNum != expectNum {
   540  		t.Errorf("Expected %q, got %q (%v)", expectNum, gotNum, out)
   541  	}
   542  }
   543  
   544  func TestAlterFuncMap_tpl(t *testing.T) {
   545  	c := &chart.Chart{
   546  		Metadata: &chart.Metadata{Name: "TplFunction"},
   547  		Templates: []*chart.File{
   548  			{Name: "templates/base", Data: []byte(`Evaluate tpl {{tpl "Value: {{ .Values.value}}" .}}`)},
   549  		},
   550  	}
   551  
   552  	v := chartutil.Values{
   553  		"Values": chartutil.Values{
   554  			"value": "myvalue",
   555  		},
   556  		"Chart": c.Metadata,
   557  		"Release": chartutil.Values{
   558  			"Name": "TestRelease",
   559  		},
   560  	}
   561  
   562  	out, err := Render(c, v)
   563  	if err != nil {
   564  		t.Fatal(err)
   565  	}
   566  
   567  	expect := "Evaluate tpl Value: myvalue"
   568  	if got := out["TplFunction/templates/base"]; got != expect {
   569  		t.Errorf("Expected %q, got %q (%v)", expect, got, out)
   570  	}
   571  }
   572  
   573  func TestAlterFuncMap_tplfunc(t *testing.T) {
   574  	c := &chart.Chart{
   575  		Metadata: &chart.Metadata{Name: "TplFunction"},
   576  		Templates: []*chart.File{
   577  			{Name: "templates/base", Data: []byte(`Evaluate tpl {{tpl "Value: {{ .Values.value | quote}}" .}}`)},
   578  		},
   579  	}
   580  
   581  	v := chartutil.Values{
   582  		"Values": chartutil.Values{
   583  			"value": "myvalue",
   584  		},
   585  		"Chart": c.Metadata,
   586  		"Release": chartutil.Values{
   587  			"Name": "TestRelease",
   588  		},
   589  	}
   590  
   591  	out, err := Render(c, v)
   592  	if err != nil {
   593  		t.Fatal(err)
   594  	}
   595  
   596  	expect := "Evaluate tpl Value: \"myvalue\""
   597  	if got := out["TplFunction/templates/base"]; got != expect {
   598  		t.Errorf("Expected %q, got %q (%v)", expect, got, out)
   599  	}
   600  }
   601  
   602  func TestAlterFuncMap_tplinclude(t *testing.T) {
   603  	c := &chart.Chart{
   604  		Metadata: &chart.Metadata{Name: "TplFunction"},
   605  		Templates: []*chart.File{
   606  			{Name: "templates/base", Data: []byte(`{{ tpl "{{include ` + "`" + `TplFunction/templates/_partial` + "`" + ` .  | quote }}" .}}`)},
   607  			{Name: "templates/_partial", Data: []byte(`{{.Template.Name}}`)},
   608  		},
   609  	}
   610  	v := chartutil.Values{
   611  		"Values": chartutil.Values{
   612  			"value": "myvalue",
   613  		},
   614  		"Chart": c.Metadata,
   615  		"Release": chartutil.Values{
   616  			"Name": "TestRelease",
   617  		},
   618  	}
   619  
   620  	out, err := Render(c, v)
   621  	if err != nil {
   622  		t.Fatal(err)
   623  	}
   624  
   625  	expect := "\"TplFunction/templates/base\""
   626  	if got := out["TplFunction/templates/base"]; got != expect {
   627  		t.Errorf("Expected %q, got %q (%v)", expect, got, out)
   628  	}
   629  
   630  }