Skip to content

Conversation

@tadjik1
Copy link
Member

@tadjik1 tadjik1 commented Jan 20, 2026

Description

Summary of Changes

Notes for Reviewers

To run the tests:

MONGODB_URI=mongodb://localhost:27017,localhost:27018,localhost:27019 npm run check:runtime-independency

What is the motivation for this change?

Release Highlight

Release notes highlight

Double check the following

  • Lint is passing (npm run check:lint)
  • Self-review completed using the steps outlined here
  • PR title follows the correct format: type(NODE-xxxx)[!]: description
    • Example: feat(NODE-1234)!: rewriting everything in coffeescript
  • Changes are covered by tests
  • New TODOs have a related JIRA ticket

@@ -0,0 +1,206 @@
/* eslint-disable no-restricted-globals */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/* eslint-disable no-restricted-globals */
'use strict';
/* eslint-disable no-restricted-globals */

(this is a script, not an ES module, so strict mode is not the default)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file had been converted to ts as @PavelSafronov suggested

reporter: 'test/tools/reporter/mongodb_reporter.js',
sort: true,
color: true,
ignore: [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a comment about why these are being ignored?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, thanks! I copied this configuration from the integration tests setup, will link these files together.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I included the original file all along instead of manually picking up its' options


function createSandboxContext(filename) {
const exportsContainer = {};
return {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return {
return {
__proto__: null,

Just so none of the property lookups for built-ins fall back to the global one unintentionally

Copy link
Member Author

@tadjik1 tadjik1 Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, included!

exports: exportsContainer,
module: { exports: exportsContainer },
__filename: filename,
__dirname: path.dirname(filename),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd try to emulate the behavior of the built-in CommonJS evaluator as closely as possible.

None of these are typically globals, and modules do share a single global – all of require, module, exports, __filenameand__dirname` are injected as parameters to an implicit function that is used to wrap around user code

e.g. https://github.com/mongodb-js/mongosh/blob/5ea0a3617c9692cbb5c1e632a859d6688b69a6f1/packages/shell-api/src/runtime-independence.spec.ts#L41-L46

(you should generally be able to use that file as a reference for a lot of this)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is awesome, thanks! I haven't seen this file before, this is huge help indeed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the same style wrapper around the script and define "globals" (context) just once so it's shared.

return function sandboxRequire(moduleIdentifier) {
if (!moduleIdentifier.startsWith('.')) {
return require(moduleIdentifier);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this intentional? I figured we'd want to require almost everything inside the sandbox except for Node.js built-ins and maybe a list of modules that are explicit exceptions to this rule

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is temporary solution to be able to import all dev dependencies and to highlight the more general idea (this ticket and PR is spike), so I was focusing mostly on "running existing integration tests inside vm.Context sandbox". But you are absolutely right, ideally all prod dependencies should be required from the inside, otherwise it's pointless (if driver is browser-compatible but, say bson not - we can't run application).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we switch this file to TS? Some of our test runners are JS, but most are TS, would be nice if all new code was TS. Unless there's some reason that we can't/shouldn't.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done!

@PavelSafronov
Copy link
Contributor

Re: testing - there's a command for running tests against 3 local servers, but what is the command we should use to start those 3 servers?

I tried starting a replica set (TOPOLOGY=replica_set AUTH=noauth bash ./.evergreen/run-orchestration.sh) and executed the test command, but encountered 25 test failures.

let compilerOptions = { module: ts.ModuleKind.CommonJS };
const tsConfigPath = path.join(__dirname, '../../tsconfig.json');
const configFile = ts.readConfigFile(tsConfigPath, ts.sys.readFile);
if (!configFile.error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Throw if configFile.error is present?

@tadjik1 tadjik1 changed the title test(NODE-7345): custom vm.Context runner for mocha WIP - test(NODE-7345): custom vm.Context runner for mocha Jan 21, 2026
@tadjik1
Copy link
Member Author

tadjik1 commented Jan 21, 2026

Re: testing - there's a command for running tests against 3 local servers, but what is the command we should use to start those 3 servers?

I tried starting a replica set (TOPOLOGY=replica_set AUTH=noauth bash ./.evergreen/run-orchestration.sh) and executed the test command, but encountered 25 test failures.

I actually don't know the answer yet. I mean you did everything right, I personally use mlaunch but it doesn't matter how to run the server.
Tests are failing and I would need to dig deeper to understand if this can be easily fixed (or if this setup is not appropriate for some of our integration tests).

@tadjik1 tadjik1 changed the title WIP - test(NODE-7345): custom vm.Context runner for mocha WIP [SPIKE] - test(NODE-7345): custom vm.Context runner for mocha Jan 21, 2026
Comment on lines +156 to +163
// force instanceof to work across contexts by defining custom `instanceof` function
Object.defineProperty(value, Symbol.hasInstance, {
value: (instance: any) => {
return (
instance && (instance.constructor.name === value.name || instance instanceof value)
);
}
});
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really like this part, but I found this problem a little bit tricky. The problem is that host environment (and consequently chai) has its' own set of Error classes, so instanceof from inside the sandbox is broken. @addaleax, maybe there is more convenient way to make it work rather than re-defining instanceof?

Comment on lines +92 to +98
const sandboxedDependencies = ['bson'];
const isSandboxedDep = sandboxedDependencies.some(
dep => moduleIdentifier === dep || moduleIdentifier.startsWith(`${dep}/`)
);
if (!moduleIdentifier.startsWith('.') && !isSandboxedDep) {
return require(moduleIdentifier);
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@addaleax this seems to work kinda of fine, we can list dependencies that should be loaded from within the sandbox. i decided to go with this approach because list of dev and prod dependencies we need to import in host is large. but maybe i'm missing something and it should be the other way around (everything is inside except certain builtin modules)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants