Skip to content
Snippets Groups Projects
Commit 5f5cd425 authored by Nicholas Rishel's avatar Nicholas Rishel
Browse files

Bug 1866882 - Part 2: Add tests for `nsIWindowsMutex`. r=nalexander,mhughes

parent 995ed74f
No related branches found
No related tags found
No related merge requests found
......@@ -86,6 +86,8 @@ XPCOM_MANIFESTS += [
"components.conf",
]
XPCSHELL_TESTS_MANIFESTS += ["tests/xpcshell/xpcshell.toml"]
# If defines are added to this list that are required by the Cache,
# SetDefaultBrowser, or their dependencies (Registry, EventLog, common),
# tests/gtest/moz.build will need to be updated as well.
......
/* 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();
}
});
[DEFAULT]
run-if = ["os == 'win'"]
["test_windows_mutex.js"]
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment