Passing the basic dump testss

This commit is contained in:
David Dworken 2022-05-22 19:45:46 -07:00
parent f6273584ce
commit 47d13a9c27
5 changed files with 105 additions and 38 deletions

View File

@ -123,8 +123,16 @@ func apiQueryHandler(w http.ResponseWriter, r *http.Request) {
func apiRegisterHandler(w http.ResponseWriter, r *http.Request) {
userId := r.URL.Query().Get("user_id")
deviceId := r.URL.Query().Get("device_id")
var existingDevicesCount int64 = -1
result := GLOBAL_DB.Model(&shared.Device{}).Where("user_id = ?", userId).Count(&existingDevicesCount)
fmt.Printf("apiRegisterHandler: existingDevicesCount=%d\n", existingDevicesCount)
if result.Error != nil {
panic(result.Error)
}
GLOBAL_DB.Create(&shared.Device{UserId: userId, DeviceId: deviceId, RegistrationIp: r.RemoteAddr, RegistrationDate: time.Now()})
GLOBAL_DB.Create(&shared.DumpRequest{UserId: userId, RequestingDeviceId: deviceId, RequestTime: time.Now()})
if existingDevicesCount > 0 {
GLOBAL_DB.Create(&shared.DumpRequest{UserId: userId, RequestingDeviceId: deviceId, RequestTime: time.Now()})
}
updateUsageData(userId, deviceId)
}

View File

@ -120,12 +120,18 @@ func TestDumpRequestAndResponse(t *testing.T) {
// Register a first device for two different users
userId := data.UserId("dkey")
devId1 := uuid.Must(uuid.NewRandom()).String()
devId2 := uuid.Must(uuid.NewRandom()).String()
otherUser := data.UserId("dOtherkey")
otherDev1 := uuid.Must(uuid.NewRandom()).String()
otherDev2 := uuid.Must(uuid.NewRandom()).String()
deviceReq := httptest.NewRequest(http.MethodGet, "/?device_id="+devId1+"&user_id="+userId, nil)
apiRegisterHandler(nil, deviceReq)
deviceReq = httptest.NewRequest(http.MethodGet, "/?device_id="+devId2+"&user_id="+userId, nil)
apiRegisterHandler(nil, deviceReq)
deviceReq = httptest.NewRequest(http.MethodGet, "/?device_id="+otherDev1+"&user_id="+otherUser, nil)
apiRegisterHandler(nil, deviceReq)
deviceReq = httptest.NewRequest(http.MethodGet, "/?device_id="+otherDev2+"&user_id="+otherUser, nil)
apiRegisterHandler(nil, deviceReq)
// Query for dump requests, there should be one for userId
w := httptest.NewRecorder()
@ -140,7 +146,7 @@ func TestDumpRequestAndResponse(t *testing.T) {
t.Fatalf("expected one pending dump request, got %#v", dumpRequests)
}
dumpRequest := dumpRequests[0]
if dumpRequest.RequestingDeviceId != devId1 {
if dumpRequest.RequestingDeviceId != devId2 {
t.Fatalf("unexpected device ID")
}
if dumpRequest.UserId != userId {
@ -160,7 +166,7 @@ func TestDumpRequestAndResponse(t *testing.T) {
t.Fatalf("expected one pending dump request, got %#v", dumpRequests)
}
dumpRequest = dumpRequests[0]
if dumpRequest.RequestingDeviceId != otherDev1 {
if dumpRequest.RequestingDeviceId != otherDev2 {
t.Fatalf("unexpected device ID")
}
if dumpRequest.UserId != otherUser {
@ -189,6 +195,17 @@ func TestDumpRequestAndResponse(t *testing.T) {
t.Fatalf("got unexpected respBody: %#v", string(respBody))
}
// And none for a missing user ID
w = httptest.NewRecorder()
apiGetPendingDumpRequestsHandler(w, httptest.NewRequest(http.MethodGet, "/?user_id=", nil))
res = w.Result()
defer res.Body.Close()
respBody, err = ioutil.ReadAll(res.Body)
shared.Check(t, err)
if string(respBody) != "[]" {
t.Fatalf("got unexpected respBody: %#v", string(respBody))
}
// Now submit a dump for userId
entry1Dec := data.MakeFakeHistoryEntry("ls ~/")
entry1, err := data.EncryptHistoryEntry("dkey", entry1Dec)
@ -198,7 +215,7 @@ func TestDumpRequestAndResponse(t *testing.T) {
shared.Check(t, err)
reqBody, err := json.Marshal([]shared.EncHistoryEntry{entry1, entry2})
shared.Check(t, err)
submitReq := httptest.NewRequest(http.MethodPost, "/?user_id="+userId+"&requesting_device_id="+devId1, bytes.NewReader(reqBody))
submitReq := httptest.NewRequest(http.MethodPost, "/?user_id="+userId+"&requesting_device_id="+devId2, bytes.NewReader(reqBody))
apiSubmitDumpHandler(nil, submitReq)
// Check that the dump request is no longer there for userId
@ -225,7 +242,7 @@ func TestDumpRequestAndResponse(t *testing.T) {
t.Fatalf("expected one pending dump request, got %#v", dumpRequests)
}
dumpRequest = dumpRequests[0]
if dumpRequest.RequestingDeviceId != otherDev1 {
if dumpRequest.RequestingDeviceId != otherDev2 {
t.Fatalf("unexpected device ID")
}
if dumpRequest.UserId != otherUser {
@ -234,7 +251,7 @@ func TestDumpRequestAndResponse(t *testing.T) {
// And finally, query to ensure that the dumped entries are in the DB
w = httptest.NewRecorder()
searchReq := httptest.NewRequest(http.MethodGet, "/?device_id="+devId1+"&user_id="+userId, nil)
searchReq := httptest.NewRequest(http.MethodGet, "/?device_id="+devId2+"&user_id="+userId, nil)
apiQueryHandler(w, searchReq)
res = w.Result()
defer res.Body.Close()
@ -246,7 +263,7 @@ func TestDumpRequestAndResponse(t *testing.T) {
t.Fatalf("Expected to retrieve 2 entries, found %d", len(retrievedEntries))
}
for _, dbEntry := range retrievedEntries {
if dbEntry.DeviceId != devId1 {
if dbEntry.DeviceId != devId2 {
t.Fatalf("Response contains an incorrect device ID: %#v", *dbEntry)
}
if dbEntry.UserId != userId {

View File

@ -901,17 +901,23 @@ func testRequestAndReceiveDbDump(t *testing.T, tester shellTester) {
defer shared.BackupAndRestore(t)()
secretKey := installHishtory(t, tester, "")
// Confirm there are no pending dump requests
resp, err := lib.ApiGet("/api/v1/get-dump-requests?user_id=" + data.UserId(secretKey))
if err != nil {
t.Fatalf("failed to get pending dump requests: %v", err)
}
if string(resp) != "[]" {
t.Fatalf("There are pending dump requests! user_id=%#v, resp=%#v", data.UserId(secretKey), string(resp))
}
// Record two commands and then query for them
out := tester.RunInteractiveShell(t, `echo hello
echo other
echo tododeleteme`)
// if out != "hello\nother\n" {
// t.Fatalf("running echo had unexpected out=%#v", out)
// } // todo
echo other`)
if out != "hello\nother\n" {
t.Fatalf("running echo had unexpected out=%#v", out)
}
// Query for it and check that the directory gets recorded correctly
time.Sleep(5 * time.Second) // todo: delete this
fmt.Println(tester.RunInteractiveShell(t, `hishtory export`)) // todo: delete
out = hishtoryQuery(t, tester, "echo")
if strings.Count(out, "\n") != 3 {
t.Fatalf("hishtory query has unexpected number of lines: out=%#v", out)
@ -927,7 +933,7 @@ echo tododeleteme`)
restoreFirstInstallation := shared.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")
_, err = lib.ApiGet("/api/v1/wipe-db")
if err != nil {
t.Fatalf("failed to wipe the DB: %v", err)
}
@ -935,6 +941,15 @@ echo tododeleteme`)
// Install a new one (with the same secret key but a diff device id)
installHishtory(t, tester, secretKey)
// Confirm there are pending dump requests
resp, err = lib.ApiGet("/api/v1/get-dump-requests?user_id=" + data.UserId(secretKey))
if err != nil {
t.Fatalf("failed to get pending dump requests: %v", err)
}
if string(resp) == "[]" {
t.Fatalf("There are no pending dump requests! user_id=%#v, resp=%#v", data.UserId(secretKey), string(resp))
}
// Check that the new one doesn't have the commands yet
out = hishtoryQuery(t, tester, "echo")
if strings.Count(out, "\n") != 1 {
@ -954,13 +969,22 @@ echo tododeleteme`)
// Confirm it still has the correct entries via hishtory export (and this runs a command to trigger it to dump the DB)
out = tester.RunInteractiveShell(t, `hishtory export | grep -v pipefail`)
if out != "echo hello\necho other\nhishtory query echo\nhishtory query echo\n" {
t.Fatalf("running hishtory export had unexpected out=%#v", out)
expectedOutput := "echo hello\necho other\nhishtory query echo\nhishtory query echo\n"
if diff := cmp.Diff(expectedOutput, out); diff != "" {
t.Fatalf("hishtory export mismatch (-expected +got):\n%s\nout=%#v", diff, out)
}
// Confirm there are no pending dump requests
resp, err = lib.ApiGet("/api/v1/get-dump-requests?user_id=" + data.UserId(secretKey))
if err != nil {
t.Fatalf("failed to get pending dump requests: %v", err)
}
if string(resp) != "[]" {
t.Fatalf("There are pending dump requests! user_id=%#v, resp=%#v", data.UserId(secretKey), string(resp))
}
// Restore the second copy and confirm it has the commands
restoreSecondInstallation()
fmt.Println(tester.RunInteractiveShell(t, `hishtory status -v`)) // todo: delete this
out = hishtoryQuery(t, tester, "ech")
if strings.Count(out, "\n") != 5 {
t.Fatalf("hishtory query has unexpected number of lines=%d: out=%#v", strings.Count(out, "\n"), out)
@ -977,8 +1001,9 @@ echo tododeleteme`)
// And check hishtory export too for good measure
out = tester.RunInteractiveShell(t, `hishtory export | grep -v pipefail`)
if out != "echo hello\necho other\nhishtory query echo\nhishtory query echo\nhishtory query ech\n" {
t.Fatalf("running hishtory export had unexpected out=%#v", out)
expectedOutput = "echo hello\necho other\nhishtory query echo\nhishtory query echo\nhishtory query ech\n"
if diff := cmp.Diff(expectedOutput, out); diff != "" {
t.Fatalf("hishtory export mismatch (-expected +got):\n%s\nout=%#v", diff, out)
}
}

View File

@ -57,14 +57,23 @@ func main() {
}
func printDumpStatus(config lib.ClientConfig) {
respBody, err := lib.ApiGet("/api/v1/get-dump-requests?user_id=" + data.UserId(config.UserSecret))
dumpRequests, err := getDumpRequests(config)
lib.CheckFatalError(err)
fmt.Printf("Dump Requests: ")
for _, d := range dumpRequests {
fmt.Printf("%#v, ", *d)
}
fmt.Print("\n")
}
func getDumpRequests(config lib.ClientConfig) ([]*shared.DumpRequest, error) {
resp, err := lib.ApiGet("/api/v1/get-dump-requests?user_id=" + data.UserId(config.UserSecret) + "&device_id=" + config.DeviceId)
if err != nil {
lib.CheckFatalError(err)
return nil, err
}
var dumpRequests []*shared.DumpRequest
err = json.Unmarshal(respBody, &dumpRequests)
lib.CheckFatalError(err)
fmt.Printf("Dump Requests: %#v\n", dumpRequests)
err = json.Unmarshal(resp, &dumpRequests)
return dumpRequests, err
}
func retrieveAdditionalEntriesFromRemote(db *gorm.DB) error {
@ -132,11 +141,13 @@ func saveHistoryEntry() {
log.Fatalf("hishtory cannot save an entry because the hishtory config file does not exist, try running `hishtory init` (err=%v)", err)
}
if !config.IsEnabled {
lib.GetLogger().Printf("Skipping saving a history entry because hishtory is disabled\n")
return
}
entry, err := lib.BuildHistoryEntry(os.Args)
lib.CheckFatalError(err)
if entry == nil {
lib.GetLogger().Printf("Skipping saving a history entry because we failed to build a history entry (was the command prefixed with a space?)\n")
return
}
@ -163,18 +174,16 @@ func saveHistoryEntry() {
}
// Check if there is a pending dump request and reply to it if so
resp, err := lib.ApiGet("/api/v1/get-dump-requests?user_id=" + data.UserId(config.UserSecret) + "&device_id=" + config.DeviceId)
dumpRequests, err := getDumpRequests(config)
if err != nil {
if lib.IsOfflineError(err) {
// It is fine to just ignore this, the next command will retry the API and eventually we will respond to any pending dump requests
resp = []byte("[]")
dumpRequests = []*shared.DumpRequest{}
lib.GetLogger().Printf("Failed to check for dump requests because the device is offline!")
} else {
lib.CheckFatalError(err)
}
}
var dumpRequests []*shared.DumpRequest
err = json.Unmarshal(resp, &dumpRequests)
lib.CheckFatalError(err)
if len(dumpRequests) > 0 {
lib.CheckFatalError(retrieveAdditionalEntriesFromRemote(db))
entries, err := data.Search(db, "", 0)

View File

@ -3,6 +3,7 @@ package shared
import (
"bytes"
"fmt"
"log"
"net/http"
"os"
"os/exec"
@ -47,16 +48,23 @@ func BackupAndRestoreWithId(t *testing.T, id string) func() {
_ = os.Rename(path.Join(homedir, HISHTORY_PATH, DB_SHM_PATH), path.Join(homedir, HISHTORY_PATH, DB_SHM_PATH+id+".bak"))
_ = os.Rename(path.Join(homedir, HISHTORY_PATH, CONFIG_PATH), path.Join(homedir, HISHTORY_PATH, CONFIG_PATH+id+".bak"))
_ = os.Rename(path.Join(homedir, HISHTORY_PATH, "hishtory"), path.Join(homedir, HISHTORY_PATH, "hishtory"+id+".bak"))
_ = os.Rename(path.Join(homedir, HISHTORY_PATH, "config.sh"), path.Join(homedir, HISHTORY_PATH, "config.sh"+id+"bak"))
_ = os.Rename(path.Join(homedir, HISHTORY_PATH, "config.sh"), path.Join(homedir, HISHTORY_PATH, "config.sh"+id+".bak"))
_ = os.Rename(path.Join(homedir, HISHTORY_PATH, "config.zsh"), path.Join(homedir, HISHTORY_PATH, "config.zsh"+id+".bak"))
return func() {
_ = os.Rename(path.Join(homedir, HISHTORY_PATH, DB_PATH+id+".bak"), path.Join(homedir, HISHTORY_PATH, DB_PATH))
_ = os.Rename(path.Join(homedir, HISHTORY_PATH, DB_WAL_PATH+id+".bak"), path.Join(homedir, HISHTORY_PATH, DB_WAL_PATH))
_ = os.Rename(path.Join(homedir, HISHTORY_PATH, DB_SHM_PATH+id+".bak"), path.Join(homedir, HISHTORY_PATH, DB_SHM_PATH))
_ = os.Rename(path.Join(homedir, HISHTORY_PATH, CONFIG_PATH+id+".bak"), path.Join(homedir, HISHTORY_PATH, CONFIG_PATH))
_ = os.Rename(path.Join(homedir, HISHTORY_PATH, "hishtory"+id+".bak"), path.Join(homedir, HISHTORY_PATH, "hishtory"))
_ = os.Rename(path.Join(homedir, HISHTORY_PATH, "config.sh"+id+".bak"), path.Join(homedir, HISHTORY_PATH, "config.sh"))
_ = os.Rename(path.Join(homedir, HISHTORY_PATH, "config.zsh"+id+".bak"), path.Join(homedir, HISHTORY_PATH, "config.zsh"))
checkError(os.Rename(path.Join(homedir, HISHTORY_PATH, DB_PATH+id+".bak"), path.Join(homedir, HISHTORY_PATH, DB_PATH)))
checkError(os.Rename(path.Join(homedir, HISHTORY_PATH, DB_WAL_PATH+id+".bak"), path.Join(homedir, HISHTORY_PATH, DB_WAL_PATH)))
checkError(os.Rename(path.Join(homedir, HISHTORY_PATH, DB_SHM_PATH+id+".bak"), path.Join(homedir, HISHTORY_PATH, DB_SHM_PATH)))
checkError(os.Rename(path.Join(homedir, HISHTORY_PATH, CONFIG_PATH+id+".bak"), path.Join(homedir, HISHTORY_PATH, CONFIG_PATH)))
checkError(os.Rename(path.Join(homedir, HISHTORY_PATH, "hishtory"+id+".bak"), path.Join(homedir, HISHTORY_PATH, "hishtory")))
checkError(os.Rename(path.Join(homedir, HISHTORY_PATH, "config.sh"+id+".bak"), path.Join(homedir, HISHTORY_PATH, "config.sh")))
checkError(os.Rename(path.Join(homedir, HISHTORY_PATH, "config.zsh"+id+".bak"), path.Join(homedir, HISHTORY_PATH, "config.zsh")))
}
}
func checkError(err error) {
if err != nil {
_, filename, line, _ := runtime.Caller(1)
log.Fatalf("testutils fatal error at %s:%d: %v", filename, line, err)
}
}