diff --git a/package-lock.json b/package-lock.json index c61095565..63b9d057c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36980,6 +36980,7 @@ "@mongodb-js/eslint-config-mongosh": "^1.0.0", "@mongodb-js/prettier-config-devtools": "^1.0.1", "@mongodb-js/tsconfig-mongosh": "^1.0.0", + "@mongosh/testing": "0.0.0-dev.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.8", "@testing-library/dom": "^8.20.1", "@testing-library/react": "^12.1.5", @@ -38227,6 +38228,7 @@ "@mongodb-js/oidc-plugin": "^2.0.5", "@mongosh/cli-repl": "2.5.10", "@mongosh/service-provider-core": "3.7.0", + "@mongosh/testing": "0.0.0-dev.0", "strip-ansi": "^6.0.0" }, "devDependencies": { diff --git a/packages/e2e-tests/.mocharc.json b/packages/e2e-tests/.mocharc.json index 416694eef..f640eecf2 100644 --- a/packages/e2e-tests/.mocharc.json +++ b/packages/e2e-tests/.mocharc.json @@ -1,9 +1,5 @@ { - "require": [ - "ts-node/register", - "../../scripts/import-expansions.js", - "./test/test-shell-context.ts" - ], + "require": ["ts-node/register", "../../scripts/import-expansions.js"], "timeout": 15000, "reporter": "../../configs/mocha-config-mongosh/reporter.ts", "spec": ["./test/*.spec.ts"], diff --git a/packages/e2e-tests/package.json b/packages/e2e-tests/package.json index 5f45f2174..7c18cd646 100644 --- a/packages/e2e-tests/package.json +++ b/packages/e2e-tests/package.json @@ -29,6 +29,7 @@ "dependencies": { "@mongosh/cli-repl": "2.5.10", "@mongosh/service-provider-core": "3.7.0", + "@mongosh/testing": "0.0.0-dev.0", "@mongodb-js/oidc-plugin": "^2.0.5", "strip-ansi": "^6.0.0" }, diff --git a/packages/e2e-tests/test/e2e-analytics.spec.ts b/packages/e2e-tests/test/e2e-analytics.spec.ts index 40e6b4560..b3db914fe 100644 --- a/packages/e2e-tests/test/e2e-analytics.spec.ts +++ b/packages/e2e-tests/test/e2e-analytics.spec.ts @@ -1,6 +1,6 @@ import { expect } from 'chai'; -import { startTestCluster } from '../../testing/src/integration-testing-hooks'; -import { eventually } from '../../testing/src/eventually'; +import { startTestCluster, eventually } from '@mongosh/testing'; +import { startTestShell } from './test-shell-context'; describe('e2e Analytics Node', function () { const replSetName = 'replicaSet'; @@ -33,7 +33,7 @@ describe('e2e Analytics Node', function () { ], }; - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await rs0.connectionString()], }); await shell.waitForPrompt(); @@ -52,7 +52,7 @@ describe('e2e Analytics Node', function () { context('without readPreference', function () { it('a direct connection ends up at primary', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await rs0.connectionString()], }); await shell.waitForPrompt(); @@ -65,13 +65,13 @@ describe('e2e Analytics Node', function () { context('specifying readPreference and tags', function () { it('ends up at the ANALYTICS node', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ `${await rs0.connectionString()}?replicaSet=${replSetName}&readPreference=secondary&readPreferenceTags=nodeType:ANALYTICS`, ], }); - const directConnectionToAnalyticsShell = this.startTestShell({ + const directConnectionToAnalyticsShell = startTestShell(this, { args: [`${await rs3.connectionString()}?directConnection=true`], }); await Promise.all([ diff --git a/packages/e2e-tests/test/e2e-auth.spec.ts b/packages/e2e-tests/test/e2e-auth.spec.ts index b1a9ed5d4..1be4cbc4c 100644 --- a/packages/e2e-tests/test/e2e-auth.spec.ts +++ b/packages/e2e-tests/test/e2e-auth.spec.ts @@ -1,12 +1,13 @@ import { expect } from 'chai'; import type { Db, Document, MongoClientOptions } from 'mongodb'; import { MongoClient } from 'mongodb'; -import { eventually } from '../../testing/src/eventually'; import type { TestShell } from './test-shell'; import { + eventually, skipIfApiStrict, startSharedTestServer, -} from '../../testing/src/integration-testing-hooks'; +} from '@mongosh/testing'; +import { startTestShell } from './test-shell-context'; type AssertUserExists = (opts?: Document, username?: string) => Promise; function createAssertUserExists(db: Db, dbName: string): AssertUserExists { @@ -110,7 +111,7 @@ describe('Auth e2e', function () { beforeEach(async function () { const connectionString = await testServer.connectionString(); dbName = `test-${Date.now()}`; - shell = this.startTestShell({ args: [connectionString] }); + shell = startTestShell(this, { args: [connectionString] }); client = await MongoClient.connect(connectionString, {}); @@ -878,7 +879,7 @@ describe('Auth e2e', function () { pathname: `/${dbName}`, } ); - shell = this.startTestShell({ args: [authConnectionString] }); + shell = startTestShell(this, { args: [authConnectionString] }); await shell.waitForPrompt(); shell.assertNoErrors(); await shell.executeLine(`use ${dbName}`); @@ -902,7 +903,7 @@ describe('Auth e2e', function () { pathname: `/${dbName}`, } ); - shell = this.startTestShell({ args: [authConnectionString] }); + shell = startTestShell(this, { args: [authConnectionString] }); await shell.waitForPrompt(); shell.assertNoErrors(); await shell.executeLine(`use ${dbName}`); @@ -929,7 +930,7 @@ describe('Auth e2e', function () { }); it('can auth when there is -u and -p', async function () { const connectionString = await testServer.connectionString(); - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ connectionString, '-u', @@ -964,7 +965,7 @@ describe('Auth e2e', function () { return this.skip(); // No SCRAM-SHA-1 in FIPS mode } const connectionString = await testServer.connectionString(); - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ connectionString, '-u', @@ -988,7 +989,7 @@ describe('Auth e2e', function () { // This test is not particularly meaningful if we're using the system OpenSSL installation // and it is not properly configured for FIPS to begin with. This is the case on e.g. // Ubuntu 22.04 in evergreen CI. - const preTestShell = this.startTestShell({ + const preTestShell = startTestShell(this, { args: [ '--quiet', '--nodb', @@ -1008,7 +1009,7 @@ describe('Auth e2e', function () { } const connectionString = await testServer.connectionString(); - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ connectionString, '--tlsFIPSMode', @@ -1033,7 +1034,7 @@ describe('Auth e2e', function () { }); it('can auth with SCRAM-SHA-256', async function () { const connectionString = await testServer.connectionString(); - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ connectionString, '-u', @@ -1054,7 +1055,7 @@ describe('Auth e2e', function () { }); it('cannot auth when authenticationMechanism mismatches (sha256 -> sha1)', async function () { const connectionString = await testServer.connectionString(); - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ connectionString, '-u', @@ -1075,7 +1076,7 @@ describe('Auth e2e', function () { }); it('cannot auth when authenticationMechanism mismatches (sha1 -> sha256)', async function () { const connectionString = await testServer.connectionString(); - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ connectionString, '-u', @@ -1096,7 +1097,7 @@ describe('Auth e2e', function () { }); it('does not fail with kerberos not found for GSSAPI', async function () { const connectionString = await testServer.connectionString(); - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ connectionString, '-u', diff --git a/packages/e2e-tests/test/e2e-aws.spec.ts b/packages/e2e-tests/test/e2e-aws.spec.ts index 003f7b6c8..80dbced03 100644 --- a/packages/e2e-tests/test/e2e-aws.spec.ts +++ b/packages/e2e-tests/test/e2e-aws.spec.ts @@ -1,5 +1,6 @@ import { expect } from 'chai'; import { spawnSync } from 'child_process'; +import { startTestShell } from './test-shell-context'; function assertEnvVariable(variableName: string): string { if (process.env.MONGOSH_TEST_FORCE_API_STRICT) { @@ -123,7 +124,7 @@ describe('e2e AWS AUTH', function () { context('without environment variables being present', function () { context('specifying explicit parameters', function () { it('connects with access key and secret', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ getConnectionString(), '--username', @@ -145,7 +146,7 @@ describe('e2e AWS AUTH', function () { it('connects with access key, secret, and session token for IAM role', async function () { const tokenDetails = generateIamSessionToken(); - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ getConnectionString(), '--username', @@ -170,7 +171,7 @@ describe('e2e AWS AUTH', function () { context('specifying connection string parameters', function () { it('connects with access key and secret', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [getConnectionString(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)], }); const result = await shell.waitForPromptOrExit( @@ -186,7 +187,7 @@ describe('e2e AWS AUTH', function () { it('connects with access key, secret, and session token for IAM role', async function () { const tokenDetails = generateIamSessionToken(); - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ `${getConnectionString( tokenDetails.key, @@ -212,7 +213,7 @@ describe('e2e AWS AUTH', function () { context('with AWS environment variables', function () { context('without any other parameters', function () { it('connects for the IAM user', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [getConnectionString()], env: { ...process.env, @@ -233,7 +234,7 @@ describe('e2e AWS AUTH', function () { it('connects for the IAM role session', async function () { const tokenDetails = generateIamSessionToken(); - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [getConnectionString()], env: { ...process.env, @@ -256,7 +257,7 @@ describe('e2e AWS AUTH', function () { context('with invalid environment but valid parameters', function () { it('connects for the IAM user', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ getConnectionString(), '--username', @@ -283,7 +284,7 @@ describe('e2e AWS AUTH', function () { it('connects for the IAM role session', async function () { const tokenDetails = generateIamSessionToken(); - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ getConnectionString(), '--username', diff --git a/packages/e2e-tests/test/e2e-banners.spec.ts b/packages/e2e-tests/test/e2e-banners.spec.ts index 5e2300add..53bc9ecdb 100644 --- a/packages/e2e-tests/test/e2e-banners.spec.ts +++ b/packages/e2e-tests/test/e2e-banners.spec.ts @@ -1,8 +1,6 @@ -import { - skipIfApiStrict, - startSharedTestServer, -} from '../../testing/src/integration-testing-hooks'; +import { skipIfApiStrict, startSharedTestServer } from '@mongosh/testing'; import type { TestShell } from './test-shell'; +import { startTestShell } from './test-shell-context'; describe('e2e startup banners', function () { skipIfApiStrict(); @@ -11,7 +9,7 @@ describe('e2e startup banners', function () { context('without special configuration', function () { it('shows startup warnings', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await testServer.connectionString()], }); await shell.waitForPrompt(); @@ -29,7 +27,7 @@ describe('e2e startup banners', function () { let helperShell: TestShell; beforeEach(async function () { - helperShell = this.startTestShell({ + helperShell = startTestShell(this, { args: [await testServer.connectionString()], }); await helperShell.waitForPrompt(); @@ -46,7 +44,7 @@ describe('e2e startup banners', function () { }); it('shows automation notices', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await testServer.connectionString()], }); await shell.waitForPrompt(); diff --git a/packages/e2e-tests/test/e2e-bson.spec.ts b/packages/e2e-tests/test/e2e-bson.spec.ts index e84942bd0..8f738253c 100644 --- a/packages/e2e-tests/test/e2e-bson.spec.ts +++ b/packages/e2e-tests/test/e2e-bson.spec.ts @@ -3,7 +3,8 @@ import type { Db } from 'mongodb'; import { MongoClient } from 'mongodb'; import * as bson from 'bson'; import type { TestShell } from './test-shell'; -import { startSharedTestServer } from '../../testing/src/integration-testing-hooks'; +import { startSharedTestServer } from '@mongosh/testing'; +import { startTestShell } from './test-shell-context'; describe('BSON e2e', function () { const testServer = startSharedTestServer(); @@ -15,7 +16,7 @@ describe('BSON e2e', function () { beforeEach(async function () { const connectionString = await testServer.connectionString(); dbName = `test-${Date.now()}`; - shell = this.startTestShell({ args: [connectionString] }); + shell = startTestShell(this, { args: [connectionString] }); client = await MongoClient.connect(connectionString, {}); @@ -674,7 +675,7 @@ describe('BSON e2e', function () { it('can explicitly disable full-depth nesting (interactive mode)', async function () { shell.kill(); - shell = this.startTestShell({ + shell = startTestShell(this, { args: [await testServer.connectionString(), '--deepInspect=false'], }); await shell.waitForPrompt(); @@ -686,7 +687,7 @@ describe('BSON e2e', function () { it('does not deeply inspect objects in non-interactive mode for intermediate output', async function () { shell.kill(); - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer.connectionString(), '--eval', @@ -694,7 +695,7 @@ describe('BSON e2e', function () { ], }); checkForDeepOutput(await shell.waitForCleanOutput(), false); - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer.connectionString(), '--eval', @@ -706,7 +707,7 @@ describe('BSON e2e', function () { it('inspect full objects in non-interactive mode for final output', async function () { shell.kill(); - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer.connectionString(), '--eval', @@ -714,7 +715,7 @@ describe('BSON e2e', function () { ], }); checkForDeepOutput(await shell.waitForCleanOutput(), true); - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer.connectionString(), '--eval', @@ -726,7 +727,7 @@ describe('BSON e2e', function () { it('can explicitly disable full-depth nesting (non-interactive mode)', async function () { shell.kill(); - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer.connectionString(), '--deepInspect=false', @@ -735,7 +736,7 @@ describe('BSON e2e', function () { ], }); checkForDeepOutput(await shell.waitForCleanOutput(), false); - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer.connectionString(), '--deepInspect=false', diff --git a/packages/e2e-tests/test/e2e-direct.spec.ts b/packages/e2e-tests/test/e2e-direct.spec.ts index 3496075d8..ad55dd3ef 100644 --- a/packages/e2e-tests/test/e2e-direct.spec.ts +++ b/packages/e2e-tests/test/e2e-direct.spec.ts @@ -1,11 +1,12 @@ import { + eventually, startTestCluster, skipIfServerVersion, skipIfApiStrict, -} from '../../testing/src/integration-testing-hooks'; -import { eventually } from '../../testing/src/eventually'; +} from '@mongosh/testing'; import { expect } from 'chai'; import type { TestShell } from './test-shell'; +import { startTestShell } from './test-shell-context'; describe('e2e direct connection', function () { skipIfApiStrict(); @@ -31,7 +32,7 @@ describe('e2e direct connection', function () { { server: rs2, name: 'rs2' }, ].forEach(({ server, name }) => { it(`works when connecting to node ${name} of uninitialized set`, async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await server.connectionString()], }); await shell.waitForPrompt(); @@ -56,7 +57,7 @@ describe('e2e direct connection', function () { ], }; - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await rs0.connectionString()], }); await shell.waitForPrompt(); @@ -83,7 +84,7 @@ describe('e2e direct connection', function () { shell.writeInputLine('exit'); }); after(async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await rs0.connectionString()], }); await shell.waitForPrompt(); @@ -94,7 +95,7 @@ describe('e2e direct connection', function () { context('connecting to secondary members directly', function () { it('works when specifying a connection string', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await rs1.connectionString()], }); await shell.waitForPrompt(); @@ -105,7 +106,7 @@ describe('e2e direct connection', function () { }); it('works when specifying just host and port', async function () { - const shell = this.startTestShell({ args: [await rs1.hostport()] }); + const shell = startTestShell(this, { args: [await rs1.hostport()] }); await shell.waitForPrompt(); await shell.executeLine('db.isMaster()'); shell.assertContainsOutput('ismaster: false'); @@ -114,7 +115,7 @@ describe('e2e direct connection', function () { }); it('lists collections without explicit readPreference', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [`${await rs1.connectionString()}`], }); await shell.waitForPrompt(); @@ -124,7 +125,7 @@ describe('e2e direct connection', function () { }); it('lists collections when an incompatible readPreference is provided', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [`${await rs1.connectionString()}`], }); await shell.waitForPrompt(); @@ -136,7 +137,7 @@ describe('e2e direct connection', function () { }); it('lists collections when readPreference is set via Mongo', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await rs1.connectionString()], }); await shell.waitForPrompt(); @@ -149,7 +150,7 @@ describe('e2e direct connection', function () { }); it('slists databases without explicit readPreference', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await rs1.connectionString()], }); await shell.waitForPrompt(); @@ -159,7 +160,7 @@ describe('e2e direct connection', function () { }); it('lists databases when an incompatible readPreference is provided', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await rs1.connectionString()], }); await shell.waitForPrompt(); @@ -171,7 +172,7 @@ describe('e2e direct connection', function () { }); it('lists databases when readPreference is set via Mongo', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await rs1.connectionString()], }); await shell.waitForPrompt(); @@ -184,7 +185,7 @@ describe('e2e direct connection', function () { }); it('lists collections and dbs using show by default', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await rs1.connectionString()], }); await shell.waitForPrompt(); @@ -199,7 +200,7 @@ describe('e2e direct connection', function () { if (process.arch === 's390x') { return this.skip(); // https://jira.mongodb.org/browse/MONGOSH-746 } - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await rs1.connectionString({}, { pathname: `/${dbname}` })], forceTerminal: true, }); @@ -215,7 +216,7 @@ describe('e2e direct connection', function () { skipIfServerVersion(rs0, '< 4.2'); it('allows aggregate with $merge with secondary readpref', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await rs1.connectionString( { @@ -247,7 +248,7 @@ describe('e2e direct connection', function () { context('connecting to primary', function () { it('when specifying replicaSet', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await rs1.connectionString({ replicaSet: replSetId })], }); await shell.waitForPrompt(); @@ -257,7 +258,7 @@ describe('e2e direct connection', function () { shell.assertContainsOutput(`setName: '${replSetId}'`); }); it('when setting directConnection to false', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await rs1.connectionString({ directConnection: 'false' })], }); await shell.waitForPrompt(); @@ -274,7 +275,7 @@ describe('e2e direct connection', function () { (await rs1.hostport()) + ',' + (await rs0.hostport()); - const shell = this.startTestShell({ args: [connectionString] }); + const shell = startTestShell(this, { args: [connectionString] }); await shell.waitForPrompt(); await shell.executeLine('db.isMaster()'); shell.assertContainsOutput('ismaster: true'); @@ -288,7 +289,7 @@ describe('e2e direct connection', function () { (await rs1.hostport()) + ',' + (await rs0.hostport()); - const shell = this.startTestShell({ args: ['--host', hostlist] }); + const shell = startTestShell(this, { args: ['--host', hostlist] }); await shell.waitForPrompt(); await shell.executeLine('db.isMaster()'); await shell.executeLine('({ dbname: db.getName() })'); @@ -306,7 +307,7 @@ describe('e2e direct connection', function () { (await rs1.hostport()) + ',' + (await rs0.hostport()); - const shell = this.startTestShell({ args: ['--host', hostlist] }); + const shell = startTestShell(this, { args: ['--host', hostlist] }); await shell.waitForPrompt(); await shell.executeLine('db.isMaster()'); await shell.executeLine('({ dbname: db.getName() })'); @@ -324,7 +325,7 @@ describe('e2e direct connection', function () { (await rs1.hostport()) + ',' + (await rs0.hostport()); - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: ['--host', hostlist, 'admin'], }); await shell.waitForPrompt(); @@ -343,7 +344,7 @@ describe('e2e direct connection', function () { (await rs1.hostport()) + ',' + (await rs0.hostport()); - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: ['--host', hostlist, 'admin'], }); await shell.waitForAnyExit(); @@ -351,7 +352,7 @@ describe('e2e direct connection', function () { }); it('lists collections and dbs using show by default', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [`${await rs1.connectionString()}`], }); await shell.waitForPrompt(); @@ -365,7 +366,7 @@ describe('e2e direct connection', function () { if (process.arch === 's390x') { return this.skip(); // https://jira.mongodb.org/browse/MONGOSH-746 } - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await rs1.connectionString({}, { pathname: `/${dbname}` })], forceTerminal: true, }); @@ -385,7 +386,7 @@ describe('e2e direct connection', function () { (await rs1.hostport()) + ',' + (await rs0.hostport()); - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ '--host', hostlist, @@ -400,7 +401,7 @@ describe('e2e direct connection', function () { shell.assertContainsOutput("user: 'anna'"); }); it('drops indexes even if a read preference is specified in the connection url', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await rs0.connectionString({ readPreference: 'secondary' })], }); @@ -414,7 +415,7 @@ describe('e2e direct connection', function () { describe('fail-fast connections', function () { it('does not fail fast for ECONNREFUSED errors when one host is reachable', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ `mongodb://${await rs1.hostport()},127.0.0.1:1/?replicaSet=${replSetId}&readPreference=secondary`, ], diff --git a/packages/e2e-tests/test/e2e-editor.spec.ts b/packages/e2e-tests/test/e2e-editor.spec.ts index eaf0da3b0..75dc3f79d 100644 --- a/packages/e2e-tests/test/e2e-editor.spec.ts +++ b/packages/e2e-tests/test/e2e-editor.spec.ts @@ -1,9 +1,9 @@ import { expect } from 'chai'; import path from 'path'; import { promises as fs } from 'fs'; -import { eventually } from '../../testing/src/eventually'; +import { eventually } from '@mongosh/testing'; import { TestShell } from './test-shell'; -import { ensureTestShellAfterHook } from './test-shell-context'; +import { ensureTestShellAfterHook, startTestShell } from './test-shell-context'; import { useTmpdir, fakeExternalEditor, @@ -22,7 +22,7 @@ describe('external editor e2e', function () { homedir = homeInfo.homedir; env = homeInfo.env; - shell = this.startTestShell({ + shell = startTestShell(this, { args: ['--nodb'], forceTerminal: true, env, diff --git a/packages/e2e-tests/test/e2e-fle.spec.ts b/packages/e2e-tests/test/e2e-fle.spec.ts index f0f9ddc6f..38c6d4293 100644 --- a/packages/e2e-tests/test/e2e-fle.spec.ts +++ b/packages/e2e-tests/test/e2e-fle.spec.ts @@ -1,15 +1,15 @@ import { expect } from 'chai'; import { MongoClient } from 'mongodb'; import type { TestShell } from './test-shell'; -import { eventually } from '../../testing/src/eventually'; import { + eventually, startTestServer, skipIfApiStrict, skipIfServerVersion, skipIfCommunityServer, downloadCurrentCryptSharedLibrary, sortObjectArray, -} from '../../testing/src/integration-testing-hooks'; +} from '@mongosh/testing'; import { makeFakeHTTPServer, fakeAWSHandlers, @@ -18,6 +18,7 @@ import { once } from 'events'; import { serialize } from 'v8'; import { inspect } from 'util'; import path from 'path'; +import { startTestShell } from './test-shell-context'; describe('FLE tests', function () { const testServer = startTestServer('e2e-fle', { @@ -228,7 +229,7 @@ describe('FLE tests', function () { } it('works when the original shell was started with --nodb', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: ['--nodb'], }); await shell.waitForPrompt(); @@ -259,7 +260,7 @@ describe('FLE tests', function () { }); it('works when a schemaMap option has been passed', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: ['--nodb', `--cryptSharedLibPath=${cryptLibrary}`], }); await shell.waitForPrompt(); @@ -305,7 +306,7 @@ describe('FLE tests', function () { }); it('skips automatic encryption when a bypassQueryAnalysis option has been passed', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: ['--nodb', `--cryptSharedLibPath=${cryptLibrary}`], }); const uri = JSON.stringify(await testServer.connectionString()); @@ -384,7 +385,7 @@ describe('FLE tests', function () { }); it('does not allow compactStructuredEncryptionData command when mongo instance configured without auto encryption', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await testServer.connectionString()], }); await shell.waitForPrompt(); @@ -403,7 +404,7 @@ describe('FLE tests', function () { it('can read existing QEv1 data', async function () { const uri = await testServer.connectionString(); - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [uri, `--cryptSharedLibPath=${cryptLibrary}`], }); await shell.waitForPrompt(); @@ -514,7 +515,7 @@ describe('FLE tests', function () { it('allows explicit enryption with bypassQueryAnalysis', async function () { // No --cryptSharedLibPath since bypassQueryAnalysis is also a community edition feature - const shell = this.startTestShell({ args: ['--nodb'] }); + const shell = startTestShell(this, { args: ['--nodb'] }); const uri = JSON.stringify(await testServer.connectionString()); await shell.waitForPrompt(); @@ -576,7 +577,7 @@ describe('FLE tests', function () { }); it('drops fle2 collection with all helper collections when encryptedFields options are in listCollections', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: ['--nodb', `--cryptSharedLibPath=${cryptLibrary}`], }); const uri = JSON.stringify(await testServer.connectionString()); @@ -651,7 +652,7 @@ describe('FLE tests', function () { }); it('creates an encrypted collection and generates data encryption keys automatically per encrypted fields', async function () { - const shell = this.startTestShell({ args: ['--nodb'] }); + const shell = startTestShell(this, { args: ['--nodb'] }); const uri = JSON.stringify(await testServer.connectionString()); await shell.waitForPrompt(); await shell.executeLine( @@ -705,7 +706,7 @@ describe('FLE tests', function () { }`; it('allows compactStructuredEncryptionData command when mongo instance configured with auto encryption', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: ['--nodb', `--cryptSharedLibPath=${cryptLibrary}`], }); const uri = JSON.stringify(await testServer.connectionString()); @@ -750,7 +751,7 @@ describe('FLE tests', function () { }); it('creates an encrypted collection and generates data encryption keys automatically per encrypted fields', async function () { - const shell = this.startTestShell({ args: ['--nodb'] }); + const shell = startTestShell(this, { args: ['--nodb'] }); const uri = JSON.stringify(await testServer.connectionString()); await shell.waitForPrompt(); await shell.executeLine( @@ -792,7 +793,7 @@ describe('FLE tests', function () { it('allows explicit range encryption with bypassQueryAnalysis', async function () { // No --cryptSharedLibPath since bypassQueryAnalysis is also a community edition feature - const shell = this.startTestShell({ args: ['--nodb'] }); + const shell = startTestShell(this, { args: ['--nodb'] }); const uri = JSON.stringify(await testServer.connectionString()); await shell.waitForPrompt(); @@ -867,7 +868,7 @@ describe('FLE tests', function () { }); it('allows automatic range encryption', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: ['--nodb', `--cryptSharedLibPath=${cryptLibrary}`], }); const uri = JSON.stringify(await testServer.connectionString()); @@ -926,7 +927,7 @@ describe('FLE tests', function () { skipIfCommunityServer(testServer); it('allows $lookup with a collection with automatic encryption', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ `--cryptSharedLibPath=${cryptLibrary82}`, await testServer.connectionString(), @@ -1030,7 +1031,7 @@ describe('FLE tests', function () { const testCollection = 'qeSubstringTest'; beforeEach(async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ `--cryptSharedLibPath=${cryptLibrary82}`, await testServer.connectionString(), @@ -1229,7 +1230,7 @@ describe('FLE tests', function () { skipIfServerVersion(testServer, '>= 6.0'); // FLE2 available on 6.0+ it('provides a good error message when createCollection fails due to low server version', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ `--cryptSharedLibPath=${cryptLibrary}`, await testServer.connectionString(), @@ -1243,7 +1244,7 @@ describe('FLE tests', function () { }); it('provides a good error message when createCollection fails due to low FCV', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ `--cryptSharedLibPath=${cryptLibrary}`, await testServer.connectionString(), @@ -1260,7 +1261,7 @@ describe('FLE tests', function () { }); it('performs KeyVault data key management as expected', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await testServer.connectionString(), `--cryptSharedLibPath=${cryptLibrary}`, diff --git a/packages/e2e-tests/test/e2e-oidc.spec.ts b/packages/e2e-tests/test/e2e-oidc.spec.ts index a8ac8a772..fa0a9c816 100644 --- a/packages/e2e-tests/test/e2e-oidc.spec.ts +++ b/packages/e2e-tests/test/e2e-oidc.spec.ts @@ -1,8 +1,9 @@ import { + getTestCertificatePath as getCertPath, MongoRunnerSetup, skipIfApiStrict, skipIfEnvServerVersion, -} from '../../testing/src/integration-testing-hooks'; +} from '@mongosh/testing'; import { promises as fs } from 'fs'; import type { OIDCMockProviderConfig } from '@mongodb-js/oidc-mock-provider'; import { OIDCMockProvider } from '@mongodb-js/oidc-mock-provider'; @@ -10,13 +11,14 @@ import type { TestShell } from './test-shell'; import path from 'path'; import { expect } from 'chai'; import { createServer as createHTTPSServer } from 'https'; -import { getCertPath, readReplLogFile, useTmpdir } from './repl-helpers'; +import { readReplLogFile, useTmpdir } from './repl-helpers'; import { baseOidcServerConfig, commonOidcServerArgs, skipOIDCTestsDueToPlatformOrServerVersion, } from './oidc-helpers'; import { createMongoDBOIDCPlugin } from '@mongodb-js/oidc-plugin'; +import { startTestShell } from './test-shell-context'; /** * @securityTest OIDC Authentication End-to-End Tests @@ -215,7 +217,7 @@ describe('OIDC auth e2e', function () { args.push('--oidcNoNonce'); } - shell = this.startTestShell({ + shell = startTestShell(this, { args, }); if (!expectNonce || provideNonce) { @@ -234,7 +236,7 @@ describe('OIDC auth e2e', function () { } it('can successfully authenticate using OIDC Auth Code Flow when a username is specified', async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer.connectionString(), '--username=testuser', @@ -250,7 +252,7 @@ describe('OIDC auth e2e', function () { }); it('can successfully authenticate using OIDC Device Auth Flow', async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer.connectionString(), '--authenticationMechanism=MONGODB-OIDC', @@ -268,7 +270,7 @@ describe('OIDC auth e2e', function () { }); it('hints the user to use Device Auth Flow if starting a browser fails', async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer.connectionString(), '--authenticationMechanism=MONGODB-OIDC', @@ -290,7 +292,7 @@ describe('OIDC auth e2e', function () { payload: (await originalGetPayload(metadata)).payload, }; }; - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer.connectionString({ maxIdleTimeMS: '1', @@ -312,7 +314,7 @@ describe('OIDC auth e2e', function () { it('keeps authentication state when resetting connection options', async function () { const cs = await testServer.connectionString(); - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ cs, '--authenticationMechanism=MONGODB-OIDC', @@ -336,7 +338,7 @@ describe('OIDC auth e2e', function () { it('re-authenticates when connecting to a different endpoint from the same shell', async function () { const urlOptions = { username: 'testuser' }; // Make sure these match between the two connections - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer.connectionString({}, urlOptions), '--authenticationMechanism=MONGODB-OIDC', @@ -360,7 +362,7 @@ describe('OIDC auth e2e', function () { }); it('can share state with another shell', async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer.connectionString(), '--authenticationMechanism=MONGODB-OIDC', @@ -388,7 +390,7 @@ describe('OIDC auth e2e', function () { handle = handle.slice(0, -1); } - const shell2 = this.startTestShell({ + const shell2 = startTestShell(this, { args: [ await testServer.connectionString(), '--authenticationMechanism=MONGODB-OIDC', @@ -415,7 +417,7 @@ describe('OIDC auth e2e', function () { path.join(tmpdir.path, 'certs', 'somefilename.crt') ); - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer2.connectionString( {}, @@ -445,7 +447,7 @@ describe('OIDC auth e2e', function () { path.join(tmpdir.path, 'certs', 'somefilename.crt') ); - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer2.connectionString( {}, @@ -487,7 +489,7 @@ describe('OIDC auth e2e', function () { }; // Consistency check: ID token is *not* used by default - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer3.connectionString(), '--authenticationMechanism=MONGODB-OIDC', @@ -500,7 +502,7 @@ describe('OIDC auth e2e', function () { await verifyUser(shell, 'testuser-at', 'testuser-at-group'); // Actual test: ID token data is used when --oidcIdTokenAsAccessToken is set - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer3.connectionString(), '--authenticationMechanism=MONGODB-OIDC', @@ -516,7 +518,7 @@ describe('OIDC auth e2e', function () { }); it('can print tokens as debug information if requested', async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer.connectionString(), '--authenticationMechanism=MONGODB-OIDC', @@ -536,7 +538,7 @@ describe('OIDC auth e2e', function () { shell.assertContainsOutput('"lastServerIdPInfo":'); shell.assertNotContainsOutput(/"refreshToken": "(?!debugid:)/); - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer.connectionString(), '--authenticationMechanism=MONGODB-OIDC', @@ -558,7 +560,7 @@ describe('OIDC auth e2e', function () { }); it('logs OIDC HTTP calls', async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer.connectionString(), '--authenticationMechanism=MONGODB-OIDC', @@ -606,7 +608,7 @@ describe('OIDC auth e2e', function () { } await fs.writeFile(tokenFile, accessToken); - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer.connectionString({ authMechanism: 'MONGODB-OIDC', diff --git a/packages/e2e-tests/test/e2e-proxy.spec.ts b/packages/e2e-tests/test/e2e-proxy.spec.ts index b120abeb5..093fc87a0 100644 --- a/packages/e2e-tests/test/e2e-proxy.spec.ts +++ b/packages/e2e-tests/test/e2e-proxy.spec.ts @@ -5,19 +5,16 @@ import type { } from 'http'; import { createServer as createHTTPServer, request } from 'http'; import { + getTestCertificatePath as getCertPath, MongoRunnerSetup, skipIfApiStrict, skipIfEnvServerVersion, startSharedTestServer, startTestServer, -} from '../../testing/src/integration-testing-hooks'; +} from '@mongosh/testing'; import type { Server as HTTPSServer } from 'https'; import { createServer as createHTTPSServer } from 'https'; -import { - connectionStringWithLocalhost, - getCertPath, - useTmpdir, -} from './repl-helpers'; +import { connectionStringWithLocalhost, useTmpdir } from './repl-helpers'; import { once } from 'events'; import { connect } from 'net'; import type { AddressInfo, Socket } from 'net'; @@ -31,6 +28,7 @@ import { commonOidcServerArgs, skipOIDCTestsDueToPlatformOrServerVersion, } from './oidc-helpers'; +import { startTestShell } from './test-shell-context'; const CA_CERT = getCertPath('ca.crt'); const SERVER_BUNDLE = getCertPath('server.bundle.pem'); @@ -129,7 +127,7 @@ describe('e2e proxy support', function () { }); it('can connect using an HTTP proxy', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await testServer.connectionString()], env: { ...process.env, @@ -149,7 +147,7 @@ describe('e2e proxy support', function () { }); it('can connect using an HTTP proxy with auth', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await testServer.connectionString()], env: { ...process.env, @@ -171,7 +169,7 @@ describe('e2e proxy support', function () { }); it('can connect using an HTTP proxy specified via ALL_PROXY', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await testServer.connectionString()], env: { ...process.env, @@ -193,7 +191,7 @@ describe('e2e proxy support', function () { }); it('can connect using an HTTPS proxy (explicit CA on command line)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await testServer.connectionString(), '--tlsCAFile', CA_CERT], env: { ...process.env, @@ -213,7 +211,7 @@ describe('e2e proxy support', function () { }); it('can connect using an HTTPS proxy (CA in connection string)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await testServer.connectionString({ tlsCAFile: CA_CERT })], env: { ...process.env, @@ -240,7 +238,7 @@ describe('e2e proxy support', function () { path.join(tmpdir.path, 'certs', 'somefilename.crt') ); - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await testServer.connectionString()], env: { ...process.env, @@ -261,7 +259,7 @@ describe('e2e proxy support', function () { }); it('fails to connect using HTTPS proxy (no CA)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await testServer.connectionString({ connectTimeoutMS: '2000' })], env: { ...process.env, @@ -289,7 +287,7 @@ describe('e2e proxy support', function () { }); it('can connect using an HTTP proxy', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(tlsServer, { tlsCAFile: CA_CERT, @@ -314,7 +312,7 @@ describe('e2e proxy support', function () { }); it('can connect using an HTTPS proxy', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(tlsServer, { tlsCAFile: CA_CERT, @@ -340,7 +338,7 @@ describe('e2e proxy support', function () { }); it('will exclude a proxy host specified in NO_PROXY', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [await testServer.connectionString()], env: { ...process.env, @@ -454,7 +452,7 @@ describe('e2e proxy support', function () { }); it('can route all traffic through the proxy', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await oidcTestServer.connectionString({}, { username: 'testuser' }), '--authenticationMechanism=MONGODB-OIDC', @@ -498,7 +496,7 @@ describe('e2e proxy support', function () { }); it('can route only http traffic through the proxy', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await oidcTestServer.connectionString({}, { username: 'testuser' }), '--authenticationMechanism=MONGODB-OIDC', @@ -557,7 +555,7 @@ describe('e2e proxy support', function () { })().catch(console.error); } ); - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await oidcTestServer.connectionString({}, { username: 'testuser' }), '--authenticationMechanism=MONGODB-OIDC', @@ -602,7 +600,7 @@ describe('e2e proxy support', function () { }); it('can route all traffic through the proxy (https, incomplete without CA)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await oidcTestServer.connectionString( {}, diff --git a/packages/e2e-tests/test/e2e-snapshot.spec.ts b/packages/e2e-tests/test/e2e-snapshot.spec.ts index 29f83612a..492df0e16 100644 --- a/packages/e2e-tests/test/e2e-snapshot.spec.ts +++ b/packages/e2e-tests/test/e2e-snapshot.spec.ts @@ -1,8 +1,6 @@ -import { - skipIfApiStrict, - startSharedTestServer, -} from '../../testing/src/integration-testing-hooks'; +import { skipIfApiStrict, startSharedTestServer } from '@mongosh/testing'; import { expect } from 'chai'; +import { startTestShell } from './test-shell-context'; const setDifference = (a: T[], b: T[]) => a.filter((e) => !b.includes(e)); const expectIsSubset = (a: T[], b: T[]) => @@ -56,7 +54,7 @@ describe('e2e snapshot support', function () { ] = ( await Promise.all( argLists.map((args) => - this.startTestShell({ args }).waitForCleanOutput() + startTestShell(this, { args }).waitForCleanOutput() ) ) ).map((output) => diff --git a/packages/e2e-tests/test/e2e-snippet.spec.ts b/packages/e2e-tests/test/e2e-snippet.spec.ts index c79b63e65..6982ba20c 100644 --- a/packages/e2e-tests/test/e2e-snippet.spec.ts +++ b/packages/e2e-tests/test/e2e-snippet.spec.ts @@ -3,7 +3,8 @@ import path from 'path'; import { expect } from 'chai'; import type { TestShell } from './test-shell'; import { useTmpdir } from './repl-helpers'; -import { eventually } from '../../testing/src/eventually'; +import { eventually } from '@mongosh/testing'; +import { startTestShell } from './test-shell-context'; describe('snippet integration tests', function () { this.timeout(120_000); @@ -19,7 +20,7 @@ describe('snippet integration tests', function () { } makeTestShell = () => - this.startTestShell({ + startTestShell(this, { args: ['--nodb'], cwd: tmpdir.path, env: { diff --git a/packages/e2e-tests/test/e2e-streams.spec.ts b/packages/e2e-tests/test/e2e-streams.spec.ts index 914b390ea..2b0eae7a9 100644 --- a/packages/e2e-tests/test/e2e-streams.spec.ts +++ b/packages/e2e-tests/test/e2e-streams.spec.ts @@ -4,7 +4,8 @@ import { MongoClient } from 'mongodb'; import { expect } from 'chai'; import type { TestShell } from './test-shell'; import { sleep } from './util-helpers'; -import { eventually } from '../../testing/src/eventually'; +import { eventually } from '@mongosh/testing'; +import { startTestShell } from './test-shell-context'; const { STREAMS_E2E_SPI_CONNECTION_STRING = '', @@ -57,7 +58,7 @@ describe('e2e Streams', function () { let client: MongoClient; beforeEach(async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ STREAMS_E2E_SPI_CONNECTION_STRING, '--tls', @@ -277,7 +278,7 @@ describe('e2e Streams', function () { describe('sampling from a running stream processor', function () { beforeEach(async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ STREAMS_E2E_SPI_CONNECTION_STRING, '--tls', @@ -323,7 +324,7 @@ describe('e2e Streams', function () { const collectionName = 'processedData'; beforeEach(async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ STREAMS_E2E_SPI_CONNECTION_STRING, '--tls', diff --git a/packages/e2e-tests/test/e2e-tls.spec.ts b/packages/e2e-tests/test/e2e-tls.spec.ts index 8101faa35..d7f8cb17b 100644 --- a/packages/e2e-tests/test/e2e-tls.spec.ts +++ b/packages/e2e-tests/test/e2e-tls.spec.ts @@ -1,14 +1,17 @@ import { expect } from 'chai'; import { promises as fs } from 'fs'; import path from 'path'; -import { startTestServer } from '../../testing/src/integration-testing-hooks'; +import { + getTestCertificatePath as getCertPath, + startTestServer, +} from '@mongosh/testing'; import { useTmpdir, setTemporaryHomeDirectory, readReplLogFile, - getCertPath, connectionStringWithLocalhost, } from './repl-helpers'; +import { startTestShell } from './test-shell-context'; const CA_CERT = getCertPath('ca.crt'); const NON_CA_CERT = getCertPath('non-ca.crt'); @@ -82,7 +85,7 @@ describe('e2e TLS', function () { // and subsequently can't connect to the server to find out if it's up, // then thinks it isn't and doesn't shut it down cleanly. We shut it down // here to work around that. - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server), '--tls', @@ -109,7 +112,7 @@ describe('e2e TLS', function () { }); it('works with matching CA (args)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server), '--tls', @@ -122,7 +125,7 @@ describe('e2e TLS', function () { }); it('works with matching CA (connection string)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { tls: 'true', @@ -135,7 +138,7 @@ describe('e2e TLS', function () { }); it('fails when not using --tls (args)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { serverSelectionTimeoutMS: '1500', @@ -148,7 +151,7 @@ describe('e2e TLS', function () { }); it('fails when not using --tls (connection string)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { serverSelectionTimeoutMS: '1500', @@ -162,7 +165,7 @@ describe('e2e TLS', function () { }); it('fails with invalid CA (args)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { serverSelectionTimeoutMS: '1500', @@ -180,7 +183,7 @@ describe('e2e TLS', function () { }); it('fails with invalid CA (connection string)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { serverSelectionTimeoutMS: '1500', @@ -197,7 +200,7 @@ describe('e2e TLS', function () { }); it('fails when providing a CRL including the servers cert', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { serverSelectionTimeoutMS: '1500', @@ -223,7 +226,7 @@ describe('e2e TLS', function () { CA_CERT, path.join(tmpdir.path, 'certs', 'somefilename.crt') ); - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { serverSelectionTimeoutMS: '1500', @@ -261,7 +264,7 @@ describe('e2e TLS', function () { CA_CERT, path.join(tmpdir.path, 'certs', 'somefilename.crt') ); - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { serverSelectionTimeoutMS: '1500', @@ -294,7 +297,7 @@ describe('e2e TLS', function () { if (process.platform !== 'darwin' && process.platform !== 'win32') { return this.skip(); } - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { serverSelectionTimeoutMS: '1500', @@ -342,7 +345,7 @@ describe('e2e TLS', function () { }); it('works with matching CA (connection string)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { tls: 'true', @@ -365,7 +368,7 @@ describe('e2e TLS', function () { path.join(tmpdir.path, 'certs', 'somefilename.crt') ); - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { serverSelectionTimeoutMS: '1500', @@ -387,7 +390,7 @@ describe('e2e TLS', function () { context('connecting with client cert to server with valid cert', function () { after(async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server), '--tls', @@ -421,7 +424,7 @@ describe('e2e TLS', function () { return this.skip(); // createUser is unversioned } /* connect with cert to create user */ - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { serverSelectionTimeoutMS: '1500', @@ -445,7 +448,7 @@ describe('e2e TLS', function () { }); it('works with valid cert (args)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { serverSelectionTimeoutMS: '1500', @@ -476,7 +479,7 @@ describe('e2e TLS', function () { }); it('works with valid cert (args, encrypted)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { serverSelectionTimeoutMS: '1500', @@ -514,7 +517,7 @@ describe('e2e TLS', function () { }); it('works with valid cert (connection string)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { serverSelectionTimeoutMS: '1500', @@ -542,7 +545,7 @@ describe('e2e TLS', function () { }); it('works with valid cert (connection string, encrypted)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { serverSelectionTimeoutMS: '1500', @@ -576,7 +579,7 @@ describe('e2e TLS', function () { }); it('asks for tlsCertificateKeyFilePassword when it is needed (connection string, encrypted)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { serverSelectionTimeoutMS: '1500', @@ -611,7 +614,7 @@ describe('e2e TLS', function () { }); it('fails with invalid cert (args)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { serverSelectionTimeoutMS: '1500', @@ -631,7 +634,7 @@ describe('e2e TLS', function () { }); it('fails with invalid cert (connection string)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { serverSelectionTimeoutMS: '1500', @@ -662,7 +665,7 @@ describe('e2e TLS', function () { }); ` ); - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { serverSelectionTimeoutMS: '1500', @@ -687,7 +690,7 @@ describe('e2e TLS', function () { }); it('fails with an invalid tlsCertificateSelector', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server, { serverSelectionTimeoutMS: '1500', @@ -725,7 +728,7 @@ describe('e2e TLS', function () { // and subsequently can't connect to the server to find out if it's up, // then thinks it isn't and doesn't shut it down cleanly. We shut it down // here to work around that. - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server), '--tls', @@ -751,7 +754,7 @@ describe('e2e TLS', function () { }); it('works with allowInvalidCertificates', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server), '--tls', @@ -765,7 +768,7 @@ describe('e2e TLS', function () { }); it('works with allowInvalidHostnames', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server), '--tls', @@ -779,7 +782,7 @@ describe('e2e TLS', function () { }); it('fails when no additional args are provided', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await connectionStringWithLocalhost(server), '--tls', diff --git a/packages/e2e-tests/test/e2e.spec.ts b/packages/e2e-tests/test/e2e.spec.ts index 7adc59e31..7749fbd15 100644 --- a/packages/e2e-tests/test/e2e.spec.ts +++ b/packages/e2e-tests/test/e2e.spec.ts @@ -3,13 +3,13 @@ import { expect } from 'chai'; import type { Db } from 'mongodb'; import { MongoClient, ObjectId } from 'mongodb'; -import { eventually } from '../../testing/src/eventually'; import { TestShell } from './test-shell'; -import { ensureTestShellAfterHook } from './test-shell-context'; +import { ensureTestShellAfterHook, startTestShell } from './test-shell-context'; import { + eventually, skipIfServerVersion, startSharedTestServer, -} from '../../testing/src/integration-testing-hooks'; +} from '@mongosh/testing'; import { promises as fs, createReadStream } from 'fs'; import { promisify } from 'util'; import path from 'path'; @@ -42,17 +42,17 @@ describe('e2e', function () { // version() sources its version data from the shell-api package's generated files, // --version from the cli-repl package.json and --build-info from the generated build-info.json // (if available), which should all match. - const shell = this.startTestShell({ args: ['--nodb'] }); + const shell = startTestShell(this, { args: ['--nodb'] }); await shell.waitForPrompt(); const versionFromShellApi = (await shell.executeLine('version()')) .replace(/>/g, '') .trim(); - const versionShell = this.startTestShell({ args: ['--version'] }); + const versionShell = startTestShell(this, { args: ['--version'] }); await versionShell.waitForSuccessfulExit(); const versionFromCliFlag = versionShell.output.trim(); - const buildInfoShell = this.startTestShell({ args: ['--build-info'] }); + const buildInfoShell = startTestShell(this, { args: ['--build-info'] }); await buildInfoShell.waitForSuccessfulExit(); const versionFromBuildInfo = JSON.parse(buildInfoShell.output).version; @@ -63,7 +63,7 @@ describe('e2e', function () { describe('--build-info', function () { it('shows build info in JSON format', async function () { - const shell = this.startTestShell({ args: ['--build-info'] }); + const shell = startTestShell(this, { args: ['--build-info'] }); await shell.waitForSuccessfulExit(); const data = JSON.parse(shell.output); @@ -111,7 +111,7 @@ describe('e2e', function () { let processReport: any; { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ '--quiet', '--nodb', @@ -129,7 +129,7 @@ describe('e2e', function () { }); it('provides build info via the buildInfo() builtin', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ '--quiet', '--eval', @@ -148,7 +148,7 @@ describe('e2e', function () { describe('--nodb', function () { let shell: TestShell; beforeEach(async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: ['--nodb'], }); await shell.waitForPrompt(); @@ -175,7 +175,7 @@ describe('e2e', function () { expect(shell.output).to.include('No connected database\n> '); }); it('colorizes syntax errors', async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: ['--nodb'], env: { ...process.env, FORCE_COLOR: 'true', TERM: 'xterm-256color' }, forceTerminal: true, @@ -258,7 +258,7 @@ describe('e2e', function () { }); }); it('accepts a --tlsFIPSMode argument', async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: ['--nodb', '--tlsFIPSMode'], }); const result = await shell.waitForPromptOrExit(); @@ -274,7 +274,7 @@ describe('e2e', function () { } }); it('prints full output even when that output is buffered', async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ '--nodb', '--quiet', @@ -299,7 +299,7 @@ describe('e2e', function () { }); it('handles custom prompt() function in conjunction with line-by-line input well', async function () { // https://jira.mongodb.org/browse/MONGOSH-1617 - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ '--nodb', '--shell', @@ -315,7 +315,7 @@ describe('e2e', function () { expect(await shell.waitForCleanOutput()).to.include('3628800'); }); it('ignores control characters in TTY input', async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: ['--nodb'], forceTerminal: true, }); @@ -328,7 +328,7 @@ describe('e2e', function () { ).to.include('\n72\n'); }); it('ignores control characters in TTY input inside of .editor', async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: ['--nodb'], forceTerminal: true, }); @@ -368,7 +368,7 @@ describe('e2e', function () { describe('via host:port/test', function () { let shell: TestShell; beforeEach(async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: [`${await testServer.hostport()}/${dbname}`], }); await shell.waitForPrompt(); @@ -382,7 +382,7 @@ describe('e2e', function () { describe('via mongodb://uri', function () { let shell: TestShell; beforeEach(async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: [`mongodb://${await testServer.hostport()}/${dbnameUri}`], }); await shell.waitForPrompt(); @@ -397,7 +397,7 @@ describe('e2e', function () { let shell: TestShell; beforeEach(async function () { const port = await testServer.port(); - shell = this.startTestShell({ args: [dbname, `--port=${port}`] }); + shell = startTestShell(this, { args: [dbname, `--port=${port}`] }); await shell.waitForPrompt(); shell.assertNoErrors(); }); @@ -409,7 +409,7 @@ describe('e2e', function () { describe('via use() method', function () { let shell: TestShell; beforeEach(async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: [`mongodb://${await testServer.hostport()}/`], }); await shell.waitForPrompt(); @@ -430,7 +430,7 @@ describe('e2e', function () { context('with default appName', function () { let shell: TestShell; beforeEach(async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: [`mongodb://${await testServer.hostport()}/`], }); await shell.waitForPrompt(); @@ -452,7 +452,7 @@ describe('e2e', function () { context('with custom appName', function () { let shell: TestShell; beforeEach(async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: [`mongodb://${await testServer.hostport()}/?appName=Felicia`], }); await shell.waitForPrompt(); @@ -479,7 +479,7 @@ describe('e2e', function () { beforeEach(async function () { const connectionString = await testServer.connectionString(); dbName = `test-${Date.now()}`; - shell = this.startTestShell({ args: [connectionString] }); + shell = startTestShell(this, { args: [connectionString] }); client = await MongoClient.connect(connectionString, {}); @@ -944,7 +944,7 @@ describe('e2e', function () { describe('with --host', function () { let shell: TestShell; it('allows invalid hostnames with _', async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: ['--host', 'xx_invalid_domain_xx'], env: { ...process.env, FORCE_COLOR: 'true', TERM: 'xterm-256color' }, forceTerminal: true, @@ -983,7 +983,7 @@ describe('e2e', function () { 'load', 'long-sleep.js' ); - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: ['--nodb', ...jsContextFlags, filename], removeSigintListeners: true, forceTerminal: true, @@ -1011,7 +1011,7 @@ describe('e2e', function () { describe('interactive', function () { let shell: TestShell; beforeEach(async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: ['--nodb'], removeSigintListeners: true, }); @@ -1069,7 +1069,7 @@ describe('e2e', function () { describe('printing', function () { let shell: TestShell; beforeEach(async function () { - shell = this.startTestShell({ args: ['--nodb'] }); + shell = startTestShell(this, { args: ['--nodb'] }); await shell.waitForPrompt(); shell.assertNoErrors(); }); @@ -1088,7 +1088,7 @@ describe('e2e', function () { describe('pipe from stdin', function () { let shell: TestShell; beforeEach(async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: [await testServer.connectionString()], }); }); @@ -1144,7 +1144,7 @@ describe('e2e', function () { it('works fine with custom prompts', async function () { // https://jira.mongodb.org/browse/MONGOSH-1617 - shell = this.startTestShell({ + shell = startTestShell(this, { args: [ await testServer.connectionString(), '--eval', @@ -1163,7 +1163,7 @@ describe('e2e', function () { describe('Node.js builtin APIs in the shell', function () { let shell: TestShell; beforeEach(async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: ['--nodb'], cwd: path.resolve(__dirname, 'fixtures', 'require-base'), env: { @@ -1221,7 +1221,7 @@ describe('e2e', function () { )})`, function () { context('file from disk', function () { it('loads a file from the command line as requested', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: ['--nodb', ...jsContextFlags, './hello1.js'], cwd: path.resolve( __dirname, @@ -1245,7 +1245,7 @@ describe('e2e', function () { if (!jsContextFlags.includes('--jsContext=plain-vm')) { it('drops into shell if --shell is used', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: ['--nodb', ...jsContextFlags, '--shell', './hello1.js'], cwd: path.resolve( __dirname, @@ -1264,7 +1264,7 @@ describe('e2e', function () { }); it('fails with the error if the loaded script throws', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: ['--nodb', ...jsContextFlags, '--shell', './throw.js'], cwd: path.resolve( __dirname, @@ -1287,7 +1287,7 @@ describe('e2e', function () { context('--eval', function () { const script = 'const a = "hello", b = " one"; a + b'; it('loads a script from the command line as requested', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: ['--nodb', ...jsContextFlags, '--eval', script], }); await eventually(() => { @@ -1298,7 +1298,7 @@ describe('e2e', function () { if (!jsContextFlags.includes('--jsContext=plain-vm')) { it('drops into shell if --shell is used', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: ['--nodb', ...jsContextFlags, '--eval', script, '--shell'], }); await shell.waitForPrompt(); @@ -1309,7 +1309,7 @@ describe('e2e', function () { } it('fails with the error if the loaded script throws synchronously', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ '--nodb', ...jsContextFlags, @@ -1324,7 +1324,7 @@ describe('e2e', function () { }); it('fails with the error if the loaded script throws asynchronously (setImmediate)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ '--nodb', ...jsContextFlags, @@ -1341,7 +1341,7 @@ describe('e2e', function () { }); it('fails with the error if the loaded script throws asynchronously (Promise)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ '--nodb', ...jsContextFlags, @@ -1365,7 +1365,7 @@ describe('e2e', function () { executionAsyncId: async_hooks.executionAsyncId() }; })()`; - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ '--nodb', ...jsContextFlags, @@ -1408,7 +1408,10 @@ describe('e2e', function () { let readLogFile: ( customBasePath?: string ) => Promise; - let startTestShell: (...extraArgs: string[]) => Promise; + let startNodbTestShellAndWaitForPrompt: ( + context: Mocha.Context, + ...extraArgs: string[] + ) => Promise; beforeEach(function () { const homeInfo = setTemporaryHomeDirectory(); @@ -1456,8 +1459,11 @@ describe('e2e', function () { ); return readReplLogFile(logPath); }; - startTestShell = async (...extraArgs: string[]) => { - const shell = this.startTestShell({ + startNodbTestShellAndWaitForPrompt = async ( + context: Mocha.Context, + ...extraArgs: string[] + ) => { + const shell = startTestShell(context, { args: ['--nodb', ...extraArgs], env, forceTerminal: true, @@ -1485,7 +1491,7 @@ describe('e2e', function () { context('in fully accessible environment', function () { beforeEach(async function () { await fs.mkdir(homedir, { recursive: true }); - shell = await startTestShell(); + shell = await startNodbTestShellAndWaitForPrompt(this); }); describe('config file', function () { @@ -1499,7 +1505,7 @@ describe('e2e', function () { it('persists between sessions', async function () { const config1 = await readConfig(); - await startTestShell(); + await startNodbTestShellAndWaitForPrompt(this); const config2 = await readConfig(); expect(config1.userId).to.equal(config2.userId); }); @@ -1510,7 +1516,7 @@ describe('e2e', function () { globalConfig, 'mongosh:\n redactHistory: remove-redact' ); - shell = this.startTestShell({ + shell = startTestShell(this, { args: ['--nodb'], env, globalConfigPath: globalConfig, @@ -1565,7 +1571,7 @@ describe('e2e', function () { it('does not get created if global config has disableLogging', async function () { const globalConfig = path.join(homedir, 'globalconfig.conf'); await fs.writeFile(globalConfig, 'mongosh:\n disableLogging: true'); - shell = this.startTestShell({ + shell = startTestShell(this, { args: ['--nodb'], env, globalConfigPath: globalConfig, @@ -1584,7 +1590,7 @@ describe('e2e', function () { it('gets created if global config has disableLogging set to false', async function () { const globalConfig = path.join(homedir, 'globalconfig.conf'); await fs.writeFile(globalConfig, 'mongosh:\n disableLogging: false'); - shell = this.startTestShell({ + shell = startTestShell(this, { args: ['--nodb'], env, globalConfigPath: globalConfig, @@ -1619,7 +1625,7 @@ describe('e2e', function () { `mongosh:\n logLocation: "./some-relative-path"` ); - shell = this.startTestShell({ + shell = startTestShell(this, { args: ['--nodb'], env, globalConfigPath: globalConfig, @@ -1647,7 +1653,7 @@ describe('e2e', function () { `mongosh:\n logLocation: ${JSON.stringify(customLogDir.path)}` ); - shell = this.startTestShell({ + shell = startTestShell(this, { args: ['--nodb'], env, globalConfigPath: globalConfig, @@ -1780,7 +1786,7 @@ describe('e2e', function () { )}\n logCompressionEnabled: true` ); - shell = this.startTestShell({ + shell = startTestShell(this, { args: ['--nodb'], env, globalConfigPath: globalConfig, @@ -1847,7 +1853,7 @@ describe('e2e', function () { expect(await getFilesState(paths)).equals('1111111111'); - shell = this.startTestShell({ + shell = startTestShell(this, { args: ['--nodb'], env, globalConfigPath: globalConfig, @@ -1901,7 +1907,7 @@ describe('e2e', function () { // All 7 existing log files exist. expect(await getFilesState(paths)).to.equal('111111'); - shell = this.startTestShell({ + shell = startTestShell(this, { args: ['--nodb'], env: { ...env, @@ -1940,7 +1946,7 @@ describe('e2e', function () { // All 10 existing log files exist. expect(await getFilesState(paths)).to.equal('1111111111'); - shell = this.startTestShell({ + shell = startTestShell(this, { args: ['--nodb'], env, globalConfigPath: globalConfig, @@ -1988,7 +1994,7 @@ describe('e2e', function () { // All 10 existing log files exist. expect(await getFilesState(paths)).to.equal('1111111111'); - shell = this.startTestShell({ + shell = startTestShell(this, { args: ['--nodb'], env, globalConfigPath: globalConfig, @@ -2178,7 +2184,7 @@ describe('e2e', function () { }); it('flushes log file (normal exit)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ '--nodb', '--eval', @@ -2197,7 +2203,7 @@ describe('e2e', function () { }); it('flushes log file (exception thrown)', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ '--nodb', '--eval', @@ -2224,7 +2230,7 @@ describe('e2e', function () { shell.writeInput('.exit\n'); await shell.waitForSuccessfulExit(); - shell = await startTestShell(); + shell = await startNodbTestShellAndWaitForPrompt(this); // Arrow up twice to skip the .exit line shell.writeInput('\u001b[A\u001b[A'); await eventually(() => { @@ -2272,12 +2278,12 @@ describe('e2e', function () { }); it('loads .mongoshrc.js if it is there', async function () { - shell = await startTestShell(); + shell = await startNodbTestShellAndWaitForPrompt(this); shell.assertContainsOutput('hi from mongoshrc'); }); it('does not load .mongoshrc.js if --norc is passed', async function () { - shell = await startTestShell('--norc'); + shell = await startNodbTestShellAndWaitForPrompt(this, '--norc'); shell.assertNotContainsOutput('hi from mongoshrc'); }); }); @@ -2308,7 +2314,10 @@ describe('e2e', function () { it('shows an update notification if a newer version is available', async function () { { - const shell = await startTestShell('--quiet'); + const shell = await startNodbTestShellAndWaitForPrompt( + this, + '--quiet' + ); await shell.executeLine( `config.set("updateURL", ${JSON.stringify(httpServerUrl)})` ); @@ -2321,7 +2330,7 @@ describe('e2e', function () { env.MONGOSH_ASSUME_DIFFERENT_VERSION_FOR_UPDATE_NOTIFICATION_TEST = '1.0.0'; { - const shell = await startTestShell(); + const shell = await startNodbTestShellAndWaitForPrompt(this); await eventually(async () => { expect( JSON.parse( @@ -2337,7 +2346,7 @@ describe('e2e', function () { } { - const shell = await startTestShell(); + const shell = await startNodbTestShellAndWaitForPrompt(this); shell.writeInputLine('exit'); await shell.waitForSuccessfulExit(); shell.assertContainsOutput( @@ -2351,7 +2360,7 @@ describe('e2e', function () { context('in a restricted environment', function () { it('keeps working when the home directory cannot be created at all', async function () { await fs.writeFile(homedir, 'this is a file and not a directory'); - const shell = await startTestShell(); + const shell = await startNodbTestShellAndWaitForPrompt(this); await eventually(() => { expect(shell.output).to.include('Warning: Could not access file:'); }); @@ -2365,7 +2374,7 @@ describe('e2e', function () { it('keeps working when the log files cannot be created', async function () { await fs.mkdir(path.dirname(logBasePath), { recursive: true }); await fs.writeFile(logBasePath, 'also not a directory'); - const shell = await startTestShell(); + const shell = await startNodbTestShellAndWaitForPrompt(this); await eventually(() => { expect(shell.output).to.include('Warning: Could not access file:'); }); @@ -2390,7 +2399,7 @@ describe('e2e', function () { await fs.mkdir(path.dirname(configPath), { recursive: true }); await fs.writeFile(configPath, '{}'); await fs.chmod(configPath, 0); // Remove all permissions - const shell = await startTestShell(); + const shell = await startNodbTestShellAndWaitForPrompt(this); await eventually(() => { expect(shell.output).to.include('Warning: Could not access file:'); }); @@ -2427,7 +2436,7 @@ describe('e2e', function () { skipIfServerVersion(testServer, '> 4.4'); it('errors if an API version is specified', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await testServer.connectionString({}, { pathname: `/${dbName}` }), '--apiVersion', @@ -2445,7 +2454,7 @@ describe('e2e', function () { skipIfServerVersion(testServer, '<= 4.4'); it('can specify an API version', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await testServer.connectionString({}, { pathname: `/${dbName}` }), '--apiVersion', @@ -2461,7 +2470,7 @@ describe('e2e', function () { }); it('can specify an API version and strict mode', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await testServer.connectionString({}, { pathname: `/${dbName}` }), '--apiVersion', @@ -2480,7 +2489,7 @@ describe('e2e', function () { it('can iterate cursors', async function () { // Make sure SERVER-55593 doesn't happen to us. - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ await testServer.connectionString({}, { pathname: `/${dbName}` }), '--apiVersion', @@ -2502,7 +2511,7 @@ describe('e2e', function () { describe('fail-fast connections', function () { it('fails fast for ENOTFOUND errors', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ 'mongodb://' + 'verymuchnonexistentdomainname'.repeat(4) + @@ -2516,7 +2525,7 @@ describe('e2e', function () { it('fails fast for ENOTFOUND/EINVAL errors', async function () { // Very long & nonexistent domain can result in EINVAL in Node.js >= 20.11 // In lower versions, it would be ENOTFOUND - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ 'mongodb://' + 'verymuchnonexistentdomainname'.repeat(10) + @@ -2528,7 +2537,7 @@ describe('e2e', function () { }); it('fails fast for ECONNREFUSED errors to a single host', async function () { - const shell = this.startTestShell({ args: ['--port', '1'] }); + const shell = startTestShell(this, { args: ['--port', '1'] }); const result = await shell.waitForPromptOrExit(); expect(result).to.deep.equal({ state: 'exit', exitCode: 1 }); }); @@ -2540,7 +2549,7 @@ describe('e2e', function () { // isn't a shell-specific issue. return this.skip(); } - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [ 'mongodb://127.0.0.1:1,127.0.0.2:1,127.0.0.3:1/?replicaSet=foo&readPreference=secondary', ], @@ -2554,7 +2563,7 @@ describe('e2e', function () { let shell: TestShell; beforeEach(async function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: [await testServer.connectionString()], }); await shell.waitForPrompt(); @@ -2594,7 +2603,7 @@ describe('e2e', function () { let shell: TestShell; beforeEach(function () { - shell = this.startTestShell({ + shell = startTestShell(this, { args: [], env: { ...process.env, MONGOSH_FORCE_CONNECTION_STRING_PROMPT: '1' }, forceTerminal: true, @@ -2619,7 +2628,7 @@ describe('e2e', function () { describe('with incomplete loadBalanced connectivity', function () { it('prints a warning at startup', async function () { - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: ['mongodb://localhost:1/?loadBalanced=true'], }); await shell.waitForPrompt(); @@ -2641,7 +2650,7 @@ describe('e2e', function () { 'fixtures', 'simple-console-log.js' ); - const shell = this.startTestShell({ + const shell = startTestShell(this, { args: [filename], env: { ...process.env, MONGOSH_RUN_NODE_SCRIPT: '1' }, }); @@ -2659,10 +2668,10 @@ describe('e2e', function () { const OPERATION_TIME = CURRENT_OP_WAIT_TIME * 2; beforeEach(async function () { - helperShell = this.startTestShell({ + helperShell = startTestShell(this, { args: [await testServer.connectionString()], }); - currentOpShell = this.startTestShell({ + currentOpShell = startTestShell(this, { args: [await testServer.connectionString()], }); await helperShell.waitForPrompt(); diff --git a/packages/e2e-tests/test/repl-helpers.ts b/packages/e2e-tests/test/repl-helpers.ts index 5617e0337..8fea5acfe 100644 --- a/packages/e2e-tests/test/repl-helpers.ts +++ b/packages/e2e-tests/test/repl-helpers.ts @@ -5,7 +5,7 @@ import rimraf from 'rimraf'; import * as chai from 'chai'; import sinonChai from 'sinon-chai'; import chaiAsPromised from 'chai-as-promised'; -import type { MongodSetup } from '../../testing/src/integration-testing-hooks'; +import type { MongodSetup } from '@mongosh/testing'; import type { MongoLogEntry } from 'mongodb-log-writer'; chai.use(sinonChai); @@ -140,10 +140,6 @@ const setTemporaryHomeDirectory = () => { return { homedir, env }; }; -function getCertPath(filename: string): string { - return path.join(__dirname, '..', '..', 'testing', 'certificates', filename); -} - // TLS requires matching hostnames, so here we need to explicitly // specify `localhost` + IPv4 instead of `127.0.0.1` async function connectionStringWithLocalhost( @@ -166,7 +162,6 @@ export { readReplLogFile, fakeExternalEditor, setTemporaryHomeDirectory, - getCertPath, connectionStringWithLocalhost, MongoLogEntryFromFile, }; diff --git a/packages/e2e-tests/test/test-shell-context.spec.ts b/packages/e2e-tests/test/test-shell-context.spec.ts index 01f144e57..0e4275b0a 100644 --- a/packages/e2e-tests/test/test-shell-context.spec.ts +++ b/packages/e2e-tests/test/test-shell-context.spec.ts @@ -1,37 +1,37 @@ import { TestShell } from './test-shell'; -import { ensureTestShellAfterHook } from './test-shell-context'; +import { ensureTestShellAfterHook, startTestShell } from './test-shell-context'; describe('TestShell context', function () { context('hooks and tests', function () { before(async function () { - const shell = this.startTestShell({ args: ['--nodb'] }); + const shell = startTestShell(this, { args: ['--nodb'] }); await shell.waitForPrompt(); }); beforeEach(async function () { - const shell = this.startTestShell({ args: ['--nodb'] }); + const shell = startTestShell(this, { args: ['--nodb'] }); await shell.waitForPrompt(); }); after(async function () { - const shell = this.startTestShell({ args: ['--nodb'] }); + const shell = startTestShell(this, { args: ['--nodb'] }); await shell.waitForPrompt(); }); afterEach(async function () { - const shell = this.startTestShell({ args: ['--nodb'] }); + const shell = startTestShell(this, { args: ['--nodb'] }); await shell.waitForPrompt(); }); it("doesn't explode", async function () { - const shell = this.startTestShell({ args: ['--nodb'] }); + const shell = startTestShell(this, { args: ['--nodb'] }); await shell.waitForPrompt(); }); }); context('adding an after each running after cleanup', function () { beforeEach(async function () { - const shell = this.startTestShell({ args: ['--nodb'] }); + const shell = startTestShell(this, { args: ['--nodb'] }); await shell.waitForPrompt(); }); diff --git a/packages/e2e-tests/test/test-shell-context.ts b/packages/e2e-tests/test/test-shell-context.ts index 3241f68b1..b1acab94a 100644 --- a/packages/e2e-tests/test/test-shell-context.ts +++ b/packages/e2e-tests/test/test-shell-context.ts @@ -2,15 +2,6 @@ import assert from 'assert'; import Mocha from 'mocha'; import { TestShell, type TestShellOptions } from './test-shell'; -declare module 'mocha' { - interface Context { - /** - * Starts a test shell and registers a hook to kill it after the test - */ - startTestShell(options?: TestShellOptions): TestShell; - } -} - const TEST_SHELLS_AFTER_ALL = Symbol('test-shells-after-all'); const TEST_SHELLS_AFTER_EACH = Symbol('test-shells-after-each'); @@ -67,11 +58,11 @@ export function ensureTestShellAfterHook( } } -Mocha.Context.prototype.startTestShell = function ( - this: Mocha.Context, +export function startTestShell( + context: Mocha.Context, options: TestShellOptions ) { - const { test: runnable } = this; + const { test: runnable } = context; assert(runnable, 'Expected a runnable / test'); const { parent } = runnable; assert(parent, 'Expected runnable to have a parent'); @@ -101,4 +92,4 @@ Mocha.Context.prototype.startTestShell = function ( throw new Error('Unexpected Runnable: Expected a Hook or a Test'); } return shell; -}; +} diff --git a/packages/e2e-tests/test/test-shell.ts b/packages/e2e-tests/test/test-shell.ts index 9bdeaed01..4b9dd1603 100644 --- a/packages/e2e-tests/test/test-shell.ts +++ b/packages/e2e-tests/test/test-shell.ts @@ -9,7 +9,7 @@ import { inspect } from 'util'; import path from 'path'; import stripAnsi from 'strip-ansi'; import { EJSON } from 'bson'; -import { eventually } from '../../testing/src/eventually'; +import { eventually } from '@mongosh/testing'; /* eslint-disable mocha/no-exports -- This file export hooks wrapping Mocha's Hooks APIs */ diff --git a/packages/testing/src/integration-testing-hooks.ts b/packages/testing/src/integration-testing-hooks.ts index b28925a47..bd190769f 100644 --- a/packages/testing/src/integration-testing-hooks.ts +++ b/packages/testing/src/integration-testing-hooks.ts @@ -211,7 +211,6 @@ export async function downloadCurrentCryptSharedLibrary( * @export * @returns {MongodSetup} - Object with information about the started server. */ -let sharedSetup: MongodSetup | null = null; export function startTestServer( id: string, args: Partial = {} @@ -230,6 +229,8 @@ export function startTestServer( return server; } +let installedGlobalAfterHook = false; +let sharedSetup: MongodSetup | null = null; /** * Starts or reuse an existing shared local server managed by this process. * @@ -242,11 +243,17 @@ export function startTestServer( * @returns {MongodSetup} - Object with information about the started server. */ export function startSharedTestServer(): MongodSetup { + if (!installedGlobalAfterHook) { + throw new Error( + 'Trying to start shared test server, but no global after hook was available at module load time' + ); + } + if (process.env.MONGOSH_TEST_SERVER_URL) { return new MongodSetup(process.env.MONGOSH_TEST_SERVER_URL); } - const server = sharedSetup ?? (sharedSetup = new MongoRunnerSetup('shared')); + const server = (sharedSetup ??= new MongoRunnerSetup('shared')); before(async function () { this.timeout(120_000); // Include potential mongod download time. @@ -258,12 +265,15 @@ export function startSharedTestServer(): MongodSetup { return server; } -global.after?.(async function () { - if (sharedSetup !== null) { - this.timeout(30_000); - await sharedSetup.stop(); - } -}); +if ('after' in globalThis) { + installedGlobalAfterHook = true; + after(async function () { + if (sharedSetup !== null) { + this.timeout(30_000); + await sharedSetup.stop(); + } + }); +} // The same as startTestServer(), except that this starts multiple servers // in parallel in the same before() call.