browser_messagemanager_loadprocessscript.js (5966B)
1 function getBaseNumberOfProcesses() { 2 // We should have three processes for this test, the parent process and two 3 // content processes for the tabs craeted by this test. 4 let processCount = 3; 5 6 // If we run WebExtensions out-of-process (see bug 1190679), there might be 7 // additional processes for those, so let's add these to the base count to 8 // not have system WebExtensions cause test failures. 9 for (let i = 0; i < Services.ppmm.childCount; i++) { 10 if ( 11 Services.ppmm.getChildAt(i).remoteType === E10SUtils.EXTENSION_REMOTE_TYPE 12 ) { 13 processCount += 1; 14 } 15 } 16 17 return processCount; 18 } 19 20 function checkBaseProcessCount(description) { 21 const baseProcessCount = getBaseNumberOfProcesses(); 22 const { childCount } = Services.ppmm; 23 // With preloaded activity-stream, process count is a bit undeterministic, so 24 // allow for some variation 25 const extraCount = baseProcessCount + 1; 26 ok( 27 childCount === baseProcessCount || childCount === extraCount, 28 `${description} (${baseProcessCount} or ${extraCount})` 29 ); 30 } 31 32 function processScript() { 33 /* eslint-env mozilla/process-script */ 34 if (Services.cpmm !== this) { 35 dump("Test failed: wrong global object\n"); 36 return; 37 } 38 39 this.cpmm = Services.cpmm; 40 41 addMessageListener("ProcessTest:Reply", function listener(msg) { 42 removeMessageListener("ProcessTest:Reply", listener); 43 sendAsyncMessage("ProcessTest:Finished"); 44 }); 45 sendSyncMessage("ProcessTest:Loaded"); 46 } 47 var processScriptURL = "data:,(" + processScript.toString() + ").call(this)"; 48 49 function initTestScript() { 50 /* eslint-env mozilla/process-script */ 51 let init = initialProcessData; 52 if (init.test123 != "hello") { 53 dump("Initial data incorrect\n"); 54 return; 55 } 56 57 sendAsyncMessage("ProcessTest:InitGood", init.test456.get("hi")); 58 } 59 var initTestScriptURL = "data:,(" + initTestScript.toString() + ")()"; 60 61 var checkProcess = async function (mm) { 62 let { target } = await promiseMessage(mm, "ProcessTest:Loaded"); 63 target.sendAsyncMessage("ProcessTest:Reply"); 64 await promiseMessage(target, "ProcessTest:Finished"); 65 ok(true, "Saw process finished"); 66 }; 67 68 function promiseMessage(messageManager, message) { 69 return new Promise(resolve => { 70 let listener = msg => { 71 messageManager.removeMessageListener(message, listener); 72 resolve(msg); 73 }; 74 75 messageManager.addMessageListener(message, listener); 76 }); 77 } 78 79 add_task(async function () { 80 // We want to count processes in this test, so let's disable the pre-allocated process manager. 81 await SpecialPowers.pushPrefEnv({ 82 set: [["dom.ipc.processPrelaunch.enabled", false]], 83 }); 84 }); 85 86 add_task(async function () { 87 // This test is only relevant in e10s. 88 if (!gMultiProcessBrowser) { 89 return; 90 } 91 92 Services.ppmm.releaseCachedProcesses(); 93 94 await SpecialPowers.pushPrefEnv({ set: [["dom.ipc.processCount", 5]] }); 95 await SpecialPowers.pushPrefEnv({ 96 set: [["dom.ipc.keepProcessesAlive.web", 5]], 97 }); 98 99 let tabs = []; 100 for (let i = 0; i < 3; i++) { 101 tabs[i] = await BrowserTestUtils.openNewForegroundTab( 102 gBrowser, 103 "about:blank" 104 ); 105 } 106 107 for (let i = 0; i < 3; i++) { 108 // FIXME: This should wait for the tab removal gets reflected to the 109 // process count (bug 1446726). 110 let sessionStorePromise = BrowserTestUtils.waitForSessionStoreUpdate( 111 tabs[i] 112 ); 113 BrowserTestUtils.removeTab(tabs[i]); 114 await sessionStorePromise; 115 } 116 117 Services.ppmm.releaseCachedProcesses(); 118 checkBaseProcessCount( 119 "Should get back to the base number of processes at this point" 120 ); 121 }); 122 123 // Test that loading a process script loads in all existing processes 124 add_task(async function () { 125 let checks = []; 126 for (let i = 0; i < Services.ppmm.childCount; i++) { 127 checks.push(checkProcess(Services.ppmm.getChildAt(i))); 128 } 129 130 Services.ppmm.loadProcessScript(processScriptURL, false); 131 await Promise.all(checks); 132 }); 133 134 // Test that loading a process script loads in new processes 135 add_task(async function () { 136 // This test is only relevant in e10s 137 if (!gMultiProcessBrowser) { 138 return; 139 } 140 141 checkBaseProcessCount( 142 "Should still be at the base number of processes at this point" 143 ); 144 145 // Load something in the main process 146 BrowserTestUtils.startLoadingURIString( 147 gBrowser.selectedBrowser, 148 "about:mozilla" 149 ); 150 await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); 151 152 let init = Services.ppmm.initialProcessData; 153 init.test123 = "hello"; 154 init.test456 = new Map(); 155 init.test456.set("hi", "bye"); 156 157 // With no remote frames left we should be down to one process. 158 // However, stuff like remote thumbnails can cause a content 159 // process to exist nonetheless. This should be rare, though, 160 // so the test is useful most of the time. 161 if (Services.ppmm.childCount == 2) { 162 let mainMM = Services.ppmm.getChildAt(0); 163 164 let check = checkProcess(Services.ppmm); 165 Services.ppmm.loadProcessScript(processScriptURL, true); 166 167 // The main process should respond 168 await check; 169 170 check = checkProcess(Services.ppmm); 171 // Reset the default browser to start a new child process 172 gBrowser.updateBrowserRemoteness(gBrowser.selectedBrowser, { 173 remoteType: E10SUtils.DEFAULT_REMOTE_TYPE, 174 }); 175 BrowserTestUtils.startLoadingURIString( 176 gBrowser.selectedBrowser, 177 "about:blank" 178 ); 179 await BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser); 180 181 checkBaseProcessCount( 182 "Should be back to the base number of processes at this point" 183 ); 184 185 // The new process should have responded 186 await check; 187 188 Services.ppmm.removeDelayedProcessScript(processScriptURL); 189 190 let childMM; 191 childMM = Services.ppmm.getChildAt(2); 192 193 childMM.loadProcessScript(initTestScriptURL, false); 194 let msg = await promiseMessage(childMM, "ProcessTest:InitGood"); 195 is(msg.data, "bye", "initial process data was correct"); 196 } else { 197 info("Unable to finish test entirely"); 198 } 199 });