forked from mirrors/gecko-dev
Bug 1866882 - Part 2: Add tests for nsIWindowsMutex. r=nalexander,mhughes
Differential Revision: https://phabricator.services.mozilla.com/D195190
This commit is contained in:
parent
995ed74f53
commit
5f5cd425b6
3 changed files with 150 additions and 0 deletions
|
|
@ -86,6 +86,8 @@ XPCOM_MANIFESTS += [
|
||||||
"components.conf",
|
"components.conf",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
XPCSHELL_TESTS_MANIFESTS += ["tests/xpcshell/xpcshell.toml"]
|
||||||
|
|
||||||
# If defines are added to this list that are required by the Cache,
|
# If defines are added to this list that are required by the Cache,
|
||||||
# SetDefaultBrowser, or their dependencies (Registry, EventLog, common),
|
# SetDefaultBrowser, or their dependencies (Registry, EventLog, common),
|
||||||
# tests/gtest/moz.build will need to be updated as well.
|
# tests/gtest/moz.build will need to be updated as well.
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
[DEFAULT]
|
||||||
|
run-if = ["os == 'win'"]
|
||||||
|
|
||||||
|
["test_windows_mutex.js"]
|
||||||
Loading…
Reference in a new issue