Skip to content

Commit 6fa5e09

Browse files
fix(e2e/test): stderr stripRE + race-free resolver injection
Signed-off-by: Jaisheesh-2006 <jaicodes2006@gmail.com>
1 parent f77d3ef commit 6fa5e09

5 files changed

Lines changed: 82 additions & 21 deletions

File tree

e2e/testdata/fn-render/image-pull-policy-never/.expected/config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ exitCode: 1
1717
# The output in stderr is different depending on the runtime.
1818
# "No such image" is from docker and "image not known" is from podman.
1919
stdErrRegEx: No such image|image not known
20-
diffStripRegEx: "\\+\\s+stderr:|docker: Error response from daemon|Run 'docker run|Error:.*image not known|^\\+$"
20+
diffStripRegEx: "\\+\\s*stderr:|docker: Error response from daemon|Run 'docker run|Error:.*image not known|^\\+$"

e2e/testdata/fn-render/missing-fn-image/.expected/config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@
1414

1515
exitCode: 1
1616
StdErrRegEx: "(docker: Error response from daemon: Head.*denied|Error.*initializing source docker)"
17-
diffStripRegEx: "\\+\\s+stderr:|docker: Error response from daemon|Run 'docker run|Error:.*initializing source|^\\+\\s+denied$|^\\+$"
17+
diffStripRegEx: "\\+\\s*stderr:|docker: Error response from daemon|Run 'docker run|Error:.*initializing source|^\\+\\s*denied$|^\\+$"

pkg/lib/util/parse/parse.go

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,27 +35,37 @@ type Target struct {
3535
Destination string
3636
}
3737

