aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/bisect/bisect_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/bisect/bisect_test.go')
-rw-r--r--pkg/bisect/bisect_test.go334
1 files changed, 171 insertions, 163 deletions
diff --git a/pkg/bisect/bisect_test.go b/pkg/bisect/bisect_test.go
index 72e12fbe3..04609e701 100644
--- a/pkg/bisect/bisect_test.go
+++ b/pkg/bisect/bisect_test.go
@@ -7,7 +7,6 @@ import (
"bytes"
"fmt"
"io/ioutil"
- "math"
"os"
"strconv"
"testing"
@@ -21,13 +20,9 @@ import (
// testEnv will implement instance.BuilderTester. This allows us to
// set bisect.env.inst to a testEnv object.
type testEnv struct {
- repo *vcs.TestRepo
- r vcs.Repo
- t *testing.T
- fix bool
- brokenStart float64
- brokenEnd float64
- culprit float64
+ t *testing.T
+ r vcs.Repo
+ test BisectionTest
}
func (env *testEnv) BuildSyzkaller(repo, commit string) error {
@@ -35,90 +30,68 @@ func (env *testEnv) BuildSyzkaller(repo, commit string) error {
}
func (env *testEnv) BuildKernel(compilerBin, userspaceDir, cmdlineFile, sysctlFile string,
- kernelConfig []byte) (string, error) {
- return "", nil
-}
-
-func crashErrors(num int, title string) []error {
- var errors []error
- for i := 0; i < num; i++ {
- errors = append(errors, &instance.CrashError{
- Report: &report.Report{
- Title: fmt.Sprintf("crashes at %v", title),
- },
- })
+ kernelConfig []byte) (string, string, error) {
+ commit := env.headCommit()
+ kernelSign := fmt.Sprintf("sign-%v", commit)
+ if commit >= env.test.sameBinaryStart && commit <= env.test.sameBinaryEnd {
+ kernelSign = "same-sign"
}
- return errors
+ return "", kernelSign, nil
}
-func nilErrors(num int) []error {
- var errors []error
- for i := 0; i < num; i++ {
- errors = append(errors, nil)
+func (env *testEnv) Test(numVMs int, reproSyz, reproOpts, reproC []byte) ([]error, error) {
+ commit := env.headCommit()
+ if commit >= env.test.brokenStart && commit <= env.test.brokenEnd {
+ return nil, fmt.Errorf("broken build")
}
- return errors
+ if !env.test.fix && commit >= env.test.culprit || env.test.fix && commit < env.test.culprit {
+ return crashErrors(numVMs, "crash occurs"), nil
+ }
+ return make([]error, numVMs), nil
}
-func (env *testEnv) Test(numVMs int, reproSyz, reproOpts, reproC []byte) ([]error, error) {
- hc, err := env.r.HeadCommit()
+func (env *testEnv) headCommit() int {
+ com, err := env.r.HeadCommit()
if err != nil {
env.t.Fatal(err)
}
- commit, err := strconv.ParseFloat(hc.Title, 64)
+ commit, err := strconv.ParseUint(com.Title, 10, 64)
if err != nil {
- env.t.Fatalf("invalid commit title: %v", hc.Title)
- }
- var e error
- var res []error
- if commit >= env.brokenStart && commit <= env.brokenEnd {
- e = fmt.Errorf("broken build")
- } else if commit < env.culprit && !env.fix || commit >= env.culprit && env.fix {
- res = nilErrors(numVMs)
- } else {
- res = crashErrors(numVMs, "crash occurs")
+ env.t.Fatalf("invalid commit title: %v", com.Title)
}
- return res, e
+ return int(commit)
}
-type Ctx struct {
- t *testing.T
- baseDir string
- repo *vcs.TestRepo
- r vcs.Repo
- cfg *Config
- inst *testEnv
- originRepo *vcs.TestRepo
-}
-
-func NewCtx(t *testing.T, fix bool, brokenStart, brokenEnd, culprit float64, commit string) *Ctx {
- baseDir, err := ioutil.TempDir("", "syz-git-test")
+func runBisection(t *testing.T, test BisectionTest) (*Result, error) {
+ baseDir, err := ioutil.TempDir("", "syz-bisect-test")
if err != nil {
t.Fatal(err)
}
- originRepo := vcs.CreateTestRepo(t, baseDir, "originRepo")
+ defer os.RemoveAll(baseDir)
+ repo := vcs.CreateTestRepo(t, baseDir, "repo")
+ if !repo.SupportsBisection() {
+ t.Skip("bisection is unsupported by git (probably too old version)")
+ }
for rv := 4; rv < 10; rv++ {
for i := 0; i < 6; i++ {
- originRepo.CommitChange(fmt.Sprintf("%v", rv*100+i))
+ repo.CommitChange(fmt.Sprintf("%v", rv*100+i))
if i == 0 {
- originRepo.SetTag(fmt.Sprintf("v%v.0", rv))
+ repo.SetTag(fmt.Sprintf("v%v.0", rv))
}
}
}
- if !originRepo.SupportsBisection() {
- t.Skip("bisection is unsupported by git (probably too old version)")
- }
- repo := vcs.CloneTestRepo(t, baseDir, "repo", originRepo)
r, err := vcs.NewRepo("test", "64", repo.Dir)
if err != nil {
t.Fatal(err)
}
- sc, err := r.GetCommitByTitle(commit)
+ sc, err := r.GetCommitByTitle(fmt.Sprint(test.startCommit))
if err != nil {
t.Fatal(err)
}
+ trace := new(bytes.Buffer)
cfg := &Config{
- Fix: fix,
- Trace: new(bytes.Buffer),
+ Fix: test.fix,
+ Trace: trace,
Manager: mgrconfig.Config{
TargetOS: "test",
TargetVMArch: "64",
@@ -126,177 +99,212 @@ func NewCtx(t *testing.T, fix bool, brokenStart, brokenEnd, culprit float64, com
KernelSrc: repo.Dir,
},
Kernel: KernelConfig{
- Repo: originRepo.Dir,
+ Repo: repo.Dir,
Commit: sc.Hash,
},
}
inst := &testEnv{
- repo: repo,
- r: r,
- t: t,
- fix: fix,
- brokenStart: brokenStart,
- brokenEnd: brokenEnd,
- culprit: culprit,
- }
- c := &Ctx{
- t: t,
- baseDir: baseDir,
- repo: repo,
- r: r,
- cfg: cfg,
- inst: inst,
- originRepo: originRepo,
+ t: t,
+ r: r,
+ test: test,
}
- return c
+ res, err := runImpl(cfg, r, r.(vcs.Bisecter), inst)
+ t.Log(trace.String())
+ return res, err
}
-type BisectionTests struct {
+type BisectionTest struct {
// input environment
name string
fix bool
- startCommit string
- brokenStart float64
- brokenEnd float64
+ startCommit int
+ brokenStart int
+ brokenEnd int
+ // Range of commits that result in the same kernel binary signature.
+ sameBinaryStart int
+ sameBinaryEnd int
// expected output
- errIsNil bool
+ expectErr bool
+ expectRep bool
+ noopChange bool
commitLen int
- repIsNil bool
- oldestLatest string
+ oldestLatest int
// input and output
- culprit float64
+ culprit int
}
func TestBisectionResults(t *testing.T) {
t.Parallel()
- var tests = []BisectionTests{
+ tests := []BisectionTest{
// Tests that bisection returns the correct cause commit.
{
- name: "bisect cause finds cause",
- fix: false,
- startCommit: "905",
- brokenStart: math.Inf(0),
- brokenEnd: 0,
- errIsNil: true,
+ name: "cause-finds-cause",
+ startCommit: 905,
commitLen: 1,
- repIsNil: false,
+ expectRep: true,
culprit: 602,
},
// Tests that cause bisection returns error when crash does not reproduce
// on the original commit.
{
- name: "bisect cause does not repro",
- fix: false,
- startCommit: "400",
- brokenStart: math.Inf(0),
- brokenEnd: 0,
- errIsNil: false,
- commitLen: 0,
- repIsNil: true,
- culprit: math.Inf(0),
+ name: "cause-does-not-repro",
+ startCommit: 400,
+ expectErr: true,
},
// Tests that no commits are returned when crash occurs on oldest commit
// for cause bisection.
{
- name: "bisect cause crashes oldest",
- fix: false,
- startCommit: "905",
- brokenStart: math.Inf(0),
- brokenEnd: 0,
- errIsNil: true,
+ name: "cause-crashes-oldest",
+ startCommit: 905,
commitLen: 0,
- repIsNil: false,
+ expectRep: true,
culprit: 0,
- oldestLatest: "400",
+ oldestLatest: 400,
},
- // Tests that more than 1 commit is returned when cause bisection is
- // inconclusive.
+ // Tests that more than 1 commit is returned when cause bisection is inconclusive.
{
- name: "bisect cause inconclusive",
- fix: false,
- startCommit: "802",
+ name: "cause-inconclusive",
+ startCommit: 802,
brokenStart: 500,
brokenEnd: 700,
- errIsNil: true,
commitLen: 14,
- repIsNil: true,
culprit: 605,
},
// Tests that bisection returns the correct fix commit.
{
- name: "bisect fix finds fix",
+ name: "fix-finds-fix",
fix: true,
- startCommit: "400",
- brokenStart: math.Inf(0),
- brokenEnd: 0,
- errIsNil: true,
+ startCommit: 400,
commitLen: 1,
- repIsNil: true,
culprit: 500,
},
// Tests that fix bisection returns error when crash does not reproduce
// on the original commit.
{
- name: "bisect fix does not repro",
+ name: "fix-does-not-repro",
fix: true,
- startCommit: "905",
- brokenStart: math.Inf(0),
- brokenEnd: 0,
- errIsNil: false,
- commitLen: 0,
- repIsNil: true,
- culprit: 0,
+ startCommit: 905,
+ expectErr: true,
},
// Tests that no commits are returned when crash occurs on HEAD
// for fix bisection.
{
- name: "bisect fix crashes HEAD",
+ name: "fix-crashes-HEAD",
fix: true,
- startCommit: "400",
- brokenStart: math.Inf(0),
- brokenEnd: 0,
- errIsNil: true,
+ startCommit: 400,
commitLen: 0,
- repIsNil: false,
+ expectRep: true,
culprit: 1000,
- oldestLatest: "905",
+ oldestLatest: 905,
},
- // Tests that more than 1 commit is returned when fix bisection is
- // inconclusive.
+ // Tests that more than 1 commit is returned when fix bisection is inconclusive.
{
- name: "bisect fix inconclusive",
+ name: "fix-inconclusive",
fix: true,
- startCommit: "400",
+ startCommit: 400,
brokenStart: 500,
brokenEnd: 600,
- errIsNil: true,
commitLen: 8,
- repIsNil: true,
culprit: 501,
},
+ {
+ name: "cause-same-binary",
+ startCommit: 905,
+ commitLen: 1,
+ expectRep: true,
+ culprit: 503,
+ sameBinaryStart: 502,
+ sameBinaryEnd: 503,
+ noopChange: true,
+ },
+ {
+ name: "cause-same-binary-off-by-one",
+ startCommit: 905,
+ commitLen: 1,
+ expectRep: true,
+ culprit: 503,
+ sameBinaryStart: 400,
+ sameBinaryEnd: 502,
+ },
+ {
+ name: "cause-same-binary-off-by-one-2",
+ startCommit: 905,
+ commitLen: 1,
+ expectRep: true,
+ culprit: 503,
+ sameBinaryStart: 503,
+ sameBinaryEnd: 905,
+ },
+ {
+ name: "fix-same-binary",
+ fix: true,
+ startCommit: 400,
+ commitLen: 1,
+ culprit: 503,
+ sameBinaryStart: 502,
+ sameBinaryEnd: 504,
+ noopChange: true,
+ },
}
for _, test := range tests {
- t.Run(fmt.Sprintf("%v", test.name), func(t *testing.T) {
- c := NewCtx(t, test.fix, test.brokenStart, test.brokenEnd, test.culprit, test.startCommit)
- defer os.RemoveAll(c.baseDir)
- commits, rep, com, err := runImpl(c.cfg, c.r, c.r.(vcs.Bisecter), c.inst)
- if test.errIsNil && err != nil || !test.errIsNil && err == nil {
- t.Fatalf("returned error: '%v'", err)
+ test := test
+ t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
+ if test.expectErr &&
+ (test.commitLen != 0 ||
+ test.expectRep ||
+ test.oldestLatest != 0 ||
+ test.culprit != 0) {
+ t.Fatalf("expecting non-default values on error")
+ }
+ if test.brokenStart > test.brokenEnd {
+ t.Fatalf("bad broken start/end: %v/%v",
+ test.brokenStart, test.brokenEnd)
+ }
+ if test.sameBinaryStart > test.sameBinaryEnd {
+ t.Fatalf("bad same binary start/end: %v/%v",
+ test.sameBinaryStart, test.sameBinaryEnd)
+ }
+ res, err := runBisection(t, test)
+ if test.expectErr != (err != nil) {
+ t.Fatalf("returned error: %v", err)
+ }
+ if err != nil {
+ if res != nil {
+ t.Fatalf("got both result and error: '%v' %+v", err, *res)
+ }
+ return
+ }
+ if len(res.Commits) != test.commitLen {
+ t.Fatalf("expected %d commits got %d commits", test.commitLen, len(res.Commits))
}
- if len(commits) != test.commitLen {
- t.Fatalf("expected %d commits got %d commits", test.commitLen, len(commits))
+ expectedTitle := fmt.Sprint(test.culprit)
+ if len(res.Commits) == 1 && expectedTitle != res.Commits[0].Title {
+ t.Fatalf("expected commit '%v' got '%v'", expectedTitle, res.Commits[0].Title)
}
- expectedTitle := fmt.Sprintf("%v", test.culprit)
- if len(commits) == 1 && expectedTitle != commits[0].Title {
- t.Fatalf("expected commit '%v' got '%v'", expectedTitle, commits[0].Title)
+ if test.expectRep != (res.Report != nil) {
+ t.Fatalf("got rep: %v, want: %v", res.Report, test.expectRep)
}
- if test.repIsNil && rep != nil || !test.repIsNil && rep == nil {
- t.Fatalf("returned rep: '%v'", err)
+ if res.NoopChange != test.noopChange {
+ t.Fatalf("got noop change: %v, want: %v", res.NoopChange, test.noopChange)
}
- if test.oldestLatest != "" && test.oldestLatest != com.Title ||
- test.oldestLatest == "" && com != nil {
- t.Fatalf("expected latest/oldest: '%v' got '%v'", test.oldestLatest, com.Title)
+ if test.oldestLatest != 0 && fmt.Sprint(test.oldestLatest) != res.Commit.Title ||
+ test.oldestLatest == 0 && res.Commit != nil {
+ t.Fatalf("expected latest/oldest: %v got '%v'",
+ test.oldestLatest, res.Commit.Title)
}
})
}
}
+
+func crashErrors(num int, title string) []error {
+ var errors []error
+ for i := 0; i < num; i++ {
+ errors = append(errors, &instance.CrashError{
+ Report: &report.Report{
+ Title: fmt.Sprintf("crashes at %v", title),
+ },
+ })
+ }
+ return errors
+}