mirror of
https://github.com/helm/helm.git
synced 2026-03-21 18:10:33 -04:00
This provides support for "global" variables. It does this by declaring "global" to be a special namespace. It then copies this namespace into every subchart, coalescing it into any "global" namespace found there. The net result is that if "global.foo" is set in the YAML file, it will be available to every chart/subchart as ".global.foo" regardless of where that chart is in the subchart tree.
268 lines
6.1 KiB
Go
268 lines
6.1 KiB
Go
package engine
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"testing"
|
|
|
|
"k8s.io/helm/pkg/chartutil"
|
|
"k8s.io/helm/pkg/proto/hapi/chart"
|
|
)
|
|
|
|
func TestEngine(t *testing.T) {
|
|
e := New()
|
|
|
|
// Forbidden because they allow access to the host OS.
|
|
forbidden := []string{"env", "expandenv"}
|
|
for _, f := range forbidden {
|
|
if _, ok := e.FuncMap[f]; ok {
|
|
t.Errorf("Forbidden function %s exists in FuncMap.", f)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRender(t *testing.T) {
|
|
c := &chart.Chart{
|
|
Metadata: &chart.Metadata{
|
|
Name: "moby",
|
|
Version: "1.2.3",
|
|
},
|
|
Templates: []*chart.Template{
|
|
{Name: "test1", Data: []byte("{{.outer | title }} {{.inner | title}}")},
|
|
{Name: "test2", Data: []byte("{{.global.callme | lower }}")},
|
|
},
|
|
Values: &chart.Config{
|
|
Raw: "outer: DEFAULT\ninner: DEFAULT",
|
|
},
|
|
}
|
|
|
|
vals := &chart.Config{
|
|
Raw: "outer: BAD\ninner: inn",
|
|
}
|
|
|
|
overrides := map[string]interface{}{
|
|
"outer": "spouter",
|
|
"global": map[string]interface{}{
|
|
"callme": "Ishmael",
|
|
},
|
|
}
|
|
|
|
e := New()
|
|
v, err := chartutil.CoalesceValues(c, vals, overrides)
|
|
if err != nil {
|
|
t.Fatalf("Failed to coalesce values: %s", err)
|
|
}
|
|
out, err := e.Render(c, v)
|
|
if err != nil {
|
|
t.Errorf("Failed to render templates: %s", err)
|
|
}
|
|
|
|
expect := "Spouter Inn"
|
|
if out["test1"] != expect {
|
|
t.Errorf("Expected %q, got %q", expect, out["test1"])
|
|
}
|
|
|
|
expect = "ishmael"
|
|
if out["test2"] != expect {
|
|
t.Errorf("Expected %q, got %q", expect, out["test2"])
|
|
}
|
|
|
|
if _, err := e.Render(c, v); err != nil {
|
|
t.Errorf("Unexpected error: %s", err)
|
|
}
|
|
}
|
|
|
|
func TestRenderInternals(t *testing.T) {
|
|
// Test the internals of the rendering tool.
|
|
e := New()
|
|
|
|
vals := chartutil.Values{"Name": "one", "Value": "two"}
|
|
tpls := map[string]renderable{
|
|
"one": {tpl: `Hello {{title .Name}}`, vals: vals},
|
|
"two": {tpl: `Goodbye {{upper .Value}}`, vals: vals},
|
|
// Test whether a template can reliably reference another template
|
|
// without regard for ordering.
|
|
"three": {tpl: `{{template "two" dict "Value" "three"}}`, vals: vals},
|
|
}
|
|
|
|
out, err := e.render(tpls)
|
|
if err != nil {
|
|
t.Fatalf("Failed template rendering: %s", err)
|
|
}
|
|
|
|
if len(out) != 3 {
|
|
t.Fatalf("Expected 3 templates, got %d", len(out))
|
|
}
|
|
|
|
if out["one"] != "Hello One" {
|
|
t.Errorf("Expected 'Hello One', got %q", out["one"])
|
|
}
|
|
|
|
if out["two"] != "Goodbye TWO" {
|
|
t.Errorf("Expected 'Goodbye TWO'. got %q", out["two"])
|
|
}
|
|
|
|
if out["three"] != "Goodbye THREE" {
|
|
t.Errorf("Expected 'Goodbye THREE'. got %q", out["two"])
|
|
}
|
|
}
|
|
|
|
func TestParallelRenderInternals(t *testing.T) {
|
|
// Make sure that we can use one Engine to run parallel template renders.
|
|
e := New()
|
|
var wg sync.WaitGroup
|
|
for i := 0; i < 20; i++ {
|
|
wg.Add(1)
|
|
go func(i int) {
|
|
fname := "my/file/name"
|
|
tt := fmt.Sprintf("expect-%d", i)
|
|
v := chartutil.Values{"val": tt}
|
|
tpls := map[string]renderable{fname: {tpl: `{{.val}}`, vals: v}}
|
|
out, err := e.render(tpls)
|
|
if err != nil {
|
|
t.Errorf("Failed to render %s: %s", tt, err)
|
|
}
|
|
if out[fname] != tt {
|
|
t.Errorf("Expected %q, got %q", tt, out[fname])
|
|
}
|
|
wg.Done()
|
|
}(i)
|
|
}
|
|
wg.Wait()
|
|
}
|
|
|
|
func TestAllTemplates(t *testing.T) {
|
|
ch1 := &chart.Chart{
|
|
Templates: []*chart.Template{
|
|
{Name: "foo", Data: []byte("foo")},
|
|
{Name: "bar", Data: []byte("bar")},
|
|
},
|
|
Dependencies: []*chart.Chart{
|
|
{
|
|
Templates: []*chart.Template{
|
|
{Name: "pinky", Data: []byte("pinky")},
|
|
{Name: "brain", Data: []byte("brain")},
|
|
},
|
|
Dependencies: []*chart.Chart{
|
|
{Templates: []*chart.Template{
|
|
{Name: "innermost", Data: []byte("innermost")},
|
|
}},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
var v chartutil.Values
|
|
tpls := allTemplates(ch1, v)
|
|
if len(tpls) != 5 {
|
|
t.Errorf("Expected 5 charts, got %d", len(tpls))
|
|
}
|
|
}
|
|
|
|
func TestRenderDependency(t *testing.T) {
|
|
e := New()
|
|
deptpl := `{{define "myblock"}}World{{end}}`
|
|
toptpl := `Hello {{template "myblock"}}`
|
|
ch := &chart.Chart{
|
|
Templates: []*chart.Template{
|
|
{Name: "outer", Data: []byte(toptpl)},
|
|
},
|
|
Dependencies: []*chart.Chart{
|
|
{
|
|
Templates: []*chart.Template{
|
|
{Name: "inner", Data: []byte(deptpl)},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
out, err := e.Render(ch, map[string]interface{}{})
|
|
|
|
if err != nil {
|
|
t.Fatalf("failed to render chart: %s", err)
|
|
}
|
|
|
|
if len(out) != 2 {
|
|
t.Errorf("Expected 2, got %d", len(out))
|
|
}
|
|
|
|
expect := "Hello World"
|
|
if out["outer"] != expect {
|
|
t.Errorf("Expected %q, got %q", expect, out["outer"])
|
|
}
|
|
|
|
}
|
|
|
|
func TestRenderNestedValues(t *testing.T) {
|
|
e := New()
|
|
|
|
innerpath := "charts/inner/templates/inner.tpl"
|
|
outerpath := "templates/outer.tpl"
|
|
deepestpath := "charts/inner/charts/deepest/templates/deepest.tpl"
|
|
|
|
deepest := &chart.Chart{
|
|
Metadata: &chart.Metadata{Name: "deepest"},
|
|
Templates: []*chart.Template{
|
|
{Name: deepestpath, Data: []byte(`And this same {{.what}} that smiles {{.global.when}}`)},
|
|
},
|
|
Values: &chart.Config{Raw: `what: "milkshake"`},
|
|
}
|
|
|
|
inner := &chart.Chart{
|
|
Metadata: &chart.Metadata{Name: "herrick"},
|
|
Templates: []*chart.Template{
|
|
{Name: innerpath, Data: []byte(`Old {{.who}} is still a-flyin'`)},
|
|
},
|
|
Values: &chart.Config{Raw: `who: "Robert"`},
|
|
Dependencies: []*chart.Chart{deepest},
|
|
}
|
|
|
|
outer := &chart.Chart{
|
|
Metadata: &chart.Metadata{Name: "top"},
|
|
Templates: []*chart.Template{
|
|
{Name: outerpath, Data: []byte(`Gather ye {{.what}} while ye may`)},
|
|
},
|
|
Values: &chart.Config{
|
|
Raw: `
|
|
what: stinkweed
|
|
who: me
|
|
herrick:
|
|
who: time`,
|
|
},
|
|
Dependencies: []*chart.Chart{inner},
|
|
}
|
|
|
|
injValues := chart.Config{
|
|
Raw: `
|
|
what: rosebuds
|
|
herrick:
|
|
deepest:
|
|
what: flower
|
|
global:
|
|
when: to-day`,
|
|
}
|
|
|
|
inject, err := chartutil.CoalesceValues(outer, &injValues, map[string]interface{}{})
|
|
if err != nil {
|
|
t.Fatalf("Failed to coalesce values: %s", err)
|
|
}
|
|
|
|
t.Logf("Calculated values: %v", inject)
|
|
|
|
out, err := e.Render(outer, inject)
|
|
if err != nil {
|
|
t.Fatalf("failed to render templates: %s", err)
|
|
}
|
|
|
|
if out[outerpath] != "Gather ye rosebuds while ye may" {
|
|
t.Errorf("Unexpected outer: %q", out[outerpath])
|
|
}
|
|
|
|
if out[innerpath] != "Old time is still a-flyin'" {
|
|
t.Errorf("Unexpected inner: %q", out[innerpath])
|
|
}
|
|
|
|
if out[deepestpath] != "And this same flower that smiles to-day" {
|
|
t.Errorf("Unexpected deepest: %q", out[deepestpath])
|
|
}
|
|
}
|