| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 47f2f45 commit 7ed7ef7
10 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -962,7 +962,7 @@ the original WPT harness, see [the WPT tests README][]. | |||
| 962 | 962 | ||
| 963 | 963 | ### Class: WPTRunner | |
| 964 | 964 | ||
| 965 | - A driver class for running WPT with the WPT harness in a vm. | ||
| 965 | + A driver class for running WPT with the WPT harness in a worker thread. | ||
| 966 | 966 | ||
| 967 | 967 | See [the WPT tests README][] for details. | |
| 968 | 968 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -6,8 +6,8 @@ const fixtures = require('../common/fixtures'); | |||
| 6 | 6 | const fs = require('fs'); | |
| 7 | 7 | const fsPromises = fs.promises; | |
| 8 | 8 | const path = require('path'); | |
| 9 | - const vm = require('vm'); | ||
| 10 | 9 | const { inspect } = require('util'); | |
| 10 | + const { Worker } = require('worker_threads'); | ||
| 11 | 11 | ||
| 12 | 12 | // https://github.com/w3c/testharness.js/blob/master/testharness.js | |
| 13 | 13 | // TODO: get rid of this half-baked harness in favor of the one | |
@@ -222,7 +222,6 @@ class IntlRequirement { | |||
| 222 | 222 | ||
| 223 | 223 | const intlRequirements = new IntlRequirement(); | |
| 224 | 224 | ||
| 225 | - | ||
| 226 | 225 | class StatusLoader { | |
| 227 | 226 | /** | |
| 228 | 227 | * @param {string} path relative path of the WPT subset | |
@@ -287,10 +286,9 @@ class WPTRunner { | |||
| 287 | 286 | constructor(path) { | |
| 288 | 287 | this.path = path; | |
| 289 | 288 | this.resource = new ResourceLoader(path); | |
| 290 | - this.sandbox = null; | ||
| 291 | - this.context = null; | ||
| 292 | 289 | ||
| 293 | - this.globals = new Map(); | ||
| 290 | + this.flags = []; | ||
| 291 | + this.initScript = null; | ||
| 294 | 292 | ||
| 295 | 293 | this.status = new StatusLoader(path); | |
| 296 | 294 | this.status.load(); | |
@@ -304,28 +302,19 @@ class WPTRunner { | |||
| 304 | 302 | } | |
| 305 | 303 | ||
| 306 | 304 | /** | |
| 307 | - * Specify that certain global descriptors from the object | ||
| 308 | - * should be defined in the vm | ||
| 309 | - * @param {object} obj | ||
| 310 | - * @param {string[]} names | ||
| 305 | + * Sets the Node.js flags passed to the worker. | ||
| 306 | + * @param {Array<string>} flags | ||
| 311 | 307 | */ | |
| 312 | - copyGlobalsFromObject(obj, names) { | ||
| 313 | - for (const name of names) { | ||
| 314 | - const desc = Object.getOwnPropertyDescriptor(obj, name); | ||
| 315 | - if (!desc) { | ||
| 316 | - assert.fail(`${name} does not exist on the object`); | ||
| 317 | - } | ||
| 318 | - this.globals.set(name, desc); | ||
| 319 | - } | ||
| 308 | + setFlags(flags) { | ||
| 309 | + this.flags = flags; | ||
| 320 | 310 | } | |
| 321 | 311 | ||
| 322 | 312 | /** | |
| 323 | - * Specify that certain global descriptors should be defined in the vm | ||
| 324 | - * @param {string} name | ||
| 325 | - * @param {object} descriptor | ||
| 313 | + * Sets a script to be run in the worker before executing the tests. | ||
| 314 | + * @param {string} script | ||
| 326 | 315 | */ | |
| 327 | - defineGlobal(name, descriptor) { | ||
| 328 | - this.globals.set(name, descriptor); | ||
| 316 | + setInitScript(script) { | ||
| 317 | + this.initScript = script; | ||
| 329 | 318 | } | |
| 330 | 319 | ||
| 331 | 320 | // TODO(joyeecheung): work with the upstream to port more tests in .html | |
@@ -353,8 +342,8 @@ class WPTRunner { | |||
| 353 | 342 | const meta = spec.title = this.getMeta(content); | |
| 354 | 343 | ||
| 355 | 344 | const absolutePath = spec.getAbsolutePath(); | |
| 356 | - const context = this.generateContext(spec); | ||
| 357 | 345 | const relativePath = spec.getRelativePath(); | |
| 346 | + const harnessPath = fixtures.path('wpt', 'resources', 'testharness.js'); | ||
| 358 | 347 | const scriptsToRun = []; | |
| 359 | 348 | // Scripts specified with the `// META: script=` header | |
| 360 | 349 | if (meta.script) { | |
@@ -371,24 +360,46 @@ class WPTRunner { | |||
| 371 | 360 | filename: absolutePath | |
| 372 | 361 | }); | |
| 373 | 362 | ||
| 374 | - for (const { code, filename } of scriptsToRun) { | ||
| 375 | - try { | ||
| 376 | - vm.runInContext(code, context, { filename }); | ||
| 377 | - } catch (err) { | ||
| 378 | - this.fail( | ||
| 379 | - testFileName, | ||
| 380 | - { | ||
| 381 | - status: NODE_UNCAUGHT, | ||
| 382 | - name: 'evaluation in WPTRunner.runJsTests()', | ||
| 383 | - message: err.message, | ||
| 384 | - stack: inspect(err) | ||
| 385 | - }, | ||
| 386 | - kUncaught | ||
| 387 | - ); | ||
| 388 | - this.inProgress.delete(filename); | ||
| 389 | - break; | ||
| 363 | + const workerPath = path.join(__dirname, 'wpt/worker.js'); | ||
| 364 | + const worker = new Worker(workerPath, { | ||
| 365 | + execArgv: this.flags, | ||
| 366 | + workerData: { | ||
| 367 | + filename: testFileName, | ||
| 368 | + wptRunner: __filename, | ||
| 369 | + wptPath: this.path, | ||
| 370 | + initScript: this.initScript, | ||
| 371 | + harness: { | ||
| 372 | + code: fs.readFileSync(harnessPath, 'utf8'), | ||
| 373 | + filename: harnessPath, | ||
| 374 | + }, | ||
| 375 | + scriptsToRun, | ||
| 376 | + }, | ||
| 377 | + }); | ||
| 378 | + | ||
| 379 | + worker.on('message', (message) => { | ||
| 380 | + switch (message.type) { | ||
| 381 | + case 'result': | ||
| 382 | + return this.resultCallback(testFileName, message.result); | ||
| 383 | + case 'completion': | ||
| 384 | + return this.completionCallback(testFileName, message.status); | ||
| 385 | + default: | ||
| 386 | + throw new Error(`Unexpected message from worker: ${message.type}`); | ||
| 390 | 387 | } | |
| 391 | - } | ||
| 388 | + }); | ||
| 389 | + | ||
| 390 | + worker.on('error', (err) => { | ||
| 391 | + this.fail( | ||
| 392 | + testFileName, | ||
| 393 | + { | ||
| 394 | + status: NODE_UNCAUGHT, | ||
| 395 | + name: 'evaluation in WPTRunner.runJsTests()', | ||
| 396 | + message: err.message, | ||
| 397 | + stack: inspect(err) | ||
| 398 | + }, | ||
| 399 | + kUncaught | ||
| 400 | + ); | ||
| 401 | + this.inProgress.delete(testFileName); | ||
| 402 | + }); | ||
| 392 | 403 | } | |
| 393 | 404 | ||
| 394 | 405 | process.on('exit', () => { | |
@@ -430,56 +441,6 @@ class WPTRunner { | |||
| 430 | 441 | }); | |
| 431 | 442 | } | |
| 432 | 443 | ||
| 433 | - mock(testfile) { | ||
| 434 | - const resource = this.resource; | ||
| 435 | - const result = { | ||
| 436 | - // This is a mock, because at the moment fetch is not implemented | ||
| 437 | - // in Node.js, but some tests and harness depend on this to pull | ||
| 438 | - // resources. | ||
| 439 | - fetch(file) { | ||
| 440 | - return resource.read(testfile, file, true); | ||
| 441 | - }, | ||
| 442 | - GLOBAL: { | ||
| 443 | - isWindow() { return false; } | ||
| 444 | - }, | ||
| 445 | - Object | ||
| 446 | - }; | ||
| 447 | - | ||
| 448 | - return result; | ||
| 449 | - } | ||
| 450 | - | ||
| 451 | - // Note: this is how our global space for the WPT test should look like | ||
| 452 | - getSandbox(filename) { | ||
| 453 | - const result = this.mock(filename); | ||
| 454 | - for (const [name, desc] of this.globals) { | ||
| 455 | - Object.defineProperty(result, name, desc); | ||
| 456 | - } | ||
| 457 | - return result; | ||
| 458 | - } | ||
| 459 | - | ||
| 460 | - generateContext(test) { | ||
| 461 | - const filename = test.filename; | ||
| 462 | - const sandbox = this.sandbox = this.getSandbox(test.getRelativePath()); | ||
| 463 | - const context = this.context = vm.createContext(sandbox); | ||
| 464 | - | ||
| 465 | - const harnessPath = fixtures.path('wpt', 'resources', 'testharness.js'); | ||
| 466 | - const harness = fs.readFileSync(harnessPath, 'utf8'); | ||
| 467 | - vm.runInContext(harness, context, { | ||
| 468 | - filename: harnessPath | ||
| 469 | - }); | ||
| 470 | - | ||
| 471 | - sandbox.add_result_callback( | ||
| 472 | - this.resultCallback.bind(this, filename) | ||
| 473 | - ); | ||
| 474 | - sandbox.add_completion_callback( | ||
| 475 | - this.completionCallback.bind(this, filename) | ||
| 476 | - ); | ||
| 477 | - sandbox.self = sandbox; | ||
| 478 | - // TODO(joyeecheung): we are not a window - work with the upstream to | ||
| 479 | - // add a new scope for us. | ||
| 480 | - return context; | ||
| 481 | - } | ||
| 482 | - | ||
| 483 | 444 | getTestTitle(filename) { | |
| 484 | 445 | const spec = this.specMap.get(filename); | |
| 485 | 446 | const title = spec.meta && spec.meta.title; | |
@@ -524,9 +485,9 @@ class WPTRunner { | |||
| 524 | 485 | * Report the status of each WPT test (one per file) | |
| 525 | 486 | * | |
| 526 | 487 | * @param {string} filename | |
| 527 | - * @param {Test[]} test The Test objects returned by WPT harness | ||
| 488 | + * @param {object} harnessStatus - The status object returned by WPT harness. | ||
| 528 | 489 | */ | |
| 529 | - completionCallback(filename, tests, harnessStatus) { | ||
| 490 | + completionCallback(filename, harnessStatus) { | ||
| 530 | 491 | // Treat it like a test case failure | |
| 531 | 492 | if (harnessStatus.status === 2) { | |
| 532 | 493 | const title = this.getTestTitle(filename); | |
@@ -644,5 +605,6 @@ class WPTRunner { | |||
| 644 | 605 | ||
| 645 | 606 | module.exports = { | |
| 646 | 607 | harness: harnessMock, | |
| 608 | + ResourceLoader, | ||
| 647 | 609 | WPTRunner | |
| 648 | 610 | }; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,55 @@ | |||
| 1 | + /* eslint-disable node-core/required-modules,node-core/require-common-first */ | ||
| 2 | + | ||
| 3 | + 'use strict'; | ||
| 4 | + | ||
| 5 | + const { runInThisContext } = require('vm'); | ||
| 6 | + const { parentPort, workerData } = require('worker_threads'); | ||
| 7 | + | ||
| 8 | + const { ResourceLoader } = require(workerData.wptRunner); | ||
| 9 | + const resource = new ResourceLoader(workerData.wptPath); | ||
| 10 | + | ||
| 11 | + global.self = global; | ||
| 12 | + global.GLOBAL = { | ||
| 13 | + isWindow() { return false; } | ||
| 14 | + }; | ||
| 15 | + global.require = require; | ||
| 16 | + | ||
| 17 | + // This is a mock, because at the moment fetch is not implemented | ||
| 18 | + // in Node.js, but some tests and harness depend on this to pull | ||
| 19 | + // resources. | ||
| 20 | + global.fetch = function fetch(file) { | ||
| 21 | + return resource.read(workerData.filename, file, true); | ||
| 22 | + }; | ||
| 23 | + | ||
| 24 | + if (workerData.initScript) { | ||
| 25 | + runInThisContext(workerData.initScript); | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + runInThisContext(workerData.harness.code, { | ||
| 29 | + filename: workerData.harness.filename | ||
| 30 | + }); | ||
| 31 | + | ||
| 32 | + // eslint-disable-next-line no-undef | ||
| 33 | + add_result_callback((result) => { | ||
| 34 | + parentPort.postMessage({ | ||
| 35 | + type: 'result', | ||
| 36 | + result: { | ||
| 37 | + status: result.status, | ||
| 38 | + name: result.name, | ||
| 39 | + message: result.message, | ||
| 40 | + stack: result.stack, | ||
| 41 | + }, | ||
| 42 | + }); | ||
| 43 | + }); | ||
| 44 | + | ||
| 45 | + // eslint-disable-next-line no-undef | ||
| 46 | + add_completion_callback((_, status) => { | ||
| 47 | + parentPort.postMessage({ | ||
| 48 | + type: 'completion', | ||
| 49 | + status, | ||
| 50 | + }); | ||
| 51 | + }); | ||
| 52 | + | ||
| 53 | + for (const scriptToRun of workerData.scriptsToRun) { | ||
| 54 | + runInThisContext(scriptToRun.code, { filename: scriptToRun.filename }); | ||
| 55 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -45,23 +45,20 @@ For example, for the URL tests, add a file `test/wpt/test-url.js`: | |||
| 45 | 45 | ```js | |
| 46 | 46 | 'use strict'; | |
| 47 | 47 | ||
| 48 | - // This flag is required by the WPT Runner to patch the internals | ||
| 49 | - // for the tests to run in a vm. | ||
| 50 | - // Flags: --expose-internals | ||
| 51 | - | ||
| 52 | 48 | require('../common'); | |
| 53 | 49 | const { WPTRunner } = require('../common/wpt'); | |
| 54 | 50 | ||
| 55 | 51 | const runner = new WPTRunner('url'); | |
| 56 | 52 | ||
| 57 | - // Copy global descriptors from the global object | ||
| 58 | - runner.copyGlobalsFromObject(global, ['URL', 'URLSearchParams']); | ||
| 59 | - // Define any additional globals with descriptors | ||
| 60 | - runner.defineGlobal('DOMException', { | ||
| 61 | - get() { | ||
| 62 | - return require('internal/domexception'); | ||
| 63 | - } | ||
| 64 | - }); | ||
| 53 | + // Set Node.js flags required for the tests. | ||
| 54 | + runner.setFlags(['--expose-internals']); | ||
| 55 | + | ||
| 56 | + // Set a script that will be executed in the worker before running the tests. | ||
| 57 | + runner.setInitScript(` | ||
| 58 | + const { internalBinding } = require('internal/test/binding'); | ||
| 59 | + const { DOMException } = internalBinding('messaging'); | ||
| 60 | + global.DOMException = DOMException; | ||
| 61 | + `); | ||
| 65 | 62 | ||
| 66 | 63 | runner.runJsTests(); | |
| 67 | 64 | ``` | |
@@ -82,7 +79,7 @@ To run a specific test in WPT, for example, `url/url-searchparams.any.js`, | |||
| 82 | 79 | pass the file name as argument to the corresponding test driver: | |
| 83 | 80 | ||
| 84 | 81 | ```text | |
| 85 | - node --expose-internals test/wpt/test-url.js url-searchparams.any.js | ||
| 82 | + node test/wpt/test-url.js url-searchparams.any.js | ||
| 86 | 83 | ``` | |
| 87 | 84 | ||
| 88 | 85 | If there are any failures, update the corresponding status file | |
@@ -138,9 +135,9 @@ loads: | |||
| 138 | 135 | * Status file (for example, `test/wpt/status/url.json` for `url`) | |
| 139 | 136 | * The WPT harness | |
| 140 | 137 | ||
| 141 | - Then, for each test, it creates a vm with the globals and mocks, | ||
| 138 | + Then, for each test, it creates a worker thread with the globals and mocks, | ||
| 142 | 139 | sets up the harness result hooks, loads the metadata in the test (including | |
| 143 | - loading extra resources), and runs all the tests in that vm, | ||
| 140 | + loading extra resources), and runs all the tests in that worker thread, | ||
| 144 | 141 | skipping tests that cannot be run because of lack of dependency or | |
| 145 | 142 | expected failures. | |
| 146 | 143 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -4,7 +4,4 @@ const { WPTRunner } = require('../common/wpt'); | |||
| 4 | 4 | ||
| 5 | 5 | const runner = new WPTRunner('console'); | |
| 6 | 6 | ||
| 7 | - // Copy global descriptors from the global object | ||
| 8 | - runner.copyGlobalsFromObject(global, ['console']); | ||
| 9 | - | ||
| 10 | 7 | runner.runJsTests(); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,16 +1,11 @@ | |||
| 1 | 1 | 'use strict'; | |
| 2 | 2 | require('../common'); | |
| 3 | - const { MessageChannel } = require('worker_threads'); | ||
| 4 | 3 | const { WPTRunner } = require('../common/wpt'); | |
| 5 | 4 | const runner = new WPTRunner('encoding'); | |
| 6 | 5 | ||
| 7 | - // Copy global descriptors from the global object | ||
| 8 | - runner.copyGlobalsFromObject(global, ['TextDecoder', 'TextEncoder']); | ||
| 9 | - | ||
| 10 | - runner.defineGlobal('MessageChannel', { | ||
| 11 | - get() { | ||
| 12 | - return MessageChannel; | ||
| 13 | - } | ||
| 14 | - }); | ||
| 6 | + runner.setInitScript(` | ||
| 7 | + const { MessageChannel } = require('worker_threads'); | ||
| 8 | + global.MessageChannel = MessageChannel; | ||
| 9 | + `); | ||
| 15 | 10 | ||
| 16 | 11 | runner.runJsTests(); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,27 +1,14 @@ | |||
| 1 | 1 | 'use strict'; | |
| 2 | 2 | ||
| 3 | - // Flags: --expose-internals | ||
| 4 | - | ||
| 5 | 3 | require('../common'); | |
| 6 | 4 | const { WPTRunner } = require('../common/wpt'); | |
| 7 | - const { performance, PerformanceObserver } = require('perf_hooks'); | ||
| 8 | 5 | ||
| 9 | 6 | const runner = new WPTRunner('hr-time'); | |
| 10 | 7 | ||
| 11 | - runner.copyGlobalsFromObject(global, [ | ||
| 12 | - 'setInterval', | ||
| 13 | - 'clearInterval', | ||
| 14 | - 'setTimeout', | ||
| 15 | - 'clearTimeout' | ||
| 16 | - ]); | ||
| 17 | - | ||
| 18 | - runner.defineGlobal('performance', { | ||
| 19 | - get() { | ||
| 20 | - return performance; | ||
| 21 | - } | ||
| 22 | - }); | ||
| 23 | - runner.defineGlobal('PerformanceObserver', { | ||
| 24 | - value: PerformanceObserver | ||
| 25 | - }); | ||
| 8 | + runner.setInitScript(` | ||
| 9 | + const { performance, PerformanceObserver } = require('perf_hooks'); | ||
| 10 | + global.performance = performance; | ||
| 11 | + global.PerformanceObserver = PerformanceObserver; | ||
| 12 | + `); | ||
| 26 | 13 | ||
| 27 | 14 | runner.runJsTests(); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments