зеркало из https://github.com/mozilla/gecko-dev.git
Bug 498998: Implement XHR timeout in Workers. r=sicking
This commit is contained in:
Родитель
ec9c9696c3
Коммит
621eeb9127
|
@ -26,6 +26,34 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=525816
|
|||
<script class="testbody"
|
||||
type="text/javascript"
|
||||
src="test_XHR_timeout.js"></script>
|
||||
<script type="text/javascript">
|
||||
window.addEventListener("message", function (event) {
|
||||
if (event.data == "done") {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
if (event.data == "start") {
|
||||
return;
|
||||
}
|
||||
if (event.data.type == "is") {
|
||||
SimpleTest.is(event.data.got, event.data.expected, event.data.msg);
|
||||
return;
|
||||
}
|
||||
if (event.data.type == "ok") {
|
||||
SimpleTest.ok(event.data.bool, event.data.msg);
|
||||
return;
|
||||
}
|
||||
});
|
||||
// Final test harness setup and launch.
|
||||
(function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.requestLongerTimeout(TestRequests.length);
|
||||
var msg = "This test will take approximately " + (TestRequests.length * 10)
|
||||
msg += " seconds to complete, at most.";
|
||||
document.getElementById("content").firstChild.nodeValue = msg;
|
||||
window.postMessage("start", "*");
|
||||
})();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -5,6 +5,32 @@
|
|||
request handlers.
|
||||
*/
|
||||
|
||||
var inWorker = false;
|
||||
try {
|
||||
inWorker = !(self instanceof Window);
|
||||
} catch (e) {
|
||||
inWorker = true;
|
||||
}
|
||||
|
||||
function is(got, expected, msg) {
|
||||
var obj = {};
|
||||
obj.type = "is";
|
||||
obj.got = got;
|
||||
obj.expected = expected;
|
||||
obj.msg = msg;
|
||||
|
||||
self.postMessage(obj, "*");
|
||||
}
|
||||
|
||||
function ok(bool, msg) {
|
||||
var obj = {};
|
||||
obj.type = "ok";
|
||||
obj.bool = bool;
|
||||
obj.msg = msg;
|
||||
|
||||
self.postMessage(obj, "*");
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and track results from a XMLHttpRequest with regards to timeouts.
|
||||
*
|
||||
|
@ -23,14 +49,15 @@
|
|||
* @constructor
|
||||
* @implements DOMEventListener
|
||||
*/
|
||||
function RequestTracker(id, timeLimit /*[, resetAfter, resetTo]*/) {
|
||||
function RequestTracker(async, id, timeLimit /*[, resetAfter, resetTo]*/) {
|
||||
this.async = async;
|
||||
this.id = id;
|
||||
this.timeLimit = timeLimit;
|
||||
|
||||
if (arguments.length > 2) {
|
||||
if (arguments.length > 3) {
|
||||
this.mustReset = true;
|
||||
this.resetAfter = arguments[2];
|
||||
this.resetTo = arguments[3];
|
||||
this.resetAfter = arguments[3];
|
||||
this.resetTo = arguments[4];
|
||||
}
|
||||
|
||||
this.hasFired = false;
|
||||
|
@ -42,7 +69,7 @@ RequestTracker.prototype = {
|
|||
startXHR: function() {
|
||||
var req = new XMLHttpRequest();
|
||||
this.request = req;
|
||||
req.open("GET", "file_XHR_timeout.sjs");
|
||||
req.open("GET", "file_XHR_timeout.sjs", this.async);
|
||||
req.onerror = this;
|
||||
req.onload = this;
|
||||
req.onabort = this;
|
||||
|
@ -52,7 +79,7 @@ RequestTracker.prototype = {
|
|||
|
||||
if (this.mustReset) {
|
||||
var resetTo = this.resetTo;
|
||||
window.setTimeout(function() {
|
||||
self.setTimeout(function() {
|
||||
req.timeout = resetTo;
|
||||
}, this.resetAfter);
|
||||
}
|
||||
|
@ -137,7 +164,7 @@ AbortedRequest.prototype = {
|
|||
}
|
||||
|
||||
if (!this.shouldAbort) {
|
||||
window.setTimeout(function() {
|
||||
self.setTimeout(function() {
|
||||
try {
|
||||
_this.noEventsFired();
|
||||
}
|
||||
|
@ -154,7 +181,7 @@ AbortedRequest.prototype = {
|
|||
abortReq();
|
||||
}
|
||||
else {
|
||||
window.setTimeout(abortReq, this.abortDelay);
|
||||
self.setTimeout(abortReq, this.abortDelay);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -229,22 +256,22 @@ var SyncRequestSettingTimeoutBeforeOpen = {
|
|||
|
||||
var TestRequests = [
|
||||
// Simple timeouts.
|
||||
new RequestTracker("no time out scheduled, load fires normally", 0),
|
||||
new RequestTracker("load fires normally", 5000),
|
||||
new RequestTracker("timeout hit before load", 2000),
|
||||
new RequestTracker(true, "no time out scheduled, load fires normally", 0),
|
||||
new RequestTracker(true, "load fires normally", 5000),
|
||||
new RequestTracker(true, "timeout hit before load", 2000),
|
||||
|
||||
// Timeouts reset after a certain delay.
|
||||
new RequestTracker("load fires normally with no timeout set, twice", 0, 2000, 0),
|
||||
new RequestTracker("load fires normally with same timeout set twice", 5000, 2000, 5000),
|
||||
new RequestTracker("timeout fires normally with same timeout set twice", 2000, 1000, 2000),
|
||||
new RequestTracker(true, "load fires normally with no timeout set, twice", 0, 2000, 0),
|
||||
new RequestTracker(true, "load fires normally with same timeout set twice", 5000, 2000, 5000),
|
||||
new RequestTracker(true, "timeout fires normally with same timeout set twice", 2000, 1000, 2000),
|
||||
|
||||
new RequestTracker("timeout disabled after initially set", 5000, 2000, 0),
|
||||
new RequestTracker("timeout overrides load after a delay", 5000, 1000, 2000),
|
||||
new RequestTracker("timeout enabled after initially disabled", 0, 2000, 5000),
|
||||
new RequestTracker(true, "timeout disabled after initially set", 5000, 2000, 0),
|
||||
new RequestTracker(true, "timeout overrides load after a delay", 5000, 1000, 2000),
|
||||
new RequestTracker(true, "timeout enabled after initially disabled", 0, 2000, 5000),
|
||||
|
||||
new RequestTracker("timeout set to expiring value after load fires", 5000, 4000, 1000),
|
||||
new RequestTracker("timeout set to expired value before load fires", 5000, 2000, 1000),
|
||||
new RequestTracker("timeout set to non-expiring value after timeout fires", 1000, 2000, 5000),
|
||||
new RequestTracker(true, "timeout set to expiring value after load fires", 5000, 4000, 1000),
|
||||
new RequestTracker(true, "timeout set to expired value before load fires", 5000, 2000, 1000),
|
||||
new RequestTracker(true, "timeout set to non-expiring value after timeout fires", 1000, 2000, 5000),
|
||||
|
||||
// Aborted requests.
|
||||
new AbortedRequest(false),
|
||||
|
@ -252,17 +279,34 @@ var TestRequests = [
|
|||
new AbortedRequest(true, 0),
|
||||
new AbortedRequest(true, 1000),
|
||||
new AbortedRequest(true, 5000),
|
||||
];
|
||||
|
||||
var MainThreadTestRequests = [
|
||||
// Synchronous requests.
|
||||
SyncRequestSettingTimeoutAfterOpen,
|
||||
SyncRequestSettingTimeoutBeforeOpen
|
||||
];
|
||||
|
||||
var WorkerThreadTestRequests = [
|
||||
// Simple timeouts.
|
||||
new RequestTracker(false, "no time out scheduled, load fires normally", 0),
|
||||
new RequestTracker(false, "load fires normally", 5000),
|
||||
new RequestTracker(false, "timeout hit before load", 2000),
|
||||
|
||||
// Reset timeouts don't make much sense with a sync request ...
|
||||
];
|
||||
|
||||
if (inWorker) {
|
||||
TestRequests = TestRequests.concat(WorkerThreadTestRequests);
|
||||
} else {
|
||||
TestRequests = TestRequests.concat(MainThreadTestRequests);
|
||||
}
|
||||
|
||||
// This code controls moving from one test to another.
|
||||
var TestCounter = {
|
||||
testComplete: function() {
|
||||
// Allow for the possibility there are other events coming.
|
||||
window.setTimeout(function() {
|
||||
self.setTimeout(function() {
|
||||
TestCounter.next();
|
||||
}, 5000);
|
||||
},
|
||||
|
@ -274,17 +318,13 @@ var TestCounter = {
|
|||
test.startXHR();
|
||||
}
|
||||
else {
|
||||
SimpleTest.finish();
|
||||
self.postMessage("done", "*");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Final test harness setup and launch.
|
||||
(function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.requestLongerTimeout(TestRequests.length);
|
||||
var msg = "This test will take approximately " + (TestRequests.length * 10)
|
||||
msg += " seconds to complete, at most.";
|
||||
document.getElementById("content").firstChild.nodeValue = msg;
|
||||
TestCounter.next();
|
||||
})();
|
||||
self.addEventListener("message", function (event) {
|
||||
if (event.data == "start") {
|
||||
TestCounter.next();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -435,6 +435,8 @@ ListenerManager::DispatchEvent(JSContext* aCx, JSObject* aTarget,
|
|||
|
||||
static const char sHandleEventChars[] = "handleEvent";
|
||||
|
||||
JSObject* thisObj = aTarget;
|
||||
|
||||
JSBool hasHandleEvent;
|
||||
if (!JS_HasProperty(aCx, listenerObj, sHandleEventChars, &hasHandleEvent)) {
|
||||
if (!JS_ReportPendingException(aCx)) {
|
||||
|
@ -450,11 +452,13 @@ ListenerManager::DispatchEvent(JSContext* aCx, JSObject* aTarget,
|
|||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
thisObj = listenerObj;
|
||||
}
|
||||
|
||||
jsval argv[] = { OBJECT_TO_JSVAL(aEvent) };
|
||||
jsval rval = JSVAL_VOID;
|
||||
if (!JS_CallFunctionValue(aCx, aTarget, listenerVal, ArrayLength(argv),
|
||||
if (!JS_CallFunctionValue(aCx, thisObj, listenerVal, ArrayLength(argv),
|
||||
argv, &rval)) {
|
||||
if (!JS_ReportPendingException(aCx)) {
|
||||
return false;
|
||||
|
|
|
@ -75,6 +75,7 @@ class XMLHttpRequestUpload : public events::EventTarget
|
|||
STRING_onloadstart,
|
||||
STRING_onprogress,
|
||||
STRING_onloadend,
|
||||
STRING_ontimeout,
|
||||
|
||||
STRING_COUNT
|
||||
};
|
||||
|
@ -239,6 +240,8 @@ JSPropertySpec XMLHttpRequestUpload::sProperties[] = {
|
|||
GetEventListener, SetEventListener },
|
||||
{ sEventStrings[STRING_onloadend], STRING_onloadend, PROPERTY_FLAGS,
|
||||
GetEventListener, SetEventListener },
|
||||
{ sEventStrings[STRING_ontimeout], STRING_ontimeout, PROPERTY_FLAGS,
|
||||
GetEventListener, SetEventListener },
|
||||
{ 0, 0, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -248,7 +251,8 @@ const char* const XMLHttpRequestUpload::sEventStrings[STRING_COUNT] = {
|
|||
"onload",
|
||||
"onloadstart",
|
||||
"onprogress",
|
||||
"onloadend"
|
||||
"onloadend",
|
||||
"ontimeout"
|
||||
};
|
||||
|
||||
class XMLHttpRequest
|
||||
|
@ -271,6 +275,7 @@ class XMLHttpRequest
|
|||
SLOT_withCredentials,
|
||||
SLOT_upload,
|
||||
SLOT_responseType,
|
||||
SLOT_timeout,
|
||||
|
||||
SLOT_COUNT
|
||||
};
|
||||
|
@ -292,6 +297,7 @@ class XMLHttpRequest
|
|||
STRING_onloadstart,
|
||||
STRING_onprogress,
|
||||
STRING_onloadend,
|
||||
STRING_ontimeout,
|
||||
|
||||
STRING_COUNT
|
||||
};
|
||||
|
@ -399,6 +405,7 @@ private:
|
|||
JS_SetReservedSlot(obj, SLOT_withCredentials, JSVAL_FALSE);
|
||||
JS_SetReservedSlot(obj, SLOT_upload, JSVAL_NULL);
|
||||
JS_SetReservedSlot(obj, SLOT_responseType, STRING_TO_JSVAL(textStr));
|
||||
JS_SetReservedSlot(obj, SLOT_timeout, zero);
|
||||
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
|
||||
XMLHttpRequestPrivate* priv = new XMLHttpRequestPrivate(obj, workerPrivate);
|
||||
|
@ -528,6 +535,7 @@ private:
|
|||
IMPL_SETTER(MozBackgroundRequest)
|
||||
IMPL_SETTER(WithCredentials)
|
||||
IMPL_SETTER(ResponseType)
|
||||
IMPL_SETTER(Timeout)
|
||||
|
||||
#undef IMPL_SETTER
|
||||
|
||||
|
@ -798,6 +806,8 @@ JSPropertySpec XMLHttpRequest::sProperties[] = {
|
|||
js_GetterOnlyPropertyStub },
|
||||
{ "responseType", SLOT_responseType, PROPERTY_FLAGS, GetProperty,
|
||||
SetResponseType },
|
||||
{ "timeout", SLOT_timeout, PROPERTY_FLAGS, GetProperty,
|
||||
SetTimeout },
|
||||
{ sEventStrings[STRING_onreadystatechange], STRING_onreadystatechange,
|
||||
PROPERTY_FLAGS, GetEventListener, SetEventListener },
|
||||
{ sEventStrings[STRING_onabort], STRING_onabort, PROPERTY_FLAGS,
|
||||
|
@ -812,6 +822,8 @@ JSPropertySpec XMLHttpRequest::sProperties[] = {
|
|||
GetEventListener, SetEventListener },
|
||||
{ sEventStrings[STRING_onloadend], STRING_onloadend, PROPERTY_FLAGS,
|
||||
GetEventListener, SetEventListener },
|
||||
{ sEventStrings[STRING_ontimeout], STRING_ontimeout, PROPERTY_FLAGS,
|
||||
GetEventListener, SetEventListener },
|
||||
|
||||
#undef GENERIC_READONLY_PROPERTY
|
||||
|
||||
|
@ -846,7 +858,8 @@ const char* const XMLHttpRequest::sEventStrings[STRING_COUNT] = {
|
|||
"onload",
|
||||
"onloadstart",
|
||||
"onprogress",
|
||||
"onloadend"
|
||||
"onloadend",
|
||||
"ontimeout"
|
||||
};
|
||||
|
||||
// static
|
||||
|
|
|
@ -266,13 +266,14 @@ enum
|
|||
STRING_load,
|
||||
STRING_loadstart,
|
||||
STRING_progress,
|
||||
STRING_timeout,
|
||||
STRING_readystatechange,
|
||||
STRING_loadend,
|
||||
|
||||
STRING_COUNT,
|
||||
|
||||
STRING_LAST_XHR = STRING_loadend,
|
||||
STRING_LAST_EVENTTARGET = STRING_progress
|
||||
STRING_LAST_EVENTTARGET = STRING_timeout
|
||||
};
|
||||
|
||||
JS_STATIC_ASSERT(STRING_LAST_XHR >= STRING_LAST_EVENTTARGET);
|
||||
|
@ -285,6 +286,7 @@ const char* const sEventStrings[] = {
|
|||
"load",
|
||||
"loadstart",
|
||||
"progress",
|
||||
"timeout",
|
||||
|
||||
// nsIXMLHttpRequest event types, supported only by XHR.
|
||||
"readystatechange",
|
||||
|
@ -1007,6 +1009,24 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class SetTimeoutRunnable : public WorkerThreadProxySyncRunnable
|
||||
{
|
||||
PRUint32 mTimeout;
|
||||
|
||||
public:
|
||||
SetTimeoutRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
|
||||
PRUint32 aTimeout)
|
||||
: WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy),
|
||||
mTimeout(aTimeout)
|
||||
{ }
|
||||
|
||||
int
|
||||
MainThreadRun()
|
||||
{
|
||||
return GetDOMExceptionCodeFromResult(mProxy->mXHR->SetTimeout(mTimeout));
|
||||
}
|
||||
};
|
||||
|
||||
class AbortRunnable : public WorkerThreadProxySyncRunnable
|
||||
{
|
||||
public:
|
||||
|
@ -1081,15 +1101,18 @@ class OpenRunnable : public WorkerThreadProxySyncRunnable
|
|||
bool mMultipart;
|
||||
bool mBackgroundRequest;
|
||||
bool mWithCredentials;
|
||||
PRUint32 mTimeout;
|
||||
|
||||
public:
|
||||
OpenRunnable(WorkerPrivate* aWorkerPrivate, Proxy* aProxy,
|
||||
const nsCString& aMethod, const nsCString& aURL,
|
||||
const nsString& aUser, const nsString& aPassword,
|
||||
bool aMultipart, bool aBackgroundRequest, bool aWithCredentials)
|
||||
bool aMultipart, bool aBackgroundRequest, bool aWithCredentials,
|
||||
PRUint32 aTimeout)
|
||||
: WorkerThreadProxySyncRunnable(aWorkerPrivate, aProxy), mMethod(aMethod),
|
||||
mURL(aURL), mUser(aUser), mPassword(aPassword), mMultipart(aMultipart),
|
||||
mBackgroundRequest(aBackgroundRequest), mWithCredentials(aWithCredentials)
|
||||
mBackgroundRequest(aBackgroundRequest), mWithCredentials(aWithCredentials),
|
||||
mTimeout(aTimeout)
|
||||
{ }
|
||||
|
||||
int
|
||||
|
@ -1134,6 +1157,13 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
if (mTimeout) {
|
||||
rv = mProxy->mXHR->SetTimeout(mTimeout);
|
||||
if (NS_FAILED(rv)) {
|
||||
return GetDOMExceptionCodeFromResult(rv);
|
||||
}
|
||||
}
|
||||
|
||||
mProxy->mPreviousStatusText.Truncate();
|
||||
|
||||
NS_ASSERTION(!mProxy->mInOpen, "Reentrancy is bad!");
|
||||
|
@ -1487,7 +1517,7 @@ XMLHttpRequestPrivate::XMLHttpRequestPrivate(JSObject* aObj,
|
|||
WorkerPrivate* aWorkerPrivate)
|
||||
: mJSObject(aObj), mUploadJSObject(nsnull), mWorkerPrivate(aWorkerPrivate),
|
||||
mJSObjectRooted(false), mMultipart(false), mBackgroundRequest(false),
|
||||
mWithCredentials(false), mCanceled(false)
|
||||
mWithCredentials(false), mCanceled(false), mTimeout(0)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
MOZ_COUNT_CTOR(mozilla::dom::workers::xhr::XMLHttpRequestPrivate);
|
||||
|
@ -1745,6 +1775,33 @@ XMLHttpRequestPrivate::SetResponseType(JSContext* aCx, jsval aOldVal,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
XMLHttpRequestPrivate::SetTimeout(JSContext* aCx, jsval aOldVal, jsval *aVp)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
uint32_t timeout;
|
||||
if (!JS_ValueToECMAUint32(aCx, *aVp, &timeout)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mTimeout = timeout;
|
||||
|
||||
if (!mProxy) {
|
||||
// Open may not have been called yet, in which case we'll handle the
|
||||
// timeout in OpenRunnable.
|
||||
return true;
|
||||
}
|
||||
|
||||
nsRefPtr<SetTimeoutRunnable> runnable =
|
||||
new SetTimeoutRunnable(mWorkerPrivate, mProxy, timeout);
|
||||
if (!runnable->Dispatch(aCx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
XMLHttpRequestPrivate::Abort(JSContext* aCx)
|
||||
{
|
||||
|
@ -1854,7 +1911,7 @@ XMLHttpRequestPrivate::Open(JSContext* aCx, JSString* aMethod, JSString* aURL,
|
|||
nsRefPtr<OpenRunnable> runnable =
|
||||
new OpenRunnable(mWorkerPrivate, mProxy, NS_ConvertUTF16toUTF8(method),
|
||||
NS_ConvertUTF16toUTF8(url), user, password, mMultipart,
|
||||
mBackgroundRequest, mWithCredentials);
|
||||
mBackgroundRequest, mWithCredentials, mTimeout);
|
||||
|
||||
// These were only useful before we had a proxy. From here on out changing
|
||||
// those values makes no difference.
|
||||
|
|
|
@ -67,6 +67,7 @@ class XMLHttpRequestPrivate : public events::EventTarget,
|
|||
bool mBackgroundRequest;
|
||||
bool mWithCredentials;
|
||||
bool mCanceled;
|
||||
PRUint32 mTimeout;
|
||||
|
||||
public:
|
||||
XMLHttpRequestPrivate(JSObject* aObj, WorkerPrivate* aWorkerPrivate);
|
||||
|
@ -122,6 +123,9 @@ public:
|
|||
bool
|
||||
SetResponseType(JSContext* aCx, jsval aOldVal, jsval *aVp);
|
||||
|
||||
bool
|
||||
SetTimeout(JSContext* aCx, jsval aOldVal, jsval *aVp);
|
||||
|
||||
bool
|
||||
Abort(JSContext* aCx);
|
||||
|
||||
|
|
|
@ -122,6 +122,7 @@ _TEST_FILES = \
|
|||
workersDisabled_worker.js \
|
||||
test_xhr_implicit_cancel.html \
|
||||
xhr_implicit_cancel_worker.js \
|
||||
test_xhr_timeout.html \
|
||||
$(NULL)
|
||||
|
||||
_SUBDIR_TEST_FILES = \
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=498998
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 498998</title>
|
||||
<script type="application/javascript"
|
||||
src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="application/javascript"
|
||||
src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet"
|
||||
type="text/css"
|
||||
href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=498998"
|
||||
>Mozilla Bug 498998 (Worker XMLHttpRequest timeout)</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
This test takes over 1 minute to run, probably over 2 minutes.
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="text/javascript">
|
||||
var worker = new Worker("../../../content/base/test/test_XHR_timeout.js");
|
||||
|
||||
worker.addEventListener("message", function (event) {
|
||||
if (event.data == "done") {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
if (event.data == "start") {
|
||||
return;
|
||||
}
|
||||
if (event.data.type == "is") {
|
||||
SimpleTest.is(event.data.got, event.data.expected, event.data.msg);
|
||||
return;
|
||||
}
|
||||
if (event.data.type == "ok") {
|
||||
SimpleTest.ok(event.data.bool, event.data.msg);
|
||||
return;
|
||||
}
|
||||
});
|
||||
// Final test harness setup and launch.
|
||||
(function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.requestLongerTimeout(20);
|
||||
var msg = "This test will take approximately " + (20 * 10)
|
||||
msg += " seconds to complete, at most.";
|
||||
document.getElementById("content").firstChild.nodeValue = msg;
|
||||
worker.postMessage("start");
|
||||
})();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче