Skip to content

Commit

Permalink
metamorphic: make a reduce parameter configurable
Browse files Browse the repository at this point in the history
Make the number of attempts for each probability configurable. When
the problem doesn't reproduce most of the time, we need more attempts.
  • Loading branch information
RaduBerinde committed May 9, 2024
1 parent 4301b8f commit 2b26224
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 15 deletions.
4 changes: 2 additions & 2 deletions internal/metamorphic/meta_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func runTestMeta(t *testing.T, multiInstance bool) {
}
testRootDir, runSubdirs := runOnceFlags.ParseCompare()
if runOnceFlags.TryToReduce {
tryToReduceCompare(t, runOnceFlags.Dir, testRootDir, runSubdirs)
tryToReduceCompare(t, runOnceFlags.Dir, testRootDir, runSubdirs, runOnceFlags.ReduceAttempts)
return
}
metamorphic.Compare(t, testRootDir, runOnceFlags.Seed, runSubdirs, onceOpts...)
Expand All @@ -81,7 +81,7 @@ func runTestMeta(t *testing.T, multiInstance bool) {
onceOpts = append(onceOpts, metamorphic.MultiInstance(2))
}
if runOnceFlags.TryToReduce {
tryToReduce(t, runOnceFlags.Dir, runOnceFlags.RunDir)
tryToReduce(t, runOnceFlags.Dir, runOnceFlags.RunDir, runOnceFlags.ReduceAttempts)
return
}
metamorphic.RunOnce(t, runOnceFlags.RunDir, runOnceFlags.Seed, filepath.Join(runOnceFlags.RunDir, "history"), onceOpts...)
Expand Down
6 changes: 6 additions & 0 deletions internal/metamorphic/metaflags/meta_flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ type RunOnceFlags struct {
// operations that reproduce a problem during a test run (e.g. panic or
// internal error).
TryToReduce bool
// ReduceAttempts is the number of attempts to reduce (for each op removal
// probability).
ReduceAttempts int
}

func initRunOnceFlags(c *CommonFlags) *RunOnceFlags {
Expand All @@ -114,6 +117,9 @@ Example, --compare '_meta/231220-164251.3552792807512/{standard-000,random-025}'
`if set, we will try to reduce the number of operations that cause a failure. The
verbose flag should be used with this flag.`)

flag.IntVar(&ro.ReduceAttempts, "reduce-attempts", 100,
`the number of attempts to reduce, for each probability; only used with --try-to-reduce.`)

return ro
}

Expand Down
28 changes: 15 additions & 13 deletions internal/metamorphic/reduce_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ import (
//
// The test will save the smallest reproduction found and print out the relevant
// information.
func tryToReduce(t *testing.T, testStateDir string, runDir string) {
func tryToReduce(t *testing.T, testStateDir string, runDir string, reduceAttempts int) {
testRootDir := filepath.Dir(runDir)
runSubdir := filepath.Base(runDir)
r := makeReducer(t, testStateDir, testRootDir, []string{runSubdir})
r := makeReducer(t, testStateDir, testRootDir, []string{runSubdir}, reduceAttempts)
r.Run(t)
}

Expand All @@ -52,18 +52,19 @@ func tryToReduce(t *testing.T, testStateDir string, runDir string) {
// The test will save the smallest reproduction found and print out the relevant
// information.
func tryToReduceCompare(
t *testing.T, testStateDir string, testRootDir string, runSubdirs []string,
t *testing.T, testStateDir string, testRootDir string, runSubdirs []string, reduceAttempts int,
) {
r := makeReducer(t, testStateDir, testRootDir, runSubdirs)
r := makeReducer(t, testStateDir, testRootDir, runSubdirs, reduceAttempts)
r.Run(t)
}

// reducer is a helper that starts with a reproduction of a RunOnce failure and
// tries to reduce the number of operations.
type reducer struct {
// testRootDir is the directory of the test, which contains the "ops" file.
testRootDir string
configs []testConfig
testRootDir string
configs []testConfig
reduceAttempts int

ops []string

Expand All @@ -83,7 +84,7 @@ type testConfig struct {
}

func makeReducer(
t *testing.T, testStateDir string, testRootDir string, runSubdirs []string,
t *testing.T, testStateDir string, testRootDir string, runSubdirs []string, reduceAttempts int,
) *reducer {
// All run dirs should have the same parent path.
opsData, err := os.ReadFile(filepath.Join(testRootDir, "ops"))
Expand All @@ -104,10 +105,11 @@ func makeReducer(
t.Logf("Starting with %d operations", len(ops))

return &reducer{
testRootDir: testRootDir,
configs: tc,
ops: ops,
testStateDir: testStateDir,
testRootDir: testRootDir,
configs: tc,
ops: ops,
reduceAttempts: reduceAttempts,
testStateDir: testStateDir,
}
}

Expand Down Expand Up @@ -196,8 +198,8 @@ func (r *reducer) Run(t *testing.T) {
// find any reductions we decrease it. This works well even if the problem is
// not deterministic and isn't reproduced on every run.
for removeProbability := 0.1; removeProbability > 1e-5 && removeProbability > 0.1/float64(len(ops)); removeProbability *= 0.5 {
t.Logf("removeProbability %.2f", removeProbability)
for i := 0; i < 100; i++ {
t.Logf("removeProbability %.2f%%", removeProbability*100.0)
for i := 0; i < r.reduceAttempts; i++ {
if o := randomSubset(t, ops, removeProbability); r.try(t, o) {
ops = o
// Reset the counter.
Expand Down

0 comments on commit 2b26224

Please sign in to comment.