blob: ff46022783a9f2e4595c7911eeb88bd000c523bb [file] [log] [blame]
// Copyright 2019 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
package bisect
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"strconv"
"testing"
"github.com/google/syzkaller/pkg/instance"
"github.com/google/syzkaller/pkg/mgrconfig"
"github.com/google/syzkaller/pkg/report"
"github.com/google/syzkaller/pkg/vcs"
)
// 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
// TODO: add a "fix bool" here so that Test() can return results according to
// whether fix/cause bisection is happening.
}
func (env *testEnv) BuildSyzkaller(repo, commit string) error {
return nil
}
func (env *testEnv) BuildKernel(compilerBin, userspaceDir, cmdlineFile, sysctlFile string,
kernelConfig []byte) (string, error) {
return "", nil
}
func (env *testEnv) Test(numVMs int, reproSyz, reproOpts, reproC []byte) ([]error, error) {
hc, err := env.r.HeadCommit()
if err != nil {
env.t.Fatal(err)
}
// For cause bisection, if newer than or equal to 602, it crashes.
// -- 602 is the cause commit.
// TODO: for fix bisection(check env.fix), if older than 602, it crashes.
// -- 602 is the fix commit.
val, err := strconv.Atoi(hc.Title)
if err != nil {
env.t.Fatalf("invalid commit title: %v", val)
}
if val >= 602 {
var errors []error
for i := 0; i < numVMs; i++ {
errors = append(errors, &instance.CrashError{
Report: &report.Report{
Title: fmt.Sprintf("crashes at %v", hc.Title),
},
})
}
return errors, nil
}
var errors []error
for i := 0; i < numVMs; i++ {
errors = append(errors, nil)
}
return errors, nil
}
// TestBisectCause tests that bisection returns the correct cause
// commit.
func TestBisectCause(t *testing.T) {
t.Parallel()
baseDir, err := ioutil.TempDir("", "syz-git-test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(baseDir)
originRepo := vcs.CreateTestRepo(t, baseDir, "originRepo")
for rv := 4; rv < 10; rv++ {
for i := 0; i < 6; i++ {
originRepo.CommitChange(fmt.Sprintf("%v", rv*100+i))
if i == 0 {
originRepo.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)
}
head, err := r.HeadCommit()
if err != nil {
t.Fatal(err)
}
cfg := &Config{
Fix: false,
Trace: new(bytes.Buffer),
Manager: mgrconfig.Config{
TargetOS: "test",
TargetVMArch: "64",
Type: "qemu",
KernelSrc: repo.Dir,
},
Kernel: KernelConfig{
Commit: head.Hash,
Repo: originRepo.Dir,
},
}
inst := &testEnv{
repo: repo,
r: r,
t: t,
}
commits, rep, err := runImpl(cfg, r, r.(vcs.Bisecter), inst)
if err != nil {
t.Fatalf("returned error: '%v'", err)
}
if len(commits) != 1 {
t.Fatalf("Got %d commits: %v", len(commits), commits)
}
if commits[0].Title != "602" {
t.Fatalf("Expected commit '602' got '%v'", commits[0].Title)
}
if rep == nil {
t.Fatal("returned rep==nil, report should not be empty")
}
}