head.js (5333B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 // via xpcshell.toml 7 /* import-globals-from ../../../shared/test/shared-head.js */ 8 9 Services.prefs.setBoolPref("devtools.testing", true); 10 Services.prefs.setBoolPref("devtools.debugger.log", true); 11 registerCleanupFunction(() => { 12 Services.prefs.clearUserPref("devtools.testing"); 13 Services.prefs.clearUserPref("devtools.debugger.log"); 14 }); 15 16 var { FileUtils } = ChromeUtils.importESModule( 17 "resource://gre/modules/FileUtils.sys.mjs" 18 ); 19 var { expectState } = require("resource://devtools/server/actors/common.js"); 20 var HeapSnapshotFileUtils = require("resource://devtools/shared/heapsnapshot/HeapSnapshotFileUtils.js"); 21 var HeapAnalysesClient = require("resource://devtools/shared/heapsnapshot/HeapAnalysesClient.js"); 22 var { addDebuggerToGlobal } = ChromeUtils.importESModule( 23 "resource://gre/modules/jsdebugger.sys.mjs" 24 ); 25 var Store = require("resource://devtools/client/memory/store.js"); 26 var { L10N } = require("resource://devtools/client/memory/utils.js"); 27 var SYSTEM_PRINCIPAL = Cc["@mozilla.org/systemprincipal;1"].createInstance( 28 Ci.nsIPrincipal 29 ); 30 31 var EXPECTED_DTU_ASSERT_FAILURE_COUNT = 0; 32 33 registerCleanupFunction(function () { 34 equal( 35 DevToolsUtils.assertionFailureCount, 36 EXPECTED_DTU_ASSERT_FAILURE_COUNT, 37 "Should have had the expected number of DevToolsUtils.assert() failures." 38 ); 39 }); 40 41 function dumpn(msg) { 42 dump(`MEMORY-TEST: ${msg}\n`); 43 } 44 45 function initDebugger() { 46 const global = new Cu.Sandbox(SYSTEM_PRINCIPAL, { freshZone: true }); 47 addDebuggerToGlobal(global); 48 return new global.Debugger(); 49 } 50 51 function StubbedMemoryFront() { 52 this.state = "detached"; 53 this.dbg = initDebugger(); 54 } 55 56 StubbedMemoryFront.prototype.attach = async function () { 57 this.state = "attached"; 58 }; 59 60 StubbedMemoryFront.prototype.detach = async function () { 61 this.state = "detached"; 62 }; 63 64 StubbedMemoryFront.prototype.saveHeapSnapshot = expectState( 65 "attached", 66 async function () { 67 return ChromeUtils.saveHeapSnapshot({ runtime: true }); 68 }, 69 "saveHeapSnapshot" 70 ); 71 72 StubbedMemoryFront.prototype.startRecordingAllocations = expectState( 73 "attached", 74 async function () {} 75 ); 76 77 StubbedMemoryFront.prototype.stopRecordingAllocations = expectState( 78 "attached", 79 async function () {} 80 ); 81 82 function waitUntilSnapshotState(store, expected) { 83 const predicate = () => { 84 const snapshots = store.getState().snapshots; 85 info(snapshots.map(x => x.state)); 86 return ( 87 snapshots.length === expected.length && 88 expected.every( 89 (state, i) => state === "*" || snapshots[i].state === state 90 ) 91 ); 92 }; 93 info(`Waiting for snapshots to be of state: ${expected}`); 94 return waitUntilState(store, predicate); 95 } 96 97 function findReportLeafIndex(node, name = null) { 98 if (node.reportLeafIndex && (!name || node.name === name)) { 99 return node.reportLeafIndex; 100 } 101 102 if (node.children) { 103 for (const child of node.children) { 104 const found = findReportLeafIndex(child); 105 if (found) { 106 return found; 107 } 108 } 109 } 110 111 return null; 112 } 113 114 function waitUntilCensusState(store, getCensus, expected) { 115 const predicate = () => { 116 const snapshots = store.getState().snapshots; 117 118 info( 119 "Current census state:" + 120 snapshots.map(x => (getCensus(x) ? getCensus(x).state : null)) 121 ); 122 123 return ( 124 snapshots.length === expected.length && 125 expected.every((state, i) => { 126 const census = getCensus(snapshots[i]); 127 return ( 128 state === "*" || 129 (!census && !state) || 130 (census && census.state === state) 131 ); 132 }) 133 ); 134 }; 135 info(`Waiting for snapshots' censuses to be of state: ${expected}`); 136 return waitUntilState(store, predicate); 137 } 138 139 async function createTempFile() { 140 const file = new FileUtils.File( 141 PathUtils.join(PathUtils.tempDir, "tmp.fxsnapshot") 142 ); 143 file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, FileUtils.PERMS_FILE); 144 const destPath = file.path; 145 const stat = await IOUtils.stat(destPath); 146 Assert.strictEqual(stat.size, 0, "new file is 0 bytes at start"); 147 return destPath; 148 } 149 150 // This is a copy of the same method from shared-head.js as 151 // xpcshell test aren't using shared-head.js 152 /** 153 * Wait for a specific action type to be dispatched. 154 * 155 * If the action is async and defines a `status` property, this helper will wait 156 * for the status to reach either "error" or "done". 157 * 158 * @param {object} store 159 * Redux store where the action should be dispatched. 160 * @param {string} actionType 161 * The actionType to wait for. 162 * @param {number} repeat 163 * Optional, number of time the action is expected to be dispatched. 164 * Defaults to 1 165 * @return {Promise} 166 */ 167 function waitForDispatch(store, actionType, repeat = 1) { 168 let count = 0; 169 return new Promise(resolve => { 170 store.dispatch({ 171 type: "@@service/waitUntil", 172 predicate: action => { 173 const isDone = 174 !action.status || 175 action.status === "done" || 176 action.status === "error"; 177 178 if (action.type === actionType && isDone && ++count == repeat) { 179 return true; 180 } 181 182 return false; 183 }, 184 run: (dispatch, getState, action) => { 185 resolve(action); 186 }, 187 }); 188 }); 189 }