From 86dcf588dcbba30e735dea92c5d68796c07ea6d7 Mon Sep 17 00:00:00 2001 From: Johannah Sprinz Date: Sun, 11 Sep 2022 13:26:49 +0200 Subject: [PATCH] [WIP] session store to track executed actions --- src/core/core.js | 6 +++- src/core/helpers/session.js | 48 ++++++++++++++++++++++++++++++++ src/core/helpers/session.spec.js | 23 +++++++++++++++ src/core/plugins/index.js | 12 ++++---- src/core/plugins/index.spec.js | 9 +++++- src/lib/reporter.js | 8 ++++++ src/lib/reporter.spec.js | 7 +++-- src/lib/window.js | 8 ++++-- 8 files changed, 110 insertions(+), 11 deletions(-) create mode 100644 src/core/helpers/session.js create mode 100644 src/core/helpers/session.spec.js diff --git a/src/core/core.js b/src/core/core.js index 64dc7036..cd74217d 100644 --- a/src/core/core.js +++ b/src/core/core.js @@ -28,6 +28,7 @@ const settings = require("../lib/settings.js"); const errors = require("../lib/errors.js"); const window = require("../lib/window.js"); const api = require("./helpers/api.js"); +const Session = require("./helpers/session.js"); const PluginIndex = require("./plugins/index.js"); const packageInfo = require("../../package.json"); const semver = require("semver"); @@ -47,6 +48,7 @@ const semver = require("semver"); */ class Core { constructor() { + this.session = new Session(); this.props = {}; this.reset(); this.plugins = new PluginIndex( @@ -54,7 +56,8 @@ class Core { cachePath, mainEvent, log, - settings + settings, + this.session ); } @@ -62,6 +65,7 @@ class Core { * reset run properties */ reset() { + this.session.reset(); this.props = { config: null, os: null, diff --git a/src/core/helpers/session.js b/src/core/helpers/session.js new file mode 100644 index 00000000..76d43088 --- /dev/null +++ b/src/core/helpers/session.js @@ -0,0 +1,48 @@ +"use strict"; + +/* + * Copyright (C) 2022 UBports Foundation + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +class Session { + constructor() { + this.reset(); + } + + reset() { + this.store = new Map(); + } + + push(action, args, error = null) { + if (!this.store.get(action)?.error) this.store.set(action, { args, error }); + } + + get() { + return this.store.entries(); + } + + getActionsDebugInfo() { + return Array.from(this.get()) + .map( + ([action, { args, error }]) => + `${action}: ${error || "OK"}\n` + + (args ? ` ${JSON.stringify(args)}\n` : "") + ) + .join(""); + } +} + +module.exports = Session; diff --git a/src/core/helpers/session.spec.js b/src/core/helpers/session.spec.js new file mode 100644 index 00000000..0157187d --- /dev/null +++ b/src/core/helpers/session.spec.js @@ -0,0 +1,23 @@ +const Session = require("./session.js"); +const session = new Session(); + +describe("Session", () => { + it("should have store", () => { + expect(session.store).toBeInstanceOf(Map); + }); + it("should store", () => { + session.push("fastboot:boot", { partition: "recovery" }); + session.push("adb:shell"); + session.push("adb:shell", null, "some error"); + session.push("adb:shell"); + expect(Object.fromEntries(session.get())).toEqual({ + "adb:shell": { error: "some error", args: null }, + "fastboot:boot": { args: { partition: "recovery" }, error: null } + }); + expect(session.getActionsDebugInfo()).toEqual( + "fastboot:boot: OK\n" + + ' {"partition":"recovery"}\n' + + "adb:shell: some error\n" + ); + }); +}); diff --git a/src/core/plugins/index.js b/src/core/plugins/index.js index f512db06..8df0d2e0 100644 --- a/src/core/plugins/index.js +++ b/src/core/plugins/index.js @@ -42,10 +42,11 @@ const SystemimagePlugin = require("./systemimage/plugin.js"); * @property {SystemimagePlugin} plugins.systemimage systemimage plugin */ class PluginIndex { - constructor(props, cachePath, mainEvent, log, settings) { + constructor(props, cachePath, mainEvent, log, settings, session) { this.props = props; this.log = log; this.settings = settings; + this.session = session; this.event = mainEvent; const pluginArgs = [props, cachePath, this.event, log, settings]; this.plugins = { @@ -78,11 +79,12 @@ class PluginIndex { action(action) { return Promise.resolve(this.parsePluginId(action)).then(([p, f]) => { this.log.verbose(`running ${p} action ${f}`); - return this.plugins[p][`action__${f}`](action[`${p}:${f}`]).catch( - error => { + return this.plugins[p][`action__${f}`](action[`${p}:${f}`]) + .then(r => this.session.push(...Object.entries(action)[0]) || r) + .catch(error => { + this.session.push(...Object.entries(action)[0], error); throw { error, action: `${p}:${f}` }; - } - ); + }); }); } diff --git a/src/core/plugins/index.spec.js b/src/core/plugins/index.spec.js index 922a0b57..e88edf7b 100644 --- a/src/core/plugins/index.spec.js +++ b/src/core/plugins/index.spec.js @@ -9,8 +9,9 @@ const log = { }; const settings = {}; +const session = new (require("../helpers/session.js"))(); -const pluginArgs = [{}, "a", {}, log, settings]; +const pluginArgs = [{}, "a", {}, log, settings, session]; const pluginIndex = new (require("./index.js"))(...pluginArgs); const originalPluginList = pluginIndex.plugins; @@ -36,6 +37,7 @@ describe("PluginIndex", () => { }); describe("action", () => { it("should run action", () => { + pluginIndex.session.reset(); jest .spyOn(pluginIndex.plugins.adb, "action__format") .mockResolvedValue(1337); @@ -46,9 +48,14 @@ describe("PluginIndex", () => { }); expect(pluginIndex.plugins.adb.action__format).toHaveBeenCalledTimes(1); pluginIndex.plugins.adb.action__format.mockRestore(); + expect(Array.from(pluginIndex.session.get())).toContainEqual([ + "adb:format", + { error: null, args: { a: "b" } } + ]); }); }); it("should reject on error", done => { + pluginIndex.session.reset(); jest .spyOn(pluginIndex.plugins.adb, "action__format") .mockRejectedValue("terrible"); diff --git a/src/lib/reporter.js b/src/lib/reporter.js index 3aba3d20..bb61dcbb 100644 --- a/src/lib/reporter.js +++ b/src/lib/reporter.js @@ -190,6 +190,14 @@ class Reporter { } ], logs: [ + ...(core.session.getActionsDebugInfo() + ? [ + { + name: "actions", + content: core.session.getActionsDebugInfo() + } + ] + : []), { name: "ubports-installer.log", content: await logfile diff --git a/src/lib/reporter.spec.js b/src/lib/reporter.spec.js index 7b36801f..f8ab493c 100644 --- a/src/lib/reporter.spec.js +++ b/src/lib/reporter.spec.js @@ -157,6 +157,7 @@ describe("sendOpenCutsRun()", () => { it("should send open-cuts run", () => { log.get.mockResolvedValue("log content"); errors.errors = ["error one", "error two"]; + core.session.getActionsDebugInfo.mockReturnValue("adb:shell: OK"); const smartRun = jest.fn(); OpenCutsReporter.mockImplementation(() => ({ smartRun @@ -179,8 +180,9 @@ describe("sendOpenCutsRun()", () => { ], comment: undefined, logs: [ - { content: "log content", name: "ubports-installer.log" }, - { content: "error one\n\nerror two", name: "ignored errors" } + { name: "actions", content: "adb:shell: OK" }, + { name: "ubports-installer.log", content: "log content" }, + { name: "ignored errors", content: "error one\n\nerror two" } ], result: "FAIL" } @@ -190,6 +192,7 @@ describe("sendOpenCutsRun()", () => { it("should send open-cuts run", () => { log.get.mockResolvedValue("log content"); errors.errors = []; + core.session.getActionsDebugInfo.mockReturnValue(); const smartRun = jest.fn(); OpenCutsReporter.mockImplementation(() => ({ smartRun diff --git a/src/lib/window.js b/src/lib/window.js index 81b310d8..8c63a7ba 100755 --- a/src/lib/window.js +++ b/src/lib/window.js @@ -1,7 +1,7 @@ "use strict"; /* - * Copyright (C) 2017-2021 UBports Foundation + * Copyright (C) 2017-2022 UBports Foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,7 +43,11 @@ class Window { */ send(channel, ...args) { const main = this.getMain(); - if (main) main.send(channel, ...args); + try { + if (main) main.send(channel, ...args); + } catch (error) { + throw new Error(`Failed to send ${channel}: ${error}`); + } } }