38-
// defaultBranchResolver resolves the default branch of a remote git repo.
39-
// Indirected through a package variable so tests can swap in a hermetic
40-
// stub without making live network calls to github.com (or wherever the
41-
// repo is hosted).
42-
var defaultBranchResolver = func(ctx context.Context, repo string) (string, error) {
38+
// branchResolver looks up the default branch of a remote git repo.
39+
// Plumbed as a parameter (rather than a package-level global) so tests
40+
// can supply a hermetic stub without mutating shared state — parallel
41+
// tests stay race-free.
42+
type branchResolver func(ctx context.Context, repo string) (string, error)
43+
44+
// defaultBranchResolver is the production branchResolver. It performs a
45+
// live ls-remote against the repo; unit tests should never use it.
46+
func defaultBranchResolver(ctx context.Context, repo string) (string, error) {
4347
gur, err := gitutil.NewGitUpstreamRepo(ctx, repo)
4448
if err != nil {
4549
return "", err
4650
}
4751
return gur.GetDefaultBranch(ctx)
4852
}
4953

54+
// GitParseArgs is the public entry point; it always uses the live
55+
// defaultBranchResolver. Tests use gitParseArgs directly with a stub.
5056
func GitParseArgs(ctx context.Context, args []string, explicitDest bool) (Target, error) {
57+
return gitParseArgs(ctx, args, explicitDest, defaultBranchResolver)
58+
}
59+
60+
func gitParseArgs(ctx context.Context, args []string, explicitDest bool, resolve branchResolver) (Target, error) {
5161
g := Target{}
5262
if args[0] == "-" {
5363
return g, nil
5464
}
5565

5666
// Simple parsing if contains .git{$|/)
5767
if HasGitSuffix(args[0]) {
58-
return targetFromPkgURL(ctx, args[0], args[1], explicitDest)
68+
return targetFromPkgURL(ctx, args[0], args[1], explicitDest, resolve)
5969
}
6070

6171
// GitHub parsing if contains github.com
@@ -64,7 +74,7 @@ func GitParseArgs(ctx context.Context, args []string, explicitDest bool) (Target
6474
if err != nil {
6575
return g, err
6676
}
67-
return targetFromPkgURL(ctx, ghPkgURL, args[1], explicitDest)
77+
return targetFromPkgURL(ctx, ghPkgURL, args[1], explicitDest, resolve)
6878
}
6979

7080
uri, version, err := getURIAndVersion(args[0])
@@ -76,7 +86,7 @@ func GitParseArgs(ctx context.Context, args []string, explicitDest bool) (Target
7686
return g, err
7787
}
7888
if version == "" {
79-
defaultRef, err := defaultBranchResolver(ctx, repo)
89+
defaultRef, err := resolve(ctx, repo)
8090
if err != nil {
8191
return g, err
8292
}
@@ -95,7 +105,7 @@ func GitParseArgs(ctx context.Context, args []string, explicitDest bool) (Target
95105
}
96106

97107
// targetFromPkgURL parses a pkg url and destination into kptfile git info and local destination Target
98-
func targetFromPkgURL(ctx context.Context, pkgURL string, dest string, explicitDest bool) (Target, error) {
108+
func targetFromPkgURL(ctx context.Context, pkgURL string, dest string, explicitDest bool, resolve branchResolver) (Target, error) {
99109
g := Target{}
100110
repo, dir, ref, err := URL(pkgURL)
101111
if err != nil {
@@ -105,7 +115,7 @@ func targetFromPkgURL(ctx context.Context, pkgURL string, dest string, explicitD
105115
dir = "/"
106116
}
107117
if ref == "" {
108-
defaultRef, err := defaultBranchResolver(ctx, repo)
118+
defaultRef, err := resolve(ctx, repo)
109119
if err != nil {
110120
return g, err
111121
}

pkg/lib/util/parse/parse_test.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -217,16 +217,15 @@ func Test_parseURL(t *testing.T) {
217217
}
218218

219219
func Test_GitParseArgs(t *testing.T) {
220-
// Swap in a hermetic default-branch resolver so the test does not hit
221-
// github.com (or any network) to discover HEAD. Without this the test
222-
// failed intermittently when the remote returned transient errors
223-
// (e.g. HTTP 500 from github.com). The stub mirrors what a real
224-
// ls-remote would return for kpt's default branch.
225-
origResolver := defaultBranchResolver
226-
defaultBranchResolver = func(_ context.Context, _ string) (string, error) {
220+
// Use a hermetic stub resolver so the test does not hit github.com
221+
// (or any network) to discover HEAD. Without this the test failed
222+
// intermittently when the remote returned transient errors (e.g. HTTP
223+
// 500 from github.com). The stub is passed via the unexported
224+
// gitParseArgs helper — no package-level state is mutated, so tests
225+
// remain safe under t.Parallel().
226+
stubResolver := func(_ context.Context, _ string) (string, error) {
227227
return "main", nil
228228
}
229-
t.Cleanup(func() { defaultBranchResolver = origResolver })
230229

231230
tests := map[string]struct {
232231
ghURL string
@@ -269,7 +268,7 @@ func Test_GitParseArgs(t *testing.T) {
269268
t.SkipNow()
270269
}
271270
ctx := printer.WithContext(context.Background(), printer.New(nil, nil))
272-
actual, err := GitParseArgs(ctx, []string{test.ghURL, test.expected.Destination}, true)
271+
actual, err := gitParseArgs(ctx, []string{test.ghURL, test.expected.Destination}, true, stubResolver)
273272
assert.NoError(t, err)
274273
assert.Equal(t, test.expected, actual)
275274
})

pkg/test/runner/normalize_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,3 +590,55 @@ index 1234567..89abcde 100644
590590
t.Fatalf("expected configMap lines to stay grouped with set-namespace image line, got:\n%s", got)
591591
}
592592
}
593+
594+
// TestNormalizeDiff_StripREAppliesAfterKptfileIndentStrip pins the contract
595+
// that per-test diffStripRegEx patterns are evaluated against the
596+
// post-indent-strip form of Kptfile +/- lines. Test configs (e.g.
597+
// image-pull-policy-never, missing-fn-image) therefore use `\s*` rather
598+
// than `\s+` when matching keys like `stderr:` so they survive the
599+
// Kptfile indent-stripping step. This test locks that behavior in so
600+
// future normalizer changes can't silently re-break the interaction.
601+
func TestNormalizeDiff_StripREAppliesAfterKptfileIndentStrip(t *testing.T) {
602+
// Raw pre-normalization diff, as produced by git diff against a Kptfile
603+
// where the rendered pipeline wrote a multi-line stderr block.
604+
input := `diff --git a/Kptfile b/Kptfile
605+
index 1234567..89abcde 100644
606+
--- a/Kptfile
607+
+++ b/Kptfile
608+
@@ -1,4 +1,8 @@
609+
+status:
610+
+ renderStatus:
611+
+ mutationSteps:
612+
+ - image: ghcr.io/kptdev/krm-functions-catalog/dne:latest
613+
+ exitCode: 125
614+
+ stderr: |-
615+
+ Error: ghcr.io/kptdev/krm-functions-catalog/dne:latest: image not known`
616+
617+
// \s* (not \s+) is the key: after the normalizer strips the leading
618+
// whitespace off Kptfile +/- lines, the regex still has to match
619+
// `+stderr:` with zero spaces after the `+`.
620+
stripRE := `\+\s*stderr:|Error:.*image not known`
621+
622+
got, err := normalizeDiff(input, stripRE)
623+
if err != nil {
624+
t.Fatalf("normalizeDiff failed: %v", err)
625+
}
626+
627+
if strings.Contains(got, "stderr:") {
628+
t.Fatalf("expected stderr label to be stripped, got:\n%s", got)
629+
}
630+
if strings.Contains(got, "image not known") {
631+
t.Fatalf("expected stderr body (matching Error:.*image not known) to be stripped, got:\n%s", got)
632+
}
633+
634+
// Sanity: the relaxed \s* also matches the pre-indent-strip form, so a
635+
// stripRE authored for the raw diff still wins after normalization.
636+
stripREStrictPlus := `\+\s+stderr:` // old form with \s+
637+
gotStrict, err := normalizeDiff(input, stripREStrictPlus)
638+
if err != nil {
639+
t.Fatalf("normalizeDiff failed: %v", err)
640+
}
641+
if !strings.Contains(gotStrict, "stderr:") {
642+
t.Fatalf("regression-guard: the tight \\s+ pattern *should* fail to strip the post-indent-strip line (that's the bug we fixed); got:\n%s", gotStrict)
643+
}
644+
}

0 commit comments

Comments
 (0)