Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(lint): Tests for lint flag --full-path #12923

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/helm/lint.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ func newLintCmd(out io.Writer) *cobra.Command {
f.BoolVar(&client.WithSubcharts, "with-subcharts", false, "lint dependent charts")
f.BoolVar(&client.Quiet, "quiet", false, "print only warnings and errors")
f.StringVar(&kubeVersion, "kube-version", "", "Kubernetes version used for capabilities and deprecation checks")
f.BoolVar(&client.EnableFullPath, "full-path", false, "print full path in warnings and errors")
addValueOptionsFlags(f, valueOpts)

return cmd
Expand Down
204 changes: 172 additions & 32 deletions cmd/helm/lint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,48 +18,153 @@ package main

import (
"fmt"
"os"
"path/filepath"
"strings"
"testing"
)

type lintTestCase struct {
cmdTestCase cmdTestCase
updateFullPathInOutputFile bool
}

func TestLintCmdWithSubchartsFlag(t *testing.T) {
testChart := "testdata/testcharts/chart-with-bad-subcharts"
tests := []cmdTestCase{{
name: "lint good chart with bad subcharts",
cmd: fmt.Sprintf("lint %s", testChart),
golden: "output/lint-chart-with-bad-subcharts.txt",
wantError: true,
}, {
name: "lint good chart with bad subcharts using --with-subcharts flag",
cmd: fmt.Sprintf("lint --with-subcharts %s", testChart),
golden: "output/lint-chart-with-bad-subcharts-with-subcharts.txt",
wantError: true,
}}
runTestCmd(t, tests)
tests := []lintTestCase{
{
cmdTestCase: cmdTestCase{
name: "lint good chart with bad subcharts",
cmd: fmt.Sprintf("lint %s", testChart),
golden: "output/lint-chart-with-bad-subcharts.txt",
wantError: true,
},
},
{
cmdTestCase: cmdTestCase{
name: "lint good chart with bad subcharts using --full-path flag",
cmd: fmt.Sprintf("lint --full-path %s", testChart),
golden: "output/lint-chart-with-bad-subcharts-with-full-paths-enabled.txt",
wantError: true,
},
updateFullPathInOutputFile: true,
},
{
cmdTestCase: cmdTestCase{
name: "lint good chart with bad subcharts using --with-subcharts flag",
cmd: fmt.Sprintf("lint --with-subcharts %s", testChart),
golden: "output/lint-chart-with-bad-subcharts-with-subcharts.txt",
wantError: true,
},
},
{
cmdTestCase: cmdTestCase{
name: "lint good chart with bad subcharts using --with-subcharts and --full-path flags",
cmd: fmt.Sprintf("lint --with-subcharts --full-path %s", testChart),
golden: "output/lint-chart-with-bad-subcharts-with-subcharts-with-full-paths-enabled.txt",
wantError: true,
},
updateFullPathInOutputFile: true,
},
}

workingDir, err := os.Getwd()
if err != nil {
t.Fatalf("failed to determine present working directory: '%v'", err)
}

placeholder := `<full-path>`
testCases := []cmdTestCase{}

for _, test := range tests {
if test.updateFullPathInOutputFile {
// Copy the content of golden file to a temporary file
// and replace the placeholder with working directory's
// path. Replace the golden file's name with it.
test.cmdTestCase.golden = tempFileWithUpdatedPlaceholder(
t,
filepath.Join("testdata", test.cmdTestCase.golden),
placeholder,
workingDir,
)
}

testCases = append(testCases, test.cmdTestCase)
}

runTestCmd(t, testCases)
}

func TestLintCmdWithQuietFlag(t *testing.T) {
testChart1 := "testdata/testcharts/alpine"
testChart2 := "testdata/testcharts/chart-bad-requirements"
tests := []cmdTestCase{{
name: "lint good chart using --quiet flag",
cmd: fmt.Sprintf("lint --quiet %s", testChart1),
golden: "output/lint-quiet.txt",
}, {
name: "lint two charts, one with error using --quiet flag",
cmd: fmt.Sprintf("lint --quiet %s %s", testChart1, testChart2),
golden: "output/lint-quiet-with-error.txt",
wantError: true,
}, {
name: "lint chart with warning using --quiet flag",
cmd: "lint --quiet testdata/testcharts/chart-with-only-crds",
golden: "output/lint-quiet-with-warning.txt",
}, {
name: "lint non-existent chart using --quiet flag",
cmd: "lint --quiet thischartdoesntexist/",
golden: "",
wantError: true,
}}
runTestCmd(t, tests)
tests := []lintTestCase{
{
cmdTestCase: cmdTestCase{
name: "lint good chart using --quiet flag",
cmd: fmt.Sprintf("lint --quiet %s", testChart1),
golden: "output/lint-quiet.txt",
},
},
{
cmdTestCase: cmdTestCase{
name: "lint two charts, one with error using --quiet flag",
cmd: fmt.Sprintf("lint --quiet %s %s", testChart1, testChart2),
golden: "output/lint-quiet-with-error.txt",
wantError: true,
},
},
{
cmdTestCase: cmdTestCase{
name: "lint two charts, one with error using --quiet & --full-path flags",
cmd: fmt.Sprintf("lint --quiet --full-path %s %s", testChart1, testChart2),
golden: "output/lint-quiet-with-error-with-full-paths.txt",
wantError: true,
},
updateFullPathInOutputFile: true,
},
{
cmdTestCase: cmdTestCase{
name: "lint chart with warning using --quiet flag",
cmd: "lint --quiet testdata/testcharts/chart-with-only-crds",
golden: "output/lint-quiet-with-warning.txt",
},
},
{
cmdTestCase: cmdTestCase{
name: "lint non-existent chart using --quiet flag",
cmd: "lint --quiet thischartdoesntexist/",
golden: "",
wantError: true,
},
},
}

workingDir, err := os.Getwd()
if err != nil {
t.Fatalf("failed to determine present working directory: '%v'", err)
}

placeholder := `<full-path>`
testCases := []cmdTestCase{}

for _, test := range tests {
if test.updateFullPathInOutputFile {
// Copy the content of golden file to a temporary file
// and replace the placeholder with working directory's
// path. Replace the golden file's name with it.
test.cmdTestCase.golden = tempFileWithUpdatedPlaceholder(
t,
filepath.Join("testdata", test.cmdTestCase.golden),
placeholder,
workingDir,
)
}

testCases = append(testCases, test.cmdTestCase)
}

runTestCmd(t, testCases)

}

Expand Down Expand Up @@ -95,3 +200,38 @@ func TestLintFileCompletion(t *testing.T) {
checkFileCompletion(t, "lint", true)
checkFileCompletion(t, "lint mypath", true) // Multiple paths can be given
}

// tempFileWithUpdatedPlaceholder creates a temporary file, copies
// the content of source file to it, and replaces the placeholder
// with input value.
//
// The temporary file automatically gets deleted during test clean-up.
func tempFileWithUpdatedPlaceholder(t *testing.T, src string, placeholder,
value string) string {
// Create the temporary file in test's temporary directory.
// This lets the test delete the directory along with file
// during the test clean-up step.
dst, err := os.CreateTemp(t.TempDir(), filepath.Base(src))
if err != nil {
t.Fatalf("failed to create temporary destination file: '%v'", err)
}

// Read source file's content
srcData, err := os.ReadFile(src)
if err != nil {
t.Fatalf("failed to read source file %q: '%v'", src, err)
}

// Replace placeholder with input value
dstData := strings.ReplaceAll(string(srcData), placeholder, value)

// Write to destination (temporary) file
_, err = dst.WriteString(dstData)
if err != nil {
t.Fatalf("failed to write to temporary destination file %q: '%v'",
dst.Name(), err)
}

// Return temporary file's name
return dst.Name()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
==> Linting testdata/testcharts/chart-with-bad-subcharts
[INFO] <full-path>/testdata/testcharts/chart-with-bad-subcharts/Chart.yaml: icon is recommended
[ERROR] <full-path>/testdata/testcharts/chart-with-bad-subcharts/templates/: error unpacking bad-subchart in chart-with-bad-subcharts: validation: chart.metadata.name is required
[ERROR] : unable to load chart
error unpacking bad-subchart in chart-with-bad-subcharts: validation: chart.metadata.name is required

Error: 1 chart(s) linted, 1 chart(s) failed
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
==> Linting testdata/testcharts/chart-with-bad-subcharts
[INFO] <full-path>/testdata/testcharts/chart-with-bad-subcharts/Chart.yaml: icon is recommended
[ERROR] <full-path>/testdata/testcharts/chart-with-bad-subcharts/templates/: error unpacking bad-subchart in chart-with-bad-subcharts: validation: chart.metadata.name is required
[ERROR] : unable to load chart
error unpacking bad-subchart in chart-with-bad-subcharts: validation: chart.metadata.name is required

==> Linting testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart
[ERROR] <full-path>/testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart/Chart.yaml: name is required
[ERROR] <full-path>/testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart/Chart.yaml: apiVersion is required. The value must be either "v1" or "v2"
[ERROR] <full-path>/testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart/Chart.yaml: version is required
[INFO] <full-path>/testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart/Chart.yaml: icon is recommended
[ERROR] <full-path>/testdata/testcharts/chart-with-bad-subcharts/charts/bad-subchart/templates/: validation: chart.metadata.name is required
[ERROR] : unable to load chart
validation: chart.metadata.name is required

==> Linting testdata/testcharts/chart-with-bad-subcharts/charts/good-subchart
[INFO] <full-path>/testdata/testcharts/chart-with-bad-subcharts/charts/good-subchart/Chart.yaml: icon is recommended

Error: 3 chart(s) linted, 2 chart(s) failed
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
==> Linting testdata/testcharts/chart-bad-requirements
[ERROR] <full-path>/testdata/testcharts/chart-bad-requirements/Chart.yaml: unable to parse YAML
error converting YAML to JSON: yaml: line 6: did not find expected '-' indicator
[ERROR] <full-path>/testdata/testcharts/chart-bad-requirements/templates/: cannot load Chart.yaml: error converting YAML to JSON: yaml: line 6: did not find expected '-' indicator
[ERROR] : unable to load chart
cannot load Chart.yaml: error converting YAML to JSON: yaml: line 6: did not find expected '-' indicator

Error: 2 chart(s) linted, 1 chart(s) failed
18 changes: 10 additions & 8 deletions pkg/action/lint.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ import (
//
// It provides the implementation of 'helm lint'.
type Lint struct {
Strict bool
Namespace string
WithSubcharts bool
Quiet bool
KubeVersion *chartutil.KubeVersion
Strict bool
Namespace string
WithSubcharts bool
Quiet bool
KubeVersion *chartutil.KubeVersion
EnableFullPath bool
}

// LintResult is the result of Lint
Expand All @@ -59,7 +60,7 @@ func (l *Lint) Run(paths []string, vals map[string]interface{}) *LintResult {
}
result := &LintResult{}
for _, path := range paths {
linter, err := lintChart(path, vals, l.Namespace, l.KubeVersion)
linter, err := lintChart(path, vals, l.Namespace, l.KubeVersion, l.EnableFullPath)
if err != nil {
result.Errors = append(result.Errors, err)
continue
Expand All @@ -86,7 +87,8 @@ func HasWarningsOrErrors(result *LintResult) bool {
return len(result.Errors) > 0
}

func lintChart(path string, vals map[string]interface{}, namespace string, kubeVersion *chartutil.KubeVersion) (support.Linter, error) {
func lintChart(path string, vals map[string]interface{}, namespace string, kubeVersion *chartutil.KubeVersion,
enableFullPath bool) (support.Linter, error) {
var chartPath string
linter := support.Linter{}

Expand Down Expand Up @@ -125,5 +127,5 @@ func lintChart(path string, vals map[string]interface{}, namespace string, kubeV
return linter, errors.Wrap(err, "unable to check Chart.yaml file in chart")
}

return lint.AllWithKubeVersion(chartPath, vals, namespace, kubeVersion), nil
return lint.AllWithKubeVersion(chartPath, vals, namespace, kubeVersion, enableFullPath), nil
}