aboutsummaryrefslogtreecommitdiffstats
path: root/syz-hub/state/state_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'syz-hub/state/state_test.go')
-rw-r--r--syz-hub/state/state_test.go237
1 files changed, 162 insertions, 75 deletions
diff --git a/syz-hub/state/state_test.go b/syz-hub/state/state_test.go
index 0972ad6bc..8db7a30f6 100644
--- a/syz-hub/state/state_test.go
+++ b/syz-hub/state/state_test.go
@@ -4,111 +4,198 @@
package state
import (
- "fmt"
"io/ioutil"
"os"
- "path/filepath"
- "runtime"
+ "sort"
"testing"
+
+ "github.com/google/go-cmp/cmp"
+ "github.com/google/syzkaller/pkg/rpctype"
)
-func TestState(t *testing.T) {
+type TestState struct {
+ t *testing.T
+ dir string
+ state *State
+}
+
+func MakeTestState(t *testing.T) *TestState {
+ t.Parallel()
dir, err := ioutil.TempDir("", "syz-hub-state-test")
if err != nil {
t.Fatalf("failed to create temp dir: %v", err)
}
- defer os.RemoveAll(dir)
-
- st, err := Make(dir)
+ state, err := Make(dir)
if err != nil {
+ os.RemoveAll(dir)
t.Fatalf("failed to make state: %v", err)
}
- _, _, err = st.Sync("foo", nil, nil)
- if err == nil {
- t.Fatalf("synced with unconnected manager")
- }
- calls := []string{"read", "write"}
- if err := st.Connect("foo", false, calls, nil); err != nil {
- t.Fatalf("Connect failed: %v", err)
- }
- _, _, err = st.Sync("foo", nil, nil)
+ return &TestState{t, dir, state}
+}
+
+func (ts *TestState) Close() {
+ os.RemoveAll(ts.dir)
+}
+
+func (ts *TestState) Reload() {
+ ts.state.Flush()
+ state, err := Make(ts.dir)
if err != nil {
- t.Fatalf("Sync failed: %v", err)
+ ts.t.Fatalf("failed to make state: %v", err)
}
+ ts.state = state
}
-func TestRepro(t *testing.T) {
- dir, err := ioutil.TempDir("", "syz-hub-state-test")
- if err != nil {
- t.Fatalf("failed to create temp dir: %v", err)
+func (ts *TestState) Connect(name, domain string, fresh bool, calls []string, corpus [][]byte) {
+ ts.t.Helper()
+ if err := ts.state.Connect(name, domain, fresh, calls, corpus); err != nil {
+ ts.t.Fatalf("Connect failed: %v", err)
}
- defer os.RemoveAll(dir)
+}
- st, err := Make(dir)
+func (ts *TestState) Sync(name string, add [][]byte, del []string) (string, []rpctype.HubInput, int) {
+ ts.t.Helper()
+ domain, inputs, pending, err := ts.state.Sync(name, add, del)
if err != nil {
- t.Fatalf("failed to make state: %v", err)
- }
+ ts.t.Fatalf("Sync failed: %v", err)
+ }
+ sort.Slice(inputs, func(i, j int) bool {
+ if inputs[i].Domain != inputs[j].Domain {
+ return inputs[i].Domain < inputs[j].Domain
+ }
+ return string(inputs[i].Prog) < string(inputs[j].Prog)
+ })
+ return domain, inputs, pending
+}
- if err := st.Connect("foo", false, []string{"open", "read", "write"}, nil); err != nil {
- t.Fatalf("Connect failed: %v", err)
+func (ts *TestState) AddRepro(name string, repro []byte) {
+ ts.t.Helper()
+ if err := ts.state.AddRepro(name, repro); err != nil {
+ ts.t.Fatalf("AddRepro failed: %v", err)
}
- if err := st.Connect("bar", false, []string{"open", "read", "close"}, nil); err != nil {
- t.Fatalf("Connect failed: %v", err)
+}
+
+func (ts *TestState) PendingRepro(name string) []byte {
+ ts.t.Helper()
+ repro, err := ts.state.PendingRepro(name)
+ if err != nil {
+ ts.t.Fatalf("PendingRepro failed: %v", err)
}
- checkPendingRepro(t, st, "foo", "")
- checkPendingRepro(t, st, "bar", "")
+ return repro
+}
+
+func TestBasic(t *testing.T) {
+ st := MakeTestState(t)
+ defer st.Close()
- if err := st.AddRepro("foo", []byte("open()")); err != nil {
- t.Fatalf("AddRepro failed: %v", err)
+ if _, _, _, err := st.state.Sync("foo", nil, nil); err == nil {
+ t.Fatalf("synced with unconnected manager")
}
- checkPendingRepro(t, st, "foo", "")
- checkPendingRepro(t, st, "bar", "open()")
- checkPendingRepro(t, st, "bar", "")
+ calls := []string{"read", "write"}
+ st.Connect("foo", "", false, calls, nil)
+ st.Sync("foo", nil, nil)
+}
+
+func TestRepro(t *testing.T) {
+ st := MakeTestState(t)
+ defer st.Close()
+
+ st.Connect("foo", "", false, []string{"open", "read", "write"}, nil)
+ st.Connect("bar", "", false, []string{"open", "read", "close"}, nil)
+
+ expectPendingRepro := func(name, result string) {
+ t.Helper()
+ repro := st.PendingRepro(name)
+ if string(repro) != result {
+ t.Fatalf("PendingRepro returned %q, want %q", string(repro), result)
+ }
+ }
+ expectPendingRepro("foo", "")
+ expectPendingRepro("bar", "")
+ st.AddRepro("foo", []byte("open()"))
+ expectPendingRepro("foo", "")
+ expectPendingRepro("bar", "open()")
+ expectPendingRepro("bar", "")
// This repro is already present.
- if err := st.AddRepro("bar", []byte("open()")); err != nil {
- t.Fatalf("AddRepro failed: %v", err)
- }
- if err := st.AddRepro("bar", []byte("read()")); err != nil {
- t.Fatalf("AddRepro failed: %v", err)
- }
- if err := st.AddRepro("bar", []byte("open()\nread()")); err != nil {
- t.Fatalf("AddRepro failed: %v", err)
- }
+ st.AddRepro("bar", []byte("open()"))
+ st.AddRepro("bar", []byte("read()"))
+ st.AddRepro("bar", []byte("open()\nread()"))
// This does not satisfy foo's call set.
- if err := st.AddRepro("bar", []byte("close()")); err != nil {
- t.Fatalf("AddRepro failed: %v", err)
- }
- checkPendingRepro(t, st, "bar", "")
+ st.AddRepro("bar", []byte("close()"))
+ expectPendingRepro("bar", "")
// Check how persistence works.
- st, err = Make(dir)
- if err != nil {
- t.Fatalf("failed to make state: %v", err)
- }
- if err := st.Connect("foo", false, []string{"open", "read", "write"}, nil); err != nil {
- t.Fatalf("Connect failed: %v", err)
- }
- if err := st.Connect("bar", false, []string{"open", "read", "close"}, nil); err != nil {
- t.Fatalf("Connect failed: %v", err)
- }
- checkPendingRepro(t, st, "bar", "")
- checkPendingRepro(t, st, "foo", "read()")
- checkPendingRepro(t, st, "foo", "open()\nread()")
- checkPendingRepro(t, st, "foo", "")
+ st.Reload()
+ st.Connect("foo", "", false, []string{"open", "read", "write"}, nil)
+ st.Connect("bar", "", false, []string{"open", "read", "close"}, nil)
+ expectPendingRepro("bar", "")
+ expectPendingRepro("foo", "read()")
+ expectPendingRepro("foo", "open()\nread()")
+ expectPendingRepro("foo", "")
}
-func checkPendingRepro(t *testing.T, st *State, name, result string) {
- repro, err := st.PendingRepro(name)
- if err != nil {
- t.Fatalf("\n%v: PendingRepro failed: %v", caller(1), err)
- }
- if string(repro) != result {
- t.Fatalf("\n%v: PendingRepro returned %q, want %q", caller(1), string(repro), result)
- }
-}
+func TestDomain(t *testing.T) {
+ st := MakeTestState(t)
+ defer st.Close()
-func caller(skip int) string {
- _, file, line, _ := runtime.Caller(skip + 1)
- return fmt.Sprintf("%v:%v", filepath.Base(file), line)
+ st.Connect("client0", "", false, []string{"open"}, nil)
+ st.Connect("client1", "domain1", false, []string{"open"}, nil)
+ st.Connect("client2", "domain2", false, []string{"open"}, nil)
+ st.Connect("client3", "domain3", false, []string{"open"}, nil)
+ {
+ domain, inputs, pending := st.Sync("client0", [][]byte{[]byte("open(0x0)")}, nil)
+ if domain != "" || len(inputs) != 0 || pending != 0 {
+ t.Fatalf("bad sync result: %v, %v, %v", domain, inputs, pending)
+ }
+ }
+ {
+ domain, inputs, pending := st.Sync("client0", [][]byte{[]byte("open(0x1)")}, nil)
+ if domain != "" || len(inputs) != 0 || pending != 0 {
+ t.Fatalf("bad sync result: %v, %v, %v", domain, inputs, pending)
+ }
+ }
+ {
+ domain, inputs, pending := st.Sync("client1", [][]byte{[]byte("open(0x2)"), []byte("open(0x1)")}, nil)
+ if domain != "domain1" || pending != 0 {
+ t.Fatalf("bad sync result: %v, %v, %v", domain, inputs, pending)
+ }
+ if diff := cmp.Diff(inputs, []rpctype.HubInput{
+ {Domain: "", Prog: []byte("open(0x0)")},
+ }); diff != "" {
+ t.Fatal(diff)
+ }
+ }
+ {
+ _, inputs, _ := st.Sync("client2", [][]byte{[]byte("open(0x3)")}, nil)
+ if diff := cmp.Diff(inputs, []rpctype.HubInput{
+ {Domain: "", Prog: []byte("open(0x0)")},
+ {Domain: "domain1", Prog: []byte("open(0x1)")},
+ {Domain: "domain1", Prog: []byte("open(0x2)")},
+ }); diff != "" {
+ t.Fatal(diff)
+ }
+ }
+ {
+ _, inputs, _ := st.Sync("client0", nil, nil)
+ if diff := cmp.Diff(inputs, []rpctype.HubInput{
+ {Domain: "domain1", Prog: []byte("open(0x2)")},
+ {Domain: "domain2", Prog: []byte("open(0x3)")},
+ }); diff != "" {
+ t.Fatal(diff)
+ }
+ }
+ st.Reload()
+ st.Connect("client3", "domain3", false, []string{"open"}, nil)
+ {
+ _, inputs, _ := st.Sync("client3", nil, nil)
+ if diff := cmp.Diff(inputs, []rpctype.HubInput{
+ {Domain: "", Prog: []byte("open(0x0)")},
+ {Domain: "domain1", Prog: []byte("open(0x1)")},
+ {Domain: "domain1", Prog: []byte("open(0x2)")},
+ {Domain: "domain2", Prog: []byte("open(0x3)")},
+ }); diff != "" {
+ t.Fatal(diff)
+ }
+ }
}