mirror of https://github.com/coder/coder.git
155 lines
4.6 KiB
Go
155 lines
4.6 KiB
Go
package tests // nolint: testpackage
|
|
|
|
import (
|
|
"bytes"
|
|
"flag"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"runtime"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"golang.org/x/xerrors"
|
|
)
|
|
|
|
// These tests run `helm template` with the values file specified in each test
|
|
// and compare the output to the contents of the corresponding golden file.
|
|
// All values and golden files are located in the `testdata` directory.
|
|
// To update golden files, run `go test . -update`.
|
|
|
|
// UpdateGoldenFiles is a flag that can be set to update golden files.
|
|
var UpdateGoldenFiles = flag.Bool("update", false, "Update golden files")
|
|
|
|
var TestCases = []TestCase{
|
|
{
|
|
name: "default_values",
|
|
expectedError: "",
|
|
},
|
|
{
|
|
name: "missing_values",
|
|
expectedError: `You must specify the coder.image.tag value if you're installing the Helm chart directly from Git.`,
|
|
},
|
|
{
|
|
name: "tls",
|
|
expectedError: "",
|
|
},
|
|
}
|
|
|
|
type TestCase struct {
|
|
name string // Name of the test case. This is used to control which values and golden file are used.
|
|
expectedError string // Expected error from running `helm template`.
|
|
}
|
|
|
|
func (tc TestCase) valuesFilePath() string {
|
|
return filepath.Join("./testdata", tc.name+".yaml")
|
|
}
|
|
|
|
func (tc TestCase) goldenFilePath() string {
|
|
return filepath.Join("./testdata", tc.name+".golden")
|
|
}
|
|
|
|
func TestRenderChart(t *testing.T) {
|
|
t.Parallel()
|
|
if *UpdateGoldenFiles {
|
|
t.Skip("Golden files are being updated. Skipping test.")
|
|
}
|
|
if _, runningInCI := os.LookupEnv("CI"); runningInCI {
|
|
switch runtime.GOOS {
|
|
case "windows", "darwin":
|
|
t.Skip("Skipping tests on Windows and macOS in CI")
|
|
}
|
|
}
|
|
|
|
// Ensure that Helm is available in $PATH
|
|
helmPath := lookupHelm(t)
|
|
for _, tc := range TestCases {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Ensure that the values file exists.
|
|
valuesFilePath := tc.valuesFilePath()
|
|
if _, err := os.Stat(valuesFilePath); os.IsNotExist(err) {
|
|
t.Fatalf("values file %q does not exist", valuesFilePath)
|
|
}
|
|
|
|
// Run helm template with the values file.
|
|
templateOutput, err := runHelmTemplate(t, helmPath, "..", valuesFilePath)
|
|
if tc.expectedError != "" {
|
|
require.Error(t, err, "helm template should have failed")
|
|
require.Contains(t, templateOutput, tc.expectedError, "helm template output should contain expected error")
|
|
} else {
|
|
require.NoError(t, err, "helm template should not have failed")
|
|
require.NotEmpty(t, templateOutput, "helm template output should not be empty")
|
|
goldenFilePath := tc.goldenFilePath()
|
|
goldenBytes, err := os.ReadFile(goldenFilePath)
|
|
require.NoError(t, err, "failed to read golden file %q", goldenFilePath)
|
|
|
|
// Remove carriage returns to make tests pass on Windows.
|
|
goldenBytes = bytes.Replace(goldenBytes, []byte("\r"), []byte(""), -1)
|
|
expected := string(goldenBytes)
|
|
|
|
require.NoError(t, err, "failed to load golden file %q")
|
|
require.Equal(t, expected, templateOutput)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUpdateGoldenFiles(t *testing.T) {
|
|
t.Parallel()
|
|
if !*UpdateGoldenFiles {
|
|
t.Skip("Run with -update to update golden files")
|
|
}
|
|
|
|
helmPath := lookupHelm(t)
|
|
for _, tc := range TestCases {
|
|
if tc.expectedError != "" {
|
|
t.Logf("skipping test case %q with render error", tc.name)
|
|
continue
|
|
}
|
|
|
|
valuesPath := tc.valuesFilePath()
|
|
templateOutput, err := runHelmTemplate(t, helmPath, "..", valuesPath)
|
|
|
|
require.NoError(t, err, "failed to run `helm template -f %q`", valuesPath)
|
|
|
|
goldenFilePath := tc.goldenFilePath()
|
|
err = os.WriteFile(goldenFilePath, []byte(templateOutput), 0o644) // nolint:gosec
|
|
require.NoError(t, err, "failed to write golden file %q", goldenFilePath)
|
|
}
|
|
t.Log("Golden files updated. Please review the changes and commit them.")
|
|
}
|
|
|
|
// runHelmTemplate runs helm template on the given chart with the given values and
|
|
// returns the raw output.
|
|
func runHelmTemplate(t testing.TB, helmPath, chartDir, valuesFilePath string) (string, error) {
|
|
// Ensure that valuesFilePath exists
|
|
if _, err := os.Stat(valuesFilePath); err != nil {
|
|
return "", xerrors.Errorf("values file %q does not exist: %w", valuesFilePath, err)
|
|
}
|
|
|
|
cmd := exec.Command(helmPath, "template", chartDir, "-f", valuesFilePath, "--namespace", "default")
|
|
t.Logf("exec command: %v", cmd.Args)
|
|
out, err := cmd.CombinedOutput()
|
|
return string(out), err
|
|
}
|
|
|
|
// lookupHelm ensures that Helm is available in $PATH and returns the path to the
|
|
// Helm executable.
|
|
func lookupHelm(t testing.TB) string {
|
|
helmPath, err := exec.LookPath("helm")
|
|
if err != nil {
|
|
t.Fatalf("helm not found in $PATH: %v", err)
|
|
return ""
|
|
}
|
|
t.Logf("Using helm at %q", helmPath)
|
|
return helmPath
|
|
}
|
|
|
|
func TestMain(m *testing.M) {
|
|
flag.Parse()
|
|
os.Exit(m.Run())
|
|
}
|