diff options
Diffstat (limited to 'toolkit/components/asyncshutdown')
7 files changed, 2 insertions, 579 deletions
diff --git a/toolkit/components/asyncshutdown/moz.build b/toolkit/components/asyncshutdown/moz.build index 79a4c44c7..0051c97a0 100644 --- a/toolkit/components/asyncshutdown/moz.build +++ b/toolkit/components/asyncshutdown/moz.build @@ -4,22 +4,12 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini'] - XPIDL_MODULE = 'toolkit_asyncshutdown' +XPIDL_SOURCES += ['nsIAsyncShutdown.idl'] -XPIDL_SOURCES += [ - 'nsIAsyncShutdown.idl', -] - -EXTRA_JS_MODULES += [ - 'AsyncShutdown.jsm', -] +EXTRA_JS_MODULES += ['AsyncShutdown.jsm'] EXTRA_COMPONENTS += [ 'nsAsyncShutdown.js', 'nsAsyncShutdown.manifest', ] - -with Files('**'): - BUG_COMPONENT = ('Toolkit', 'Async Tooling') diff --git a/toolkit/components/asyncshutdown/tests/xpcshell/.eslintrc.js b/toolkit/components/asyncshutdown/tests/xpcshell/.eslintrc.js deleted file mode 100644 index d35787cd2..000000000 --- a/toolkit/components/asyncshutdown/tests/xpcshell/.eslintrc.js +++ /dev/null @@ -1,7 +0,0 @@ -"use strict"; - -module.exports = { - "extends": [ - "../../../../../testing/xpcshell/xpcshell.eslintrc.js" - ] -}; diff --git a/toolkit/components/asyncshutdown/tests/xpcshell/head.js b/toolkit/components/asyncshutdown/tests/xpcshell/head.js deleted file mode 100644 index 9de489808..000000000 --- a/toolkit/components/asyncshutdown/tests/xpcshell/head.js +++ /dev/null @@ -1,174 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ -"use strict"; - -var Cu = Components.utils; -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cr = Components.results; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource://gre/modules/Task.jsm"); -Cu.import("resource://gre/modules/AsyncShutdown.jsm"); - -var asyncShutdownService = Cc["@mozilla.org/async-shutdown-service;1"]. - getService(Ci.nsIAsyncShutdownService); - - -Services.prefs.setBoolPref("toolkit.asyncshutdown.testing", true); - -/** - * Utility function used to provide the same API for various sources - * of async shutdown barriers. - * - * @param {string} kind One of - * - "phase" to test an AsyncShutdown phase; - * - "barrier" to test an instance of AsyncShutdown.Barrier; - * - "xpcom-barrier" to test an instance of nsIAsyncShutdownBarrier; - * - "xpcom-barrier-unwrapped" to test the field `jsclient` of a nsIAsyncShutdownClient. - * - * @return An object with the following methods: - * - addBlocker() - the same method as AsyncShutdown phases and barrier clients - * - wait() - trigger the resolution of the lock - */ -function makeLock(kind) { - if (kind == "phase") { - let topic = "test-Phase-" + ++makeLock.counter; - let phase = AsyncShutdown._getPhase(topic); - return { - addBlocker: function(...args) { - return phase.addBlocker(...args); - }, - removeBlocker: function(blocker) { - return phase.removeBlocker(blocker); - }, - wait: function() { - Services.obs.notifyObservers(null, topic, null); - return Promise.resolve(); - } - }; - } else if (kind == "barrier") { - let name = "test-Barrier-" + ++makeLock.counter; - let barrier = new AsyncShutdown.Barrier(name); - return { - addBlocker: barrier.client.addBlocker, - removeBlocker: barrier.client.removeBlocker, - wait: function() { - return barrier.wait(); - } - }; - } else if (kind == "xpcom-barrier") { - let name = "test-xpcom-Barrier-" + ++makeLock.counter; - let barrier = asyncShutdownService.makeBarrier(name); - return { - addBlocker: function(blockerName, condition, state) { - if (condition == null) { - // Slight trick as `null` or `undefined` cannot be used as keys - // for `xpcomMap`. Note that this has no incidence on the result - // of the test as the XPCOM interface imposes that the condition - // is a method, so it cannot be `null`/`undefined`. - condition = "<this case can't happen with the xpcom interface>"; - } - let blocker = makeLock.xpcomMap.get(condition); - if (!blocker) { - blocker = { - name: blockerName, - state: state, - blockShutdown: function(aBarrierClient) { - return Task.spawn(function*() { - try { - if (typeof condition == "function") { - yield Promise.resolve(condition()); - } else { - yield Promise.resolve(condition); - } - } finally { - aBarrierClient.removeBlocker(blocker); - } - }); - }, - }; - makeLock.xpcomMap.set(condition, blocker); - } - let {fileName, lineNumber, stack} = (new Error()); - return barrier.client.addBlocker(blocker, fileName, lineNumber, stack); - }, - removeBlocker: function(condition) { - let blocker = makeLock.xpcomMap.get(condition); - if (!blocker) { - return; - } - barrier.client.removeBlocker(blocker); - }, - wait: function() { - return new Promise(resolve => { - barrier.wait(resolve); - }); - } - }; - } else if ("unwrapped-xpcom-barrier") { - let name = "unwrapped-xpcom-barrier-" + ++makeLock.counter; - let barrier = asyncShutdownService.makeBarrier(name); - let client = barrier.client.jsclient; - return { - addBlocker: client.addBlocker, - removeBlocker: client.removeBlocker, - wait: function() { - return new Promise(resolve => { - barrier.wait(resolve); - }); - } - }; - } - throw new TypeError("Unknown kind " + kind); -} -makeLock.counter = 0; -makeLock.xpcomMap = new Map(); // Note: Not a WeakMap as we wish to handle non-gc-able keys (e.g. strings) - -/** - * An asynchronous task that takes several ticks to complete. - * - * @param {*=} resolution The value with which the resulting promise will be - * resolved once the task is complete. This may be a rejected promise, - * in which case the resulting promise will itself be rejected. - * @param {object=} outResult An object modified by side-effect during the task. - * Initially, its field |isFinished| is set to |false|. Once the task is - * complete, its field |isFinished| is set to |true|. - * - * @return {promise} A promise fulfilled once the task is complete - */ -function longRunningAsyncTask(resolution = undefined, outResult = {}) { - outResult.isFinished = false; - if (!("countFinished" in outResult)) { - outResult.countFinished = 0; - } - let deferred = Promise.defer(); - do_timeout(100, function() { - ++outResult.countFinished; - outResult.isFinished = true; - deferred.resolve(resolution); - }); - return deferred.promise; -} - -function get_exn(f) { - try { - f(); - return null; - } catch (ex) { - return ex; - } -} - -function do_check_exn(exn, constructor) { - do_check_neq(exn, null); - if (exn.name == constructor) { - do_check_eq(exn.constructor.name, constructor); - return; - } - do_print("Wrong error constructor"); - do_print(exn.constructor.name); - do_print(exn.stack); - do_check_true(false); -} diff --git a/toolkit/components/asyncshutdown/tests/xpcshell/test_AsyncShutdown.js b/toolkit/components/asyncshutdown/tests/xpcshell/test_AsyncShutdown.js deleted file mode 100644 index f1aebc3ad..000000000 --- a/toolkit/components/asyncshutdown/tests/xpcshell/test_AsyncShutdown.js +++ /dev/null @@ -1,194 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ -"use strict"; - -Cu.import("resource://gre/modules/PromiseUtils.jsm", this); - -function run_test() { - run_next_test(); -} - -add_task(function* test_no_condition() { - for (let kind of ["phase", "barrier", "xpcom-barrier", "xpcom-barrier-unwrapped"]) { - do_print("Testing a barrier with no condition (" + kind + ")"); - let lock = makeLock(kind); - yield lock.wait(); - do_print("Barrier with no condition didn't lock"); - } -}); - -add_task(function* test_phase_various_failures() { - for (let kind of ["phase", "barrier", "xpcom-barrier", "xpcom-barrier-unwrapped"]) { - do_print("Kind: " + kind); - // Testing with wrong arguments - let lock = makeLock(kind); - - Assert.throws(() => lock.addBlocker(), /TypeError|NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS/); - Assert.throws(() => lock.addBlocker(null, true), /TypeError|NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS/); - - if (kind != "xpcom-barrier") { - // xpcom-barrier actually expects a string in that position - Assert.throws(() => lock.addBlocker("Test 2", () => true, "not a function"), /TypeError/); - } - - // Attempting to add a blocker after we are done waiting - yield lock.wait(); - Assert.throws(() => lock.addBlocker("Test 3", () => true), /is finished/); - } -}); - -add_task(function* test_reentrant() { - do_print("Ensure that we can call addBlocker from within a blocker"); - - for (let kind of ["phase", "barrier", "xpcom-barrier", "xpcom-barrier-unwrapped"]) { - do_print("Kind: " + kind); - let lock = makeLock(kind); - - let deferredOuter = PromiseUtils.defer(); - let deferredInner = PromiseUtils.defer(); - let deferredBlockInner = PromiseUtils.defer(); - - lock.addBlocker("Outer blocker", () => { - do_print("Entering outer blocker"); - deferredOuter.resolve(); - lock.addBlocker("Inner blocker", () => { - do_print("Entering inner blocker"); - deferredInner.resolve(); - return deferredBlockInner.promise; - }); - }); - - // Note that phase-style locks spin the event loop and do not return from - // `lock.wait()` until after all blockers have been resolved. Therefore, - // to be able to test them, we need to dispatch the following steps to the - // event loop before calling `lock.wait()`, which we do by forcing - // a Promise.resolve(). - // - let promiseSteps = Task.spawn(function* () { - yield Promise.resolve(); - - do_print("Waiting until we have entered the outer blocker"); - yield deferredOuter.promise; - - do_print("Waiting until we have entered the inner blocker"); - yield deferredInner.promise; - - do_print("Allowing the lock to resolve") - deferredBlockInner.resolve(); - }); - - do_print("Starting wait"); - yield lock.wait(); - - do_print("Waiting until all steps have been walked"); - yield promiseSteps; - } -}); - - -add_task(function* test_phase_removeBlocker() { - do_print("Testing that we can call removeBlocker before, during and after the call to wait()"); - - for (let kind of ["phase", "barrier", "xpcom-barrier", "xpcom-barrier-unwrapped"]) { - - do_print("Switching to kind " + kind); - do_print("Attempt to add then remove a blocker before wait()"); - let lock = makeLock(kind); - let blocker = () => { - do_print("This promise will never be resolved"); - return Promise.defer().promise; - }; - - lock.addBlocker("Wait forever", blocker); - let do_remove_blocker = function(aLock, aBlocker, aShouldRemove) { - do_print("Attempting to remove blocker " + aBlocker + ", expecting result " + aShouldRemove); - if (kind == "xpcom-barrier") { - // The xpcom variant always returns `undefined`, so we can't - // check its result. - aLock.removeBlocker(aBlocker); - return; - } - do_check_eq(aLock.removeBlocker(aBlocker), aShouldRemove); - }; - do_remove_blocker(lock, blocker, true); - do_remove_blocker(lock, blocker, false); - do_print("Attempt to remove non-registered blockers before wait()"); - do_remove_blocker(lock, "foo", false); - do_remove_blocker(lock, null, false); - do_print("Waiting (should lift immediately)"); - yield lock.wait(); - - do_print("Attempt to add a blocker then remove it during wait()"); - lock = makeLock(kind); - let blockers = [ - () => { - do_print("This blocker will self-destruct"); - do_remove_blocker(lock, blockers[0], true); - return Promise.defer().promise; - }, - () => { - do_print("This blocker will self-destruct twice"); - do_remove_blocker(lock, blockers[1], true); - do_remove_blocker(lock, blockers[1], false); - return Promise.defer().promise; - }, - () => { - do_print("Attempt to remove non-registered blockers during wait()"); - do_remove_blocker(lock, "foo", false); - do_remove_blocker(lock, null, false); - } - ]; - for (let i in blockers) { - lock.addBlocker("Wait forever again: " + i, blockers[i]); - } - do_print("Waiting (should lift very quickly)"); - yield lock.wait(); - do_remove_blocker(lock, blockers[0], false); - - - do_print("Attempt to remove a blocker after wait"); - lock = makeLock(kind); - blocker = Promise.resolve.bind(Promise); - yield lock.wait(); - do_remove_blocker(lock, blocker, false); - - do_print("Attempt to remove non-registered blocker after wait()"); - do_remove_blocker(lock, "foo", false); - do_remove_blocker(lock, null, false); - } - -}); - -add_task(function* test_state() { - do_print("Testing information contained in `state`"); - - let BLOCKER_NAME = "test_state blocker " + Math.random(); - - // Set up the barrier. Note that we cannot test `barrier.state` - // immediately, as it initially contains "Not started" - let barrier = new AsyncShutdown.Barrier("test_filename"); - let deferred = Promise.defer(); - let {filename, lineNumber} = Components.stack; - barrier.client.addBlocker(BLOCKER_NAME, - function() { - return deferred.promise; - }); - - let promiseDone = barrier.wait(); - - // Now that we have called `wait()`, the state contains interesting things - let state = barrier.state[0]; - do_print("State: " + JSON.stringify(barrier.state, null, "\t")); - Assert.equal(state.filename, filename); - Assert.equal(state.lineNumber, lineNumber + 1); - Assert.equal(state.name, BLOCKER_NAME); - Assert.ok(state.stack.some(x => x.includes("test_state")), "The stack contains the caller function's name"); - Assert.ok(state.stack.some(x => x.includes(filename)), "The stack contains the calling file's name"); - - deferred.resolve(); - yield promiseDone; -}); - -add_task(function*() { - Services.prefs.clearUserPref("toolkit.asyncshutdown.testing"); -}); diff --git a/toolkit/components/asyncshutdown/tests/xpcshell/test_AsyncShutdown_leave_uncaught.js b/toolkit/components/asyncshutdown/tests/xpcshell/test_AsyncShutdown_leave_uncaught.js deleted file mode 100644 index 33da1f53f..000000000 --- a/toolkit/components/asyncshutdown/tests/xpcshell/test_AsyncShutdown_leave_uncaught.js +++ /dev/null @@ -1,96 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ -"use strict"; - -// -// This file contains tests that need to leave uncaught asynchronous -// errors. If your test catches all its asynchronous errors, please -// put it in another file. -// - -Promise.Debugging.clearUncaughtErrorObservers(); - -function run_test() { - run_next_test(); -} - -add_task(function* test_phase_simple_async() { - do_print("Testing various combinations of a phase with a single condition"); - for (let kind of ["phase", "barrier", "xpcom-barrier", "xpcom-barrier-unwrapped"]) { - for (let arg of [undefined, null, "foo", 100, new Error("BOOM")]) { - for (let resolution of [arg, Promise.reject(arg)]) { - for (let success of [false, true]) { - for (let state of [[null], - [], - [() => "some state"], - [function() { - throw new Error("State BOOM"); }], - [function() { - return { - toJSON: function() { - throw new Error("State.toJSON BOOM"); - } - }; - }]]) { - // Asynchronous phase - do_print("Asynchronous test with " + arg + ", " + resolution + ", " + kind); - let lock = makeLock(kind); - let outParam = { isFinished: false }; - lock.addBlocker( - "Async test", - function() { - if (success) { - return longRunningAsyncTask(resolution, outParam); - } - throw resolution; - }, - ...state - ); - do_check_false(outParam.isFinished); - yield lock.wait(); - do_check_eq(outParam.isFinished, success); - } - } - - // Synchronous phase - just test that we don't throw/freeze - do_print("Synchronous test with " + arg + ", " + resolution + ", " + kind); - let lock = makeLock(kind); - lock.addBlocker( - "Sync test", - resolution - ); - yield lock.wait(); - } - } - } -}); - -add_task(function* test_phase_many() { - do_print("Testing various combinations of a phase with many conditions"); - for (let kind of ["phase", "barrier", "xpcom-barrier", "xpcom-barrier-unwrapped"]) { - let lock = makeLock(kind); - let outParams = []; - for (let arg of [undefined, null, "foo", 100, new Error("BOOM")]) { - for (let resolve of [true, false]) { - do_print("Testing with " + kind + ", " + arg + ", " + resolve); - let resolution = resolve ? arg : Promise.reject(arg); - let outParam = { isFinished: false }; - lock.addBlocker( - "Test " + Math.random(), - () => longRunningAsyncTask(resolution, outParam) - ); - } - } - do_check_true(outParams.every((x) => !x.isFinished)); - yield lock.wait(); - do_check_true(outParams.every((x) => x.isFinished)); - } -}); - - - - -add_task(function*() { - Services.prefs.clearUserPref("toolkit.asyncshutdown.testing"); -}); - diff --git a/toolkit/components/asyncshutdown/tests/xpcshell/test_converters.js b/toolkit/components/asyncshutdown/tests/xpcshell/test_converters.js deleted file mode 100644 index c6c923187..000000000 --- a/toolkit/components/asyncshutdown/tests/xpcshell/test_converters.js +++ /dev/null @@ -1,88 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ -"use strict"; - -/** - * Test conversion between nsIPropertyBag and JS values. - */ - -var PropertyBagConverter = asyncShutdownService.wrappedJSObject._propertyBagConverter; - -function run_test() { - test_conversions(); -} - -function normalize(obj) { - if (obj == null || typeof obj != "object") { - return obj; - } - if (Array.isArray(obj)) { - return obj.map(normalize); - } - let result = {}; - for (let k of Object.keys(obj).sort()) { - result[k] = normalize(obj[k]); - } - return result; -} - -function test_conversions() { - const SAMPLES = [ - // Simple values - 1, - true, - "string", - null, - - // Objects - { - a: 1, - b: true, - c: "string", - d:.5, - e: [2, false, "another string", .3], - f: [], - g: { - a2: 1, - b2: true, - c2: "string", - d2:.5, - e2: [2, false, "another string", .3], - f2: [], - g2: [{ - a3: 1, - b3: true, - c3: "string", - d3:.5, - e3: [2, false, "another string", .3], - f3: [], - g3: {} - }] - } - }]; - - for (let sample of SAMPLES) { - let stringified = JSON.stringify(normalize(sample), null, "\t"); - do_print("Testing conversions of " + stringified); - let rewrites = [sample]; - for (let i = 1; i < 3; ++i) { - let source = rewrites[i - 1]; - let bag = PropertyBagConverter.fromValue(source); - do_print(" => " + bag); - if (source == null) { - Assert.ok(bag == null, "The bag is null"); - } else if (typeof source == "object") { - Assert.ok(bag instanceof Ci.nsIPropertyBag, "The bag is a property bag"); - } else { - Assert.ok(typeof bag != "object", "The bag is not an object"); - } - let dest = PropertyBagConverter.toValue(bag); - let restringified = JSON.stringify(normalize(dest), null, "\t"); - do_print("Comparing"); - do_print(stringified); - do_print(restringified); - Assert.deepEqual(sample, dest, "Testing after " + i + " conversions"); - rewrites.push(dest); - } - } -} diff --git a/toolkit/components/asyncshutdown/tests/xpcshell/xpcshell.ini b/toolkit/components/asyncshutdown/tests/xpcshell/xpcshell.ini deleted file mode 100644 index f573955bc..000000000 --- a/toolkit/components/asyncshutdown/tests/xpcshell/xpcshell.ini +++ /dev/null @@ -1,8 +0,0 @@ -[DEFAULT] -head=head.js -tail= -skip-if = toolkit == 'android' - -[test_AsyncShutdown.js] -[test_AsyncShutdown_leave_uncaught.js] -[test_converters.js] |