Move testutils to a separate package so as to move test-only code out of the main binary

This commit is contained in:
David Dworken 2022-10-27 21:53:47 -07:00
parent bed19f5316
commit cdc5421a7b
9 changed files with 282 additions and 264 deletions

View File

@ -12,6 +12,7 @@ import (
"github.com/ddworken/hishtory/client/data"
"github.com/ddworken/hishtory/shared"
"github.com/ddworken/hishtory/shared/testutils"
"github.com/go-test/deep"
"github.com/google/uuid"
)
@ -34,11 +35,11 @@ func TestESubmitThenQuery(t *testing.T) {
apiRegisterHandler(nil, deviceReq)
// Submit a few entries for different devices
entry := data.MakeFakeHistoryEntry("ls ~/")
entry := testutils.MakeFakeHistoryEntry("ls ~/")
encEntry, err := data.EncryptHistoryEntry("key", entry)
shared.Check(t, err)
testutils.Check(t, err)
reqBody, err := json.Marshal([]shared.EncHistoryEntry{encEntry})
shared.Check(t, err)
testutils.Check(t, err)
submitReq := httptest.NewRequest(http.MethodPost, "/", bytes.NewReader(reqBody))
apiSubmitHandler(nil, submitReq)
@ -49,9 +50,9 @@ func TestESubmitThenQuery(t *testing.T) {
res := w.Result()
defer res.Body.Close()
respBody, err := ioutil.ReadAll(res.Body)
shared.Check(t, err)
testutils.Check(t, err)
var retrievedEntries []*shared.EncHistoryEntry
shared.Check(t, json.Unmarshal(respBody, &retrievedEntries))
testutils.Check(t, json.Unmarshal(respBody, &retrievedEntries))
if len(retrievedEntries) != 1 {
t.Fatalf("Expected to retrieve 1 entry, found %d", len(retrievedEntries))
}
@ -66,7 +67,7 @@ func TestESubmitThenQuery(t *testing.T) {
t.Fatalf("db.ReadCount should have been 1, was %v", dbEntry.ReadCount)
}
decEntry, err := data.DecryptHistoryEntry("key", *dbEntry)
shared.Check(t, err)
testutils.Check(t, err)
if !data.EntryEquals(decEntry, entry) {
t.Fatalf("DB data is different than input! \ndb =%#v\ninput=%#v", *dbEntry, entry)
}
@ -78,8 +79,8 @@ func TestESubmitThenQuery(t *testing.T) {
res = w.Result()
defer res.Body.Close()
respBody, err = ioutil.ReadAll(res.Body)
shared.Check(t, err)
shared.Check(t, json.Unmarshal(respBody, &retrievedEntries))
testutils.Check(t, err)
testutils.Check(t, json.Unmarshal(respBody, &retrievedEntries))
if len(retrievedEntries) != 1 {
t.Fatalf("Expected to retrieve 1 entry, found %d", len(retrievedEntries))
}
@ -94,7 +95,7 @@ func TestESubmitThenQuery(t *testing.T) {
t.Fatalf("db.ReadCount should have been 1, was %v", dbEntry.ReadCount)
}
decEntry, err = data.DecryptHistoryEntry("key", *dbEntry)
shared.Check(t, err)
testutils.Check(t, err)
if !data.EntryEquals(decEntry, entry) {
t.Fatalf("DB data is different than input! \ndb =%#v\ninput=%#v", *dbEntry, entry)
}
@ -106,8 +107,8 @@ func TestESubmitThenQuery(t *testing.T) {
res = w.Result()
defer res.Body.Close()
respBody, err = ioutil.ReadAll(res.Body)
shared.Check(t, err)
shared.Check(t, json.Unmarshal(respBody, &retrievedEntries))
testutils.Check(t, err)
testutils.Check(t, json.Unmarshal(respBody, &retrievedEntries))
if len(retrievedEntries) != 2 {
t.Fatalf("Expected to retrieve 2 entries, found %d", len(retrievedEntries))
}
@ -139,9 +140,9 @@ func TestDumpRequestAndResponse(t *testing.T) {
res := w.Result()
defer res.Body.Close()
respBody, err := ioutil.ReadAll(res.Body)
shared.Check(t, err)
testutils.Check(t, err)
var dumpRequests []*shared.DumpRequest
shared.Check(t, json.Unmarshal(respBody, &dumpRequests))
testutils.Check(t, json.Unmarshal(respBody, &dumpRequests))
if len(dumpRequests) != 1 {
t.Fatalf("expected one pending dump request, got %#v", dumpRequests)
}
@ -159,9 +160,9 @@ func TestDumpRequestAndResponse(t *testing.T) {
res = w.Result()
defer res.Body.Close()
respBody, err = ioutil.ReadAll(res.Body)
shared.Check(t, err)
testutils.Check(t, err)
dumpRequests = make([]*shared.DumpRequest, 0)
shared.Check(t, json.Unmarshal(respBody, &dumpRequests))
testutils.Check(t, json.Unmarshal(respBody, &dumpRequests))
if len(dumpRequests) != 1 {
t.Fatalf("expected one pending dump request, got %#v", dumpRequests)
}
@ -179,7 +180,7 @@ func TestDumpRequestAndResponse(t *testing.T) {
res = w.Result()
defer res.Body.Close()
respBody, err = ioutil.ReadAll(res.Body)
shared.Check(t, err)
testutils.Check(t, err)
if string(respBody) != "[]" {
t.Fatalf("got unexpected respBody: %#v", string(respBody))
}
@ -190,20 +191,20 @@ func TestDumpRequestAndResponse(t *testing.T) {
res = w.Result()
defer res.Body.Close()
respBody, err = ioutil.ReadAll(res.Body)
shared.Check(t, err)
testutils.Check(t, err)
if string(respBody) != "[]" {
t.Fatalf("got unexpected respBody: %#v", string(respBody))
}
// Now submit a dump for userId
entry1Dec := data.MakeFakeHistoryEntry("ls ~/")
entry1Dec := testutils.MakeFakeHistoryEntry("ls ~/")
entry1, err := data.EncryptHistoryEntry("dkey", entry1Dec)
shared.Check(t, err)
entry2Dec := data.MakeFakeHistoryEntry("aaaaaaáaaa")
testutils.Check(t, err)
entry2Dec := testutils.MakeFakeHistoryEntry("aaaaaaáaaa")
entry2, err := data.EncryptHistoryEntry("dkey", entry1Dec)
shared.Check(t, err)
testutils.Check(t, err)
reqBody, err := json.Marshal([]shared.EncHistoryEntry{entry1, entry2})
shared.Check(t, err)
testutils.Check(t, err)
submitReq := httptest.NewRequest(http.MethodPost, "/?user_id="+userId+"&requesting_device_id="+devId2+"&source_device_id="+devId1, bytes.NewReader(reqBody))
apiSubmitDumpHandler(nil, submitReq)
@ -213,7 +214,7 @@ func TestDumpRequestAndResponse(t *testing.T) {
res = w.Result()
defer res.Body.Close()
respBody, err = ioutil.ReadAll(res.Body)
shared.Check(t, err)
testutils.Check(t, err)
if string(respBody) != "[]" {
t.Fatalf("got unexpected respBody: %#v", string(respBody))
}
@ -223,7 +224,7 @@ func TestDumpRequestAndResponse(t *testing.T) {
res = w.Result()
defer res.Body.Close()
respBody, err = ioutil.ReadAll(res.Body)
shared.Check(t, err)
testutils.Check(t, err)
if string(respBody) != "[]" {
t.Fatalf("got unexpected respBody: %#v", string(respBody))
}
@ -234,9 +235,9 @@ func TestDumpRequestAndResponse(t *testing.T) {
res = w.Result()
defer res.Body.Close()
respBody, err = ioutil.ReadAll(res.Body)
shared.Check(t, err)
testutils.Check(t, err)
dumpRequests = make([]*shared.DumpRequest, 0)
shared.Check(t, json.Unmarshal(respBody, &dumpRequests))
testutils.Check(t, json.Unmarshal(respBody, &dumpRequests))
if len(dumpRequests) != 1 {
t.Fatalf("expected one pending dump request, got %#v", dumpRequests)
}
@ -255,9 +256,9 @@ func TestDumpRequestAndResponse(t *testing.T) {
res = w.Result()
defer res.Body.Close()
respBody, err = ioutil.ReadAll(res.Body)
shared.Check(t, err)
testutils.Check(t, err)
var retrievedEntries []*shared.EncHistoryEntry
shared.Check(t, json.Unmarshal(respBody, &retrievedEntries))
testutils.Check(t, json.Unmarshal(respBody, &retrievedEntries))
if len(retrievedEntries) != 2 {
t.Fatalf("Expected to retrieve 2 entries, found %d", len(retrievedEntries))
}
@ -272,7 +273,7 @@ func TestDumpRequestAndResponse(t *testing.T) {
t.Fatalf("db.ReadCount should have been 1, was %v", dbEntry.ReadCount)
}
decEntry, err := data.DecryptHistoryEntry("dkey", *dbEntry)
shared.Check(t, err)
testutils.Check(t, err)
if !data.EntryEquals(decEntry, entry1Dec) && !data.EntryEquals(decEntry, entry2Dec) {
t.Fatalf("DB data is different than input! \ndb =%#v\nentry1=%#v\nentry2=%#v", *dbEntry, entry1Dec, entry2Dec)
}
@ -280,7 +281,7 @@ func TestDumpRequestAndResponse(t *testing.T) {
}
func TestUpdateReleaseVersion(t *testing.T) {
if !shared.IsOnline() {
if !testutils.IsOnline() {
t.Skip("skipping because we're currently offline")
}
@ -329,33 +330,33 @@ func TestDeletionRequests(t *testing.T) {
apiRegisterHandler(nil, deviceReq)
// Add an entry for user1
entry1 := data.MakeFakeHistoryEntry("ls ~/")
entry1 := testutils.MakeFakeHistoryEntry("ls ~/")
entry1.DeviceId = devId1
encEntry, err := data.EncryptHistoryEntry("dkey", entry1)
shared.Check(t, err)
testutils.Check(t, err)
reqBody, err := json.Marshal([]shared.EncHistoryEntry{encEntry})
shared.Check(t, err)
testutils.Check(t, err)
submitReq := httptest.NewRequest(http.MethodPost, "/", bytes.NewReader(reqBody))
apiSubmitHandler(nil, submitReq)
// And another entry for user1
entry2 := data.MakeFakeHistoryEntry("ls /foo/bar")
entry2 := testutils.MakeFakeHistoryEntry("ls /foo/bar")
entry2.DeviceId = devId2
encEntry, err = data.EncryptHistoryEntry("dkey", entry2)
shared.Check(t, err)
testutils.Check(t, err)
reqBody, err = json.Marshal([]shared.EncHistoryEntry{encEntry})
shared.Check(t, err)
testutils.Check(t, err)
submitReq = httptest.NewRequest(http.MethodPost, "/", bytes.NewReader(reqBody))
apiSubmitHandler(nil, submitReq)
// And an entry for user2 that has the same timestamp as the previous entry
entry3 := data.MakeFakeHistoryEntry("ls /foo/bar")
entry3 := testutils.MakeFakeHistoryEntry("ls /foo/bar")
entry3.StartTime = entry1.StartTime
entry3.EndTime = entry1.EndTime
encEntry, err = data.EncryptHistoryEntry("dOtherkey", entry3)
shared.Check(t, err)
testutils.Check(t, err)
reqBody, err = json.Marshal([]shared.EncHistoryEntry{encEntry})
shared.Check(t, err)
testutils.Check(t, err)
submitReq = httptest.NewRequest(http.MethodPost, "/", bytes.NewReader(reqBody))
apiSubmitHandler(nil, submitReq)
@ -366,9 +367,9 @@ func TestDeletionRequests(t *testing.T) {
res := w.Result()
defer res.Body.Close()
respBody, err := ioutil.ReadAll(res.Body)
shared.Check(t, err)
testutils.Check(t, err)
var retrievedEntries []*shared.EncHistoryEntry
shared.Check(t, json.Unmarshal(respBody, &retrievedEntries))
testutils.Check(t, json.Unmarshal(respBody, &retrievedEntries))
if len(retrievedEntries) != 2 {
t.Fatalf("Expected to retrieve 1 entry, found %d", len(retrievedEntries))
}
@ -383,7 +384,7 @@ func TestDeletionRequests(t *testing.T) {
t.Fatalf("db.ReadCount should have been 1, was %v", dbEntry.ReadCount)
}
decEntry, err := data.DecryptHistoryEntry("dkey", *dbEntry)
shared.Check(t, err)
testutils.Check(t, err)
if !data.EntryEquals(decEntry, entry1) && !data.EntryEquals(decEntry, entry2) {
t.Fatalf("DB data is different than input! \ndb =%#v\nentry1=%#v\nentry2=%#v", *dbEntry, entry1, entry2)
}
@ -399,7 +400,7 @@ func TestDeletionRequests(t *testing.T) {
}},
}
reqBody, err = json.Marshal(delReq)
shared.Check(t, err)
testutils.Check(t, err)
req := httptest.NewRequest(http.MethodPost, "/", bytes.NewReader(reqBody))
addDeletionRequestHandler(nil, req)
@ -410,8 +411,8 @@ func TestDeletionRequests(t *testing.T) {
res = w.Result()
defer res.Body.Close()
respBody, err = ioutil.ReadAll(res.Body)
shared.Check(t, err)
shared.Check(t, json.Unmarshal(respBody, &retrievedEntries))
testutils.Check(t, err)
testutils.Check(t, json.Unmarshal(respBody, &retrievedEntries))
if len(retrievedEntries) != 1 {
t.Fatalf("Expected to retrieve 1 entry, found %d", len(retrievedEntries))
}
@ -426,7 +427,7 @@ func TestDeletionRequests(t *testing.T) {
t.Fatalf("db.ReadCount should have been 1, was %v", dbEntry.ReadCount)
}
decEntry, err := data.DecryptHistoryEntry("dkey", *dbEntry)
shared.Check(t, err)
testutils.Check(t, err)
if !data.EntryEquals(decEntry, entry2) {
t.Fatalf("DB data is different than input! \ndb =%#v\nentry=%#v", *dbEntry, entry2)
}
@ -438,8 +439,8 @@ func TestDeletionRequests(t *testing.T) {
res = w.Result()
defer res.Body.Close()
respBody, err = ioutil.ReadAll(res.Body)
shared.Check(t, err)
shared.Check(t, json.Unmarshal(respBody, &retrievedEntries))
testutils.Check(t, err)
testutils.Check(t, json.Unmarshal(respBody, &retrievedEntries))
if len(retrievedEntries) != 1 {
t.Fatalf("Expected to retrieve 1 entry, found %d", len(retrievedEntries))
}
@ -454,7 +455,7 @@ func TestDeletionRequests(t *testing.T) {
t.Fatalf("db.ReadCount should have been 1, was %v", dbEntry.ReadCount)
}
decEntry, err = data.DecryptHistoryEntry("dOtherkey", *dbEntry)
shared.Check(t, err)
testutils.Check(t, err)
if !data.EntryEquals(decEntry, entry3) {
t.Fatalf("DB data is different than input! \ndb =%#v\nentry=%#v", *dbEntry, entry3)
}
@ -466,9 +467,9 @@ func TestDeletionRequests(t *testing.T) {
res = w.Result()
defer res.Body.Close()
respBody, err = ioutil.ReadAll(res.Body)
shared.Check(t, err)
testutils.Check(t, err)
var deletionRequests []*shared.DeletionRequest
shared.Check(t, json.Unmarshal(respBody, &deletionRequests))
testutils.Check(t, json.Unmarshal(respBody, &deletionRequests))
if len(deletionRequests) != 1 {
t.Fatalf("received %d deletion requests, expected only one", len(deletionRequests))
}

View File

@ -22,6 +22,7 @@ import (
"github.com/ddworken/hishtory/client/hctx"
"github.com/ddworken/hishtory/client/lib"
"github.com/ddworken/hishtory/shared"
"github.com/ddworken/hishtory/shared/testutils"
)
func skipSlowTests() bool {
@ -29,7 +30,7 @@ func skipSlowTests() bool {
}
func TestMain(m *testing.M) {
defer shared.RunTestServer()()
defer testutils.RunTestServer()()
cmd := exec.Command("go", "build", "-o", "/tmp/client")
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, "CGO_ENABLED=0")
@ -154,7 +155,7 @@ func TestParameterized(t *testing.T) {
func testIntegration(t *testing.T, tester shellTester) {
// Set up
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
// Run the test
testBasicUserFlow(t, tester)
@ -162,13 +163,13 @@ func testIntegration(t *testing.T, tester shellTester) {
func testIntegrationWithNewDevice(t *testing.T, tester shellTester) {
// Set up
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
// Run the test
userSecret := testBasicUserFlow(t, tester)
// Clear all local state
shared.ResetLocalState(t)
testutils.ResetLocalState(t)
// Install it again
installHishtory(t, tester, userSecret)
@ -195,7 +196,7 @@ func testIntegrationWithNewDevice(t *testing.T, tester shellTester) {
}
// Clear local state again
shared.ResetLocalState(t)
testutils.ResetLocalState(t)
// Install it a 3rd time
installHishtory(t, tester, "adifferentsecret")
@ -209,7 +210,7 @@ func testIntegrationWithNewDevice(t *testing.T, tester shellTester) {
// Set the secret key to the previous secret key
out, err := tester.RunInteractiveShellRelaxed(t, `yes | hishtory init `+userSecret)
shared.Check(t, err)
testutils.Check(t, err)
if !strings.Contains(out, "Setting secret hishtory key to "+userSecret) {
t.Fatalf("Failed to re-init with the user secret: %v", out)
}
@ -241,7 +242,7 @@ func testIntegrationWithNewDevice(t *testing.T, tester shellTester) {
// Manually submit an event that isn't in the local DB, and then we'll
// check if we see it when we do a query without ever having done an init
newEntry := data.MakeFakeHistoryEntry("othercomputer")
newEntry := testutils.MakeFakeHistoryEntry("othercomputer")
newEntry.StartTime = time.Now()
newEntry.EndTime = time.Now()
manuallySubmitHistoryEntry(t, userSecret, newEntry)
@ -292,7 +293,7 @@ func testBasicUserFlow(t *testing.T, tester shellTester) string {
if err != nil {
t.Fatalf("failed to get homedir: %v", err)
}
dat, err := os.ReadFile(path.Join(homedir, shared.HISHTORY_PATH, "config.sh"))
dat, err := os.ReadFile(path.Join(homedir, data.HISHTORY_PATH, "config.sh"))
if err != nil {
t.Fatalf("failed to read config.sh: %v", err)
}
@ -348,22 +349,22 @@ echo thisisrecorded`)
line2Matcher := hostnameMatcher + tableDividerMatcher + pathMatcher + tableDividerMatcher + datetimeMatcher + tableDividerMatcher + runtimeMatcher + tableDividerMatcher + exitCodeMatcher + tableDividerMatcher + pipefailMatcher + tableDividerMatcher + `\n`
line3Matcher := hostnameMatcher + tableDividerMatcher + pathMatcher + tableDividerMatcher + datetimeMatcher + tableDividerMatcher + runtimeMatcher + tableDividerMatcher + exitCodeMatcher + tableDividerMatcher + `echo thisisrecorded` + tableDividerMatcher + `\n`
match, err := regexp.MatchString(line3Matcher, out)
shared.Check(t, err)
testutils.Check(t, err)
if !match {
t.Fatalf("output is missing the row for `echo thisisrecorded`: %v", out)
}
match, err = regexp.MatchString(line1Matcher, out)
shared.Check(t, err)
testutils.Check(t, err)
if !match {
t.Fatalf("output is missing the headings: %v", out)
}
match, err = regexp.MatchString(line2Matcher, out)
shared.Check(t, err)
testutils.Check(t, err)
if !match {
t.Fatalf("output is missing the pipefail: %v", out)
}
match, err = regexp.MatchString(line1Matcher+line2Matcher+line3Matcher, out)
shared.Check(t, err)
testutils.Check(t, err)
if !match {
t.Fatalf("output doesn't match the expected table: %v", out)
}
@ -404,7 +405,7 @@ echo thisisrecorded`)
func testAdvancedQuery(t *testing.T, tester shellTester) {
// Set up
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
// Install hishtory
userSecret := installHishtory(t, tester, "")
@ -514,7 +515,7 @@ hishtory disable`)
}
// Manually submit an entry with a different hostname and username so we can test those atoms
entry := data.MakeFakeHistoryEntry("cmd_with_diff_hostname_and_username")
entry := testutils.MakeFakeHistoryEntry("cmd_with_diff_hostname_and_username")
entry.LocalUsername = "otheruser"
entry.Hostname = "otherhostname"
manuallySubmitHistoryEntry(t, userSecret, entry)
@ -575,7 +576,7 @@ hishtory disable`)
}
// Test filtering out a search item that also looks like it could be a search for a flag
entry = data.MakeFakeHistoryEntry("foo -echo")
entry = testutils.MakeFakeHistoryEntry("foo -echo")
manuallySubmitHistoryEntry(t, userSecret, entry)
out = hishtoryQuery(t, tester, `-echo -install`)
if strings.Contains(out, "echo") {
@ -586,7 +587,7 @@ hishtory disable`)
}
// Search for a cwd based on the home directory
entry = data.MakeFakeHistoryEntry("foobar")
entry = testutils.MakeFakeHistoryEntry("foobar")
entry.HomeDirectory = "/home/david/"
entry.CurrentWorkingDirectory = "~/dir/"
manuallySubmitHistoryEntry(t, userSecret, entry)
@ -605,7 +606,7 @@ hishtory disable`)
}
func testUpdate(t *testing.T, tester shellTester) {
if !shared.IsOnline() {
if !testutils.IsOnline() {
t.Skip("skipping because we're currently offline")
}
if runtime.GOOS == "linux" && runtime.GOARCH == "arm64" {
@ -615,7 +616,7 @@ func testUpdate(t *testing.T, tester shellTester) {
t.Skip("skipping slow tests")
}
// Set up
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
userSecret := installHishtory(t, tester, "")
// Record a command before the update
@ -662,7 +663,7 @@ func testUpdate(t *testing.T, tester shellTester) {
func testRepeatedCommandThenQuery(t *testing.T, tester shellTester) {
// Set up
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
userSecret := installHishtory(t, tester, "")
// Check the status command
@ -701,7 +702,7 @@ echo mycommand-3`)
func testRepeatedCommandAndQuery(t *testing.T, tester shellTester) {
// Set up
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
userSecret := installHishtory(t, tester, "")
// Check the status command
@ -726,7 +727,7 @@ func testRepeatedCommandAndQuery(t *testing.T, tester shellTester) {
func testRepeatedEnableDisable(t *testing.T, tester shellTester) {
// Set up
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
installHishtory(t, tester, "")
// Run a command many times
@ -758,7 +759,7 @@ hishtory enable`, i))
func testExcludeHiddenCommand(t *testing.T, tester shellTester) {
// Set up
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
installHishtory(t, tester, "")
tester.RunInteractiveShell(t, `echo hello1
@ -829,14 +830,14 @@ func hishtoryQuery(t *testing.T, tester shellTester, query string) string {
func manuallySubmitHistoryEntry(t *testing.T, userSecret string, entry data.HistoryEntry) {
encEntry, err := data.EncryptHistoryEntry(userSecret, entry)
shared.Check(t, err)
testutils.Check(t, err)
if encEntry.Date != entry.EndTime {
t.Fatalf("encEntry.Date does not match the entry")
}
jsonValue, err := json.Marshal([]shared.EncHistoryEntry{encEntry})
shared.Check(t, err)
testutils.Check(t, err)
resp, err := http.Post("http://localhost:8080/api/v1/submit", "application/json", bytes.NewBuffer(jsonValue))
shared.Check(t, err)
testutils.Check(t, err)
if resp.StatusCode != 200 {
t.Fatalf("failed to submit result to backend, status_code=%d", resp.StatusCode)
}
@ -844,7 +845,7 @@ func manuallySubmitHistoryEntry(t *testing.T, userSecret string, entry data.Hist
func testTimestampsAreReasonablyCorrect(t *testing.T, tester shellTester) {
// Setup
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
installHishtory(t, tester, "")
// Record a command
@ -866,7 +867,7 @@ func testTimestampsAreReasonablyCorrect(t *testing.T, tester shellTester) {
func testTableDisplayCwd(t *testing.T, tester shellTester) {
// Setup
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
installHishtory(t, tester, "")
// Record a command
@ -901,11 +902,11 @@ func testHishtoryBackgroundSaving(t *testing.T, tester shellTester) {
}
// Setup
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
// Check that we can find the go binary
_, err := exec.LookPath("go")
shared.Check(t, err)
testutils.Check(t, err)
// Test install with an unset HISHTORY_TEST var so that we save in the background (this is likely to be flakey!)
out := tester.RunInteractiveShell(t, `unset HISHTORY_TEST
@ -923,7 +924,7 @@ CGO_ENABLED=0 go build -o /tmp/client
if err != nil {
t.Fatalf("failed to get homedir: %v", err)
}
dat, err := os.ReadFile(path.Join(homedir, shared.HISHTORY_PATH, "config.sh"))
dat, err := os.ReadFile(path.Join(homedir, data.HISHTORY_PATH, "config.sh"))
if err != nil {
t.Fatalf("failed to read config.sh: %v", err)
}
@ -971,7 +972,7 @@ echo foo`)
func testDisplayTable(t *testing.T, tester shellTester) {
// Setup
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
userSecret := installHishtory(t, tester, "")
// Submit two fake entries
@ -979,11 +980,11 @@ func testDisplayTable(t *testing.T, tester shellTester) {
if err != nil {
t.Fatalf("failed to load timezone: %v", err)
}
entry1 := data.MakeFakeHistoryEntry("table_cmd1")
entry1 := testutils.MakeFakeHistoryEntry("table_cmd1")
entry1.StartTime = time.Unix(1650096186, 0).In(tmz)
entry1.EndTime = time.Unix(1650096190, 0).In(tmz)
manuallySubmitHistoryEntry(t, userSecret, entry1)
entry2 := data.MakeFakeHistoryEntry("table_cmd2")
entry2 := testutils.MakeFakeHistoryEntry("table_cmd2")
entry2.StartTime = time.Unix(1650096196, 0).In(tmz)
entry2.EndTime = time.Unix(1650096220, 0).In(tmz)
entry2.CurrentWorkingDirectory = "~/foo/"
@ -1005,7 +1006,7 @@ func testDisplayTable(t *testing.T, tester shellTester) {
func testRequestAndReceiveDbDump(t *testing.T, tester shellTester) {
// Set up
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
secretKey := installHishtory(t, tester, "")
// Confirm there are no pending dump requests
@ -1039,7 +1040,7 @@ echo other`)
}
// Back up this copy
restoreFirstInstallation := shared.BackupAndRestoreWithId(t, "-install1")
restoreFirstInstallation := testutils.BackupAndRestoreWithId(t, "-install1")
// Wipe the DB to simulate entries getting deleted because they've already been read and expired
_, err = lib.ApiGet("/api/v1/wipe-db")
@ -1073,7 +1074,7 @@ echo other`)
}
// Restore the first copy
restoreSecondInstallation := shared.BackupAndRestoreWithId(t, "-install2")
restoreSecondInstallation := testutils.BackupAndRestoreWithId(t, "-install2")
restoreFirstInstallation()
// Confirm it still has the correct entries via hishtory export (and this runs a command to trigger it to dump the DB)
@ -1118,8 +1119,8 @@ echo other`)
func testInstallViaPythonScript(t *testing.T, tester shellTester) {
// Set up
defer shared.BackupAndRestore(t)()
defer shared.BackupAndRestoreEnv("HISHTORY_TEST")()
defer testutils.BackupAndRestore(t)()
defer testutils.BackupAndRestoreEnv("HISHTORY_TEST")()
// Install via the python script
out := tester.RunInteractiveShell(t, `curl https://hishtory.dev/install.py | python3 -`)
@ -1154,7 +1155,7 @@ func testInstallViaPythonScript(t *testing.T, tester shellTester) {
func testExportWithQuery(t *testing.T, tester shellTester) {
// Setup
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
installHishtory(t, tester, "")
// Test recording commands
@ -1220,7 +1221,7 @@ sleep 1`)
func testHelpCommand(t *testing.T, tester shellTester) {
// Setup
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
installHishtory(t, tester, "")
// Test the help command
@ -1240,7 +1241,7 @@ func testStripBashTimePrefix(t *testing.T, tester shellTester) {
}
// Setup
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
installHishtory(t, tester, "")
// Add a HISTTIMEFORMAT to the bashrc
@ -1296,13 +1297,13 @@ func testStripBashTimePrefix(t *testing.T, tester shellTester) {
func testReuploadHistoryEntries(t *testing.T, tester shellTester) {
// Setup
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
// Init an initial device
userSecret := installHishtory(t, tester, "")
// Set up a second device
restoreFirstProfile := shared.BackupAndRestoreWithId(t, "-install1")
restoreFirstProfile := testutils.BackupAndRestoreWithId(t, "-install1")
installHishtory(t, tester, userSecret)
// Device 2: Record a command
@ -1312,7 +1313,7 @@ func testReuploadHistoryEntries(t *testing.T, tester shellTester) {
tester.RunInteractiveShell(t, `echo 2; export HISHTORY_SIMULATE_NETWORK_ERROR=1; echo 3`)
// Device 1: Run an export and confirm that the network only contains the first command
restoreSecondProfile := shared.BackupAndRestoreWithId(t, "-install2")
restoreSecondProfile := testutils.BackupAndRestoreWithId(t, "-install2")
restoreFirstProfile()
out := tester.RunInteractiveShell(t, "hishtory export | grep -v pipefail")
expectedOutput := "echo 1\n"
@ -1321,7 +1322,7 @@ func testReuploadHistoryEntries(t *testing.T, tester shellTester) {
}
// Device 2: Run another command but with the network re-enabled
restoreFirstProfile = shared.BackupAndRestoreWithId(t, "-install1")
restoreFirstProfile = testutils.BackupAndRestoreWithId(t, "-install1")
restoreSecondProfile()
tester.RunInteractiveShell(t, `unset HISHTORY_SIMULATE_NETWORK_ERROR; echo 4`)
@ -1343,20 +1344,20 @@ func testReuploadHistoryEntries(t *testing.T, tester shellTester) {
func testHishtoryOffline(t *testing.T, tester shellTester) {
// Setup
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
// Init an initial device
userSecret := installHishtory(t, tester, "")
// Set up a second device
restoreFirstProfile := shared.BackupAndRestoreWithId(t, "-install1")
restoreFirstProfile := testutils.BackupAndRestoreWithId(t, "-install1")
installHishtory(t, tester, userSecret)
// Device 2: Record a command
tester.RunInteractiveShell(t, `echo dev2`)
// Device 1: Run a command
restoreSecondProfile := shared.BackupAndRestoreWithId(t, "-install2")
restoreSecondProfile := testutils.BackupAndRestoreWithId(t, "-install2")
restoreFirstProfile()
tester.RunInteractiveShell(t, `echo dev1-a`)
@ -1368,7 +1369,7 @@ func testHishtoryOffline(t *testing.T, tester shellTester) {
}
// Device 2: Record another command
restoreFirstProfile = shared.BackupAndRestoreWithId(t, "-install1")
restoreFirstProfile = testutils.BackupAndRestoreWithId(t, "-install1")
restoreSecondProfile()
tester.RunInteractiveShell(t, `echo dev2-b`)
@ -1390,7 +1391,7 @@ func testHishtoryOffline(t *testing.T, tester shellTester) {
func testInitialHistoryImport(t *testing.T, tester shellTester) {
// Setup
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
// Record some commands before installing hishtory
randomCmdUuid := uuid.Must(uuid.NewRandom()).String()
@ -1440,7 +1441,7 @@ echo %v-bar`, randomCmdUuid, randomCmdUuid)
func testLocalRedaction(t *testing.T, tester shellTester) {
// Setup
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
// Install hishtory
installHishtory(t, tester, "")
@ -1496,7 +1497,7 @@ ls /tmp`, randomCmdUuid, randomCmdUuid)
// Redact it without --force
out, err := tester.RunInteractiveShellRelaxed(t, `yes | hishtory redact hello`)
shared.Check(t, err)
testutils.Check(t, err)
if out != "This will permanently delete 1 entries, are you sure? [y/N]" {
t.Fatalf("hishtory redact gave unexpected output=%#v", out)
}
@ -1511,7 +1512,7 @@ ls /tmp`, randomCmdUuid, randomCmdUuid)
func testRemoteRedaction(t *testing.T, tester shellTester) {
// Setup
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
// Install hishtory client 1
userSecret := installHishtory(t, tester, "")
@ -1532,7 +1533,7 @@ ls /tmp`, randomCmdUuid, randomCmdUuid)
}
// Install hishtory client 2
restoreInstall1 := shared.BackupAndRestoreWithId(t, "-1")
restoreInstall1 := testutils.BackupAndRestoreWithId(t, "-1")
installHishtory(t, tester, userSecret)
// And confirm that it has the commands too
@ -1542,7 +1543,7 @@ ls /tmp`, randomCmdUuid, randomCmdUuid)
}
// Restore the first client, and redact some commands
restoreInstall2 := shared.BackupAndRestoreWithId(t, "-2")
restoreInstall2 := testutils.BackupAndRestoreWithId(t, "-2")
restoreInstall1()
out = tester.RunInteractiveShell(t, `hishtory redact --force `+randomCmdUuid)
if out != "Permanently deleting 2 entries\n" {
@ -1566,7 +1567,7 @@ ls /tmp`, randomCmdUuid, randomCmdUuid)
func testConfigGetSet(t *testing.T, tester shellTester) {
// Setup
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
installHishtory(t, tester, "")
// Initially is true
@ -1592,24 +1593,24 @@ func testConfigGetSet(t *testing.T, tester shellTester) {
func clearControlRSearchFromConfig(t *testing.T) {
configContents, err := hctx.GetConfigContents()
shared.Check(t, err)
testutils.Check(t, err)
configContents = []byte(strings.ReplaceAll(string(configContents), "enable_control_r_search", "something-else"))
homedir, err := os.UserHomeDir()
shared.Check(t, err)
err = os.WriteFile(path.Join(homedir, shared.HISHTORY_PATH, shared.CONFIG_PATH), configContents, 0o644)
shared.Check(t, err)
testutils.Check(t, err)
err = os.WriteFile(path.Join(homedir, data.HISHTORY_PATH, data.CONFIG_PATH), configContents, 0o644)
testutils.Check(t, err)
}
func testHandleUpgradedFeatures(t *testing.T, tester shellTester) {
// Setup
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
installHishtory(t, tester, "")
// Install, and there is no prompt since the config already mentions control-r
_, err := tester.RunInteractiveShellRelaxed(t, `/tmp/client install`)
shared.Check(t, err)
testutils.Check(t, err)
_, err = tester.RunInteractiveShellRelaxed(t, `hishtory disable`)
shared.Check(t, err)
testutils.Check(t, err)
// Ensure that the config doesn't mention control-r
clearControlRSearchFromConfig(t)
@ -1633,7 +1634,7 @@ func testHandleUpgradedFeatures(t *testing.T, tester shellTester) {
func TestFish(t *testing.T) {
// Setup
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
tester := bashTester{}
installHishtory(t, tester, "")
@ -1680,7 +1681,7 @@ func compareGoldens(t *testing.T, out, goldenName string) {
if os.IsNotExist(err) {
expected = []byte{}
} else {
shared.Check(t, err)
testutils.Check(t, err)
}
}
if diff := cmp.Diff(string(expected), out); diff != "" {
@ -1688,15 +1689,14 @@ func compareGoldens(t *testing.T, out, goldenName string) {
_, filename, line, _ := runtime.Caller(1)
t.Fatalf("hishtory golden mismatch at %s:%d (-expected +got):\n%s", filename, line, diff)
} else {
shared.Check(t, os.WriteFile(goldenPath, []byte(out), 0644))
testutils.Check(t, os.WriteFile(goldenPath, []byte(out), 0644))
}
}
}
func TestTui(t *testing.T) {
// Setup
data.ResetFakeHistoryTimestamp() // TODO: move this to backupandrestore
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
tester := zshTester{}
installHishtory(t, tester, "")
@ -1705,8 +1705,8 @@ func TestTui(t *testing.T) {
// Insert a couple hishtory entries
db := hctx.GetDb(hctx.MakeContext())
db.Create(data.MakeFakeHistoryEntry("ls ~/"))
db.Create(data.MakeFakeHistoryEntry("echo 'aaaaaa bbbb'"))
db.Create(testutils.MakeFakeHistoryEntry("ls ~/"))
db.Create(testutils.MakeFakeHistoryEntry("echo 'aaaaaa bbbb'"))
// Check the initial output when there is no search
out := captureTerminalOutput(t, tester, []string{"hishtory SPACE tquery ENTER"})
@ -1775,8 +1775,7 @@ func testControlR(t *testing.T, tester shellTester, shellName string) {
}
// Setup
data.ResetFakeHistoryTimestamp() // TODO: move this to backupandrestore
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
installHishtory(t, tester, "")
// Disable recording so that all our testing commands don't get recorded
@ -1785,15 +1784,15 @@ func testControlR(t *testing.T, tester shellTester, shellName string) {
// Insert a few hishtory entries
db := hctx.GetDb(hctx.MakeContext())
e1 := data.MakeFakeHistoryEntry("ls ~/")
e1 := testutils.MakeFakeHistoryEntry("ls ~/")
e1.CurrentWorkingDirectory = "/etc/"
e1.Hostname = "server"
e1.ExitCode = 127
db.Create(e1)
db.Create(data.MakeFakeHistoryEntry("ls ~/foo/"))
db.Create(data.MakeFakeHistoryEntry("ls ~/bar/"))
db.Create(data.MakeFakeHistoryEntry("echo 'aaaaaa bbbb'"))
db.Create(data.MakeFakeHistoryEntry("echo 'bar' &"))
db.Create(testutils.MakeFakeHistoryEntry("ls ~/foo/"))
db.Create(testutils.MakeFakeHistoryEntry("ls ~/bar/"))
db.Create(testutils.MakeFakeHistoryEntry("echo 'aaaaaa bbbb'"))
db.Create(testutils.MakeFakeHistoryEntry("echo 'bar' &"))
// And check that the control-r binding brings up the search
out := captureTerminalOutputWithShellName(t, tester, shellName, []string{"C-R"})
@ -1878,8 +1877,8 @@ func createDevice(t *testing.T, tester shellTester, devices *deviceSet, key, dev
}
installHishtory(t, tester, key)
(*devices.deviceMap)[d] = deviceOp{
backup: func() { shared.BackupAndRestoreWithId(t, key+deviceId) },
restore: shared.BackupAndRestoreWithId(t, key+deviceId),
backup: func() { testutils.BackupAndRestoreWithId(t, key+deviceId) },
restore: testutils.BackupAndRestoreWithId(t, key+deviceId),
}
}
@ -1895,7 +1894,7 @@ func switchToDevice(devices *deviceSet, d device) {
}
func testMultipleUsers(t *testing.T, tester shellTester) {
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
// Create all our devices
var deviceMap map[device]deviceOp = make(map[device]deviceOp)
@ -1939,7 +1938,7 @@ func testMultipleUsers(t *testing.T, tester shellTester) {
for i, d := range []device{u1d1, u1d2} {
switchToDevice(&devices, d)
out, err := tester.RunInteractiveShellRelaxed(t, `hishtory export`)
shared.Check(t, err)
testutils.Check(t, err)
expectedOutput := "echo u1d1\necho u1d2\necho u1d1-b\necho u1d1-c\necho u1d2-b\necho u1d2-c\n"
for j := 0; j < i; j++ {
expectedOutput += "hishtory export\n"
@ -1961,7 +1960,7 @@ func testMultipleUsers(t *testing.T, tester shellTester) {
for i, d := range []device{u2d1, u2d2, u2d3} {
switchToDevice(&devices, d)
out, err := tester.RunInteractiveShellRelaxed(t, `hishtory export`)
shared.Check(t, err)
testutils.Check(t, err)
expectedOutput := "echo u2d1\necho u2d2\necho u2d3\necho u1d1-b\necho u1d1-c\necho u2d3-b\necho u2d3-c\n"
for j := 0; j < i; j++ {
expectedOutput += "hishtory export\n"
@ -2019,7 +2018,7 @@ func fuzzTest(t *testing.T, tester shellTester, input string) {
}
// Set up and create the devices
defer shared.BackupAndRestore(t)()
defer testutils.BackupAndRestore(t)()
var deviceMap map[device]deviceOp = make(map[device]deviceOp)
var devices deviceSet = deviceSet{}
devices.deviceMap = &deviceMap
@ -2041,11 +2040,11 @@ func fuzzTest(t *testing.T, tester shellTester, input string) {
switchToDevice(&devices, op.device)
if op.cmd != "" {
_, err := tester.RunInteractiveShellRelaxed(t, op.cmd)
shared.Check(t, err)
testutils.Check(t, err)
}
if op.redactQuery != "" {
_, err := tester.RunInteractiveShellRelaxed(t, `hishtory redact --force `+op.redactQuery)
shared.Check(t, err)
testutils.Check(t, err)
}
// Calculate the expected output of hishtory export
@ -2073,7 +2072,7 @@ func fuzzTest(t *testing.T, tester shellTester, input string) {
// Run hishtory export and check the output
out, err := tester.RunInteractiveShellRelaxed(t, `hishtory export | grep -v export`)
shared.Check(t, err)
testutils.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)
@ -2084,7 +2083,7 @@ func fuzzTest(t *testing.T, tester shellTester, input string) {
for _, op := range ops {
switchToDevice(&devices, op.device)
out, err := tester.RunInteractiveShellRelaxed(t, `hishtory export | grep -v export`)
shared.Check(t, err)
testutils.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)

View File

@ -268,24 +268,8 @@ func EntryEquals(entry1, entry2 HistoryEntry) bool {
entry1.EndTime.Format(time.RFC3339) == entry2.EndTime.Format(time.RFC3339)
}
// TODO: move this code to testutils
var fakeHistoryTimestamp int64 = 1666068191
func ResetFakeHistoryTimestamp() {
fakeHistoryTimestamp = 1666068191
}
func MakeFakeHistoryEntry(command string) HistoryEntry {
fakeHistoryTimestamp += 5
return HistoryEntry{
LocalUsername: "david",
Hostname: "localhost",
Command: command,
CurrentWorkingDirectory: "/tmp/",
HomeDirectory: "/home/david/",
ExitCode: 2,
StartTime: time.Unix(fakeHistoryTimestamp, 0),
EndTime: time.Unix(fakeHistoryTimestamp+3, 0),
}
}
const (
CONFIG_PATH = ".hishtory.config"
HISHTORY_PATH = ".hishtory"
DB_PATH = ".hishtory.db"
)

View File

@ -3,8 +3,6 @@ package data
import (
"testing"
"time"
"github.com/ddworken/hishtory/shared"
)
func TestEncryptDecrypt(t *testing.T) {
@ -15,9 +13,9 @@ func TestEncryptDecrypt(t *testing.T) {
}
ciphertext, nonce, err := Encrypt("key", []byte("hello world!"), []byte("extra"))
shared.Check(t, err)
checkError(t, err)
plaintext, err := Decrypt("key", ciphertext, []byte("extra"), nonce)
shared.Check(t, err)
checkError(t, err)
if string(plaintext) != "hello world!" {
t.Fatalf("Expected decrypt(encrypt(x)) to work, but it didn't!")
}
@ -25,62 +23,70 @@ func TestEncryptDecrypt(t *testing.T) {
func TestParseTimeGenerously(t *testing.T) {
ts, err := parseTimeGenerously("2006-01-02T15:04:00-08:00")
shared.Check(t, err)
checkError(t, err)
if ts.Unix() != 1136243040 {
t.Fatalf("parsed time incorrectly: %d", ts.Unix())
}
ts, err = parseTimeGenerously("2006-01-02 T15:04:00 -08:00")
shared.Check(t, err)
checkError(t, err)
if ts.Unix() != 1136243040 {
t.Fatalf("parsed time incorrectly: %d", ts.Unix())
}
ts, err = parseTimeGenerously("2006-01-02_T15:04:00_-08:00")
shared.Check(t, err)
checkError(t, err)
if ts.Unix() != 1136243040 {
t.Fatalf("parsed time incorrectly: %d", ts.Unix())
}
ts, err = parseTimeGenerously("2006-01-02T15:04:00")
shared.Check(t, err)
checkError(t, err)
if ts.Year() != 2006 || ts.Month() != time.January || ts.Day() != 2 || ts.Hour() != 15 || ts.Minute() != 4 || ts.Second() != 0 {
t.Fatalf("parsed time incorrectly: %d", ts.Unix())
}
ts, err = parseTimeGenerously("2006-01-02_T15:04:00")
shared.Check(t, err)
checkError(t, err)
if ts.Year() != 2006 || ts.Month() != time.January || ts.Day() != 2 || ts.Hour() != 15 || ts.Minute() != 4 || ts.Second() != 0 {
t.Fatalf("parsed time incorrectly: %d", ts.Unix())
}
ts, err = parseTimeGenerously("2006-01-02_15:04:00")
shared.Check(t, err)
checkError(t, err)
if ts.Year() != 2006 || ts.Month() != time.January || ts.Day() != 2 || ts.Hour() != 15 || ts.Minute() != 4 || ts.Second() != 0 {
t.Fatalf("parsed time incorrectly: %d", ts.Unix())
}
ts, err = parseTimeGenerously("2006-01-02T15:04")
shared.Check(t, err)
checkError(t, err)
if ts.Year() != 2006 || ts.Month() != time.January || ts.Day() != 2 || ts.Hour() != 15 || ts.Minute() != 4 || ts.Second() != 0 {
t.Fatalf("parsed time incorrectly: %d", ts.Unix())
}
ts, err = parseTimeGenerously("2006-01-02_15:04")
shared.Check(t, err)
checkError(t, err)
if ts.Year() != 2006 || ts.Month() != time.January || ts.Day() != 2 || ts.Hour() != 15 || ts.Minute() != 4 || ts.Second() != 0 {
t.Fatalf("parsed time incorrectly: %d", ts.Unix())
}
ts, err = parseTimeGenerously("2006-01-02")
shared.Check(t, err)
checkError(t, err)
if ts.Year() != 2006 || ts.Month() != time.January || ts.Day() != 2 || ts.Hour() != 0 || ts.Minute() != 0 || ts.Second() != 0 {
t.Fatalf("parsed time incorrectly: %d", ts.Unix())
}
}
func checkError(t *testing.T, err error) {
if err != nil {
t.Fatal(err)
}
}
func TestCustomColumnSerialization(t *testing.T) {
// cc1 := CustomColumn{
// Name: "name1",
// Val: "val1",
// }
// cc2 := CustomColumn{
// Name: "name2",
// Val: "val2",
// }
cc1 := CustomColumn{
Name: "name1",
Val: "val1",
}
cc2 := CustomColumn{
Name: "name2",
Val: "val2",
}
var ccs CustomColumns = make(CustomColumns, 0)
// Empty array
v, err := ccs.Value()
if err != nil {
t.Fatalf("unexpected err: %v", err)
@ -89,4 +95,16 @@ func TestCustomColumnSerialization(t *testing.T) {
if val != "[]" {
t.Fatalf("unexpected val for empty CustomColumns: %#v", val)
}
// Non-empty array
ccs = append(ccs, cc1, cc2)
v, err = ccs.Value()
if err != nil {
t.Fatalf("unexpected err: %v", err)
}
val = string(v.([]uint8))
if val != "[{\"name\":\"name1\",\"value\":\"val1\"},{\"name\":\"name2\",\"value\":\"val2\"}]" {
t.Fatalf("unexpected val for empty CustomColumns: %#v", val)
}
}

View File

@ -13,7 +13,6 @@ import (
"time"
"github.com/ddworken/hishtory/client/data"
"github.com/ddworken/hishtory/shared"
"gorm.io/gorm"
"gorm.io/gorm/logger"
@ -38,7 +37,7 @@ func GetLogger() *log.Logger {
if err != nil {
panic(err)
}
f, err := os.OpenFile(path.Join(homedir, shared.HISHTORY_PATH, "hishtory.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o660)
f, err := os.OpenFile(path.Join(homedir, data.HISHTORY_PATH, "hishtory.log"), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o660)
if err != nil {
panic(fmt.Errorf("failed to open hishtory.log: %v", err))
}
@ -53,7 +52,7 @@ func MakeHishtoryDir() error {
if err != nil {
return fmt.Errorf("failed to get user's home directory: %v", err)
}
err = os.MkdirAll(path.Join(homedir, shared.HISHTORY_PATH), 0o744)
err = os.MkdirAll(path.Join(homedir, data.HISHTORY_PATH), 0o744)
if err != nil {
return fmt.Errorf("failed to create ~/.hishtory dir: %v", err)
}
@ -79,7 +78,7 @@ func OpenLocalSqliteDb() (*gorm.DB, error) {
Colorful: false,
},
)
db, err := gorm.Open(sqlite.Open(path.Join(homedir, shared.HISHTORY_PATH, shared.DB_PATH)), &gorm.Config{SkipDefaultTransaction: true, Logger: newLogger})
db, err := gorm.Open(sqlite.Open(path.Join(homedir, data.HISHTORY_PATH, data.DB_PATH)), &gorm.Config{SkipDefaultTransaction: true, Logger: newLogger})
if err != nil {
return nil, fmt.Errorf("failed to connect to the DB: %v", err)
}
@ -174,9 +173,9 @@ func GetConfigContents() ([]byte, error) {
if err != nil {
return nil, fmt.Errorf("failed to retrieve homedir: %v", err)
}
data, err := os.ReadFile(path.Join(homedir, shared.HISHTORY_PATH, shared.CONFIG_PATH))
dat, err := os.ReadFile(path.Join(homedir, data.HISHTORY_PATH, data.CONFIG_PATH))
if err != nil {
files, err := ioutil.ReadDir(path.Join(homedir, shared.HISHTORY_PATH))
files, err := ioutil.ReadDir(path.Join(homedir, data.HISHTORY_PATH))
if err != nil {
return nil, fmt.Errorf("failed to read config file (and failed to list too): %v", err)
}
@ -187,7 +186,7 @@ func GetConfigContents() ([]byte, error) {
}
return nil, fmt.Errorf("failed to read config file (files in ~/.hishtory/: %s): %v", filenames, err)
}
return data, nil
return dat, nil
}
func GetConfig() (ClientConfig, error) {
@ -219,7 +218,7 @@ func SetConfig(config ClientConfig) error {
if err != nil {
return err
}
configPath := path.Join(homedir, shared.HISHTORY_PATH, shared.CONFIG_PATH)
configPath := path.Join(homedir, data.HISHTORY_PATH, data.CONFIG_PATH)
stagedConfigPath := configPath + ".tmp"
err = os.WriteFile(stagedConfigPath, serializedConfig, 0o644)
if err != nil {
@ -237,7 +236,7 @@ func InitConfig() error {
if err != nil {
return err
}
_, err = os.Stat(path.Join(homedir, shared.HISHTORY_PATH, shared.CONFIG_PATH))
_, err = os.Stat(path.Join(homedir, data.HISHTORY_PATH, data.CONFIG_PATH))
if errors.Is(err, os.ErrNotExist) {
return SetConfig(ClientConfig{})
}

View File

@ -677,7 +677,7 @@ func configureFish(homedir, binaryPath string) error {
return nil
}
// Create the file we're going to source. Do this no matter what in case there are updates to it.
fishConfigPath := path.Join(homedir, shared.HISHTORY_PATH, "config.fish")
fishConfigPath := path.Join(homedir, data.HISHTORY_PATH, "config.fish")
configContents := ConfigFishContents
if os.Getenv("HISHTORY_TEST") != "" {
testConfig, err := tweakConfigForTests(ConfigFishContents)
@ -708,7 +708,7 @@ func configureFish(homedir, binaryPath string) error {
return fmt.Errorf("failed to append to ~/.config/fish/config.fish: %v", err)
}
defer f.Close()
_, err = f.WriteString("\n# Hishtory Config:\nexport PATH=\"$PATH:" + path.Join(homedir, shared.HISHTORY_PATH) + "\"\nsource " + fishConfigPath + "\n")
_, err = f.WriteString("\n# Hishtory Config:\nexport PATH=\"$PATH:" + path.Join(homedir, data.HISHTORY_PATH) + "\"\nsource " + fishConfigPath + "\n")
if err != nil {
return fmt.Errorf("failed to append to zshrc: %v", err)
}
@ -729,7 +729,7 @@ func isFishConfigured(homedir string) (bool, error) {
func configureZshrc(homedir, binaryPath string) error {
// Create the file we're going to source in our zshrc. Do this no matter what in case there are updates to it.
zshConfigPath := path.Join(homedir, shared.HISHTORY_PATH, "config.zsh")
zshConfigPath := path.Join(homedir, data.HISHTORY_PATH, "config.zsh")
configContents := ConfigZshContents
if os.Getenv("HISHTORY_TEST") != "" {
testConfig, err := tweakConfigForTests(configContents)
@ -756,7 +756,7 @@ func configureZshrc(homedir, binaryPath string) error {
return fmt.Errorf("failed to append to zshrc: %v", err)
}
defer f.Close()
_, err = f.WriteString("\n# Hishtory Config:\nexport PATH=\"$PATH:" + path.Join(homedir, shared.HISHTORY_PATH) + "\"\nsource " + zshConfigPath + "\n")
_, err = f.WriteString("\n# Hishtory Config:\nexport PATH=\"$PATH:" + path.Join(homedir, data.HISHTORY_PATH) + "\"\nsource " + zshConfigPath + "\n")
if err != nil {
return fmt.Errorf("failed to append to zshrc: %v", err)
}
@ -777,7 +777,7 @@ func isZshConfigured(homedir string) (bool, error) {
func configureBashrc(homedir, binaryPath string) error {
// Create the file we're going to source in our bashrc. Do this no matter what in case there are updates to it.
bashConfigPath := path.Join(homedir, shared.HISHTORY_PATH, "config.sh")
bashConfigPath := path.Join(homedir, data.HISHTORY_PATH, "config.sh")
configContents := ConfigShContents
if os.Getenv("HISHTORY_TEST") != "" {
testConfig, err := tweakConfigForTests(ConfigShContents)
@ -804,7 +804,7 @@ func configureBashrc(homedir, binaryPath string) error {
return fmt.Errorf("failed to append to bashrc: %v", err)
}
defer f.Close()
_, err = f.WriteString("\n# Hishtory Config:\nexport PATH=\"$PATH:" + path.Join(homedir, shared.HISHTORY_PATH) + "\"\nsource " + bashConfigPath + "\n")
_, err = f.WriteString("\n# Hishtory Config:\nexport PATH=\"$PATH:" + path.Join(homedir, data.HISHTORY_PATH) + "\"\nsource " + bashConfigPath + "\n")
if err != nil {
return fmt.Errorf("failed to append to bashrc: %v", err)
}
@ -826,7 +826,7 @@ func isBashConfigured(homedir string) (bool, error) {
func installBinary(homedir string) (string, error) {
clientPath, err := exec.LookPath("hishtory")
if err != nil {
clientPath = path.Join(homedir, shared.HISHTORY_PATH, "hishtory")
clientPath = path.Join(homedir, data.HISHTORY_PATH, "hishtory")
}
if _, err := os.Stat(clientPath); err == nil {
err = syscall.Unlink(clientPath)
@ -919,9 +919,9 @@ func Update(ctx *context.Context) error {
// Unlink the existing binary so we can overwrite it even though it is still running
if runtime.GOOS == "linux" {
homedir := hctx.GetHome(ctx)
err = syscall.Unlink(path.Join(homedir, shared.HISHTORY_PATH, "hishtory"))
err = syscall.Unlink(path.Join(homedir, data.HISHTORY_PATH, "hishtory"))
if err != nil {
return fmt.Errorf("failed to unlink %s for update: %v", path.Join(homedir, shared.HISHTORY_PATH, "hishtory"), err)
return fmt.Errorf("failed to unlink %s for update: %v", path.Join(homedir, data.HISHTORY_PATH, "hishtory"), err)
}
}

View File

@ -11,37 +11,37 @@ import (
"github.com/ddworken/hishtory/client/data"
"github.com/ddworken/hishtory/client/hctx"
"github.com/ddworken/hishtory/shared"
"github.com/ddworken/hishtory/shared/testutils"
)
func TestSetup(t *testing.T) {
defer shared.BackupAndRestore(t)()
defer shared.RunTestServer()()
defer testutils.BackupAndRestore(t)()
defer testutils.RunTestServer()()
homedir, err := os.UserHomeDir()
shared.Check(t, err)
if _, err := os.Stat(path.Join(homedir, shared.HISHTORY_PATH, shared.CONFIG_PATH)); err == nil {
testutils.Check(t, err)
if _, err := os.Stat(path.Join(homedir, data.HISHTORY_PATH, data.CONFIG_PATH)); err == nil {
t.Fatalf("hishtory secret file already exists!")
}
shared.Check(t, Setup([]string{}))
if _, err := os.Stat(path.Join(homedir, shared.HISHTORY_PATH, shared.CONFIG_PATH)); err != nil {
testutils.Check(t, Setup([]string{}))
if _, err := os.Stat(path.Join(homedir, data.HISHTORY_PATH, data.CONFIG_PATH)); err != nil {
t.Fatalf("hishtory secret file does not exist after Setup()!")
}
data, err := os.ReadFile(path.Join(homedir, shared.HISHTORY_PATH, shared.CONFIG_PATH))
shared.Check(t, err)
data, err := os.ReadFile(path.Join(homedir, data.HISHTORY_PATH, data.CONFIG_PATH))
testutils.Check(t, err)
if len(data) < 10 {
t.Fatalf("hishtory secret has unexpected length: %d", len(data))
}
}
func TestBuildHistoryEntry(t *testing.T) {
defer shared.BackupAndRestore(t)()
defer shared.RunTestServer()()
shared.Check(t, Setup([]string{}))
defer testutils.BackupAndRestore(t)()
defer testutils.RunTestServer()()
testutils.Check(t, Setup([]string{}))
// Test building an actual entry for bash
entry, err := BuildHistoryEntry(hctx.MakeContext(), []string{"unused", "saveHistoryEntry", "bash", "120", " 123 ls /foo ", "1641774958"})
shared.Check(t, err)
testutils.Check(t, err)
if entry.ExitCode != 120 {
t.Fatalf("history entry has unexpected exit code: %v", entry.ExitCode)
}
@ -70,7 +70,7 @@ func TestBuildHistoryEntry(t *testing.T) {
// Test building an entry for zsh
entry, err = BuildHistoryEntry(hctx.MakeContext(), []string{"unused", "saveHistoryEntry", "zsh", "120", "ls /foo\n", "1641774958"})
shared.Check(t, err)
testutils.Check(t, err)
if entry.ExitCode != 120 {
t.Fatalf("history entry has unexpected exit code: %v", entry.ExitCode)
}
@ -95,7 +95,7 @@ func TestBuildHistoryEntry(t *testing.T) {
// Test building an entry for fish
entry, err = BuildHistoryEntry(hctx.MakeContext(), []string{"unused", "saveHistoryEntry", "fish", "120", "ls /foo\n", "1641774958"})
shared.Check(t, err)
testutils.Check(t, err)
if entry.ExitCode != 120 {
t.Fatalf("history entry has unexpected exit code: %v", entry.ExitCode)
}
@ -120,17 +120,17 @@ func TestBuildHistoryEntry(t *testing.T) {
// Test building an entry that is empty, and thus not saved
entry, err = BuildHistoryEntry(hctx.MakeContext(), []string{"unused", "saveHistoryEntry", "zsh", "120", " \n", "1641774958"})
shared.Check(t, err)
testutils.Check(t, err)
if entry != nil {
t.Fatalf("expected history entry to be nil")
}
}
func TestBuildHistoryEntryWithTimestampStripping(t *testing.T) {
defer shared.BackupAndRestoreEnv("HISTTIMEFORMAT")()
defer shared.BackupAndRestore(t)()
defer shared.RunTestServer()()
shared.Check(t, Setup([]string{}))
defer testutils.BackupAndRestoreEnv("HISTTIMEFORMAT")()
defer testutils.BackupAndRestore(t)()
defer testutils.RunTestServer()()
testutils.Check(t, Setup([]string{}))
testcases := []struct {
input, histtimeformat, expectedCommand string
@ -142,11 +142,11 @@ func TestBuildHistoryEntryWithTimestampStripping(t *testing.T) {
for _, tc := range testcases {
conf := hctx.GetConf(hctx.MakeContext())
conf.LastSavedHistoryLine = ""
shared.Check(t, hctx.SetConfig(conf))
testutils.Check(t, hctx.SetConfig(conf))
os.Setenv("HISTTIMEFORMAT", tc.histtimeformat)
entry, err := BuildHistoryEntry(hctx.MakeContext(), []string{"unused", "saveHistoryEntry", "bash", "120", tc.input, "1641774958"})
shared.Check(t, err)
testutils.Check(t, err)
if entry == nil {
t.Fatalf("entry is unexpectedly nil")
}
@ -157,15 +157,15 @@ func TestBuildHistoryEntryWithTimestampStripping(t *testing.T) {
}
func TestPersist(t *testing.T) {
defer shared.BackupAndRestore(t)()
shared.Check(t, hctx.InitConfig())
defer testutils.BackupAndRestore(t)()
testutils.Check(t, hctx.InitConfig())
db := hctx.GetDb(hctx.MakeContext())
entry := data.MakeFakeHistoryEntry("ls ~/")
entry := testutils.MakeFakeHistoryEntry("ls ~/")
db.Create(entry)
var historyEntries []*data.HistoryEntry
result := db.Find(&historyEntries)
shared.Check(t, result.Error)
testutils.Check(t, result.Error)
if len(historyEntries) != 1 {
t.Fatalf("DB has %d entries, expected 1!", len(historyEntries))
}
@ -176,19 +176,19 @@ func TestPersist(t *testing.T) {
}
func TestSearch(t *testing.T) {
defer shared.BackupAndRestore(t)()
shared.Check(t, hctx.InitConfig())
defer testutils.BackupAndRestore(t)()
testutils.Check(t, hctx.InitConfig())
db := hctx.GetDb(hctx.MakeContext())
// Insert data
entry1 := data.MakeFakeHistoryEntry("ls /foo")
entry1 := testutils.MakeFakeHistoryEntry("ls /foo")
db.Create(entry1)
entry2 := data.MakeFakeHistoryEntry("ls /bar")
entry2 := testutils.MakeFakeHistoryEntry("ls /bar")
db.Create(entry2)
// Search for data
results, err := data.Search(db, "ls", 5)
shared.Check(t, err)
testutils.Check(t, err)
if len(results) != 2 {
t.Fatalf("Search() returned %d results, expected 2!", len(results))
}
@ -202,15 +202,15 @@ func TestSearch(t *testing.T) {
func TestAddToDbIfNew(t *testing.T) {
// Set up
defer shared.BackupAndRestore(t)()
shared.Check(t, hctx.InitConfig())
defer testutils.BackupAndRestore(t)()
testutils.Check(t, hctx.InitConfig())
db := hctx.GetDb(hctx.MakeContext())
// Add duplicate entries
entry1 := data.MakeFakeHistoryEntry("ls /foo")
entry1 := testutils.MakeFakeHistoryEntry("ls /foo")
AddToDbIfNew(db, entry1)
AddToDbIfNew(db, entry1)
entry2 := data.MakeFakeHistoryEntry("ls /foo")
entry2 := testutils.MakeFakeHistoryEntry("ls /foo")
AddToDbIfNew(db, entry2)
AddToDbIfNew(db, entry2)
AddToDbIfNew(db, entry1)
@ -228,12 +228,12 @@ func TestAddToDbIfNew(t *testing.T) {
func TestParseCrossPlatformInt(t *testing.T) {
res, err := parseCrossPlatformInt("123")
shared.Check(t, err)
testutils.Check(t, err)
if res != 123 {
t.Fatalf("failed to parse cross platform int %d", res)
}
res, err = parseCrossPlatformInt("123N")
shared.Check(t, err)
testutils.Check(t, err)
if res != 123 {
t.Fatalf("failed to parse cross platform int %d", res)
}
@ -270,7 +270,7 @@ func TestGetLastCommand(t *testing.T) {
}
for _, tc := range testcases {
actualOutput, err := getLastCommand(tc.input)
shared.Check(t, err)
testutils.Check(t, err)
if actualOutput != tc.expectedOutput {
t.Fatalf("getLastCommand(%#v) returned %#v (expected=%#v)", tc.input, actualOutput, tc.expectedOutput)
}
@ -278,7 +278,7 @@ func TestGetLastCommand(t *testing.T) {
}
func TestMaybeSkipBashHistTimePrefix(t *testing.T) {
defer shared.BackupAndRestoreEnv("HISTTIMEFORMAT")()
defer testutils.BackupAndRestoreEnv("HISTTIMEFORMAT")()
testcases := []struct {
env, cmdLine, expected string
@ -312,7 +312,7 @@ func TestMaybeSkipBashHistTimePrefix(t *testing.T) {
for _, tc := range testcases {
os.Setenv("HISTTIMEFORMAT", tc.env)
stripped, err := maybeSkipBashHistTimePrefix(tc.cmdLine)
shared.Check(t, err)
testutils.Check(t, err)
if stripped != tc.expected {
t.Fatalf("skipping the time prefix returned %#v (expected=%#v for %#v)", stripped, tc.expected, tc.cmdLine)
}

View File

@ -85,9 +85,3 @@ func (m *MessageIdentifiers) Scan(value interface{}) error {
func (m MessageIdentifiers) Value() (driver.Value, error) {
return json.Marshal(m)
}
const (
CONFIG_PATH = ".hishtory.config"
HISHTORY_PATH = ".hishtory"
DB_PATH = ".hishtory.db"
)

View File

@ -1,4 +1,4 @@
package shared
package testutils
import (
"bytes"
@ -15,11 +15,13 @@ import (
"strings"
"testing"
"time"
"github.com/ddworken/hishtory/client/data"
)
const (
DB_WAL_PATH = DB_PATH + "-wal"
DB_SHM_PATH = DB_PATH + "-shm"
DB_WAL_PATH = data.DB_PATH + "-wal"
DB_SHM_PATH = data.DB_PATH + "-shm"
)
func ResetLocalState(t *testing.T) {
@ -28,13 +30,13 @@ func ResetLocalState(t *testing.T) {
t.Fatalf("failed to retrieve homedir: %v", err)
}
_ = os.Remove(path.Join(homedir, HISHTORY_PATH, DB_PATH))
_ = os.Remove(path.Join(homedir, HISHTORY_PATH, DB_WAL_PATH))
_ = os.Remove(path.Join(homedir, HISHTORY_PATH, CONFIG_PATH))
_ = os.Remove(path.Join(homedir, HISHTORY_PATH, "hishtory"))
_ = os.Remove(path.Join(homedir, HISHTORY_PATH, "config.sh"))
_ = os.Remove(path.Join(homedir, HISHTORY_PATH, "config.zsh"))
_ = os.Remove(path.Join(homedir, HISHTORY_PATH, "config.fish"))
_ = os.Remove(path.Join(homedir, data.HISHTORY_PATH, data.DB_PATH))
_ = os.Remove(path.Join(homedir, data.HISHTORY_PATH, DB_WAL_PATH))
_ = os.Remove(path.Join(homedir, data.HISHTORY_PATH, data.CONFIG_PATH))
_ = os.Remove(path.Join(homedir, data.HISHTORY_PATH, "hishtory"))
_ = os.Remove(path.Join(homedir, data.HISHTORY_PATH, "config.sh"))
_ = os.Remove(path.Join(homedir, data.HISHTORY_PATH, "config.zsh"))
_ = os.Remove(path.Join(homedir, data.HISHTORY_PATH, "config.fish"))
}
func BackupAndRestore(t *testing.T) func() {
@ -44,31 +46,32 @@ func BackupAndRestore(t *testing.T) func() {
func DeleteBakFiles(t *testing.T) {
homedir, err := os.UserHomeDir()
checkError(err)
entries, err := ioutil.ReadDir(path.Join(homedir, HISHTORY_PATH))
entries, err := ioutil.ReadDir(path.Join(homedir, data.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())))
checkError(os.Remove(path.Join(homedir, data.HISHTORY_PATH, entry.Name())))
}
}
}
func BackupAndRestoreWithId(t *testing.T, id string) func() {
ResetFakeHistoryTimestamp()
homedir, err := os.UserHomeDir()
if err != nil {
t.Fatalf("failed to retrieve homedir: %v", err)
}
renameFiles := []string{
path.Join(homedir, HISHTORY_PATH, DB_PATH),
path.Join(homedir, HISHTORY_PATH, DB_WAL_PATH),
path.Join(homedir, HISHTORY_PATH, DB_SHM_PATH),
path.Join(homedir, HISHTORY_PATH, CONFIG_PATH),
path.Join(homedir, HISHTORY_PATH, "hishtory"),
path.Join(homedir, HISHTORY_PATH, "config.sh"),
path.Join(homedir, HISHTORY_PATH, "config.zsh"),
path.Join(homedir, HISHTORY_PATH, "config.fish"),
path.Join(homedir, data.HISHTORY_PATH, data.DB_PATH),
path.Join(homedir, data.HISHTORY_PATH, DB_WAL_PATH),
path.Join(homedir, data.HISHTORY_PATH, DB_SHM_PATH),
path.Join(homedir, data.HISHTORY_PATH, data.CONFIG_PATH),
path.Join(homedir, data.HISHTORY_PATH, "hishtory"),
path.Join(homedir, data.HISHTORY_PATH, "config.sh"),
path.Join(homedir, data.HISHTORY_PATH, "config.zsh"),
path.Join(homedir, data.HISHTORY_PATH, "config.fish"),
path.Join(homedir, ".bash_history"),
path.Join(homedir, ".zsh_history"),
}
@ -249,3 +252,23 @@ func IsOnline() bool {
_, err := http.Get("https://hishtory.dev")
return err == nil
}
var fakeHistoryTimestamp int64 = 1666068191
func ResetFakeHistoryTimestamp() {
fakeHistoryTimestamp = 1666068191
}
func MakeFakeHistoryEntry(command string) data.HistoryEntry {
fakeHistoryTimestamp += 5
return data.HistoryEntry{
LocalUsername: "david",
Hostname: "localhost",
Command: command,
CurrentWorkingDirectory: "/tmp/",
HomeDirectory: "/home/david/",
ExitCode: 2,
StartTime: time.Unix(fakeHistoryTimestamp, 0),
EndTime: time.Unix(fakeHistoryTimestamp+3, 0),
}
}