Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 3d89331

Browse filesBrowse files
joyeecheungaduh95
authored andcommitted
test_runner: use module.registerHooks in module mocks
Migrate away from module.register(). This no longer needs to deal with the worker synchronization. PR-URL: #60326 Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com> Reviewed-By: Chemi Atlow <chemi@atlow.co.il> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com>
1 parent 063fbd8 commit 3d89331
Copy full SHA for 3d89331

File tree

Expand file treeCollapse file tree

5 files changed

+54
-190
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

5 files changed

+54
-190
lines changed
Open diff view settings
Collapse file

‎lib/internal/test_runner/coverage.js‎

Copy file name to clipboardExpand all lines: lib/internal/test_runner/coverage.js
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const {
3737
},
3838
} = require('internal/errors');
3939
const { matchGlobPattern } = require('internal/fs/glob');
40-
const { kMockSearchParam } = require('internal/test_runner/mock/mock');
40+
const { constants: { kMockSearchParam } } = require('internal/test_runner/mock/loader');
4141

4242
const kCoverageFileRegex = /^coverage-(\d+)-(\d{13})-(\d+)\.json$/;
4343
const kIgnoreRegex = /\/\* node:coverage ignore next (?<count>\d+ )?\*\//;
Collapse file

‎lib/internal/test_runner/mock/loader.js‎

Copy file name to clipboardExpand all lines: lib/internal/test_runner/mock/loader.js
+20-70Lines changed: 20 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,24 @@
11
'use strict';
22
const {
3-
AtomicsNotify,
4-
AtomicsStore,
53
JSONStringify,
64
SafeMap,
75
} = primordials;
8-
const {
9-
kBadExportsMessage,
10-
kMockSearchParam,
11-
kMockSuccess,
12-
kMockExists,
13-
kMockUnknownMessage,
14-
} = require('internal/test_runner/mock/mock');
6+
7+
const kMockSearchParam = 'node-test-mock';
8+
const kBadExportsMessage = 'Cannot create mock because named exports ' +
9+
'cannot be applied to the provided default export.';
10+
1511
const { URL, URLParse } = require('internal/url');
1612
let debug = require('internal/util/debuglog').debuglog('test_runner', (fn) => {
1713
debug = fn;
1814
});
1915

20-
// TODO(cjihrig): The mocks need to be thread aware because the exports are
21-
// evaluated on the thread that creates the mock. Before marking this API as
22-
// stable, one of the following issues needs to be implemented:
23-
// https://github.com/nodejs/node/issues/49472
24-
// or https://github.com/nodejs/node/issues/52219
25-
2616
const mocks = new SafeMap();
2717

