Skip to content

Commit 4b774d8

Browse files
committed
chore: fuzz test helpers
1 parent 7fc9099 commit 4b774d8

1 file changed

Lines changed: 68 additions & 18 deletions

File tree

pkg/config/fuzz_test.go

Lines changed: 68 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
package config_test
22

33
import (
4-
"runtime"
4+
"context"
55
"strings"
66
"testing"
7+
"time"
78

89
"github.com/gruntwork-io/terragrunt/pkg/config"
910
"github.com/gruntwork-io/terragrunt/test/helpers/logger"
11+
"github.com/stretchr/testify/require"
1012
)
1113

12-
// FuzzHCLStringHelpers: startswith / endswith / strcontains must never panic on any args shape.
14+
// FuzzHCLStringHelpers: wrong arity must return WrongNumberOfParamsError; otherwise the result must agree with the Go stdlib equivalent.
1315
func FuzzHCLStringHelpers(f *testing.F) {
1416
seeds := []string{
1517
"",
@@ -32,28 +34,53 @@ func FuzzHCLStringHelpers(f *testing.F) {
3234

3335
ctx, pctx := newTestParsingContext(t, "")
3436

35-
_, _ = config.StartsWith(ctx, pctx, args)
36-
_, _ = config.EndsWith(ctx, pctx, args)
37-
_, _ = config.StrContains(ctx, pctx, args)
37+
swOut, swErr := config.StartsWith(ctx, pctx, args)
38+
ewOut, ewErr := config.EndsWith(ctx, pctx, args)
39+
scOut, scErr := config.StrContains(ctx, pctx, args)
40+
41+
if len(args) != 2 {
42+
require.Error(t, swErr, "startswith with %d args must error", len(args))
43+
require.True(t, assertErrorType(t, config.WrongNumberOfParamsError{}, swErr),
44+
"startswith expected WrongNumberOfParamsError, got %T: %v", swErr, swErr)
45+
require.Error(t, ewErr, "endswith with %d args must error", len(args))
46+
require.True(t, assertErrorType(t, config.WrongNumberOfParamsError{}, ewErr),
47+
"endswith expected WrongNumberOfParamsError, got %T: %v", ewErr, ewErr)
48+
require.Error(t, scErr, "strcontains with %d args must error", len(args))
49+
require.True(t, assertErrorType(t, config.WrongNumberOfParamsError{}, scErr),
50+
"strcontains expected WrongNumberOfParamsError, got %T: %v", scErr, scErr)
51+
52+
return
53+
}
54+
55+
require.NoError(t, swErr, "startswith(%q,%q) must not error", args[0], args[1])
56+
require.Equal(t, strings.HasPrefix(args[0], args[1]), swOut,
57+
"startswith(%q,%q) must agree with strings.HasPrefix", args[0], args[1])
58+
59+
require.NoError(t, ewErr, "endswith(%q,%q) must not error", args[0], args[1])
60+
require.Equal(t, strings.HasSuffix(args[0], args[1]), ewOut,
61+
"endswith(%q,%q) must agree with strings.HasSuffix", args[0], args[1])
62+
63+
require.NoError(t, scErr, "strcontains(%q,%q) must not error", args[0], args[1])
64+
require.Equal(t, strings.Contains(args[0], args[1]), scOut,
65+
"strcontains(%q,%q) must agree with strings.Contains", args[0], args[1])
3866
})
3967
}
4068

41-
// FuzzHCLRunCommandOptions: run_cmd must never panic on any mix of recognized option flags.
42-
// Fuzz input is filtered to known --terragrunt-* flags so the fuzzer cannot launch arbitrary host commands.
43-
func FuzzHCLRunCommandOptions(f *testing.F) {
44-
if runtime.GOOS == "windows" {
45-
f.Skip("run_cmd happy-path requires bash; skip on Windows")
46-
}
47-
69+
// FuzzRunCmdOptionsParsing: exercises run_cmd's option-stripping logic without ever reaching shell-out.
70+
// Args are filtered to known --terragrunt-* flags and NO command is appended, so RunCommand always returns
71+
// EmptyStringNotAllowedError or ConflictingRunCmdCacheOptionsError before shell.RunCommandWithOutput is called.
72+
func FuzzRunCmdOptionsParsing(f *testing.F) {
4873
seeds := []string{
74+
"",
4975
"--terragrunt-quiet",
5076
"--terragrunt-no-cache",
5177
"--terragrunt-global-cache",
5278
"--terragrunt-quiet\x00--terragrunt-no-cache",
5379
"--terragrunt-quiet\x00--terragrunt-quiet",
5480
"--terragrunt-no-cache\x00--terragrunt-global-cache",
81+
"--terragrunt-global-cache\x00--terragrunt-no-cache",
82+
"--terragrunt-quiet\x00--terragrunt-no-cache\x00--terragrunt-global-cache",
5583
"--unknown-flag",
56-
"",
5784
}
5885
for _, s := range seeds {
5986
f.Add(s)
@@ -62,19 +89,42 @@ func FuzzHCLRunCommandOptions(f *testing.F) {
6289
f.Fuzz(func(t *testing.T, raw string) {
6390
parts := strings.Split(raw, "\x00")
6491

65-
args := make([]string, 0, len(parts)+2)
92+
var hasNoCache, hasGlobalCache bool
93+
94+
args := make([]string, 0, len(parts))
6695
for _, part := range parts {
6796
switch part {
68-
case "--terragrunt-quiet", "--terragrunt-no-cache", "--terragrunt-global-cache":
97+
case "--terragrunt-quiet":
98+
args = append(args, part)
99+
case "--terragrunt-no-cache":
100+
args = append(args, part)
101+
hasNoCache = true
102+
case "--terragrunt-global-cache":
69103
args = append(args, part)
104+
hasGlobalCache = true
70105
}
71106
}
72107

73-
args = append(args, "/bin/echo", "hi")
108+
baseCtx, pctx := newTestParsingContext(t, "")
109+
110+
ctx, cancel := context.WithTimeout(baseCtx, 2*time.Second)
111+
defer cancel()
74112

75113
l := logger.CreateLogger()
76-
ctx, pctx := newTestParsingContext(t, "")
77114

78-
_, _ = config.RunCommand(ctx, pctx, l, args)
115+
out, err := config.RunCommand(ctx, pctx, l, args)
116+
117+
require.Empty(t, out, "options-only call must not produce output")
118+
require.Error(t, err, "options-only call must error")
119+
120+
if hasNoCache && hasGlobalCache {
121+
require.True(t, assertErrorType(t, config.ConflictingRunCmdCacheOptionsError{}, err),
122+
"expected ConflictingRunCmdCacheOptionsError, got %T: %v", err, err)
123+
124+
return
125+
}
126+
127+
require.True(t, assertErrorType(t, config.EmptyStringNotAllowedError(""), err),
128+
"expected EmptyStringNotAllowedError, got %T: %v", err, err)
79129
})
80130
}

0 commit comments

Comments
 (0)