diff options
Diffstat (limited to 'syz-verifier')
| -rwxr-xr-x | syz-verifier/main.go | 142 | ||||
| -rw-r--r-- | syz-verifier/main_test.go | 78 | ||||
| -rw-r--r-- | syz-verifier/stats.go | 16 | ||||
| -rw-r--r-- | syz-verifier/stats_test.go | 8 | ||||
| -rw-r--r-- | syz-verifier/test_utils.go | 1 | ||||
| -rw-r--r-- | syz-verifier/verifier.go | 38 | ||||
| -rw-r--r-- | syz-verifier/verifier_test.go | 51 |
7 files changed, 197 insertions, 137 deletions
diff --git a/syz-verifier/main.go b/syz-verifier/main.go index 62de2cdf1..eea9d92ed 100755 --- a/syz-verifier/main.go +++ b/syz-verifier/main.go @@ -60,18 +60,20 @@ type Verifier struct { stats *Stats statsWrite io.Writer newEnv bool + reruns int } // RPCServer is a wrapper around the rpc.Server. It communicates with Runners, // generates programs and sends complete Results for verification. type RPCServer struct { - vrf *Verifier - port int - mu sync.Mutex - cond *sync.Cond - pools map[int]*poolInfo - progs map[int]*progInfo - notChecked int + vrf *Verifier + port int + mu sync.Mutex + cond *sync.Cond + pools map[int]*poolInfo + progs map[int]*progInfo + notChecked int + rerunsAvailable *sync.Cond } // poolInfo contains kernel-specific information for spawning virtual machines @@ -82,12 +84,14 @@ type poolInfo struct { cfg *mgrconfig.Config pool *vm.Pool Reporter report.Reporter - // vmRunners keeps track of what programs have been sent to each Runner. + // runners keeps track of what programs have been sent to each Runner. // There is one Runner executing per VM instance. - vmRunners map[int]runnerProgs + runners map[int]runnerProgs // progs stores the programs that haven't been sent to this kernel yet but // have been sent to at least one other kernel. progs []*progInfo + // toRerun stores the programs that still need to be rerun by this kernel. + toRerun []*progInfo // checked is set to true when the set of system calls not supported on the // kernel is known. checked bool @@ -97,9 +101,12 @@ type progInfo struct { prog *prog.Prog idx int serialized []byte - res []*Result + res [][]*Result // received stores the number of results received for this program. received int + + runIdx int + report *ResultReport } type runnerProgs map[int]*progInfo @@ -111,6 +118,7 @@ func main() { flagStats := flag.String("stats", "", "where stats will be written when"+ "execution of syz-verifier finishes, defaults to stdout") flagEnv := flag.Bool("new-env", true, "create a new environment for each program") + flagReruns := flag.Int("rerun", 3, "number of time program is rerun when a mismatch is found") flag.Parse() pools := make(map[int]*poolInfo) @@ -190,7 +198,7 @@ func main() { if err != nil { log.Fatalf("failed to create reporter for instance-%d: %v", idx, err) } - pi.vmRunners = make(map[int]runnerProgs) + pi.runners = make(map[int]runnerProgs) } calls := make(map[*prog.Syscall]bool) @@ -215,6 +223,7 @@ func main() { reportReasons: len(cfg.EnabledSyscalls) != 0 || len(cfg.DisabledSyscalls) != 0, statsWrite: sw, newEnv: *flagEnv, + reruns: *flagReruns, } vrf.srv, err = startRPCServer(vrf) @@ -270,6 +279,7 @@ func startRPCServer(vrf *Verifier) (*RPCServer, error) { notChecked: len(vrf.pools), } srv.cond = sync.NewCond(&srv.mu) + srv.rerunsAvailable = sync.NewCond(&srv.mu) s, err := rpctype.NewRPCServer(vrf.addr, "Verifier", srv) if err != nil { @@ -288,7 +298,7 @@ func (srv *RPCServer) Connect(a *rpctype.RunnerConnectArgs, r *rpctype.RunnerCon srv.mu.Lock() defer srv.mu.Unlock() pool, vm := a.Pool, a.VM - srv.pools[pool].vmRunners[vm] = make(runnerProgs) + srv.pools[pool].runners[vm] = make(runnerProgs) r.CheckUnsupportedCalls = !srv.pools[pool].checked return nil } @@ -362,16 +372,20 @@ func (vrf *Verifier) finalizeCallSet(w io.Writer) { func (srv *RPCServer) NextExchange(a *rpctype.NextExchangeArgs, r *rpctype.NextExchangeRes) error { srv.mu.Lock() defer srv.mu.Unlock() + + var res *Result + var prog *progInfo if a.Info.Calls != nil { - res := &Result{ + res = &Result{ Pool: a.Pool, Hanged: a.Hanged, Info: a.Info, + RunIdx: a.RunIdx, } - prog := srv.progs[a.ProgIdx] + prog = srv.progs[a.ProgIdx] if prog == nil { - // This case can happen if both of the below conditions are true: + // This case can happen if both conditions are true: // 1. a Runner calls Verifier.NextExchange, then crashes, // its corresponding Pool being the only one that hasn't // sent results for the program yet @@ -385,10 +399,11 @@ func (srv *RPCServer) NextExchange(a *rpctype.NextExchangeArgs, r *rpctype.NextE return nil } + delete(srv.pools[a.Pool].runners[a.VM], prog.idx) if srv.newResult(res, prog) { - srv.vrf.processResults(prog.res, prog.prog) - delete(srv.progs, a.ProgIdx) - delete(srv.pools[a.Pool].vmRunners[a.VM], a.ProgIdx) + if srv.vrf.processResults(prog) { + delete(srv.progs, prog.idx) + } } } @@ -397,8 +412,8 @@ func (srv *RPCServer) NextExchange(a *rpctype.NextExchangeArgs, r *rpctype.NextE srv.cond.Wait() } - prog, pi := srv.newProgram(a.Pool, a.VM) - r.RPCProg = rpctype.RPCProg{Prog: prog, ProgIdx: pi} + newProg, pi, ri := srv.newProgram(a.Pool, a.VM) + r.RPCProg = rpctype.RPCProg{Prog: newProg, ProgIdx: pi, RunIdx: ri} return nil } @@ -406,20 +421,56 @@ func (srv *RPCServer) NextExchange(a *rpctype.NextExchangeArgs, r *rpctype.NextE // Results from the corresponding programs have been received and they can be // sent for verification. Otherwise, it returns false. func (srv *RPCServer) newResult(res *Result, prog *progInfo) bool { - prog.res[res.Pool] = res + ri := prog.runIdx + if prog.res[ri][res.Pool] != nil { + return false + } + prog.res[ri][res.Pool] = res prog.received++ return prog.received == len(srv.pools) } // processResults will send a set of complete results for verification and, in -// case differences are found, it will store a result report highlighting those -// in th workdir/results directory. If writing the results fails, it returns an -// error. -func (vrf *Verifier) processResults(res []*Result, prog *prog.Prog) { - vrf.stats.Progs++ - rr := Verify(res, prog, vrf.stats) - if rr == nil { - return +// case differences are found, it will start the rerun process for the program +// (if reruns are enabled). If every rerun produces the same results, the result +// report will be printed to persistent storage. Otherwise, the program is +// discarded as flaky. +func (vrf *Verifier) processResults(prog *progInfo) bool { + // TODO: Simplify this if clause. + if prog.runIdx == 0 { + vrf.stats.TotalProgs++ + prog.report = Verify(prog.res[0], prog.prog, vrf.stats) + if prog.report == nil { + return true + } + } else { + if !VerifyRerun(prog.res[prog.runIdx], prog.report) { + vrf.stats.FlakyProgs++ + log.Printf("flaky results dected: %d", vrf.stats.FlakyProgs) + return true + } + } + + if prog.runIdx < vrf.reruns-1 { + vrf.srv.newRun(prog) + return false + } + + rr := prog.report + vrf.stats.MismatchingProgs++ + + for _, cr := range rr.Reports { + if !cr.Mismatch { + break + } + vrf.stats.Calls[cr.Call].Mismatches++ + vrf.stats.TotalMismatches++ + for _, state := range cr.States { + if state0 := cr.States[0]; state0 != state { + vrf.stats.Calls[cr.Call].States[state] = true + vrf.stats.Calls[cr.Call].States[state0] = true + } + } } oldest := 0 @@ -448,6 +499,16 @@ func (vrf *Verifier) processResults(res []*Result, prog *prog.Prog) { } log.Printf("result-%d written successfully", oldest) + return true +} + +func (srv *RPCServer) newRun(p *progInfo) { + p.runIdx++ + p.received = 0 + p.res[p.runIdx] = make([]*Result, len(srv.pools)) + for _, pool := range srv.pools { + pool.toRerun = append(pool.toRerun, p) + } } func createReport(rr *ResultReport, pools int) []byte { @@ -476,25 +537,34 @@ func createReport(rr *ResultReport, pools int) []byte { // newProgram returns a new program for the Runner identified by poolIdx and // vmIdx and the program's index. -func (srv *RPCServer) newProgram(poolIdx, vmIdx int) ([]byte, int) { +func (srv *RPCServer) newProgram(poolIdx, vmIdx int) ([]byte, int, int) { pool := srv.pools[poolIdx] + + if len(pool.toRerun) != 0 { + p := pool.toRerun[0] + pool.runners[vmIdx][p.idx] = p + pool.toRerun = pool.toRerun[1:] + return p.serialized, p.idx, p.runIdx + } + if len(pool.progs) == 0 { prog, progIdx := srv.vrf.generate() pi := &progInfo{ prog: prog, idx: progIdx, serialized: prog.Serialize(), - res: make([]*Result, len(srv.pools)), + res: make([][]*Result, srv.vrf.reruns), } + pi.res[0] = make([]*Result, len(srv.pools)) for _, pool := range srv.pools { pool.progs = append(pool.progs, pi) } srv.progs[progIdx] = pi } p := pool.progs[0] - pool.vmRunners[vmIdx][p.idx] = p + pool.runners[vmIdx][p.idx] = p pool.progs = pool.progs[1:] - return p.serialized, p.idx + return p.serialized, p.idx, p.runIdx } // generate will return a newly generated program and its index. @@ -507,13 +577,13 @@ func (vrf *Verifier) generate() (*prog.Prog, int) { func (srv *RPCServer) cleanup(poolIdx, vmIdx int) { srv.mu.Lock() defer srv.mu.Unlock() - progs := srv.pools[poolIdx].vmRunners[vmIdx] + progs := srv.pools[poolIdx].runners[vmIdx] for _, prog := range progs { if srv.newResult(&Result{Pool: poolIdx, Crashed: true}, prog) { - srv.vrf.processResults(prog.res, prog.prog) + srv.vrf.processResults(prog) delete(srv.progs, prog.idx) - delete(srv.pools[poolIdx].vmRunners[vmIdx], prog.idx) + delete(srv.pools[poolIdx].runners[vmIdx], prog.idx) continue } } diff --git a/syz-verifier/main_test.go b/syz-verifier/main_test.go index 0eb502aeb..6bf7c3d7d 100644 --- a/syz-verifier/main_test.go +++ b/syz-verifier/main_test.go @@ -40,12 +40,12 @@ func TestNewProgram(t *testing.T) { srv := createTestServer(t) srv.pools = map[int]*poolInfo{ 1: { - vmRunners: map[int]runnerProgs{ + runners: map[int]runnerProgs{ 1: {1: {}}, }, progs: []*progInfo{{idx: 3}}, }, - 2: {vmRunners: map[int]runnerProgs{ + 2: {runners: map[int]runnerProgs{ 2: {1: {}}}, progs: []*progInfo{}, }, @@ -56,7 +56,7 @@ func TestNewProgram(t *testing.T) { 3: {idx: 3}, } - _, gotProgIdx := srv.newProgram(test.pool, test.vm) + _, gotProgIdx, _ := srv.newProgram(test.pool, test.vm) if gotProgIdx != test.retProgIdx { t.Errorf("srv.newProgram returned idx: got %d, want %d", gotProgIdx, test.retProgIdx) } @@ -91,12 +91,17 @@ func TestNewResult(t *testing.T) { srv.pools = map[int]*poolInfo{0: {}, 1: {}} srv.progs = map[int]*progInfo{ 1: {idx: 1, - res: make([]*Result, 2), + res: func() [][]*Result { + res := make([][]*Result, 1) + res[0] = make([]*Result, 2) + return res + }(), }, 3: {idx: 3, - res: func() []*Result { - res := make([]*Result, 2) - res[1] = &Result{Pool: 1} + res: func() [][]*Result { + res := make([][]*Result, 1) + res[0] = make([]*Result, 2) + res[0][1] = &Result{Pool: 1} return res }(), received: 1, @@ -114,7 +119,7 @@ func TestConnect(t *testing.T) { srv := createTestServer(t) srv.pools = map[int]*poolInfo{ 1: { - vmRunners: map[int]runnerProgs{ + runners: map[int]runnerProgs{ 0: {1: {idx: 1}}, }, progs: []*progInfo{{ @@ -134,7 +139,7 @@ func TestConnect(t *testing.T) { want, got := map[int]runnerProgs{ 0: {1: {idx: 1}}, 1: {}, - }, srv.pools[a.Pool].vmRunners + }, srv.pools[a.Pool].runners if diff := cmp.Diff(want, got, cmp.AllowUnexported(progInfo{})); diff != "" { t.Errorf("srv.progs[a.Name] mismatch (-want +got):\n%s", diff) } @@ -282,8 +287,8 @@ func TestUpdateUnsupported(t *testing.T) { func TestUpdateUnsupportedNotCalledTwice(t *testing.T) { vrf := Verifier{ pools: map[int]*poolInfo{ - 0: {vmRunners: map[int]runnerProgs{0: nil, 1: nil}, checked: false}, - 1: {vmRunners: map[int]runnerProgs{}, checked: false}, + 0: {runners: map[int]runnerProgs{0: nil, 1: nil}, checked: false}, + 1: {runners: map[int]runnerProgs{}, checked: false}, }, } srv, err := startRPCServer(&vrf) @@ -307,8 +312,8 @@ func TestUpdateUnsupportedNotCalledTwice(t *testing.T) { } wantPools := map[int]*poolInfo{ - 0: {vmRunners: map[int]runnerProgs{0: nil, 1: nil}, checked: true}, - 1: {vmRunners: map[int]runnerProgs{}, checked: false}, + 0: {runners: map[int]runnerProgs{0: nil, 1: nil}, checked: true}, + 1: {runners: map[int]runnerProgs{}, checked: false}, } if diff := cmp.Diff(wantPools, srv.pools, cmp.AllowUnexported(poolInfo{}, progInfo{})); diff != "" { t.Errorf("srv.pools mismatch (-want +got):\n%s", diff) @@ -332,7 +337,7 @@ func TestProcessResults(t *testing.T) { wantExist: true, wantStats: &Stats{ TotalMismatches: 1, - Progs: 1, + TotalProgs: 1, Calls: map[string]*CallStats{ "breaks_returns": makeCallStats("breaks_returns", 1, 0, map[ReturnState]bool{}), "test$res0": makeCallStats("test$res0", 1, 1, map[ReturnState]bool{{Errno: 2}: true, {Errno: 5}: true}), @@ -347,7 +352,7 @@ func TestProcessResults(t *testing.T) { makeResult(1, []int{11, 33, 22}), }, wantStats: &Stats{ - Progs: 1, + TotalProgs: 1, Calls: map[string]*CallStats{ "breaks_returns": makeCallStats("breaks_returns", 1, 0, map[ReturnState]bool{}), "minimize$0": makeCallStats("minimize$0", 1, 0, map[ReturnState]bool{}), @@ -359,13 +364,20 @@ func TestProcessResults(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { prog := getTestProgram(t) + pi := &progInfo{ + prog: prog, + res: func() [][]*Result { + res := make([][]*Result, 1) + res[0] = test.res + return res + }()} vrf := Verifier{ resultsdir: makeTestResultDirectory(t), stats: emptyTestStats(), } resultFile := filepath.Join(vrf.resultsdir, "result-0") - vrf.processResults(test.res, prog) + vrf.processResults(pi) if diff := cmp.Diff(test.wantStats, vrf.stats); diff != "" { t.Errorf("vrf.stats mismatch (-want +got):\n%s", diff) @@ -435,15 +447,16 @@ func TestCleanup(t *testing.T) { 4: { idx: 4, received: 0, - res: func() []*Result { - res := make([]*Result, 3) + res: func() [][]*Result { + res := make([][]*Result, 1) + res[0] = make([]*Result, 3) return res }(), }}, wantProg: &progInfo{ idx: 4, received: 1, - res: []*Result{makeResultCrashed(0), nil, nil}, + res: [][]*Result{{makeResultCrashed(0), nil, nil}}, }, wantStats: emptyTestStats(), fileExists: false, @@ -455,15 +468,16 @@ func TestCleanup(t *testing.T) { idx: 4, prog: prog, received: 2, - res: func() []*Result { - res := make([]*Result, 3) - res[1] = makeResultCrashed(1) - res[2] = makeResultCrashed(2) + res: func() [][]*Result { + res := make([][]*Result, 1) + res[0] = make([]*Result, 3) + res[0][1] = makeResultCrashed(1) + res[0][2] = makeResultCrashed(2) return res }(), }}, wantStats: &Stats{ - Progs: 1, + TotalProgs: 1, Calls: map[string]*CallStats{ "breaks_returns": makeCallStats("breaks_returns", 1, 0, map[ReturnState]bool{}), "minimize$0": makeCallStats("minimize$0", 1, 0, map[ReturnState]bool{}), @@ -479,16 +493,18 @@ func TestCleanup(t *testing.T) { idx: 4, prog: prog, received: 2, - res: func() []*Result { - res := make([]*Result, 3) - res[1] = makeResult(1, []int{11, 33, 44}) - res[2] = makeResult(2, []int{11, 33, 22}) + res: func() [][]*Result { + res := make([][]*Result, 1) + res[0] = make([]*Result, 3) + res[0][1] = makeResult(1, []int{11, 33, 44}) + res[0][2] = makeResult(2, []int{11, 33, 22}) return res }(), }}, wantStats: &Stats{ - TotalMismatches: 3, - Progs: 1, + TotalMismatches: 3, + TotalProgs: 1, + MismatchingProgs: 1, Calls: map[string]*CallStats{ "breaks_returns": makeCallStats("breaks_returns", 1, 1, map[ReturnState]bool{ @@ -513,7 +529,7 @@ func TestCleanup(t *testing.T) { srv := createTestServer(t) srv.progs = test.progs srv.pools = map[int]*poolInfo{ - 0: {vmRunners: map[int]runnerProgs{ + 0: {runners: map[int]runnerProgs{ 0: {4: srv.progs[4]}}, }, 1: {}, 2: {}} resultFile := filepath.Join(srv.vrf.resultsdir, "result-0") diff --git a/syz-verifier/stats.go b/syz-verifier/stats.go index 3321de478..804b6ec75 100644 --- a/syz-verifier/stats.go +++ b/syz-verifier/stats.go @@ -18,10 +18,12 @@ import ( // of the verification process. type Stats struct { // Calls stores statistics for all supported system calls. - Calls map[string]*CallStats - TotalMismatches int - Progs int - StartTime time.Time + Calls map[string]*CallStats + TotalMismatches int + TotalProgs int + FlakyProgs int + MismatchingProgs int + StartTime time.Time } // CallStats stores information used to generate statistics for the @@ -96,7 +98,11 @@ func (s *Stats) ReportGlobalStats(w io.Writer, deltaTime float64) { tc := s.totalCallsExecuted() fmt.Fprintf(w, "total number of mismatches / total number of calls "+ "executed: %d / %d (%0.2f %%)\n\n", s.TotalMismatches, tc, getPercentage(s.TotalMismatches, tc)) - fmt.Fprintf(w, "programs / minute: %0.2f\n\n", float64(s.Progs)/deltaTime) + fmt.Fprintf(w, "programs / minute: %0.2f\n\n", float64(s.TotalProgs)/deltaTime) + fmt.Fprintf(w, "true mismatching programs: %d / total number of programs: %d (%0.2f %%)\n", + s.MismatchingProgs, s.TotalProgs, getPercentage(s.MismatchingProgs, s.TotalProgs)) + fmt.Fprintf(w, "flaky programs: %d / total number of programs: %d (%0.2f %%)\n\n", + s.FlakyProgs, s.TotalProgs, getPercentage(s.FlakyProgs, s.TotalProgs)) cs := s.getOrderedStats() for _, c := range cs { fmt.Fprintf(w, "%s\n", s.ReportCallStats(c.Name)) diff --git a/syz-verifier/stats_test.go b/syz-verifier/stats_test.go index 81dc1ef2e..38f4f4661 100644 --- a/syz-verifier/stats_test.go +++ b/syz-verifier/stats_test.go @@ -11,8 +11,10 @@ import ( func dummyStats() *Stats { return &Stats{ - Progs: 24, - TotalMismatches: 10, + TotalProgs: 24, + TotalMismatches: 10, + FlakyProgs: 4, + MismatchingProgs: 6, Calls: map[string]*CallStats{ "foo": {"foo", 2, 8, map[ReturnState]bool{ returnState(1, 7): true, @@ -69,6 +71,8 @@ func TestReportGlobalStats(t *testing.T) { "total number of mismatches / total number of calls "+ "executed: 10 / 20 (50.00 %)\n\n"+ "programs / minute: 2.40\n\n"+ + "true mismatching programs: 6 / total number of programs: 24 (25.00 %)\n"+ + "flaky programs: 4 / total number of programs: 24 (16.67 %)\n\n"+ "statistics for bar:\n"+ "\t↳ mismatches of bar / occurrences of bar: 5 / 6 (83.33 %)\n"+ "\t↳ mismatches of bar / total number of mismatches: 5 / 10 (50.00 %)\n"+ diff --git a/syz-verifier/test_utils.go b/syz-verifier/test_utils.go index 7c5df0cf5..a32c0aa29 100644 --- a/syz-verifier/test_utils.go +++ b/syz-verifier/test_utils.go @@ -24,6 +24,7 @@ func createTestServer(t *testing.T) *RPCServer { choiceTable: target.DefaultChoiceTable(), rnd: rand.New(rand.NewSource(time.Now().UnixNano())), progIdx: 3, + reruns: 1, } vrf.resultsdir = makeTestResultDirectory(t) vrf.stats = emptyTestStats() diff --git a/syz-verifier/verifier.go b/syz-verifier/verifier.go index c36d9236c..9e97046b9 100644 --- a/syz-verifier/verifier.go +++ b/syz-verifier/verifier.go @@ -22,6 +22,8 @@ type Result struct { Info ipc.ProgInfo // Crashed is set to true if a crash occurred while executing the program. Crashed bool + + RunIdx int } type ResultReport struct { @@ -67,9 +69,29 @@ func (s ReturnState) String() string { return state } +// VeifyRerun compares the results obtained from rerunning a program with what +// was reported in the initial result report. +func VerifyRerun(res []*Result, rr *ResultReport) bool { + for idx, cr := range rr.Reports { + for _, r := range res { + var state ReturnState + if r.Crashed { + state = ReturnState{Crashed: true} + } else { + ci := r.Info.Calls[idx] + state = ReturnState{Errno: ci.Errno, Flags: ci.Flags} + } + if state != cr.States[r.Pool] { + return false + } + } + } + return true +} + // Verify checks whether the Results of the same program, executed on different -// kernels are the same. If that's not the case, it returns a ResultReport -// which highlights the differences. +// kernels, are the same. If that's not the case, it returns a ResultReport, +// highlighting the differences. func Verify(res []*Result, prog *prog.Prog, s *Stats) *ResultReport { rr := &ResultReport{ Prog: string(prog.Serialize()), @@ -100,26 +122,14 @@ func Verify(res []*Result, prog *prog.Prog, s *Stats) *ResultReport { var send bool pool0 := res[0].Pool for _, cr := range rr.Reports { - cs := s.Calls[cr.Call] - - mismatch := false for _, state := range cr.States { // For each CallReport, verify whether the ReturnStates from all // the pools that executed the program are the same if state0 := cr.States[pool0]; state0 != state { cr.Mismatch = true send = true - mismatch = true - - cs.States[state] = true - cs.States[state0] = true } } - - if mismatch { - cs.Mismatches++ - s.TotalMismatches++ - } } if send { diff --git a/syz-verifier/verifier_test.go b/syz-verifier/verifier_test.go index babd87476..41344bafc 100644 --- a/syz-verifier/verifier_test.go +++ b/syz-verifier/verifier_test.go @@ -18,7 +18,7 @@ func TestVerify(t *testing.T) { name string res []*Result wantReport *ResultReport - wantStats *Stats + wantStats []*CallStats }{ { name: "only crashes", @@ -27,13 +27,6 @@ func TestVerify(t *testing.T) { makeResultCrashed(4), }, wantReport: nil, - wantStats: &Stats{ - Calls: map[string]*CallStats{ - "breaks_returns": {Name: "breaks_returns", Occurrences: 1, States: map[ReturnState]bool{}}, - "minimize$0": {Name: "minimize$0", Occurrences: 1, States: map[ReturnState]bool{}}, - "test$res0": {Name: "test$res0", Occurrences: 1, States: map[ReturnState]bool{}}, - }, - }, }, { name: "mismatches because results and crashes", @@ -62,24 +55,6 @@ func TestVerify(t *testing.T) { Mismatch: true}, }, }, - wantStats: &Stats{ - TotalMismatches: 6, - Calls: map[string]*CallStats{ - "breaks_returns": {Name: "breaks_returns", Occurrences: 1, Mismatches: 2, States: map[ReturnState]bool{ - crashedReturnState(): true, - returnState(11, 1): true, - }}, - "minimize$0": {Name: "minimize$0", Occurrences: 1, - Mismatches: 2, States: map[ReturnState]bool{ - crashedReturnState(): true, - returnState(33, 3): true, - }}, - "test$res0": {Name: "test$res0", Occurrences: 1, - Mismatches: 2, States: map[ReturnState]bool{ - crashedReturnState(): true, - returnState(22, 3): true}}, - }, - }, }, { name: "mismatches not found in results", @@ -87,13 +62,6 @@ func TestVerify(t *testing.T) { makeResult(2, []int{11, 33, 22}, []int{1, 3, 3}...), makeResult(4, []int{11, 33, 22}, []int{1, 3, 3}...)}, wantReport: nil, - wantStats: &Stats{ - Calls: map[string]*CallStats{ - "breaks_returns": {Name: "breaks_returns", Occurrences: 1, States: map[ReturnState]bool{}}, - "minimize$0": {Name: "minimize$0", Occurrences: 1, States: map[ReturnState]bool{}}, - "test$res0": {Name: "test$res0", Occurrences: 1, States: map[ReturnState]bool{}}, - }, - }, }, { name: "mismatches found in results", @@ -109,19 +77,7 @@ func TestVerify(t *testing.T) { {Call: "test$res0", States: map[int]ReturnState{1: {Errno: 2, Flags: 7}, 4: {Errno: 5, Flags: 3}}, Mismatch: true}, }, }, - wantStats: &Stats{ - TotalMismatches: 1, - Calls: map[string]*CallStats{ - "breaks_returns": {Name: "breaks_returns", Occurrences: 1, States: map[ReturnState]bool{}}, - "minimize$0": {Name: "minimize$0", Occurrences: 1, States: map[ReturnState]bool{}}, - "test$res0": {Name: "test$res0", Occurrences: 1, - Mismatches: 1, States: map[ReturnState]bool{ - {Errno: 2, Flags: 7}: true, - {Errno: 5, Flags: 3}: true}}, - }, - }, - }, - } + }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -135,9 +91,6 @@ func TestVerify(t *testing.T) { if diff := cmp.Diff(test.wantReport, got); diff != "" { t.Errorf("Verify report mismatch (-want +got):\n%s", diff) } - if diff := cmp.Diff(test.wantStats, stats); diff != "" { - t.Errorf("Verify stats mismatch (-want +got):\n%s", diff) - } }) } } |
