diff options
Diffstat (limited to 'syz-hub/state/state_test.go')
| -rw-r--r-- | syz-hub/state/state_test.go | 237 |
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) + } + } } |
