mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-26 12:20:56 +00:00
Bug 1684139 - Adding mozilla specific wpt for timer nesting level in workers r=dom-worker-reviewers,asuth
This patch is developed from D104136#3396152. This patch creates WorkerTestUtils.webidl under dom/webidl for testing workers with internal APIs. These APIs are exposed to workers only and controlled by dom.workers.testing.enabled pref. This patch creates a Mozilla-specific web-platform test, testing/web-platform/mozilla/test/workers/worker_timer_nesting_level.html, to test the timer nesting level implementation for workers. To simplify the test implementation, this patch does not implement the webidl under dom/chrome-webidl/ suggested by D104136#3396152. Depends on D104136 Differential Revision: https://phabricator.services.mozilla.com/D105332
This commit is contained in:
parent
9d5c5e771a
commit
53093e432c
10
dom/webidl/WorkerTestUtils.webidl
Normal file
10
dom/webidl/WorkerTestUtils.webidl
Normal file
@ -0,0 +1,10 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
[Exposed=Worker, Pref="dom.workers.testing.enabled"]
|
||||
namespace WorkerTestUtils {
|
||||
[Throws]
|
||||
unsigned long currentTimerNestingLevel();
|
||||
};
|
||||
|
@ -977,6 +977,7 @@ WEBIDL_FILES = [
|
||||
"WorkerGlobalScope.webidl",
|
||||
"WorkerLocation.webidl",
|
||||
"WorkerNavigator.webidl",
|
||||
"WorkerTestUtils.webidl",
|
||||
"Worklet.webidl",
|
||||
"WorkletGlobalScope.webidl",
|
||||
"XMLDocument.webidl",
|
||||
|
@ -971,6 +971,11 @@ class WorkerPrivate : public RelativeTimeline {
|
||||
|
||||
void SetCCCollectedAnything(bool collectedAnything);
|
||||
|
||||
uint32_t GetCurrentTimerNestingLevel() const {
|
||||
auto data = mWorkerThreadAccessible.Access();
|
||||
return data->mCurrentTimerNestingLevel;
|
||||
}
|
||||
|
||||
private:
|
||||
WorkerPrivate(
|
||||
WorkerPrivate* aParent, const nsAString& aScriptURL, bool aIsChromeWorker,
|
||||
|
23
dom/workers/WorkerTestUtils.cpp
Normal file
23
dom/workers/WorkerTestUtils.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "mozilla/dom/WorkerPrivate.h"
|
||||
#include "mozilla/dom/WorkerTestUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
uint32_t WorkerTestUtils::CurrentTimerNestingLevel(const GlobalObject& aGlobal,
|
||||
ErrorResult& aErr) {
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
return worker->GetCurrentTimerNestingLevel();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
40
dom/workers/WorkerTestUtils.h
Normal file
40
dom/workers/WorkerTestUtils.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_WorkerTestUtils__
|
||||
#define mozilla_dom_WorkerTestUtils__
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
|
||||
/**
|
||||
* dom/webidl/WorkerTestUtils.webidl defines APIs to expose worker's internal
|
||||
* status for glass-box testing. The APIs are only exposed to Workers with prefs
|
||||
* dom.workers.testing.enabled.
|
||||
*
|
||||
* WorkerTestUtils is the implementation of dom/webidl/WorkerTestUtils.webidl
|
||||
*/
|
||||
class WorkerTestUtils final {
|
||||
public:
|
||||
/**
|
||||
* Expose the worker's current timer nesting level.
|
||||
*
|
||||
* The worker's current timer nesting level means the executing timer
|
||||
* handler's timer nesting level. When there is no executing timer handler, 0
|
||||
* should be returned by this API. The maximum timer nesting level is 5.
|
||||
*
|
||||
* https://html.spec.whatwg.org/#timer-initialisation-steps
|
||||
*/
|
||||
static uint32_t CurrentTimerNestingLevel(const GlobalObject&,
|
||||
ErrorResult& aErr);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
#endif
|
@ -26,6 +26,7 @@ EXPORTS.mozilla.dom += [
|
||||
"WorkerRunnable.h",
|
||||
"WorkerScope.h",
|
||||
"WorkerStatus.h",
|
||||
"WorkerTestUtils.h",
|
||||
]
|
||||
|
||||
# Private stuff.
|
||||
@ -65,6 +66,7 @@ UNIFIED_SOURCES += [
|
||||
"WorkerRef.cpp",
|
||||
"WorkerRunnable.cpp",
|
||||
"WorkerScope.cpp",
|
||||
"WorkerTestUtils.cpp",
|
||||
"WorkerThread.cpp",
|
||||
]
|
||||
|
||||
|
@ -3483,6 +3483,11 @@
|
||||
type: RelaxedAtomicBool
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
- name: dom.workers.testing.enabled
|
||||
type: RelaxedAtomicBool
|
||||
value: false
|
||||
mirror: always
|
||||
|
||||
- name: dom.worklet.enabled
|
||||
type: bool
|
||||
|
1
testing/web-platform/mozilla/meta/workers/__dir__.ini
Normal file
1
testing/web-platform/mozilla/meta/workers/__dir__.ini
Normal file
@ -0,0 +1 @@
|
||||
prefs: [dom.workers.testing.enabled:true]
|
100
testing/web-platform/mozilla/tests/workers/resources/worker.js
Normal file
100
testing/web-platform/mozilla/tests/workers/resources/worker.js
Normal file
@ -0,0 +1,100 @@
|
||||
const maxNestingLevel = 5;
|
||||
let expectedNestingLevel = 1;
|
||||
let timer;
|
||||
let isInterval = false;
|
||||
let stopTimer = false;
|
||||
let lastCall = 0;
|
||||
let testStage = "ScriptLoaded";
|
||||
|
||||
let timerCallback = async () => {
|
||||
let now = Date.now();
|
||||
if (WorkerTestUtils.currentTimerNestingLevel() !== expectedNestingLevel) {
|
||||
postMessage({
|
||||
stage: testStage,
|
||||
status: "FAIL",
|
||||
msg: `current timer nesting level is ${WorkerTestUtils.currentTimerNestingLevel()}, expected ${expectedNestingLevel}`,
|
||||
});
|
||||
if (isInterval) {
|
||||
clearInterval(timer);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!stopTimer) {
|
||||
if (expectedNestingLevel === maxNestingLevel) {
|
||||
stopTimer = true;
|
||||
} else {
|
||||
expectedNestingLevel = expectedNestingLevel + 1;
|
||||
}
|
||||
if (!isInterval) {
|
||||
setTimeout(timerCallback, 0);
|
||||
}
|
||||
lastCall = now;
|
||||
return;
|
||||
}
|
||||
|
||||
await Promise.resolve(true).then(() => {
|
||||
if (WorkerTestUtils.currentTimerNestingLevel() !== expectedNestingLevel) {
|
||||
postMessage({
|
||||
stage: testStage,
|
||||
status: "FAIL",
|
||||
msg: `Timer nesting level should be in effect for immediately resolved micro-tasks`,
|
||||
});
|
||||
}
|
||||
});
|
||||
if (now - lastCall < 3) {
|
||||
postMessage({
|
||||
stage: testStage,
|
||||
status: "FAIL",
|
||||
msg: `timer nesting level reaches the max nesting level(${maxNestingLevel}), interval time should be clamped at least 3, but got ${now -
|
||||
lastCall}`,
|
||||
});
|
||||
} else {
|
||||
postMessage({ stage: testStage, status: "PASS", msg: "" });
|
||||
}
|
||||
stopTimer = false;
|
||||
if (isInterval) {
|
||||
clearInterval(timer);
|
||||
}
|
||||
};
|
||||
|
||||
onmessage = async e => {
|
||||
testStage = e.data;
|
||||
switch (e.data) {
|
||||
case "CheckInitialValue":
|
||||
if (WorkerTestUtils.currentTimerNestingLevel() === 0) {
|
||||
postMessage({ stage: testStage, status: "PASS", msg: "" });
|
||||
} else {
|
||||
postMessage({
|
||||
stage: testStage,
|
||||
status: "FAIL",
|
||||
msg: `current timer nesting level should be 0(${WorkerTestUtils.currentTimerNestingLevel()}) after top level script loaded.`,
|
||||
});
|
||||
}
|
||||
break;
|
||||
case "TestSetInterval":
|
||||
expectedNestingLevel = 1;
|
||||
isInterval = true;
|
||||
timer = setInterval(timerCallback, 0);
|
||||
break;
|
||||
case "TestSetTimeout":
|
||||
expectedNestingLevel = 1;
|
||||
isInterval = false;
|
||||
setTimeout(timerCallback, 0);
|
||||
break;
|
||||
case "CheckNoTimer":
|
||||
if (WorkerTestUtils.currentTimerNestingLevel() === 0) {
|
||||
postMessage({ stage: testStage, status: "PASS", msg: "" });
|
||||
} else {
|
||||
postMessage({
|
||||
stage: testStage,
|
||||
status: "FAIL",
|
||||
msg: `current timer nesting level should be 0(${WorkerTestUtils.currentTimerNestingLevel()}) when there is no timer in queue.`,
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
postMessage({ stage: testStage, status: "PASS" });
|
@ -0,0 +1,52 @@
|
||||
<!DOCTYPE html>
|
||||
<title>Worker: Timer Nesting Level</title>
|
||||
<Script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<script>
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* This test includes following four test stages.
|
||||
* 1. CheckInitialValue: Checking the initial value of worker's current timer
|
||||
* nesting level after the worker's top level script is loaded. The result
|
||||
* is expected as 0.
|
||||
* 2. TestSetInterval: Checking the worker's current timer nesting level with
|
||||
* setInterval with following steps
|
||||
* 1. call setInterval(callback, 0) to create a repeating timer.
|
||||
* 2. checking the current timer nesting level in the callback. The value
|
||||
* should increase every time executing the callback until it reaches the
|
||||
* maximun nesting level(5).
|
||||
* 3. Checking the worker's current timer nesting level with immediately
|
||||
* resolved promise.
|
||||
* 4. Checking the the time duration between two callback launching.
|
||||
* 3. TestSetTimeout: Checking the worker's current timer nesting level with
|
||||
* setTimeout. This stage has similar test steps with TestSetInterval.
|
||||
* The difference is this stage using the recursive setTimeout to accumulate
|
||||
* the timer nesting level.
|
||||
* 4. CheckNoTimer: Checking the situation which the worker has no pending
|
||||
* timer. The result is expected as 0.
|
||||
*/
|
||||
|
||||
let testStages = ["CheckInitialValue",
|
||||
"TestSetInterval",
|
||||
"TestSetTimeout",
|
||||
"CheckNoTimer"];
|
||||
|
||||
promise_test(async function(t) {
|
||||
let result = await new Promise( (resolve, reject) => {
|
||||
let worker = new Worker("resources/worker.js");
|
||||
worker.onmessage = (e) => {
|
||||
if (e.data.status === "FAIL") {
|
||||
resolve(e.data);
|
||||
return;
|
||||
}
|
||||
if (testStages.length !== 0) {
|
||||
worker.postMessage(testStages.shift());
|
||||
} else {
|
||||
resolve({status: "PASS", msg: "Timer nesting level for workers"});
|
||||
}
|
||||
};
|
||||
});
|
||||
assert_true(result.status === "PASS", result.msg);
|
||||
}, 'Worker timer nesting level ');
|
||||
</script>
|
Loading…
x
Reference in New Issue
Block a user