28-
async function initialize(data) {
29-
data?.port.on('message', ({ type, payload }) => {
30-
debug('mock loader received message type "%s" with payload %o', type, payload);
31-
32-
if (type === 'node:test:register') {
33-
const { baseURL } = payload;
34-
const mock = mocks.get(baseURL);
35-
36-
if (mock?.active) {
37-
debug('already mocking "%s"', baseURL);
38-
sendAck(payload.ack, kMockExists);
39-
return;
40-
}
41-
42-
const localVersion = mock?.localVersion ?? 0;
43-
44-
debug('new mock version %d for "%s"', localVersion, baseURL);
45-
mocks.set(baseURL, {
46-
__proto__: null,
47-
active: true,
48-
cache: payload.cache,
49-
exportNames: payload.exportNames,
50-
format: payload.format,
51-
hasDefaultExport: payload.hasDefaultExport,
52-
localVersion,
53-
url: baseURL,
54-
});
55-
sendAck(payload.ack);
56-
} else if (type === 'node:test:unregister') {
57-
const mock = mocks.get(payload.baseURL);
58-
59-
if (mock !== undefined) {
60-
mock.active = false;
61-
mock.localVersion++;
62-
}
63-
64-
sendAck(payload.ack);
65-
} else {
66-
sendAck(payload.ack, kMockUnknownMessage);
67-
}
68-
});
69-
}
70-
71-
async function resolve(specifier, context, nextResolve) {
18+
function resolve(specifier, context, nextResolve) {
7219
debug('resolve hook entry, specifier = "%s", context = %o', specifier, context);
7320

74-
const nextResolveResult = await nextResolve(specifier, context);
21+
const nextResolveResult = nextResolve(specifier, context);
7522
const mockSpecifier = nextResolveResult.url;
7623

7724
const mock = mocks.get(mockSpecifier);
@@ -95,7 +42,7 @@ async function resolve(specifier, context, nextResolve) {
9542
return { __proto__: null, url: href, format: nextResolveResult.format };
9643
}
9744

98-
async function load(url, context, nextLoad) {
45+
function load(url, context, nextLoad) {
9946
debug('load hook entry, url = "%s", context = %o', url, context);
10047
const parsedURL = URLParse(url);
10148
if (parsedURL) {
@@ -105,7 +52,7 @@ async function load(url, context, nextLoad) {
10552
const baseURL = parsedURL ? parsedURL.href : url;
10653
const mock = mocks.get(baseURL);
10754

108-
const original = await nextLoad(url, context);
55+
const original = nextLoad(url, context);
10956
debug('load hook, mock = %o', mock);
11057
if (mock?.active !== true) {
11158
return original;
@@ -130,14 +77,14 @@ async function load(url, context, nextLoad) {
13077
__proto__: null,
13178
format,
13279
shortCircuit: true,
133-
source: await createSourceFromMock(mock, format),
80+
source: createSourceFromMock(mock, format),
13481
};
13582

13683
debug('load hook finished, result = %o', result);
13784
return result;
13885
}
13986

140-
async function createSourceFromMock(mock, format) {
87+
function createSourceFromMock(mock, format) {
14188
// Create mock implementation from provided exports.
14289
const { exportNames, hasDefaultExport, url } = mock;
14390
const useESM = format === 'module' || format === 'module-typescript';
@@ -196,9 +143,12 @@ if (module.exports === null || typeof module.exports !== 'object') {
196143
return source;
197144
}
198145

199-
function sendAck(buf, status = kMockSuccess) {
200-
AtomicsStore(buf, 0, status);
201-
AtomicsNotify(buf, 0);
202-
}
203-
204-
module.exports = { initialize, load, resolve };
146+
module.exports = {
147+
hooks: { __proto__: null, load, resolve },
148+
mocks,
149+
constants: {
150+
__proto__: null,
151+
kBadExportsMessage,
152+
kMockSearchParam,
153+
},
154+
};
Collapse file

‎lib/internal/test_runner/mock/mock.js‎

Copy file name to clipboardExpand all lines: lib/internal/test_runner/mock/mock.js
+33-59Lines changed: 33 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,9 @@
22
const {
33
ArrayPrototypePush,
44
ArrayPrototypeSlice,
5-
AtomicsStore,
6-
AtomicsWait,
75
Error,
86
FunctionPrototypeBind,
97
FunctionPrototypeCall,
10-
Int32Array,
118
ObjectDefineProperty,
129
ObjectGetOwnPropertyDescriptor,
1310
ObjectGetPrototypeOf,
@@ -19,9 +16,6 @@ const {
1916
SafeMap,
2017
StringPrototypeSlice,
2118
StringPrototypeStartsWith,
22-
globalThis: {
23-
SharedArrayBuffer,
24-
},
2519
} = primordials;
2620
const {
2721
codes: {
@@ -54,19 +48,10 @@ const {
5448
validateOneOf,
5549
} = require('internal/validators');
5650
const { MockTimers } = require('internal/test_runner/mock/mock_timers');
57-
const { strictEqual, notStrictEqual } = require('assert');
5851
const { Module } = require('internal/modules/cjs/loader');
59-
const { MessageChannel } = require('worker_threads');
6052
const { _load, _nodeModulePaths, _resolveFilename, isBuiltin } = Module;
6153
function kDefaultFunction() {}
6254
const enableModuleMocking = getOptionValue('--experimental-test-module-mocks');
63-
const kMockSearchParam = 'node-test-mock';
64-
const kMockSuccess = 1;
65-
const kMockExists = 2;
66-
const kMockUnknownMessage = 3;
67-
const kWaitTimeout = 5_000;
68-
const kBadExportsMessage = 'Cannot create mock because named exports ' +
69-
'cannot be applied to the provided default export.';
7055
const kSupportedFormats = [
7156
'builtin',
7257
'commonjs-typescript',
@@ -76,6 +61,11 @@ const kSupportedFormats = [
7661
'module',
7762
];
7863
let sharedModuleState;
64+
const {
65+
hooks: mockHooks,
66+
mocks,
67+
constants: { kBadExportsMessage, kMockSearchParam },
68+
} = require('internal/test_runner/mock/loader');
7969

8070
class MockFunctionContext {
8171
#calls;
@@ -201,8 +191,8 @@ class MockModuleContext {
201191
hasDefaultExport,
202192
namedExports,
203193
sharedState,
194+
specifier,
204195
}) {
205-
const ack = new Int32Array(new SharedArrayBuffer(4));
206196
const config = {
207197
__proto__: null,
208198
cache,
@@ -218,28 +208,36 @@ class MockModuleContext {
218208
this.#sharedState = sharedState;
219209
this.#restore = {
220210
__proto__: null,
221-
ack,
222211
baseURL,
223212
cached: fullPath in Module._cache,
224213
format,
225214
fullPath,
226215
value: Module._cache[fullPath],
227216
};
228217

229-
sharedState.loaderPort.postMessage({
230-
__proto__: null,
231-
type: 'node:test:register',
232-
payload: {
218+
const mock = mocks.get(baseURL);
219+
220+
if (mock?.active) {
221+
debug('already mocking "%s"', baseURL);
222+
throw new ERR_INVALID_STATE(
223+
`Cannot mock '${specifier}'. The module is already mocked.`,
224+
);
225+
} else {
226+
const localVersion = mock?.localVersion ?? 0;
227+
228+
debug('new mock version %d for "%s"', localVersion, baseURL);
229+
mocks.set(baseURL, {
233230
__proto__: null,
234-
ack,
235-
baseURL,
231+
url: baseURL,
236232
cache,
237233
exportNames: ObjectKeys(namedExports),
238234
hasDefaultExport,
239235
format,
240-
},
241-
});
242-
waitForAck(ack);
236+
localVersion,
237+
active: true,
238+
});
239+
}
240+
243241
delete Module._cache[fullPath];
244242
sharedState.mockExports.set(baseURL, {
245243
__proto__: null,
@@ -261,17 +259,12 @@ class MockModuleContext {
261259
Module._cache[this.#restore.fullPath] = this.#restore.value;
262260
}
263261

264-
AtomicsStore(this.#restore.ack, 0, 0);
265-
this.#sharedState.loaderPort.postMessage({
266-
__proto__: null,
267-
type: 'node:test:unregister',
268-
payload: {
269-
__proto__: null,
270-
ack: this.#restore.ack,
271-
baseURL: this.#restore.baseURL,
272-
},
273-
});
274-
waitForAck(this.#restore.ack);
262+
const mock = mocks.get(this.#restore.baseURL);
263+
264+
if (mock !== undefined) {
265+
mock.active = false;
266+
mock.localVersion++;
267+
}
275268

276269
this.#sharedState.mockMap.delete(this.#restore.baseURL);
277270
this.#sharedState.mockMap.delete(this.#restore.fullPath);
@@ -654,7 +647,7 @@ class MockTracker {
654647
const hasFileProtocol = StringPrototypeStartsWith(filename, 'file://');
655648
const caller = hasFileProtocol ? filename : pathToFileURL(filename).href;
656649
const { format, url } = sharedState.moduleLoader.resolveSync(
657-
mockSpecifier, caller, null,
650+
mockSpecifier, caller, kEmptyObject,
658651
);
659652
debug('module mock, url = "%s", format = "%s", caller = "%s"', url, format, caller);
660653
if (format) { // Format is not yet known for ambiguous files when detection is enabled.
@@ -828,20 +821,13 @@ function setupSharedModuleState() {
828821
if (sharedModuleState === undefined) {
829822
const { mock } = require('test');
830823
const mockExports = new SafeMap();
831-
const { port1, port2 } = new MessageChannel();
824+
const { registerHooks } = require('internal/modules/customization_hooks');
832825
const moduleLoader = esmLoader.getOrInitializeCascadedLoader();
833826

834-
moduleLoader.register(
835-
'internal/test_runner/mock/loader',
836-
'node:',
837-
{ __proto__: null, port: port2 },
838-
[port2],
839-
true,
840-
);
827+
registerHooks(mockHooks);
841828

842829
sharedModuleState = {
843830
__proto__: null,
844-
loaderPort: port1,
845831
mockExports,
846832
mockMap: new SafeMap(),
847833
moduleLoader,
@@ -941,13 +927,6 @@ function findMethodOnPrototypeChain(instance, methodName) {
941927
return descriptor;
942928
}
943929

944-
function waitForAck(buf) {
945-
const result = AtomicsWait(buf, 0, 0, kWaitTimeout);
946-
947-
notStrictEqual(result, 'timed-out', 'test mocking synchronization failed');
948-
strictEqual(buf[0], kMockSuccess);
949-
}
950-
951930
function ensureNodeScheme(specifier) {
952931
if (!StringPrototypeStartsWith(specifier, 'node:')) {
953932
return `node:${specifier}`;
@@ -962,10 +941,5 @@ if (!enableModuleMocking) {
962941

963942
module.exports = {
964943
ensureNodeScheme,
965-
kBadExportsMessage,
966-
kMockSearchParam,
967-
kMockSuccess,
968-
kMockExists,
969-
kMockUnknownMessage,
970944
MockTracker,
971945
};
Collapse file

‎test/parallel/test-permission-dc-worker-threads.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-permission-dc-worker-threads.js
-19Lines changed: 0 additions & 19 deletions
This file was deleted.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.