Merge pull request #4071 from adamreese/dev-v3-template

ref(cmd): test template cmd using golden files
pull/4079/head
Adam Reese 6 years ago committed by GitHub
commit 03dacfe4f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -30,6 +30,7 @@ import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
"k8s.io/helm/cmd/helm/require"
"k8s.io/helm/pkg/chartutil"
"k8s.io/helm/pkg/engine"
"k8s.io/helm/pkg/hapi/release"
@ -80,10 +81,8 @@ func newTemplateCmd(out io.Writer) *cobra.Command {
Use: "template CHART",
Short: fmt.Sprintf("locally render templates"),
Long: templateDesc,
Args: require.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return errors.New("chart is required")
}
// verify chart path exists
if _, err := os.Stat(args[0]); err == nil {
if o.chartPath, err = filepath.Abs(args[0]); err != nil {
@ -135,8 +134,7 @@ func (o *templateOptions) run(out io.Writer) error {
// verify that output-dir exists if provided
if o.outputDir != "" {
_, err = os.Stat(o.outputDir)
if os.IsNotExist(err) {
if _, err := os.Stat(o.outputDir); os.IsNotExist(err) {
return errors.Errorf("output-dir '%s' does not exist", o.outputDir)
}
}
@ -174,12 +172,10 @@ func (o *templateOptions) run(out io.Writer) error {
Namespace: getNamespace(),
}
err = chartutil.ProcessRequirementsEnabled(c, config)
if err != nil {
if err := chartutil.ProcessRequirementsEnabled(c, config); err != nil {
return err
}
err = chartutil.ProcessRequirementsImportValues(c)
if err != nil {
if err := chartutil.ProcessRequirementsImportValues(c); err != nil {
return err
}
@ -207,10 +203,11 @@ func (o *templateOptions) run(out io.Writer) error {
}
rendered, err := renderer.Render(c, vals)
listManifests := []tiller.Manifest{}
if err != nil {
return err
}
listManifests := []tiller.Manifest{}
// extract kind and name
re := regexp.MustCompile("kind:(.*)\n")
for k, v := range rendered {
@ -235,6 +232,7 @@ func (o *templateOptions) run(out io.Writer) error {
}
return false
}
if settings.Debug {
rel := &release.Release{
Name: o.releaseName,
@ -247,41 +245,34 @@ func (o *templateOptions) run(out io.Writer) error {
}
for _, m := range tiller.SortByKind(listManifests) {
if len(o.renderFiles) > 0 && !in(m.Name, rf) {
continue
}
data := m.Content
b := filepath.Base(m.Name)
if !o.showNotes && b == "NOTES.txt" {
switch {
case len(o.renderFiles) > 0 && !in(m.Name, rf):
continue
}
if strings.HasPrefix(b, "_") {
case !o.showNotes && b == "NOTES.txt":
continue
}
if o.outputDir != "" {
case strings.HasPrefix(b, "_"):
continue
case whitespaceRegex.MatchString(m.Content):
// blank template after execution
if whitespaceRegex.MatchString(data) {
continue
}
err = writeToFile(o.outputDir, m.Name, data)
if err != nil {
continue
case o.outputDir != "":
if err := writeToFile(out, o.outputDir, m.Name, m.Content); err != nil {
return err
}
continue
default:
fmt.Fprintf(out, "---\n# Source: %s\n", m.Name)
fmt.Fprintln(out, m.Content)
}
fmt.Printf("---\n# Source: %s\n", m.Name)
fmt.Println(data)
}
return nil
}
// write the <data> to <output-dir>/<name>
func writeToFile(outputDir, name, data string) error {
func writeToFile(out io.Writer, outputDir, name, data string) error {
outfileName := strings.Join([]string{outputDir, name}, string(filepath.Separator))
err := ensureDirectoryForFile(outfileName)
if err != nil {
if err := ensureDirectoryForFile(outfileName); err != nil {
return err
}
@ -292,21 +283,18 @@ func writeToFile(outputDir, name, data string) error {
defer f.Close()
_, err = f.WriteString(fmt.Sprintf("##---\n# Source: %s\n%s", name, data))
if err != nil {
if _, err = f.WriteString(fmt.Sprintf("##---\n# Source: %s\n%s", name, data)); err != nil {
return err
}
fmt.Printf("wrote %s\n", outfileName)
fmt.Fprintf(out, "wrote %s\n", outfileName)
return nil
}
// check if the directory exists to create file. creates if don't exists
func ensureDirectoryForFile(file string) error {
baseDir := path.Dir(file)
_, err := os.Stat(baseDir)
if err != nil && !os.IsNotExist(err) {
if _, err := os.Stat(baseDir); err != nil && !os.IsNotExist(err) {
return err
}

@ -17,13 +17,7 @@ limitations under the License.
package main
import (
"bufio"
"bytes"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"testing"
)
@ -34,127 +28,53 @@ func TestTemplateCmd(t *testing.T) {
if err != nil {
t.Fatal(err)
}
tests := []struct {
name string
desc string
args []string
expectKey string
expectValue string
}{
tests := []cmdTestCase{
{
name: "check_name",
desc: "check for a known name in chart",
args: []string{chartPath},
expectKey: "subchart1/templates/service.yaml",
expectValue: "protocol: TCP\n name: nginx",
name: "check name",
cmd: "template " + chartPath,
golden: "output/template.txt",
},
{
name: "check_set_name",
desc: "verify --set values exist",
args: []string{chartPath, "-x", "templates/service.yaml", "--set", "service.name=apache"},
expectKey: "subchart1/templates/service.yaml",
expectValue: "protocol: TCP\n name: apache",
name: "check set name",
cmd: "template -x templates/service.yaml --set service.name=apache " + chartPath,
golden: "output/template-set.txt",
},
{
name: "check_execute",
desc: "verify --execute single template",
args: []string{chartPath, "-x", "templates/service.yaml", "--set", "service.name=apache"},
expectKey: "subchart1/templates/service.yaml",
expectValue: "protocol: TCP\n name: apache",
name: "check execute absolute",
cmd: "template -x " + absChartPath + "/templates/service.yaml --set service.name=apache " + chartPath,
golden: "output/template-absolute.txt",
},
{
name: "check_execute_absolute",
desc: "verify --execute single template",
args: []string{chartPath, "-x", absChartPath + "/" + "templates/service.yaml", "--set", "service.name=apache"},
expectKey: "subchart1/templates/service.yaml",
expectValue: "protocol: TCP\n name: apache",
name: "check release name",
cmd: "template --name test " + chartPath,
golden: "output/template-name.txt",
},
{
name: "check_release_name",
desc: "verify --release exists",
args: []string{chartPath, "--name", "test"},
expectKey: "subchart1/templates/service.yaml",
expectValue: "release-name: \"test\"",
name: "check notes",
cmd: "template --notes " + chartPath,
golden: "output/template-notes.txt",
},
{
name: "check_notes",
desc: "verify --notes shows notes",
args: []string{chartPath, "--notes", "true"},
expectKey: "subchart1/templates/NOTES.txt",
expectValue: "Sample notes for subchart1",
name: "check values files",
cmd: "template --values " + chartPath + "/charts/subchartA/values.yaml " + chartPath,
golden: "output/template-values-files.txt",
},
{
name: "check_values_files",
desc: "verify --values files values exist",
args: []string{chartPath, "--values", chartPath + "/charts/subchartA/values.yaml"},
expectKey: "subchart1/templates/service.yaml",
expectValue: "name: apache",
name: "check name template",
cmd: `template --name-template='foobar-{{ b64enc "abc" }}-baz' ` + chartPath,
golden: "output/template-name-template.txt",
},
{
name: "check_name_template",
desc: "verify --name-template result exists",
args: []string{chartPath, "--name-template", "foobar-{{ b64enc \"abc\" }}-baz"},
expectKey: "subchart1/templates/service.yaml",
expectValue: "release-name: \"foobar-YWJj-baz\"",
name: "check kube version",
cmd: "template --kube-version 1.6 " + chartPath,
golden: "output/template-kube-version.txt",
},
{
name: "check_kube_version",
desc: "verify --kube-version overrides the kubernetes version",
args: []string{chartPath, "--kube-version", "1.6"},
expectKey: "subchart1/templates/service.yaml",
expectValue: "kube-version/major: \"1\"\n kube-version/minor: \"6\"\n kube-version/gitversion: \"v1.6.0\"",
name: "check no args",
cmd: "template",
wantError: true,
golden: "output/template-no-args.txt",
},
}
var buf bytes.Buffer
for _, tt := range tests {
t.Run(tt.name, func(T *testing.T) {
// capture stdout
old := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
// execute template command
out := bytes.NewBuffer(nil)
cmd := newTemplateCmd(out)
cmd.SetArgs(tt.args)
err := cmd.Execute()
if err != nil {
t.Errorf("expected: %v, got %v", tt.expectValue, err)
}
// restore stdout
w.Close()
os.Stdout = old
var b bytes.Buffer
io.Copy(&b, r)
r.Close()
// scan yaml into map[<path>]yaml
scanner := bufio.NewScanner(&b)
next := false
lastKey := ""
m := map[string]string{}
for scanner.Scan() {
if scanner.Text() == "---" {
next = true
} else if next {
// remove '# Source: '
head := "# Source: "
lastKey = scanner.Text()[len(head):]
next = false
} else {
m[lastKey] = m[lastKey] + scanner.Text() + "\n"
}
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "reading standard input:", err)
}
if v, ok := m[tt.expectKey]; ok {
if !strings.Contains(v, tt.expectValue) {
t.Errorf("failed to match expected value %s in %s", tt.expectValue, v)
}
} else {
t.Errorf("could not find key %s", tt.expectKey)
}
buf.Reset()
})
}
runTestCmd(t, tests)
}

@ -0,0 +1,23 @@
---
# Source: subchart1/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subchart1
labels:
chart: "subchart1-0.1.0"
namespace: "default"
release-name: "RELEASE-NAME"
kube-version/major: "1"
kube-version/minor: "9"
kube-version/gitversion: "v1.9.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: apache
selector:
app: subchart1

@ -0,0 +1,59 @@
---
# Source: subchart1/charts/subcharta/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subcharta
labels:
chart: "subcharta-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: apache
selector:
app: subcharta
---
# Source: subchart1/charts/subchartb/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subchartb
labels:
chart: "subchartb-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nginx
selector:
app: subchartb
---
# Source: subchart1/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subchart1
labels:
chart: "subchart1-0.1.0"
namespace: "default"
release-name: "RELEASE-NAME"
kube-version/major: "1"
kube-version/minor: "6"
kube-version/gitversion: "v1.6.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nginx
selector:
app: subchart1

@ -0,0 +1,59 @@
---
# Source: subchart1/charts/subcharta/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subcharta
labels:
chart: "subcharta-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: apache
selector:
app: subcharta
---
# Source: subchart1/charts/subchartb/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subchartb
labels:
chart: "subchartb-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nginx
selector:
app: subchartb
---
# Source: subchart1/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subchart1
labels:
chart: "subchart1-0.1.0"
namespace: "default"
release-name: "foobar-YWJj-baz"
kube-version/major: "1"
kube-version/minor: "9"
kube-version/gitversion: "v1.9.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nginx
selector:
app: subchart1

@ -0,0 +1,59 @@
---
# Source: subchart1/charts/subcharta/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subcharta
labels:
chart: "subcharta-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: apache
selector:
app: subcharta
---
# Source: subchart1/charts/subchartb/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subchartb
labels:
chart: "subchartb-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nginx
selector:
app: subchartb
---
# Source: subchart1/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subchart1
labels:
chart: "subchart1-0.1.0"
namespace: "default"
release-name: "test"
kube-version/major: "1"
kube-version/minor: "9"
kube-version/gitversion: "v1.9.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nginx
selector:
app: subchart1

@ -0,0 +1,3 @@
Error: "helm template" requires 1 argument
Usage: helm template CHART [flags]

@ -0,0 +1,62 @@
---
# Source: subchart1/charts/subcharta/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subcharta
labels:
chart: "subcharta-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: apache
selector:
app: subcharta
---
# Source: subchart1/charts/subchartb/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subchartb
labels:
chart: "subchartb-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nginx
selector:
app: subchartb
---
# Source: subchart1/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subchart1
labels:
chart: "subchart1-0.1.0"
namespace: "default"
release-name: "RELEASE-NAME"
kube-version/major: "1"
kube-version/minor: "9"
kube-version/gitversion: "v1.9.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nginx
selector:
app: subchart1
---
# Source: subchart1/templates/NOTES.txt
Sample notes for subchart1

@ -0,0 +1,23 @@
---
# Source: subchart1/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subchart1
labels:
chart: "subchart1-0.1.0"
namespace: "default"
release-name: "RELEASE-NAME"
kube-version/major: "1"
kube-version/minor: "9"
kube-version/gitversion: "v1.9.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: apache
selector:
app: subchart1

@ -0,0 +1,59 @@
---
# Source: subchart1/charts/subcharta/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subcharta
labels:
chart: "subcharta-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: apache
selector:
app: subcharta
---
# Source: subchart1/charts/subchartb/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subchartb
labels:
chart: "subchartb-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nginx
selector:
app: subchartb
---
# Source: subchart1/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subchart1
labels:
chart: "subchart1-0.1.0"
namespace: "default"
release-name: "RELEASE-NAME"
kube-version/major: "1"
kube-version/minor: "9"
kube-version/gitversion: "v1.9.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: apache
selector:
app: subchart1

@ -0,0 +1,59 @@
---
# Source: subchart1/charts/subcharta/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subcharta
labels:
chart: "subcharta-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: apache
selector:
app: subcharta
---
# Source: subchart1/charts/subchartb/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subchartb
labels:
chart: "subchartb-0.1.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nginx
selector:
app: subchartb
---
# Source: subchart1/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: subchart1
labels:
chart: "subchart1-0.1.0"
namespace: "default"
release-name: "RELEASE-NAME"
kube-version/major: "1"
kube-version/minor: "9"
kube-version/gitversion: "v1.9.0"
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 80
protocol: TCP
name: nginx
selector:
app: subchart1

@ -71,7 +71,7 @@ func compare(actual []byte, filename string) error {
return errors.Wrapf(err, "unable to read testdata %s", filename)
}
if !bytes.Equal(expected, actual) {
return errors.Errorf("does not match golden file %s\n\nWANT:\n%q\n\nGOT:\n%q\n", filename, expected, actual)
return errors.Errorf("does not match golden file %s\n\nWANT:\n%s\n\nGOT:\n%s\n", filename, expected, actual)
}
return nil
}

Loading…
Cancel
Save