Skip to content

test(values): cover subchart-default nil cleanup when parent has unrelated user values#32092

Open
Y0-L0 wants to merge 1 commit intohelm:mainfrom
Y0-L0:jlohmer/subchart-nil-tests
Open

test(values): cover subchart-default nil cleanup when parent has unrelated user values#32092
Y0-L0 wants to merge 1 commit intohelm:mainfrom
Y0-L0:jlohmer/subchart-nil-tests

Conversation

@Y0-L0
Copy link
Copy Markdown
Contributor

@Y0-L0 Y0-L0 commented Apr 30, 2026

Failing tests pinning the gap left open after #31979: when the parent supplies any value under a subchart, coalescing routes through merge=true and bypasses cleanNilValues, so subchart-default nils survive.

Adds in pkg/chart/v2/util/dependencies_test.go:

  • …NoUserSubchartVals — baseline, passes.
  • …WithUnrelatedSubchartVals — fails; unrelated sibling key triggers the leak.
  • …WithPartialSameMapVals — fails; sibling nil in same map survives an override.

Also tightens TestRenderSubchartDefaultNilNoStringify to call ProcessDependencies, matching the real coalesce path. Tests-only; baseline for the follow-up fix.

Special notes for your reviewer:

So far just adds test coverage for the remaining nil values merge regression.
I did not want to pollute the PR with an AI Slop "fix".

If applicable:

  • this PR contains unit tests
  • this PR has been tested for backwards compatibility

Copilot AI review requested due to automatic review settings April 30, 2026 13:40
@pull-request-size pull-request-size Bot added the size/L Denotes a PR that changes 100-499 lines, ignoring generated files. label Apr 30, 2026
…nrelated user-defined values

Signed-off-by: Johannes Lohmer <jojo.dev@lohmer.com>
@Y0-L0 Y0-L0 force-pushed the jlohmer/subchart-nil-tests branch from ffd4a52 to 2911c68 Compare April 30, 2026 13:43
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds regression test coverage for a values-coalescing edge case where subchart default nil values can survive coalescing when the parent supplies any value under the subchart key, and updates an existing engine render test to exercise the dependency-processing path.

Changes:

  • Update TestRenderSubchartDefaultNilNoStringify to call ProcessDependencies and inject a subchart user value to follow the “real” coalesce path.
  • Add new dependency-processing/coalescing tests covering baseline and two regression scenarios around subchart default nil cleanup.
  • Introduce small test helpers to build charts and run ProcessDependencies + coalescing.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
pkg/engine/engine_test.go Adjusts an existing render regression test to include dependency processing and a subchart user value.
pkg/chart/v2/util/dependencies_test.go Adds unit tests and helpers to cover subchart default nil cleanup behavior across coalescing scenarios.
Comments suppressed due to low confidence (1)

pkg/engine/engine_test.go:1577

  • This test now injects a value under the child key, which forces the child-chart merge path (merge=true) during coalescing; with the current implementation that bypasses cleanNilValues, the rendered template is expected to include %!s(<nil>), so the test will fail until the underlying coalesce behavior is fixed. If this PR is intended to be mergeable on its own, these assertions need to be skipped/adjusted or the functional fix needs to land together with the test.
	injValues := map[string]any{
		"child": map[string]any{
			"someOtherKey": "someValue",
		},
	}

	if err := chartutil.ProcessDependencies(parent, injValues); err != nil {
		t.Fatalf("Failed to process dependencies: %s", err)
	}

	tmp, err := util.CoalesceValues(parent, injValues)
	if err != nil {
		t.Fatalf("Failed to coalesce values: %s", err)
	}

	inject := common.Values{
		"Values": tmp,
		"Chart":  parent.Metadata,
		"Release": common.Values{
			"Name": "test-release",
		},
	}

	out, err := Render(parent, inject)
	if err != nil {
		t.Fatalf("Failed to render templates: %s", err)
	}

	rendered := out["parent/charts/child/templates/test.yaml"]

	if strings.Contains(rendered, "%!s(<nil>)") {
		t.Errorf("Rendered output contains %%!s(<nil>), got: %q", rendered)
	}

	expected := "subPath: fallback"
	if rendered != expected {
		t.Errorf("Expected %q, got %q", expected, rendered)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

func processAndCoalesce(t *testing.T, parent *chart.Chart, vals common.Values) common.Values {
t.Helper()
require.NoError(t, ProcessDependencies(parent, vals))
coalesced, err := commonutil.CoalesceValues(parent, vals)
Copy link

Copilot AI Apr 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

commonutil.CoalesceValues expects a map[string]any, but this helper passes vals as common.Values (a distinct defined type), which won’t compile. Convert with vals.AsMap() (or map[string]any(vals)) when calling CoalesceValues.

Suggested change
coalesced, err := commonutil.CoalesceValues(parent, vals)
coalesced, err := commonutil.CoalesceValues(parent, vals.AsMap())

Copilot uses AI. Check for mistakes.
Comment on lines +622 to +642
// Any user value under "child" routes coalescing through merge=true and
// bypasses cleanNilValues. Covers #31919 and #31971.
func TestProcessDependenciesNilCleanedWithUnrelatedSubchartVals(t *testing.T) {
is := assert.New(t)
coalesced := processAndCoalesce(t, newParentWithNilSubchart(), common.Values{
"child": map[string]any{
"someOtherKey": "someValue",
},
"global": map[string]any{
"ingress": map[string]any{
"configureCertmanager": true,
},
},
})

_, err := common.Values(coalesced).PathValue("child.keyMapping.password")
is.ErrorAs(err, &common.ErrNoValue{}, "child.keyMapping.password should be absent")

_, err = common.Values(coalesced).PathValue("child.ingress.configureCertmanager")
is.ErrorAs(err, &common.ErrNoValue{}, "child.ingress.configureCertmanager should be absent so pluck falls through to global")
}
Copy link

Copilot AI Apr 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These new tests assert that subchart-default nil entries are removed even when a user supplies any value under the subchart key (the merge=true path). With the current coalescing logic (coalesceValues skips cleanNilValues when merging child chart tables), these tests will fail in CI until the functional fix is included. If this PR is meant to be mergeable independently, mark these cases as skipped or adjust expectations; otherwise, consider bundling the fix with the tests.

Copilot uses AI. Check for mistakes.
Comment thread pkg/engine/engine_test.go
Comment on lines +1541 to 1552
injValues := map[string]any{
"child": map[string]any{
"someOtherKey": "someValue",
},
}

if err := chartutil.ProcessDependencies(parent, injValues); err != nil {
t.Fatalf("Failed to process dependencies: %s", err)
}

tmp, err := util.CoalesceValues(parent, injValues)
if err != nil {
Copy link

Copilot AI Apr 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

chartutil.ProcessDependencies takes common.Values, but injValues is declared as map[string]any, which won’t compile (distinct defined type). Consider declaring injValues as common.Values (or converting when calling ProcessDependencies) and pass injValues.AsMap() (or a map[string]any conversion) into util.CoalesceValues which expects map[string]any.

Copilot uses AI. Check for mistakes.
is := assert.New(t)
coalesced := processAndCoalesce(t, newParentWithNilSubchart(), common.Values{
"child": map[string]any{
"someOtherKey": "someValue",
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The really nefarious part of this bug / regression is, that helms behaviour changes when the end user configures a completely unrelated part of the sub-chart.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/L Denotes a PR that changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants