Source code
Revision control
Copy as Markdown
Other Tools
/* Any copyright is dedicated to the Public Domain.
"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);
},
});
});
}