// Copyright 2016 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 state
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"testing"
)
func TestState(t *testing.T) {
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)
if err != nil {
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)
if err != nil {
t.Fatalf("Sync failed: %v", err)
}
}
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)
}
defer os.RemoveAll(dir)
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, "foo", "")
checkPendingRepro(t, st, "bar", "")
if err := st.AddRepro("foo", []byte("open()")); err != nil {
t.Fatalf("AddRepro failed: %v", err)
}
checkPendingRepro(t, st, "foo", "")
checkPendingRepro(t, st, "bar", "open()")
checkPendingRepro(t, st, "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)
}
// 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", "")
// 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", "")
}
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 caller(skip int) string {
_, file, line, _ := runtime.Caller(skip + 1)
return fmt.Sprintf("%v:%v", filepath.Base(file), line)
}