package engine import ( "fmt" "sync" "testing" chartutil "github.com/kubernetes/helm/pkg/chart" "github.com/kubernetes/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}}")}, }, Values: &chart.Config{ Raw: `outer = "DEFAULT"\ninner= "DEFAULT"\n`, }, } vals := &chart.Config{ Raw: `outer = "BAD" inner= "inn"`, } overrides := map[string]interface{}{ "outer": "spouter", } e := New() out, err := e.Render(c, vals, overrides) 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"]) } } 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, nil, 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 to-day`)}, }, 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" [herrick] who = "time" `}, Dependencies: []*chart.Chart{inner}, } inject := chart.Config{ Raw: ` what = "rosebuds" [herrick.deepest] what = "flower"`, } out, err := e.Render(outer, &inject, map[string]interface{}{}) 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]) } } func TestCoalesceTables(t *testing.T) { dst := map[string]interface{}{ "name": "Ishmael", "address": map[string]interface{}{ "street": "123 Spouter Inn Ct.", "city": "Nantucket", }, "details": map[string]interface{}{ "friends": []string{"Tashtego"}, }, "boat": "pequod", } src := map[string]interface{}{ "occupation": "whaler", "address": map[string]interface{}{ "state": "MA", "street": "234 Spouter Inn Ct.", }, "details": "empty", "boat": map[string]interface{}{ "mast": true, }, } coalesceTables(dst, src) if dst["name"] != "Ishmael" { t.Errorf("Unexpected name: %s", dst["name"]) } if dst["occupation"] != "whaler" { t.Errorf("Unexpected occupation: %s", dst["occupation"]) } addr, ok := dst["address"].(map[string]interface{}) if !ok { t.Fatal("Address went away.") } if addr["street"].(string) != "234 Spouter Inn Ct." { t.Errorf("Unexpected address: %v", addr["street"]) } if addr["city"].(string) != "Nantucket" { t.Errorf("Unexpected city: %v", addr["city"]) } if addr["state"].(string) != "MA" { t.Errorf("Unexpected state: %v", addr["state"]) } if det, ok := dst["details"].(map[string]interface{}); !ok { t.Fatalf("Details is the wrong type: %v", dst["details"]) } else if _, ok := det["friends"]; !ok { t.Error("Could not find your friends. Maybe you don't have any. :-(") } if dst["boat"].(string) != "pequod" { t.Errorf("Expected boat string, got %v", dst["boat"]) } }