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