diff options
Diffstat (limited to 'devtools/client/memory/test/xpcshell/head.js')
-rw-r--r-- | devtools/client/memory/test/xpcshell/head.js | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/devtools/client/memory/test/xpcshell/head.js b/devtools/client/memory/test/xpcshell/head.js new file mode 100644 index 0000000000..94788a60fb --- /dev/null +++ b/devtools/client/memory/test/xpcshell/head.js @@ -0,0 +1,189 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// via xpcshell.ini +/* import-globals-from ../../../shared/test/shared-head.js */ + +Services.prefs.setBoolPref("devtools.testing", true); +Services.prefs.setBoolPref("devtools.debugger.log", true); +registerCleanupFunction(() => { + Services.prefs.clearUserPref("devtools.testing"); + Services.prefs.clearUserPref("devtools.debugger.log"); +}); + +var { FileUtils } = ChromeUtils.importESModule( + "resource://gre/modules/FileUtils.sys.mjs" +); +var { expectState } = require("resource://devtools/server/actors/common.js"); +var HeapSnapshotFileUtils = require("resource://devtools/shared/heapsnapshot/HeapSnapshotFileUtils.js"); +var HeapAnalysesClient = require("resource://devtools/shared/heapsnapshot/HeapAnalysesClient.js"); +var { addDebuggerToGlobal } = ChromeUtils.importESModule( + "resource://gre/modules/jsdebugger.sys.mjs" +); +var Store = require("resource://devtools/client/memory/store.js"); +var { L10N } = require("resource://devtools/client/memory/utils.js"); +var SYSTEM_PRINCIPAL = Cc["@mozilla.org/systemprincipal;1"].createInstance( + Ci.nsIPrincipal +); + +var EXPECTED_DTU_ASSERT_FAILURE_COUNT = 0; + +registerCleanupFunction(function () { + equal( + DevToolsUtils.assertionFailureCount, + EXPECTED_DTU_ASSERT_FAILURE_COUNT, + "Should have had the expected number of DevToolsUtils.assert() failures." + ); +}); + +function dumpn(msg) { + dump(`MEMORY-TEST: ${msg}\n`); +} + +function initDebugger() { + const global = new Cu.Sandbox(SYSTEM_PRINCIPAL, { freshZone: true }); + addDebuggerToGlobal(global); + return new global.Debugger(); +} + +function StubbedMemoryFront() { + this.state = "detached"; + this.dbg = initDebugger(); +} + +StubbedMemoryFront.prototype.attach = async function () { + this.state = "attached"; +}; + +StubbedMemoryFront.prototype.detach = async function () { + this.state = "detached"; +}; + +StubbedMemoryFront.prototype.saveHeapSnapshot = expectState( + "attached", + async function () { + return ChromeUtils.saveHeapSnapshot({ runtime: true }); + }, + "saveHeapSnapshot" +); + +StubbedMemoryFront.prototype.startRecordingAllocations = expectState( + "attached", + async function () {} +); + +StubbedMemoryFront.prototype.stopRecordingAllocations = expectState( + "attached", + async function () {} +); + +function waitUntilSnapshotState(store, expected) { + const predicate = () => { + const snapshots = store.getState().snapshots; + info(snapshots.map(x => x.state)); + return ( + snapshots.length === expected.length && + expected.every( + (state, i) => state === "*" || snapshots[i].state === state + ) + ); + }; + info(`Waiting for snapshots to be of state: ${expected}`); + return waitUntilState(store, predicate); +} + +function findReportLeafIndex(node, name = null) { + if (node.reportLeafIndex && (!name || node.name === name)) { + return node.reportLeafIndex; + } + + if (node.children) { + for (const child of node.children) { + const found = findReportLeafIndex(child); + if (found) { + return found; + } + } + } + + return null; +} + +function waitUntilCensusState(store, getCensus, expected) { + const predicate = () => { + const snapshots = store.getState().snapshots; + + info( + "Current census state:" + + snapshots.map(x => (getCensus(x) ? getCensus(x).state : null)) + ); + + return ( + snapshots.length === expected.length && + expected.every((state, i) => { + const census = getCensus(snapshots[i]); + return ( + state === "*" || + (!census && !state) || + (census && census.state === state) + ); + }) + ); + }; + info(`Waiting for snapshots' censuses to be of state: ${expected}`); + return waitUntilState(store, predicate); +} + +async function createTempFile() { + const file = new FileUtils.File( + PathUtils.join(PathUtils.tempDir, "tmp.fxsnapshot") + ); + file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); + const destPath = file.path; + const stat = await IOUtils.stat(destPath); + Assert.strictEqual(stat.size, 0, "new file is 0 bytes at start"); + return destPath; +} + +// This is a copy of the same method from shared-head.js as +// xpcshell test aren't using shared-head.js +/** + * Wait for a specific action type to be dispatched. + * + * If the action is async and defines a `status` property, this helper will wait + * for the status to reach either "error" or "done". + * + * @param {Object} store + * Redux store where the action should be dispatched. + * @param {String} actionType + * The actionType to wait for. + * @param {Number} repeat + * Optional, number of time the action is expected to be dispatched. + * Defaults to 1 + * @return {Promise} + */ +function waitForDispatch(store, actionType, repeat = 1) { + let count = 0; + return new Promise(resolve => { + store.dispatch({ + type: "@@service/waitUntil", + predicate: action => { + const isDone = + !action.status || + action.status === "done" || + action.status === "error"; + + if (action.type === actionType && isDone && ++count == repeat) { + return true; + } + + return false; + }, + run: (dispatch, getState, action) => { + resolve(action); + }, + }); + }); +} |