Bug 1092102 - Implement WorkerDebugger.initialize;r=khuey

This commit is contained in:
Eddy Bruël 2015-03-17 11:15:19 +01:00
Родитель d087d1ddf6
Коммит 2d0841a4c7
22 изменённых файлов: 428 добавлений и 143 удалений

Просмотреть файл

@ -60,6 +60,7 @@
#include "Principal.h"
#include "SharedWorker.h"
#include "WorkerDebuggerManager.h"
#include "WorkerPrivate.h"
#include "WorkerRunnable.h"
#include "WorkerThread.h"
@ -1918,6 +1919,12 @@ RuntimeService::Shutdown()
// That's it, no more workers.
mShuttingDown = true;
// Remove all listeners from the worker debugger manager to ensure that it
// gets properly destroyed.
if (NS_FAILED(ClearWorkerDebuggerManagerListeners())) {
NS_WARNING("Failed to clear worker debugger manager listeners!");
}
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_WARN_IF_FALSE(obs, "Failed to get observer service?!");

Просмотреть файл

@ -53,7 +53,8 @@ ChannelFromScriptURL(nsIPrincipal* principal,
nsIIOService* ios,
nsIScriptSecurityManager* secMan,
const nsAString& aScriptURL,
bool aIsWorkerScript,
bool aIsMainScript,
WorkerScriptType aWorkerScriptType,
nsIChannel** aChannel)
{
AssertIsOnMainThread();
@ -84,10 +85,22 @@ ChannelFromScriptURL(nsIPrincipal* principal,
}
}
// If this script loader is being used to make a new worker then we need
// to do a same-origin check. Otherwise we need to clear the load with the
// security manager.
if (aIsWorkerScript) {
if (aWorkerScriptType == DebuggerScript) {
bool isChrome = false;
NS_ENSURE_SUCCESS(uri->SchemeIs("chrome", &isChrome),
NS_ERROR_DOM_SECURITY_ERR);
bool isResource = false;
NS_ENSURE_SUCCESS(uri->SchemeIs("resource", &isResource),
NS_ERROR_DOM_SECURITY_ERR);
if (!isChrome && !isResource) {
return NS_ERROR_DOM_SECURITY_ERR;
}
} else if (aIsMainScript) {
// If this script loader is being used to make a new worker then we need
// to do a same-origin check. Otherwise we need to clear the load with the
// security manager.
nsCString scheme;
rv = uri->GetScheme(scheme);
NS_ENSURE_SUCCESS(rv, rv);
@ -190,6 +203,9 @@ private:
~ScriptExecutorRunnable()
{ }
virtual bool
IsDebuggerRunnable() const MOZ_OVERRIDE;
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE;
@ -214,7 +230,8 @@ class ScriptLoaderRunnable MOZ_FINAL : public WorkerFeature,
WorkerPrivate* mWorkerPrivate;
nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
nsTArray<ScriptLoadInfo> mLoadInfos;
bool mIsWorkerScript;
bool mIsMainScript;
WorkerScriptType mWorkerScriptType;
bool mCanceled;
bool mCanceledMainThread;
@ -224,14 +241,15 @@ public:
ScriptLoaderRunnable(WorkerPrivate* aWorkerPrivate,
nsIEventTarget* aSyncLoopTarget,
nsTArray<ScriptLoadInfo>& aLoadInfos,
bool aIsWorkerScript)
bool aIsMainScript,
WorkerScriptType aWorkerScriptType)
: mWorkerPrivate(aWorkerPrivate), mSyncLoopTarget(aSyncLoopTarget),
mIsWorkerScript(aIsWorkerScript), mCanceled(false),
mCanceledMainThread(false)
mIsMainScript(aIsMainScript), mWorkerScriptType(aWorkerScriptType),
mCanceled(false), mCanceledMainThread(false)
{
aWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(aSyncLoopTarget);
MOZ_ASSERT_IF(aIsWorkerScript, aLoadInfos.Length() == 1);
MOZ_ASSERT_IF(aIsMainScript, aLoadInfos.Length() == 1);
mLoadInfos.SwapElements(aLoadInfos);
}
@ -300,6 +318,12 @@ private:
return true;
}
bool
IsMainWorkerScript() const
{
return mIsMainScript && mWorkerScriptType == WorkerScript;
}
void
CancelMainThread()
{
@ -338,7 +362,7 @@ private:
nsCOMPtr<nsILoadGroup> loadGroup = mWorkerPrivate->GetLoadGroup();
if (!principal) {
NS_ASSERTION(parentWorker, "Must have a principal!");
NS_ASSERTION(mIsWorkerScript, "Must have a principal for importScripts!");
NS_ASSERTION(mIsMainScript, "Must have a principal for importScripts!");
principal = parentWorker->GetPrincipal();
loadGroup = parentWorker->GetLoadGroup();
@ -348,7 +372,7 @@ private:
// Figure out our base URI.
nsCOMPtr<nsIURI> baseURI;
if (mIsWorkerScript) {
if (mIsMainScript) {
if (parentWorker) {
baseURI = parentWorker->GetBaseURI();
NS_ASSERTION(baseURI, "Should have been set already!");
@ -367,7 +391,7 @@ private:
nsCOMPtr<nsIDocument> parentDoc = mWorkerPrivate->GetDocument();
nsCOMPtr<nsIChannel> channel;
if (mIsWorkerScript) {
if (IsMainWorkerScript()) {
// May be null.
channel = mWorkerPrivate->ForgetWorkerChannel();
}
@ -383,8 +407,8 @@ private:
if (!channel) {
rv = ChannelFromScriptURL(principal, baseURI, parentDoc, loadGroup, ios,
secMan, loadInfo.mURL, mIsWorkerScript,
getter_AddRefs(channel));
secMan, loadInfo.mURL, mIsMainScript,
mWorkerScriptType, getter_AddRefs(channel));
if (NS_FAILED(rv)) {
return rv;
}
@ -489,7 +513,7 @@ private:
// Update the principal of the worker and its base URI if we just loaded the
// worker's primary script.
if (mIsWorkerScript) {
if (IsMainWorkerScript()) {
// Take care of the base URI first.
mWorkerPrivate->SetBaseURI(finalURI);
@ -577,7 +601,7 @@ private:
{
AssertIsOnMainThread();
if (mIsWorkerScript) {
if (IsMainWorkerScript()) {
mWorkerPrivate->WorkerScriptLoaded();
}
@ -704,6 +728,15 @@ ScriptExecutorRunnable::ScriptExecutorRunnable(
MOZ_ASSERT(aLastIndex < aScriptLoader.mLoadInfos.Length());
}
bool
ScriptExecutorRunnable::IsDebuggerRunnable() const
{
// ScriptExecutorRunnable is used to execute both worker and debugger scripts.
// In the latter case, the runnable needs to be dispatched to the debugger
// queue.
return mScriptLoader.mWorkerScriptType == DebuggerScript;
}
bool
ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
@ -762,6 +795,10 @@ ScriptExecutorRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
options.setFileAndLine(filename.get(), 1)
.setNoScriptRval(true);
if (mScriptLoader.mWorkerScriptType == DebuggerScript) {
options.setVersion(JSVERSION_LATEST);
}
JS::SourceBufferHolder srcBuf(loadInfo.mScriptTextBuf,
loadInfo.mScriptTextLength,
JS::SourceBufferHolder::GiveOwnership);
@ -819,7 +856,8 @@ ScriptExecutorRunnable::ShutdownScriptLoader(JSContext* aCx,
bool
LoadAllScripts(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
nsTArray<ScriptLoadInfo>& aLoadInfos, bool aIsWorkerScript)
nsTArray<ScriptLoadInfo>& aLoadInfos, bool aIsMainScript,
WorkerScriptType aWorkerScriptType)
{
aWorkerPrivate->AssertIsOnWorkerThread();
NS_ASSERTION(!aLoadInfos.IsEmpty(), "Bad arguments!");
@ -828,7 +866,7 @@ LoadAllScripts(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
nsRefPtr<ScriptLoaderRunnable> loader =
new ScriptLoaderRunnable(aWorkerPrivate, syncLoop.EventTarget(),
aLoadInfos, aIsWorkerScript);
aLoadInfos, aIsMainScript, aWorkerScriptType);
NS_ASSERTION(aLoadInfos.IsEmpty(), "Should have swapped!");
@ -868,7 +906,7 @@ ChannelFromScriptURLMainThread(nsIPrincipal* aPrincipal,
NS_ASSERTION(secMan, "This should never be null!");
return ChannelFromScriptURL(aPrincipal, aBaseURI, aParentDoc, aLoadGroup,
ios, secMan, aScriptURL, true, aChannel);
ios, secMan, aScriptURL, true, WorkerScript, aChannel);
}
nsresult
@ -927,7 +965,8 @@ void ReportLoadError(JSContext* aCx, const nsAString& aURL,
}
bool
LoadWorkerScript(JSContext* aCx)
LoadMainScript(JSContext* aCx, const nsAString& aScriptURL,
WorkerScriptType aWorkerScriptType)
{
WorkerPrivate* worker = GetWorkerPrivateFromContext(aCx);
NS_ASSERTION(worker, "This should never be null!");
@ -935,9 +974,9 @@ LoadWorkerScript(JSContext* aCx)
nsTArray<ScriptLoadInfo> loadInfos;
ScriptLoadInfo* info = loadInfos.AppendElement();
info->mURL = worker->ScriptURL();
info->mURL = aScriptURL;
return LoadAllScripts(aCx, worker, loadInfos, true);
return LoadAllScripts(aCx, worker, loadInfos, true, aWorkerScriptType);
}
void
@ -962,7 +1001,7 @@ Load(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
loadInfos[index].mURL = aScriptURLs[index];
}
if (!LoadAllScripts(aCx, aWorkerPrivate, loadInfos, false)) {
if (!LoadAllScripts(aCx, aWorkerPrivate, loadInfos, false, WorkerScript)) {
// LoadAllScripts can fail if we're shutting down.
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
}

Просмотреть файл

@ -29,6 +29,11 @@ class Sequence;
BEGIN_WORKERS_NAMESPACE
enum WorkerScriptType {
WorkerScript,
DebuggerScript
};
namespace scriptloader {
nsresult
@ -48,7 +53,8 @@ ChannelFromScriptURLWorkerThread(JSContext* aCx,
void ReportLoadError(JSContext* aCx, const nsAString& aURL,
nsresult aLoadResult, bool aIsMainThread);
bool LoadWorkerScript(JSContext* aCx);
bool LoadMainScript(JSContext* aCx, const nsAString& aScriptURL,
WorkerScriptType aWorkerScriptType);
void Load(JSContext* aCx,
WorkerPrivate* aWorkerPrivate,

Просмотреть файл

@ -141,6 +141,16 @@ WorkerDebuggerManager::RemoveListener(
return NS_OK;
}
void
WorkerDebuggerManager::ClearListeners()
{
AssertIsOnMainThread();
MutexAutoLock lock(mMutex);
mListeners.Clear();
}
void
WorkerDebuggerManager::RegisterDebugger(WorkerDebugger* aDebugger)
{

Просмотреть файл

@ -41,9 +41,9 @@ public:
static WorkerDebuggerManager*
GetOrCreateService()
{
nsCOMPtr<nsIWorkerDebuggerManager> wdm =
nsCOMPtr<nsIWorkerDebuggerManager> manager =
do_GetService(WORKERDEBUGGERMANAGER_CONTRACTID);
return static_cast<WorkerDebuggerManager*>(wdm.get());
return static_cast<WorkerDebuggerManager*>(manager.get());
}
WorkerDebuggerManager();
@ -51,6 +51,8 @@ public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIWORKERDEBUGGERMANAGER
void ClearListeners();
void RegisterDebugger(WorkerDebugger* aDebugger);
void UnregisterDebugger(WorkerDebugger* aDebugger);
@ -64,6 +66,19 @@ private:
void UnregisterDebuggerOnMainThread(WorkerDebugger* aDebugger);
};
inline nsresult
ClearWorkerDebuggerManagerListeners()
{
nsRefPtr<WorkerDebuggerManager> manager =
WorkerDebuggerManager::GetOrCreateService();
if (!manager) {
return NS_ERROR_FAILURE;
}
manager->ClearListeners();
return NS_OK;
}
inline nsresult
RegisterWorkerDebugger(WorkerDebugger* aDebugger)
{

Просмотреть файл

@ -1042,9 +1042,13 @@ private:
class CompileScriptRunnable MOZ_FINAL : public WorkerRunnable
{
nsString mScriptURL;
public:
explicit CompileScriptRunnable(WorkerPrivate* aWorkerPrivate)
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
explicit CompileScriptRunnable(WorkerPrivate* aWorkerPrivate,
const nsAString& aScriptURL)
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
mScriptURL(aScriptURL)
{ }
private:
@ -1059,8 +1063,9 @@ private:
}
JS::Rooted<JSObject*> global(aCx, globalScope->GetWrapper());
JSAutoCompartment ac(aCx, global);
bool result = scriptloader::LoadWorkerScript(aCx);
bool result = scriptloader::LoadMainScript(aCx, mScriptURL, WorkerScript);
if (result) {
aWorkerPrivate->SetWorkerScriptExecutedSuccessfully();
}
@ -1068,6 +1073,35 @@ private:
}
};
class CompileDebuggerScriptRunnable MOZ_FINAL : public WorkerDebuggerRunnable
{
nsString mScriptURL;
public:
CompileDebuggerScriptRunnable(WorkerPrivate* aWorkerPrivate,
const nsAString& aScriptURL)
: WorkerDebuggerRunnable(aWorkerPrivate),
mScriptURL(aScriptURL)
{ }
private:
virtual bool
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
{
WorkerDebuggerGlobalScope* globalScope =
aWorkerPrivate->CreateDebuggerGlobalScope(aCx);
if (!globalScope) {
NS_WARNING("Failed to make global!");
return false;
}
JS::Rooted<JSObject*> global(aCx, globalScope->GetWrapper());
JSAutoCompartment ac(aCx, global);
return scriptloader::LoadMainScript(aCx, mScriptURL, DebuggerScript);
}
};
class CloseEventRunnable MOZ_FINAL : public WorkerRunnable
{
public:
@ -4135,7 +4169,8 @@ WorkerDebugger::WorkerDebugger(WorkerPrivate* aWorkerPrivate)
: mMutex("WorkerDebugger::mMutex"),
mCondVar(mMutex, "WorkerDebugger::mCondVar"),
mWorkerPrivate(aWorkerPrivate),
mIsEnabled(false)
mIsEnabled(false),
mIsInitialized(false)
{
mWorkerPrivate->AssertIsOnParentThread();
}
@ -4264,6 +4299,28 @@ WorkerDebugger::GetWindow(nsIDOMWindow** aResult)
return NS_OK;
}
NS_IMETHODIMP
WorkerDebugger::Initialize(const nsAString& aURL, JSContext* aCx)
{
AssertIsOnMainThread();
MutexAutoLock lock(mMutex);
if (!mWorkerPrivate || mIsInitialized) {
return NS_ERROR_UNEXPECTED;
}
nsRefPtr<CompileDebuggerScriptRunnable> runnable =
new CompileDebuggerScriptRunnable(mWorkerPrivate, aURL);
if (!runnable->Dispatch(aCx)) {
return NS_ERROR_FAILURE;
}
mIsInitialized = true;
return NS_OK;
}
NS_IMETHODIMP
WorkerDebugger::AddListener(nsIWorkerDebuggerListener* aListener)
{
@ -4526,7 +4583,8 @@ WorkerPrivate::Constructor(JSContext* aCx,
worker->EnableDebugger();
nsRefPtr<CompileScriptRunnable> compiler = new CompileScriptRunnable(worker);
nsRefPtr<CompileScriptRunnable> compiler =
new CompileScriptRunnable(worker, aScriptURL);
if (!compiler->Dispatch(aCx)) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;

Просмотреть файл

@ -729,6 +729,7 @@ class WorkerDebugger : public nsIWorkerDebugger {
bool mIsEnabled;
// Only touched on the main thread.
bool mIsInitialized;
nsTArray<nsCOMPtr<nsIWorkerDebuggerListener>> mListeners;
public:

Просмотреть файл

@ -8,7 +8,7 @@ interface nsIWorkerDebuggerListener : nsISupports
void onClose();
};
[scriptable, builtinclass, uuid(0833b363-bffe-4cdb-ad50-1c4563e0C8ff)]
[scriptable, builtinclass, uuid(b0ea6da8-8bd9-446a-94e2-2ee979903205)]
interface nsIWorkerDebugger : nsISupports
{
const unsigned long TYPE_DEDICATED = 0;
@ -27,6 +27,9 @@ interface nsIWorkerDebugger : nsISupports
readonly attribute nsIDOMWindow window;
[implicit_jscontext]
void initialize(in DOMString url);
void addListener(in nsIWorkerDebuggerListener listener);
void removeListener(in nsIWorkerDebuggerListener listener);

Просмотреть файл

@ -0,0 +1,6 @@
"use strict";
self.onmessage = function () {};
debugger;
postMessage("worker");

Просмотреть файл

@ -0,0 +1,6 @@
"use strict";
var dbg = new Debugger(global);
dbg.onDebuggerStatement = function (frame) {
frame.eval("postMessage('debugger');");
};

Просмотреть файл

@ -0,0 +1,9 @@
"use strict";
var worker = new Worker("WorkerDebugger.initialize_childWorker.js");
worker.onmessage = function (event) {
postMessage("child:" + event.data);
};
debugger;
postMessage("worker");

Просмотреть файл

@ -1,3 +1,3 @@
"use strict";
onmessage = function () {};
self.onmessage = function () {};

Просмотреть файл

@ -1,3 +1,3 @@
"use strict";
onmessage = function () {};
self.onmessage = function () {};

Просмотреть файл

@ -1,3 +0,0 @@
"use strict";
var worker = new Worker("WorkerDebugger_childWorker.js");

Просмотреть файл

@ -1,6 +1,6 @@
"use strict";
onconnect = function (event) {
self.onconnect = function (event) {
event.ports[0].onmessage = function (event) {
switch (event.data) {
case "close":

Просмотреть файл

@ -0,0 +1,8 @@
"use strict";
var worker = new Worker("WorkerDebugger_childWorker.js");
self.onmessage = function (event) {
postMessage("child:" + event.data);
};
debugger;
postMessage("worker");

Просмотреть файл

@ -1,10 +1,13 @@
[DEFAULT]
skip-if = buildapp == 'b2g'
support-files =
WorkerDebugger.initialize_childWorker.js
WorkerDebugger.initialize_debugger.js
WorkerDebugger.initialize_worker.js
WorkerDebuggerManager_childWorker.js
WorkerDebuggerManager_parentWorker.js
WorkerDebuggerManager_worker.js
WorkerDebugger_childWorker.js
WorkerDebugger_parentWorker.js
WorkerDebugger_worker.js
WorkerDebugger_sharedWorker.js
WorkerTest.jsm
WorkerTest_subworker.js
@ -29,6 +32,7 @@ support-files =
bug1062920_worker.js
[test_WorkerDebugger.xul]
[test_WorkerDebugger.initialize.xul]
[test_WorkerDebuggerManager.xul]
[test_bug883784.jsm]
[test_bug883784.xul]

Просмотреть файл

@ -13,6 +13,8 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const wdm = Cc["@mozilla.org/dom/workers/workerdebuggermanager;1"].
getService(Ci.nsIWorkerDebuggerManager);
const BASE_URL = "chrome://mochitests/content/chrome/dom/workers/test/";
var gRemainingTests = 0;
function waitForWorkerFinish() {
@ -47,50 +49,54 @@ function* generateDebuggers() {
}
}
function findDebugger(predicate) {
function findDebugger(url) {
for (let dbg of generateDebuggers()) {
if (predicate(dbg)) {
if (dbg.url === url) {
return dbg;
}
}
return null;
}
function waitForRegister(predicate = () => true) {
function waitForRegister(url, dbgUrl) {
return new Promise(function (resolve) {
wdm.addListener({
onRegister: function (dbg) {
if (!predicate(dbg)) {
if (dbg.url !== url) {
return;
}
ok(true, "Debugger with url " + url + " should be registered.");
wdm.removeListener(this);
if (dbgUrl) {
info("Initializing worker debugger with url " + url + ".");
dbg.initialize(dbgUrl);
}
resolve(dbg);
}
});
});
}
function waitForUnregister(predicate = () => true) {
function waitForUnregister(url) {
return new Promise(function (resolve) {
wdm.addListener({
onUnregister: function (dbg) {
if (!predicate(dbg)) {
if (dbg.url !== url) {
return;
}
ok(true, "Debugger with url " + url + " should be unregistered.");
wdm.removeListener(this);
resolve(dbg);
resolve();
}
});
});
}
function waitForDebuggerClose(dbg, predicate = () => true) {
function waitForDebuggerClose(dbg) {
return new Promise(function (resolve) {
dbg.addListener({
onClose: function () {
if (!predicate()) {
return;
}
ok(true, "Debugger should be closed.");
dbg.removeListener(this);
resolve();
}
@ -98,17 +104,31 @@ function waitForDebuggerClose(dbg, predicate = () => true) {
});
}
function waitForWorkerMessage(worker, message) {
return new Promise(function (resolve) {
worker.addEventListener("message", function onmessage(event) {
if (event.data !== message) {
return;
}
ok(true, "Should receive " + message + " message from worker.");
worker.removeEventListener("message", onmessage);
resolve();
});
});
}
function waitForMultiple(promises) {
return new Promise(function (resolve) {
let results = [];
let values = [];
for (let i = 0; i < promises.length; ++i) {
let promise = promises[i];
let index = i;
promise.then(function (result) {
is(results.length, index, "events should occur in the specified order");
results.push(result);
if (results.length === promises.length) {
resolve(results);
promises[i].then(function (value) {
is(index + 1, values.length + 1,
"Promise " + (values.length + 1) + " out of " + promises.length +
" should be resolved.");
values.push(value);
if (values.length === promises.length) {
resolve(values);
}
});
}

Просмотреть файл

@ -0,0 +1,58 @@
<?xml version="1.0"?>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<window title="Test for WorkerDebugger.initialize"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
onload="test();">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
<script type="application/javascript" src="dom_worker_helper.js"/>
<script type="application/javascript">
<![CDATA[
const WORKER_URL = "WorkerDebugger.initialize_worker.js";
const CHILD_WORKER_URL = "WorkerDebugger.initialize_childWorker.js";
const DEBUGGER_URL = BASE_URL + "WorkerDebugger.initialize_debugger.js";
function test() {
Task.spawn(function* () {
SimpleTest.waitForExplicitFinish();
info("Create a worker that creates a child worker, wait for their " +
"debuggers to be registered, and initialize them.");
let promise = waitForMultiple([
waitForRegister(WORKER_URL, DEBUGGER_URL),
waitForRegister(CHILD_WORKER_URL, DEBUGGER_URL)
]);
let worker = new Worker(WORKER_URL);
yield promise;
info("Check that the debuggers are initialized before the workers " +
"start running.");
yield waitForMultiple([
waitForWorkerMessage(worker, "debugger"),
waitForWorkerMessage(worker, "worker"),
waitForWorkerMessage(worker, "child:debugger"),
waitForWorkerMessage(worker, "child:worker")
]);
SimpleTest.finish();
});
}
]]>
</script>
<body xmlns="http://www.w3.org/1999/xhtml">
<p id="display"></p>
<div id="content" style="display:none;"></div>
<pre id="test"></pre>
</body>
<label id="test-result"/>
</window>

Просмотреть файл

@ -16,7 +16,7 @@
<script type="application/javascript">
<![CDATA[
const PARENT_WORKER_URL = "WorkerDebugger_parentWorker.js";
const WORKER_URL = "WorkerDebugger_worker.js";
const CHILD_WORKER_URL = "WorkerDebugger_childWorker.js";
const SHARED_WORKER_URL = "WorkerDebugger_sharedWorker.js";
@ -24,65 +24,89 @@
Task.spawn(function* () {
SimpleTest.waitForExplicitFinish();
info("Create a top-level chrome worker that creates a non-top-level " +
"content worker and wait for their debuggers to be registered.");
let promise = waitForMultiple([
waitForRegister((dbg) => dbg.url === PARENT_WORKER_URL),
waitForRegister((dbg) => dbg.url === CHILD_WORKER_URL),
waitForRegister(WORKER_URL),
waitForRegister(CHILD_WORKER_URL)
]);
worker = new ChromeWorker(PARENT_WORKER_URL);
let dbgs = yield promise;
is(dbgs[0].isChrome, true, "debugger should be for chrome worker");
is(dbgs[0].parent, null,
"debugger for a top-level worker should not have parent");
is(dbgs[0].type, Ci.nsIWorkerDebugger.TYPE_DEDICATED,
"debugger should be for dedicated worker");
is(dbgs[0].window, window,
"debugger for top-level dedicated worker should have window");
is(dbgs[1].isChrome, false, "debugger should be for content worker");
is(dbgs[1].parent, dbgs[0],
"debugger for child worker should have parent");
is(dbgs[1].type, Ci.nsIWorkerDebugger.TYPE_DEDICATED);
is(dbgs[1].window, null,
"debugger for non-top-level worker should not have window");
worker = new ChromeWorker(WORKER_URL);
let [dbg, childDbg] = yield promise;
info("Check that the top-level chrome worker debugger has the " +
"correct properties.");
is(dbg.isChrome, true,
"Chrome worker debugger should be chrome.");
is(dbg.parent, null,
"Top-level debugger should not have parent.");
is(dbg.type, Ci.nsIWorkerDebugger.TYPE_DEDICATED,
"Chrome worker debugger should be dedicated.");
is(dbg.window, window,
"Top-level dedicated worker debugger should have window.");
info("Check that the non-top-level content worker debugger has the " +
"correct properties.");
is(childDbg.isChrome, false,
"Content worker debugger should be content.");
is(childDbg.parent, dbg,
"Non-top-level worker debugger should have parent.");
is(childDbg.type, Ci.nsIWorkerDebugger.TYPE_DEDICATED,
"Content worker debugger should be dedicated.");
is(childDbg.window, null,
"Non-top-level worker debugger should not have window.");
info("Terminate the top-level chrome worker and the non-top-level " +
"content worker, and wait for their debuggers to be " +
"unregistered and closed.");
promise = waitForMultiple([
waitForUnregister((dbg) => dbg.url === CHILD_WORKER_URL),
waitForDebuggerClose(dbgs[1]),
waitForUnregister((dbg) => dbg.url === PARENT_WORKER_URL),
waitForDebuggerClose(dbgs[0]),
waitForUnregister(CHILD_WORKER_URL),
waitForDebuggerClose(childDbg),
waitForUnregister(WORKER_URL),
waitForDebuggerClose(dbg),
]);
worker.terminate();
yield promise;
promise = waitForRegister();
info("Create a shared worker and wait for its debugger to be " +
"registered");
promise = waitForRegister(SHARED_WORKER_URL);
worker = new SharedWorker(SHARED_WORKER_URL);
let dbg = yield promise;
is(dbg.isChrome, false, "debugger should be for content worker");
is(dbg.parent, null,
"debugger for top-level worker should not have parent");
is(dbg.type, Ci.nsIWorkerDebugger.TYPE_SHARED,
"debugger should be for shared worker");
is(dbg.window, null,
"debugger for non-dedicated worker should not have window");
let sharedDbg = yield promise;
info("Check that the shared worker debugger has the correct " +
"properties.");
is(sharedDbg.isChrome, false,
"Shared worker debugger should be content.");
is(sharedDbg.parent, null,
"Shared worker debugger should not have parent.");
is(sharedDbg.type, Ci.nsIWorkerDebugger.TYPE_SHARED,
"Shared worker debugger should be shared.");
is(sharedDbg.window, null,
"Shared worker debugger should not have window.");
info("Create a shared worker with the same URL and check that its " +
"debugger is not registered again.");
let listener = {
onRegistered: function () {
ok(false,
"debugger for shared worker should not be registered twice");
"Shared worker debugger should not be registered again.");
},
};
wdm.addListener(listener);
worker = new SharedWorker(SHARED_WORKER_URL);
dbg.addListener({
onClose: function () {
is(dbg.isClosed, true, "debugger should be closed");
wdm.removeListener(listener);
dbg.removeListener(this);
SimpleTest.finish();
}
});
info("Send a message to the shared worker to tell it to close " +
"itself, and wait for its debugger to be closed.");
promise = waitForMultiple([
waitForUnregister(SHARED_WORKER_URL),
waitForDebuggerClose(sharedDbg)
]);
worker.port.start();
worker.port.postMessage("close");
yield promise;
wdm.removeListener(listener);
SimpleTest.finish();
});
}

Просмотреть файл

@ -16,65 +16,79 @@
<script type="application/javascript">
<![CDATA[
const PARENT_WORKER_URL = "WorkerDebuggerManager_parentWorker.js";
const WORKER_URL = "WorkerDebuggerManager_worker.js";
const CHILD_WORKER_URL = "WorkerDebuggerManager_childWorker.js";
function test() {
Task.spawn(function* () {
SimpleTest.waitForExplicitFinish();
ok(!findDebugger((dbg) => dbg.url === PARENT_WORKER_URL),
"debugger for parent worker should not be enumerated before it is " +
"registered");
ok(!findDebugger((dbg) => dbg.url === CHILD_WORKER_URL),
"debugger for child worker should not be enumerated before it is " +
"registered");
info("Check that worker debuggers are not enumerated before they are " +
"registered.");
ok(!findDebugger(WORKER_URL),
"Worker debugger should not be enumerated before it is registered.");
ok(!findDebugger(CHILD_WORKER_URL),
"Child worker debugger should not be enumerated before it is " +
"registered.");
info("Create a worker that creates a child worker, and wait for " +
"their debuggers to be registered.");
let promise = waitForMultiple([
waitForRegister((dbg) => dbg.url === PARENT_WORKER_URL),
waitForRegister((dbg) => dbg.url === CHILD_WORKER_URL),
waitForRegister(WORKER_URL),
waitForRegister(CHILD_WORKER_URL)
]);
let worker = new Worker(PARENT_WORKER_URL);
let dbgs = yield promise;
is(dbgs[0].isClosed, false,
"debugger for parent worker should not be closed after it is " +
"registered");
is(dbgs[1].isClosed, false,
"debugger for child worker should not be closed after it is " +
"registered");
let worker = new Worker(WORKER_URL);
let [dbg, childDbg] = yield promise;
ok(findDebugger((dbg) => dbg.url === PARENT_WORKER_URL),
"debugger for parent worker should be enumerated after it is " +
"registered");
ok(findDebugger((dbg) => dbg.url === CHILD_WORKER_URL),
"debugger for child worker should be enumerated after it is " +
"registered");
info("Check that worker debuggers are enumerated after they are " +
"registered.");
ok(findDebugger(WORKER_URL),
"Worker debugger should be enumerated after it is registered.");
ok(findDebugger(CHILD_WORKER_URL),
"Child worker debugger should be enumerated after it is " +
"registered.");
info("Check that worker debuggers are not closed before they are " +
"unregistered.");
is(dbg.isClosed, false,
"Worker debugger should not be closed before it is unregistered.");
is(childDbg.isClosed, false,
"Child worker debugger should not be closed before it is " +
"unregistered");
info("Terminate the worker and the child worker, and wait for their " +
"debuggers to be unregistered");
promise = waitForMultiple([
waitForUnregister((dbg) => dbg.url === CHILD_WORKER_URL),
waitForUnregister((dbg) => dbg.url === PARENT_WORKER_URL),
waitForUnregister(CHILD_WORKER_URL),
waitForUnregister(WORKER_URL),
]);
worker.terminate();
dbgs = yield promise;
is(dbgs[0].isClosed, true,
"debugger for parent worker should be closed after it is " +
"unregistered");
is(dbgs[1].isClosed, true,
"debugger for child worker should be closed after it is " +
"unregistered");
assertThrows(() => dbgs[0].url,
"accessing debugger for parent worker should throw " +
"after it is closed");
assertThrows(() => dbgs[0].url,
"accessing debugger for child worker should throw after " +
"it is closed");
yield promise;
ok(!findDebugger((dbg) => dbg.url === PARENT_WORKER_URL),
"debugger for parent worker should not be enumerated after it is " +
"unregistered");
ok(!findDebugger((dbg) => dbg.url === CHILD_WORKER_URL),
"debugger for child worker should not be enumerated after it is " +
"unregistered");
info("Check that worker debuggers are not enumerated after they are " +
"unregistered.");
ok(!findDebugger(WORKER_URL),
"Worker debugger should not be enumerated after it is " +
"unregistered.");
ok(!findDebugger(CHILD_WORKER_URL),
"Child worker debugger should not be enumerated after it is " +
"unregistered.");
info("Check that worker debuggers are closed after they are " +
"unregistered.");
is(dbg.isClosed, true,
"Worker debugger should be closed after it is unregistered.");
is(childDbg.isClosed, true,
"Child worker debugger should be closed after it is unregistered.");
info("Check that property accesses on worker debuggers throws " +
"after they are closed.");
assertThrows(() => dbg.url,
"Property accesses on worker debugger should throw " +
"after it is closed.");
assertThrows(() => childDbg.url,
"Property accesses on child worker debugger should " +
"throw after it is closed.");
SimpleTest.finish();
});