/* 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); }, }); }); }