diff options
Diffstat (limited to 'toolkit/mozapps/defaultagent/tests/xpcshell')
-rw-r--r-- | toolkit/mozapps/defaultagent/tests/xpcshell/test_windows_mutex.js | 144 | ||||
-rw-r--r-- | toolkit/mozapps/defaultagent/tests/xpcshell/xpcshell.toml | 4 |
2 files changed, 148 insertions, 0 deletions
diff --git a/toolkit/mozapps/defaultagent/tests/xpcshell/test_windows_mutex.js b/toolkit/mozapps/defaultagent/tests/xpcshell/test_windows_mutex.js new file mode 100644 index 0000000000..ac020ae9f2 --- /dev/null +++ b/toolkit/mozapps/defaultagent/tests/xpcshell/test_windows_mutex.js @@ -0,0 +1,144 @@ +/* Any copyright is dedicated to the Public Domain. +http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Multiple instances of a named mutex on Windows can lock on the same thread, so +// we have to run each test across at least two distinct threads. Running on a +// separate process achieves the same. +do_load_child_test_harness(); + +let parentFactory = Cc["@mozilla.org/windows-mutex-factory;1"].createInstance( + Ci.nsIWindowsMutexFactory +); + +function promiseCommand(aCommand) { + // Exceptions don't propogate to the process that called `sendCommand` nor + // tigger a test failure, so wrap the command to ensure we fail appropriately. + let wrappedCommand = `try {${aCommand}} catch(e) {Assert.ok(false, "Error running command received in child process. Note the passed in function must be self-contained. Error: \${e.toString()}");}`; + return new Promise(resolve => sendCommand(wrappedCommand, resolve)); +} + +// This is passed as a string to a child process, thus must be self-contained. +function assertLockOkOnChild(aName, aTestString) { + if (Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT) { + Assert.ok(false, `${assertLockOkOnChild.name} run on child process.`); + } + + let childFactory = Cc["@mozilla.org/windows-mutex-factory;1"].createInstance( + Ci.nsIWindowsMutexFactory + ); + + let lockingMutex = childFactory.createMutex(aName); + + info(`Locking mutex for subtest "${aTestString}"`); + lockingMutex.tryLock(); + try { + Assert.ok(lockingMutex.isLocked(), aTestString); + } finally { + lockingMutex.unlock(); + } +} + +// This is passed as a string to a child process, thus must be self-contained. +function assertLockThrowsOnChild(aName, aTestString) { + if (Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_CONTENT) { + Assert.ok(false, `${assertLockThrowsOnChild.name} run on child process.`); + } + + let childFactory = Cc["@mozilla.org/windows-mutex-factory;1"].createInstance( + Ci.nsIWindowsMutexFactory + ); + + let blockedMutex = childFactory.createMutex(aName); + + info(`Locking mutex for subtest "${aTestString}"`); + Assert.throws(blockedMutex.tryLock, /NS_ERROR_NOT_AVAILABLE/, aTestString); + Assert.ok(!blockedMutex.isLocked(), "Not locked after error."); +} + +add_task(async function test_lock_blocks() { + const kTestMutexName = Services.uuid.generateUUID().toString(); + let lockingMutex = parentFactory.createMutex(kTestMutexName); + + Assert.ok(!lockingMutex.isLocked(), "Reported unlocked before locking."); + + info(`Locking mutex named "${kTestMutexName}"`); + lockingMutex.tryLock(); + try { + Assert.ok(lockingMutex.isLocked(), "Reported locked after locking."); + + await promiseCommand( + `(${assertLockThrowsOnChild.toString()})("${kTestMutexName}", "Concurrent attempts to lock identically named mutex throws.");` + ); + } finally { + lockingMutex.unlock(); + } +}); + +add_task(async function test_unlock_unblocks() { + const kTestMutexName = Services.uuid.generateUUID().toString(); + let lockingMutex = parentFactory.createMutex(kTestMutexName); + + info(`Locking mutex named "${kTestMutexName}"`); + lockingMutex.tryLock(); + lockingMutex.unlock(); + + Assert.ok(!lockingMutex.isLocked(), "Reported unlocked after unlocking."); + + await promiseCommand( + `(${assertLockOkOnChild.toString()})("${kTestMutexName}", "Locked previously unlocked mutex.");` + ); +}); + +add_task(async function test_names_dont_conflict() { + const kTestMutexName = Services.uuid.generateUUID().toString(); + let mutex1 = parentFactory.createMutex(kTestMutexName); + + info(`Locking mutex named "${kTestMutexName}"`); + mutex1.tryLock(); + try { + await promiseCommand( + `(${assertLockOkOnChild.toString()})(Services.uuid.generateUUID().toString(), "Differently named mutexes don't conflict");` + ); + } finally { + mutex1.unlock(); + } +}); + +add_task(async function test_relock_when_locked() { + const kTestMutexName = Services.uuid.generateUUID().toString(); + let mutex = parentFactory.createMutex(kTestMutexName); + + mutex.tryLock(); + try { + Assert.ok(() => mutex.tryLock(), "Relocking locked mutex succeeds."); + Assert.ok( + mutex.isLocked(), + "Reported locked after relocking locked mutex." + ); + } finally { + mutex.unlock(); + } +}); + +add_task(async function test_unlock_without_lock() { + const kTestMutexName = Services.uuid.generateUUID().toString(); + let mutex = parentFactory.createMutex(kTestMutexName); + + mutex.unlock(); + Assert.ok( + !mutex.isLocked(), + "Reported unlocked after unnecessarily unlocking mutex." + ); + + mutex.tryLock(); + try { + Assert.ok( + mutex.isLocked(), + "Reported locked after locking unnecessarily unlocked mutex." + ); + } finally { + mutex.unlock(); + } +}); diff --git a/toolkit/mozapps/defaultagent/tests/xpcshell/xpcshell.toml b/toolkit/mozapps/defaultagent/tests/xpcshell/xpcshell.toml new file mode 100644 index 0000000000..df1992fb13 --- /dev/null +++ b/toolkit/mozapps/defaultagent/tests/xpcshell/xpcshell.toml @@ -0,0 +1,4 @@ +[DEFAULT] +run-if = ["os == 'win'"] + +["test_windows_mutex.js"] |