diff --git a/.github/workflows/fuzz.yaml b/.github/workflows/fuzz.yaml new file mode 100755 index 00000000..dddfe31a --- /dev/null +++ b/.github/workflows/fuzz.yaml @@ -0,0 +1,17 @@ +name: Fuzzing +on: [push, pull_request] +jobs: + build: + name: Fuzzing + runs-on: ubuntu-latest + steps: + - name: Check out code into the Go module directory + uses: actions/checkout@v3 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version-file: "go.mod" + + - name: Fuzz + run: go test ./tests -fuzz . -fuzztime=2m diff --git a/cmd/cmd-run.go b/cmd/cmd-run.go index 031eb335..ba784017 100755 --- a/cmd/cmd-run.go +++ b/cmd/cmd-run.go @@ -144,6 +144,13 @@ func run(cmd *cobra.Command, _ []string) error { } } + if maxReviewers < 0 { + return errors.New("max-reviewers should not be negative") + } + if maxTeamReviewers < 0 { + return errors.New("max-team-reviewers should not be negative") + } + vc, err := getVersionController(flag, true, false) if err != nil { return err diff --git a/internal/multigitter/run.go b/internal/multigitter/run.go index 2206ad71..079fda3e 100755 --- a/internal/multigitter/run.go +++ b/internal/multigitter/run.go @@ -336,6 +336,10 @@ func (r *Runner) ensurePullRequestExists(ctx context.Context, log log.FieldLogge return existingPullRequest, nil } + // if r.MaxReviewers == 1 { + // return nil, errors.New("oh no!") + // } + log.Info("Creating pull request") return r.VersionController.CreatePullRequest(ctx, repo, prRepo, scm.NewPullRequest{ Title: r.PullRequestTitle, diff --git a/tests/fuzzing_test.go b/tests/fuzzing_test.go new file mode 100644 index 00000000..768a1cfe --- /dev/null +++ b/tests/fuzzing_test.go @@ -0,0 +1,132 @@ +package tests + +import ( + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/lindell/multi-gitter/cmd" + "github.com/lindell/multi-gitter/tests/vcmock" + "github.com/stretchr/testify/assert" +) + +func FuzzRun(f *testing.F) { + f.Add( + "assignee1,assignee2", // assignees + "commit message", // commit-message + 1, // concurrent + "skip", // conflict-strategy + false, // draft + false, // dry-run + 1, // fetch-depth + false, // fork + "fork-owner", // fork-owner + "go", // git-type + "label1,label2", // labels + "text", // log-format + "info", // log-level + 1, // max-reviewers + 1, // max-team-reviewers + "pr-body", // pr-body + "pr-title", // pr-title + "reviewer1,reviewer2", // reviewers + false, // skip-forks + false, // skip-pr + "should-not-change", // skip-repo + "team-reviewer1,team-reviewer1", // team-reviewers + "topic1,topic2", // topic + ) + f.Fuzz(func( + t *testing.T, + + assignees string, + commitMessage string, + concurrent int, + conflictStrategy string, + draft bool, + dryRun bool, + fetchDepth int, + fork bool, + forkOwner string, + gitType string, + labels string, + logFormat string, + logLevel string, + maxReviewers int, + maxTeamReviewers int, + prBody string, + prTitle string, + reviewers string, + skipForks bool, + skipPr bool, + skipRepo string, + teamReviewers string, + topic string, + ) { + vcMock := &vcmock.VersionController{} + defer vcMock.Clean() + cmd.OverrideVersionController = vcMock + + tmpDir, err := os.MkdirTemp(os.TempDir(), "multi-git-test-run-") + defer os.RemoveAll(tmpDir) + assert.NoError(t, err) + + workingDir, err := os.Getwd() + assert.NoError(t, err) + + changerBinaryPath := normalizePath(filepath.Join(workingDir, changerBinaryPath)) + + changeRepo := createRepo(t, "owner", "should-change", "i like apples") + changeRepo2 := createRepo(t, "owner", "should-change-2", "i like my apple") + noChangeRepo := createRepo(t, "owner", "should-not-change", "i like oranges") + vcMock.AddRepository(changeRepo) + vcMock.AddRepository(changeRepo2) + vcMock.AddRepository(noChangeRepo) + + runOutFile := filepath.Join(tmpDir, "run-out.txt") + runLogFile := filepath.Join(tmpDir, "run-log.txt") + + command := cmd.RootCmd() + command.SetArgs([]string{"run", + "--output", runOutFile, + "--log-file", runLogFile, + "--author-name", "Test Author", + "--author-email", "test@example.com", + "--assignees", assignees, + "--commit-message", commitMessage, + "--concurrent", fmt.Sprint(concurrent), + "--conflict-strategy", conflictStrategy, + fmt.Sprintf("--draft=%t", draft), + fmt.Sprintf("--dry-run=%t", dryRun), + "--fetch-depth", fmt.Sprint(fetchDepth), + fmt.Sprintf("--fork=%t", fork), + "--fork-owner", forkOwner, + "--git-type", gitType, + "--labels", labels, + "--log-format", logFormat, + "--log-level", logLevel, + "--max-reviewers", fmt.Sprint(maxReviewers), + "--max-team-reviewers", fmt.Sprint(maxTeamReviewers), + "--pr-body", prBody, + "--pr-title", prTitle, + "--reviewers", reviewers, + fmt.Sprintf("--skip-forks=%t", skipForks), + fmt.Sprintf("--skip-pr=%t", skipPr), + "--skip-repo", skipRepo, + "--team-reviewers", teamReviewers, + "--topic", topic, + changerBinaryPath, + }) + err = command.Execute() + if err != nil { + assert.NotContains(t, err.Error(), "panic") + } + + // Verify that the output was correct + runOutData, _ := os.ReadFile(runOutFile) + assert.NotContains(t, string(runOutData), "panic") + runLogData, _ := os.ReadFile(runLogFile) + assert.NotContains(t, string(runLogData), "panic") + }) +} diff --git a/tests/testdata/fuzz/FuzzRun/87fbf8b977926b2c b/tests/testdata/fuzz/FuzzRun/87fbf8b977926b2c new file mode 100644 index 00000000..23c3a7c9 --- /dev/null +++ b/tests/testdata/fuzz/FuzzRun/87fbf8b977926b2c @@ -0,0 +1,24 @@ +go test fuzz v1 +string("0") +string("0") +int(69) +string("skip") +bool(false) +bool(false) +int(1) +bool(true) +string("0") +string("go") +string("0") +string("text") +string("info") +int(1) +int(-51) +string("0") +string("0") +string("0") +bool(false) +bool(false) +string("0") +string("0") +string("0") diff --git a/tests/testdata/fuzz/FuzzRun/ae23ef40ab4bebdf b/tests/testdata/fuzz/FuzzRun/ae23ef40ab4bebdf new file mode 100644 index 00000000..15a49f29 --- /dev/null +++ b/tests/testdata/fuzz/FuzzRun/ae23ef40ab4bebdf @@ -0,0 +1,24 @@ +go test fuzz v1 +string("0") +string("0") +int(1) +string("0") +bool(false) +bool(false) +int(1) +bool(false) +string("0") +string("0") +string("0") +string("0") +string("0") +int(1) +int(1) +string("0") +string("0") +string("0") +bool(false) +bool(false) +string("0") +string("0") +string("0")