diff options
Diffstat (limited to 'toolkit/components/processtools/tests/xpcshell')
4 files changed, 193 insertions, 0 deletions
diff --git a/toolkit/components/processtools/tests/xpcshell/test_process_kill.js b/toolkit/components/processtools/tests/xpcshell/test_process_kill.js new file mode 100644 index 0000000000..9781efaffc --- /dev/null +++ b/toolkit/components/processtools/tests/xpcshell/test_process_kill.js @@ -0,0 +1,52 @@ +/* eslint-disable mozilla/no-arbitrary-setTimeout */ +"use strict"; + +const { setTimeout } = ChromeUtils.importESModule( + "resource://gre/modules/Timer.sys.mjs" +); + +const { Subprocess } = ChromeUtils.importESModule( + "resource://gre/modules/Subprocess.sys.mjs" +); + +const ProcessTools = Cc["@mozilla.org/processtools-service;1"].getService( + Ci.nsIProcessToolsService +); + +let PYTHON; + +// Find Python. +add_task(async function setup() { + PYTHON = await Subprocess.pathSearch(Services.env.get("PYTHON")); +}); + +// Ensure that killing a process... kills the process. +add_task(async function test_subprocess_kill() { + // We launch Python, as it's a long-running process and it exists + // on all desktop platforms on which we run tests. + let proc = await Subprocess.call({ + command: PYTHON, + arguments: [], + }); + + let isTerminated = false; + + proc.wait().then(() => { + isTerminated = true; + }); + + await new Promise(resolve => setTimeout(resolve, 100)); + Assert.ok( + !isTerminated, + "We haven't killed the process yet, it should still be running." + ); + + // Time to kill the process. + ProcessTools.kill(proc.pid); + + await new Promise(resolve => setTimeout(resolve, 100)); + Assert.ok( + isTerminated, + "We have killed the process already, it shouldn't be running anymore." + ); +}); diff --git a/toolkit/components/processtools/tests/xpcshell/test_total_cpu_time.js b/toolkit/components/processtools/tests/xpcshell/test_total_cpu_time.js new file mode 100644 index 0000000000..00f1ea2b6c --- /dev/null +++ b/toolkit/components/processtools/tests/xpcshell/test_total_cpu_time.js @@ -0,0 +1,122 @@ +"use strict"; + +var cpuThreadCount; + +add_task(async function setup() { + // FOG needs a profile directory to put its data in. + do_get_profile(); + + Services.fog.initializeFOG(); + + cpuThreadCount = (await Services.sysinfo.processInfo).count; +}); + +async function getCpuTimeFromProcInfo() { + const NS_PER_MS = 1000000; + let cpuTimeForProcess = p => p.cpuTime / NS_PER_MS; + let procInfo = await ChromeUtils.requestProcInfo(); + return ( + cpuTimeForProcess(procInfo) + + procInfo.children.map(cpuTimeForProcess).reduce((a, b) => a + b, 0) + ); +} + +add_task(async function test_totalCpuTime_in_parent() { + let startTime = Date.now(); + + let initialProcInfoCpuTime = Math.floor(await getCpuTimeFromProcInfo()); + await Services.fog.testFlushAllChildren(); + + let initialCpuTime = Glean.power.totalCpuTimeMs.testGetValue(); + Assert.greater( + initialCpuTime, + 0, + "The CPU time used by starting the test harness should be more than 0" + ); + let initialProcInfoCpuTime2 = Math.ceil(await getCpuTimeFromProcInfo()); + + Assert.greaterOrEqual( + initialCpuTime, + initialProcInfoCpuTime, + "The CPU time reported through Glean should be at least as much as the CPU time reported by ProcInfo before asking Glean for the data" + ); + Assert.lessOrEqual( + initialCpuTime, + initialProcInfoCpuTime2, + "The CPU time reported through Glean should be no more than the CPU time reported by ProcInfo after asking Glean for the data" + ); + + // 50 is an arbitrary value, but the resolution is 16ms on Windows, + // so this needs to be significantly more than 16. + const kBusyWaitForMs = 50; + while (Date.now() - startTime < kBusyWaitForMs) { + // Burn CPU time... + } + + let additionalProcInfoCpuTime = + Math.floor(await getCpuTimeFromProcInfo()) - initialProcInfoCpuTime2; + await Services.fog.testFlushAllChildren(); + + let additionalCpuTime = + Glean.power.totalCpuTimeMs.testGetValue() - initialCpuTime; + info( + `additional CPU time according to ProcInfo: ${additionalProcInfoCpuTime}ms and Glean ${additionalCpuTime}ms` + ); + + // On a machine where the CPU is very busy, our busy wait loop might burn less + // CPU than expected if other processes are being scheduled instead of us. + let expectedAdditionalCpuTime = Math.min( + additionalProcInfoCpuTime, + kBusyWaitForMs + ); + Assert.greaterOrEqual( + additionalCpuTime, + expectedAdditionalCpuTime, + `The total CPU time should have increased by at least ${expectedAdditionalCpuTime}ms` + ); + let wallClockTime = Date.now() - startTime; + Assert.lessOrEqual( + additionalCpuTime, + wallClockTime * cpuThreadCount, + `The total CPU time should have increased by at most the wall clock time (${wallClockTime}ms) * ${cpuThreadCount} CPU threads` + ); +}); + +add_task(async function test_totalCpuTime_in_child() { + const MESSAGE_CHILD_TEST_DONE = "ChildTest:Done"; + + let startTime = Date.now(); + await Services.fog.testFlushAllChildren(); + let initialCpuTime = Glean.power.totalCpuTimeMs.testGetValue(); + + let initialProcInfoCpuTime = await getCpuTimeFromProcInfo(); + run_test_in_child("test_total_cpu_time_child.js"); + let burntCpuTime = await do_await_remote_message(MESSAGE_CHILD_TEST_DONE); + let additionalProcInfoCpuTime = + (await getCpuTimeFromProcInfo()) - initialProcInfoCpuTime; + + await Services.fog.testFlushAllChildren(); + let additionalCpuTime = + Glean.power.totalCpuTimeMs.testGetValue() - initialCpuTime; + info( + `additional CPU time according to ProcInfo: ${additionalProcInfoCpuTime}ms and Glean ${additionalCpuTime}ms` + ); + + // On a machine where the CPU is very busy, our busy wait loop might burn less + // CPU than expected if other processes are being scheduled instead of us. + let expectedAdditionalCpuTime = Math.min( + Math.floor(additionalProcInfoCpuTime), + burntCpuTime + ); + Assert.greaterOrEqual( + additionalCpuTime, + expectedAdditionalCpuTime, + `The total CPU time should have increased by at least ${expectedAdditionalCpuTime}ms` + ); + let wallClockTime = Date.now() - startTime; + Assert.lessOrEqual( + additionalCpuTime, + wallClockTime * cpuThreadCount, + `The total CPU time should have increased by at most the wall clock time (${wallClockTime}ms) * ${cpuThreadCount} CPU threads` + ); +}); diff --git a/toolkit/components/processtools/tests/xpcshell/test_total_cpu_time_child.js b/toolkit/components/processtools/tests/xpcshell/test_total_cpu_time_child.js new file mode 100644 index 0000000000..88ac480a09 --- /dev/null +++ b/toolkit/components/processtools/tests/xpcshell/test_total_cpu_time_child.js @@ -0,0 +1,10 @@ +const MESSAGE_CHILD_TEST_DONE = "ChildTest:Done"; + +function run_test() { + const kBusyWaitForMs = 50; + let startTime = Date.now(); + while (Date.now() - startTime < kBusyWaitForMs) { + // Burn CPU time... + } + do_send_remote_message(MESSAGE_CHILD_TEST_DONE, kBusyWaitForMs); +} diff --git a/toolkit/components/processtools/tests/xpcshell/xpcshell.ini b/toolkit/components/processtools/tests/xpcshell/xpcshell.ini new file mode 100644 index 0000000000..bd9bdaac93 --- /dev/null +++ b/toolkit/components/processtools/tests/xpcshell/xpcshell.ini @@ -0,0 +1,9 @@ +[DEFAULT] +firefox-appdir = browser +subprocess = true + +[test_process_kill.js] +skip-if = os == 'android' +[test_total_cpu_time.js] +skip-if = socketprocess_networking +support-files = test_total_cpu_time_child.js |