Skip to content

Commit

Permalink
Reset state (#1338)
Browse files Browse the repository at this point in the history
* Reset state removes proper file with warning

* Fix path errors

* Cross platfrom data path in test
  • Loading branch information
jameskerr authored Jan 8, 2021
1 parent b7e612a commit af91d29
Show file tree
Hide file tree
Showing 17 changed files with 301 additions and 139 deletions.
32 changes: 32 additions & 0 deletions src/js/electron/brim-boot.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {Brim} from "./brim"
import path from "path"

const file = `tmp-boot-test/appState.json`

test("boot starts zqd with defaults", async () => {
const createSession = () => ({
load: () => Promise.resolve(undefined)
})
// @ts-ignore
const brim = await Brim.boot(file, createSession)
expect(brim.zqd.root).toBe(path.normalize("/fake/path/data/spaces"))
expect(brim.zqd.suricataRunner).toBe("")
expect(brim.zqd.suricataUpdater).toBe("")
expect(brim.zqd.zeekRunner).toBe("")
})

test("gets global state from store", async () => {
const createSession = () => ({
load: () =>
Promise.resolve({
globalState: {
prefs: {
zeekRunner: "testing123"
}
}
})
})
// @ts-ignore
const brim = await Brim.boot(path, createSession)
expect(brim.store.getState().prefs.zeekRunner).toEqual("testing123")
})
51 changes: 51 additions & 0 deletions src/js/electron/brim-quit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import {Brim} from "./brim"
import {app, ipcMain} from "electron"

function mockIpc(response) {
jest
.spyOn(ipcMain, "once")
// @ts-ignore
.mockImplementationOnce((_channel: string, listener) =>
listener(null, response)
)
}

let brim: Brim
beforeEach(async () => {
// @ts-ignore
app.quit.mockClear()
brim = new Brim()
jest.spyOn(brim.zqd, "start").mockImplementation(() => {})
jest.spyOn(brim.zqd, "close").mockImplementation(() => Promise.resolve())
jest
.spyOn(brim.session, "load")
// @ts-ignore
.mockImplementation(() => Promise.resolve("fake-session-state"))
jest.spyOn(brim.session, "save").mockImplementation(() => Promise.resolve())
await brim.start()
})

test("quit and save", async () => {
mockIpc(true) // the confirm ipc
mockIpc(null) // the prepare ipc
mockIpc({state: "test"}) // the update window state ipc

await brim.quit()

expect(brim.isQuitting).toBe(true)
expect(brim.session.save).toHaveBeenCalledTimes(1)
expect(brim.zqd.close).toHaveBeenCalledTimes(1)
expect(app.quit).toHaveBeenCalledTimes(1)
})

test("quit without saving", async () => {
mockIpc(true) // confirm
mockIpc(null) // prepare

await brim.quit({saveSession: false})

expect(brim.isQuitting).toBe(true)
expect(brim.session.save).not.toHaveBeenCalled()
expect(brim.zqd.close).toHaveBeenCalledTimes(1)
expect(app.quit).toHaveBeenCalledTimes(1)
})
47 changes: 47 additions & 0 deletions src/js/electron/brim-reset-state.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {app} from "electron"
import {ZQD} from "ppl/zqd/zqd"
import {Brim} from "./brim"
import tron from "./tron"
import windowManager from "./tron/windowManager"

function mockZqd() {
const zqd = new ZQD("test", "srun", "supdate", "zrun")
jest.spyOn(zqd, "start").mockImplementation(() => {})
jest.spyOn(zqd, "close").mockImplementation(() => Promise.resolve())
return zqd
}

function mockSession() {
const session = tron.session()
jest.spyOn(session, "delete").mockImplementation(() => Promise.resolve())
jest.spyOn(session, "save").mockImplementation(() => Promise.resolve())
return session
}

function mockWindows() {
const windows = windowManager()
jest
.spyOn(windows, "confirmQuit")
.mockImplementation(() => Promise.resolve(true))
jest
.spyOn(windows, "prepareQuit")
.mockImplementation(() => Promise.resolve([]))
jest.spyOn(windows, "quit").mockImplementation(() => Promise.resolve())
return windows
}

test("reset state", async () => {
const brim = new Brim({
zqd: mockZqd(),
session: mockSession(),
windows: mockWindows()
})

await brim.start()
await brim.resetState()

expect(brim.session.delete).toHaveBeenCalled()
expect(brim.session.save).not.toHaveBeenCalled()
expect(app.relaunch).toHaveBeenCalled()
expect(brim.isQuitting).toBe(true)
})
43 changes: 29 additions & 14 deletions src/js/electron/brim.test.ts → src/js/electron/brim-start.test.ts
Original file line number Diff line number Diff line change
@@ -1,42 +1,57 @@
import {ZQD} from "ppl/zqd/zqd"
import {Brim} from "./brim"
import {installExtensions} from "./extensions"

jest.mock("./extensions", () => ({
installExtensions: jest.fn()
}))
import {installExtensions} from "./extensions"
import {Brim} from "./brim"

function mockZqd() {
const zqd = new ZQD("test", "srun", "supdate", "zrun")
jest.spyOn(zqd, "start").mockImplementation(() => {})
return zqd
}

let brim: Brim
beforeEach(() => {
brim = new Brim({
zqd: mockZqd()
})
})

test("start is called in zqd", async () => {
await brim.start()
expect(brim.zqd.start).toHaveBeenCalledTimes(1)
})

test("activate when zero windows open", () => {
const brim = new Brim()
expect(brim.windows.count()).toBe(0)
brim.activate()
expect(brim.windows.count()).toBe(1)
})

test("actiate when one or more windows open", () => {
const brim = new Brim()
test("actiate when one or more windows open", async () => {
brim.activate()
expect(brim.windows.count()).toBe(1)
brim.activate()
expect(brim.windows.count()).toBe(1)
})

test("start opens a window", () => {
const brim = new Brim()
brim.start()
test("start opens a window", async () => {
await brim.start()
expect(brim.windows.count()).toBe(1)
})

test("start installs dev extensions if is dev", () => {
const brim = new Brim()
test("start installs dev extensions if is dev", async () => {
jest.spyOn(brim, "isDev").mockImplementation(() => true)
brim.start()
await brim.start()
expect(installExtensions).toHaveBeenCalled()
// @ts-ignore
installExtensions.mockReset()
})

test("start does not install dev extensions if not dev", () => {
const brim = new Brim()
test("start does not install dev extensions if not dev", async () => {
jest.spyOn(brim, "isDev").mockImplementation(() => false)
brim.start()
await brim.start()
expect(installExtensions).not.toHaveBeenCalled()
})
85 changes: 79 additions & 6 deletions src/js/electron/brim.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,99 @@
import windowManager, {$WindowManager} from "./tron/windowManager"
import isDev from "./isDev"
import {installExtensions} from "./extensions"
import {SessionState} from "./tron/formatSessionState"
import formatSessionState from "./tron/formatSessionState"
import createGlobalStore from "../state/createGlobalStore"
import {Store} from "redux"
import tron, {Session} from "./tron"
import Prefs from "../state/Prefs"
import {ZQD} from "ppl/zqd/zqd"
import {app} from "electron"
import path from "path"
import {sessionStateFile} from "./tron/session"

type QuitOpts = {
saveSession?: boolean
}

type BrimArgs = {
windows?: $WindowManager
store?: Store
session?: Session
zqd?: ZQD
}

export class Brim {
readonly windows: $WindowManager
readonly data: SessionState | undefined
readonly store: Store
readonly zqd: ZQD
readonly session: Session
public isQuitting = false

constructor(data?: SessionState) {
this.data = data
this.windows = windowManager()
static async boot(
sessionPath: string = sessionStateFile(),
createSession = tron.session
) {
const session = createSession(sessionPath)
const data = await session.load()
const windows = windowManager(data)
const store = createGlobalStore(data?.globalState)
const select = (fn) => fn(store.getState())
const suricataRunner = select(Prefs.getSuricataRunner)
const suricataUpdater = select(Prefs.getSuricataUpdater)
const zeekRunner = select(Prefs.getZeekRunner)
const spaceDir = path.join(app.getPath("userData"), "data", "spaces")
const zqd = new ZQD(spaceDir, suricataRunner, suricataUpdater, zeekRunner)
return new Brim({session, windows, store, zqd})
}

constructor(args: BrimArgs = {}) {
this.windows = args.windows || windowManager()
this.store = args.store || createGlobalStore(undefined)
this.session = args.session || tron.session()
this.zqd = args.zqd || new ZQD(null, null, null, null)
}

async start() {
this.zqd.start()
if (this.isDev()) await installExtensions()
this.windows.init(this.data)
this.windows.init()
}

activate() {
if (this.windows.count() === 0) this.windows.init()
}

async resetState() {
await this.session.delete()
app.relaunch()
this.quit({saveSession: false})
}

async saveSession() {
const windowState = await this.windows.serialize()
const mainState = this.store.getState()
await this.session.save(formatSessionState(windowState, mainState))
}

async deleteSession() {
await this.session.delete()
}

async quit(opts: QuitOpts = {saveSession: true}) {
this.isQuitting = true
if (await this.windows.confirmQuit()) {
await this.windows.prepareQuit()
if (opts.saveSession) {
await this.saveSession()
}
this.windows.quit()
await this.zqd.close()
app.quit()
} else {
this.isQuitting = false
}
}

isDev() {
return isDev
}
Expand Down
6 changes: 0 additions & 6 deletions src/js/electron/config.ts

This file was deleted.

11 changes: 5 additions & 6 deletions src/js/electron/ipc/globalStore/mainHandler.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import {ipcMain} from "electron"

import {$WindowManager} from "../../tron/windowManager"
import ipc from ".."
import sendTo from "../sendTo"
import {Brim} from "../../brim"

export default function(store: any, winMan: $WindowManager) {
export default function(brim: Brim) {
ipcMain.handle("globalStore:init", () => {
return {
initialState: store.getState()
initialState: brim.store.getState()
}
})

ipcMain.handle("globalStore:dispatch", (e, {action}) => {
store.dispatch(action)
for (const win of winMan.getWindows()) {
brim.store.dispatch(action)
for (const win of brim.windows.getWindows()) {
if (!win.ref.isDestroyed()) {
sendTo(win.ref.webContents, ipc.globalStore.dispatch(action))
}
Expand Down
14 changes: 6 additions & 8 deletions src/js/electron/ipc/windows/mainHandler.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,22 @@
import log from "electron-log"

import {BrowserWindow, dialog, ipcMain} from "electron"

import {$WindowManager} from "../../tron/windowManager"
import {Brim} from "../../brim"

let started = false

export default function(manager: $WindowManager) {
export default function(brim: Brim) {
ipcMain.handle("windows:initialState", (_e, {id}) => {
const window = manager.getWindow(id)
const window = brim.windows.getWindow(id)

return window.initialState
})

ipcMain.handle("windows:open", (e, args) => {
manager.openWindow(args.name, args.params, args.state)
brim.windows.openWindow(args.name, args.params, args.state)
})

ipcMain.handle("windows:close", () => {
manager.closeWindow()
brim.windows.closeWindow()
})

ipcMain.handle("windows:ready", () => {
Expand All @@ -29,7 +27,7 @@ export default function(manager: $WindowManager) {
})

ipcMain.handle("windows:newSearchTab", (e, params) => {
manager.openSearchTab(params.params)
brim.windows.openSearchTab(params.params)
})

ipcMain.handle("windows:log", (e, {id, args}) => {
Expand Down
Loading

0 comments on commit af91d29

Please sign in to comment.