Add initial implementation of fuzz testing that fuzzes multiple devices and multiple users

This commit is contained in:
David Dworken 2022-09-22 23:06:28 -07:00
parent c18c2502cc
commit 4e4caef10f
3 changed files with 121 additions and 0 deletions

View File

@ -5,6 +5,9 @@ forcetest:
test:
HISHTORY_TEST=1 go test -p 1 ./...
fuzz:
HISHTORY_TEST=1 go test -p 1 -fuzz=FuzzTestMultipleUsers -run FuzzTestMultipleUsers client/client_test.go
acttest:
act push -j test -e .github/push_event.json --reuse --container-architecture linux/amd64

View File

@ -1643,4 +1643,108 @@ func testMultipleUsers(t *testing.T, tester shellTester) {
}
}
type operation struct {
device device
cmd string
}
func FuzzTestMultipleUsers(f *testing.F) {
f.Add("a;b|2\n")
f.Add("a;b|aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n")
f.Add("a;b|aaaBBcccDD\n")
f.Add("a;a|hello\na;a|world")
f.Add("a;a|hello\na;a|world\na;b|3")
f.Add("a;a|1\na;a|2\na;b|3\nb;a|4\na;b|5")
f.Add("a;a|1\na;a|2\na;b|1\n")
f.Add("a;a|1\na;a|2\na;b|1\nz;z|1\na;a|1\n")
f.Add("a;a|hello\na;a|wobld")
f.Add("a;a|1\nb;a|2\nc;a|2\nd;a|2\na;b|2\na;b|3\na;b|4\na;b|8\na;d|2\nb;a|1")
f.Add("a;a|1\na;b|1\na;c|1\na;d|1\na;e|1\na;f|1\na;g|1\na;b|1\na;b|1\na;b|1\na;b|1")
tmp := 0
var runCounter *int = &tmp
f.Fuzz(func(t *testing.T, input string) {
*runCounter += 1
// Parse the input
if len(input) > 1_000 {
return
}
input = strings.TrimSpace(input)
ops := make([]operation, 0)
for _, line := range strings.Split(input, "\n") {
split1 := strings.SplitN(line, "|", 2)
if len(split1) != 2 {
return
}
split2 := strings.SplitN(split1[0], ";", 2)
if len(split2) != 2 {
return
}
cmd := split1[1]
re := regexp.MustCompile(`[a-zA-Z]+`)
if !re.MatchString(cmd) {
return
}
key := split2[0]
if strings.Contains(key, "-") {
return
}
op := operation{device: device{key: key + "-" + strconv.Itoa(*runCounter), deviceId: split2[1]}, cmd: "echo " + cmd}
ops = append(ops, op)
}
// Set up and create the devices
defer shared.BackupAndRestore(t)()
tester := bashTester{}
var deviceMap map[device]deviceOp = make(map[device]deviceOp)
var devices deviceSet = deviceSet{}
devices.deviceMap = &deviceMap
devices.currentDevice = nil
for _, op := range ops {
_, ok := (*devices.deviceMap)[op.device]
if ok {
continue
}
createDevice(t, tester, &devices, op.device.key, op.device.deviceId)
}
// Persist our basic in-memory copy of expected shell commands
keyToCommands := make(map[string]string)
// Run the commands
for _, op := range ops {
// Run the command
switchToDevice(&devices, op.device)
_, _ = tester.RunInteractiveShellRelaxed(t, op.cmd)
// Calculate the expected output of hishtory export
val, ok := keyToCommands[op.device.key]
if !ok {
val = ""
}
val += op.cmd
val += "\n"
keyToCommands[op.device.key] = val
// Run hishtory export and check the output
out, err := tester.RunInteractiveShellRelaxed(t, `hishtory export | grep -v export`)
shared.Check(t, err)
expectedOutput := keyToCommands[op.device.key]
if diff := cmp.Diff(expectedOutput, out); diff != "" {
t.Fatalf("hishtory export mismatch for input=%#v key=%s (-expected +got):\n%s\nout=%#v", input, op.device.key, diff, out)
}
}
// Check that hishtory export has the expected results
for _, op := range ops {
switchToDevice(&devices, op.device)
out, err := tester.RunInteractiveShellRelaxed(t, `hishtory export | grep -v export`)
shared.Check(t, err)
expectedOutput := keyToCommands[op.device.key]
if diff := cmp.Diff(expectedOutput, out); diff != "" {
t.Fatalf("hishtory export mismatch for key=%s (-expected +got):\n%s\nout=%#v", op.device.key, diff, out)
}
}
})
}
// TODO(future): Can we do a fuzz test with lots of users and lots of devices?

View File

@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"os"
@ -39,6 +40,19 @@ func BackupAndRestore(t *testing.T) func() {
return BackupAndRestoreWithId(t, "")
}
func DeleteBakFiles(t *testing.T) {
homedir, err := os.UserHomeDir()
checkError(err)
entries, err := ioutil.ReadDir(path.Join(homedir, HISHTORY_PATH))
checkError(err)
for _, entry := range entries {
fmt.Println(entry.Name())
if strings.HasSuffix(entry.Name(), ".bak") {
checkError(os.Remove(path.Join(homedir, HISHTORY_PATH, entry.Name())))
}
}
}
func BackupAndRestoreWithId(t *testing.T, id string) func() {
homedir, err := os.UserHomeDir()
if err != nil {