helmfile/main_test.go

257 lines
5.9 KiB
Go

package main
import (
"fmt"
"os"
"path/filepath"
"strings"
"testing"
"github.com/roboll/helmfile/helmexec"
"github.com/roboll/helmfile/state"
"gopkg.in/yaml.v2"
)
func makeRenderer(readFile func(string) ([]byte, error), env string) *twoPassRenderer {
return &twoPassRenderer{
reader: readFile,
env: env,
namespace: "namespace",
filename: "",
logger: helmexec.NewLogger(os.Stdout, "debug"),
abs: filepath.Abs,
}
}
func TestReadFromYaml_MakeEnvironmentHasNoSideEffects(t *testing.T) {
yamlContent := []byte(`
environments:
staging:
values:
- default/values.yaml
production:
releases:
- name: {{ readFile "other/default/values.yaml" }}
chart: mychart1
`)
fileReaderCalls := 0
// make a reader that returns a simulated context
fileReader := func(filename string) ([]byte, error) {
expectedFilename := filepath.Clean("default/values.yaml")
if !strings.HasSuffix(filename, expectedFilename) {
return nil, fmt.Errorf("unexpected filename: expected=%s, actual=%s", expectedFilename, filename)
}
fileReaderCalls++
if fileReaderCalls == 2 {
return []byte("SecondPass"), nil
}
return []byte(""), nil
}
r := makeRenderer(fileReader, "staging")
yamlBuf, err := r.renderTemplate(yamlContent)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
var state state.HelmState
err = yaml.Unmarshal(yamlBuf.Bytes(), &state)
if fileReaderCalls > 2 {
t.Error("reader should be called only twice")
}
if state.Releases[0].Name != "SecondPass" {
t.Errorf("release name should have ben set as SecondPass")
}
}
func TestReadFromYaml_RenderTemplate(t *testing.T) {
defaultValuesYaml := []byte(`
releaseName: "hello"
conditionalReleaseTag: "yes"
`)
yamlContent := []byte(`
environments:
staging:
values:
- default/values.yaml
production:
releases:
- name: {{ .Environment.Values.releaseName }}
chart: mychart1
{{ if (eq .Environment.Values.conditionalReleaseTag "yes") }}
- name: conditionalRelease
{{ end }}
`)
// make a reader that returns a simulated context
fileReader := func(filename string) ([]byte, error) {
expectedFilename := filepath.Clean("default/values.yaml")
if !strings.HasSuffix(filename, expectedFilename) {
return nil, fmt.Errorf("unexpected filename: expected=%s, actual=%s", expectedFilename, filename)
}
return defaultValuesYaml, nil
}
r := makeRenderer(fileReader, "staging")
// test the double rendering
yamlBuf, err := r.renderTemplate(yamlContent)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
var state state.HelmState
err = yaml.Unmarshal(yamlBuf.Bytes(), &state)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if len(state.Releases) != 2 {
t.Fatal("there should be 2 releases")
}
if state.Releases[0].Name != "hello" {
t.Errorf("release name should be hello")
}
if state.Releases[1].Name != "conditionalRelease" {
t.Error("conditional release should have been present")
}
}
func TestReadFromYaml_RenderTemplateWithValuesReferenceError(t *testing.T) {
defaultValuesYaml := []byte("")
yamlContent := []byte(`
environments:
staging:
values:
- default/values.yaml
production:
{{ if (eq .Environment.Values.releaseName "a") }} # line 8
releases:
- name: a
chart: mychart1
{{ end }}
`)
// make a reader that returns a simulated context
fileReader := func(filename string) ([]byte, error) {
return defaultValuesYaml, nil
}
r := makeRenderer(fileReader, "staging")
// test the double rendering
_, err := r.renderTemplate(yamlContent)
if !strings.Contains(err.Error(), "stringTemplate:8") {
t.Fatalf("error should contain a stringTemplate error (reference to unknow key) %v", err)
}
}
// This test shows that a gotmpl reference will get rendered correctly
// even if the pre-render disables the readFile and exec functions.
// This does not apply to .gotmpl files, which is a nice side-effect.
func TestReadFromYaml_RenderTemplateWithGotmpl(t *testing.T) {
defaultValuesYamlGotmpl := []byte(`
releaseName: {{ readFile "nonIgnoredFile" }}
`)
yamlContent := []byte(`
environments:
staging:
values:
- values.yaml.gotmpl
production:
{{ if (eq .Environment.Values.releaseName "release-a") }} # line 8
releases:
- name: a
chart: mychart1
{{ end }}
`)
fileReader := func(filename string) ([]byte, error) {
if strings.HasSuffix(filename, "nonIgnoredFile") {
return []byte("release-a"), nil
}
return defaultValuesYamlGotmpl, nil
}
r := makeRenderer(fileReader, "staging")
rendered, _ := r.renderTemplate(yamlContent)
var state state.HelmState
yaml.Unmarshal(rendered.Bytes(), &state)
if len(state.Releases) != 1 {
t.Fatal("there should be 1 release")
}
if state.Releases[0].Name != "a" {
t.Fatal("release should have been declared")
}
}
func TestReadFromYaml_RenderTemplateWithNamespace(t *testing.T) {
defaultValuesYaml := []byte(``)
yamlContent := []byte(`releases:
- name: {{ .Namespace }}-myrelease
chart: mychart
`)
// make a reader that returns a simulated context
fileReader := func(filename string) ([]byte, error) {
return defaultValuesYaml, nil
}
r := makeRenderer(fileReader, "staging")
yamlBuf, err := r.renderTemplate(yamlContent)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
var state state.HelmState
err = yaml.Unmarshal(yamlBuf.Bytes(), &state)
if state.Releases[0].Name != "namespace-myrelease" {
t.Errorf("release name should be namespace-myrelease")
}
}
func TestReadFromYaml_HelfileShouldBeResilentToTemplateErrors(t *testing.T) {
yamlContent := []byte(`environments:
staging:
production:
releases:
{{ if (eq .Environment.Name "production" }} # notice syntax error: unclosed left paren
- name: prod-myrelease
{{ else }}
- name: myapp
{{ end }}
chart: mychart
`)
fileReader := func(filename string) ([]byte, error) {
return yamlContent, nil
}
r := makeRenderer(fileReader, "staging")
_, err := r.renderTemplate(yamlContent)
if err == nil {
t.Fatalf("wanted error, none returned")
}
}