From 7641c1d812bcb0786770285afb781e8f8a367df4 Mon Sep 17 00:00:00 2001 From: gagik Date: Tue, 1 Oct 2024 13:44:08 +0200 Subject: [PATCH 01/21] MONGOSH-1703: FIx mongosh error when converting invalid regular expression in db.currentOp() --- packages/shell-api/src/database.spec.ts | 15 ++++++++------- packages/shell-api/src/database.ts | 5 ++++- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/shell-api/src/database.spec.ts b/packages/shell-api/src/database.spec.ts index 2af23eae8..d4fd662e2 100644 --- a/packages/shell-api/src/database.spec.ts +++ b/packages/shell-api/src/database.spec.ts @@ -1796,10 +1796,11 @@ describe('Database', function () { }, }); - const READ_PREFERENCE = { + const AGGREGATE_OPTIONS = { $readPreference: { mode: 'primaryPreferred', }, + bsonRegExp: true, }; beforeEach(function () { @@ -1824,7 +1825,7 @@ describe('Database', function () { }) ); expect(serviceProvider.aggregateDb.firstCall.args[2]).to.deep.equal( - READ_PREFERENCE + AGGREGATE_OPTIONS ); } }); @@ -1846,7 +1847,7 @@ describe('Database', function () { }) ); expect(serviceProvider.aggregateDb.firstCall.args[2]).to.deep.equal( - READ_PREFERENCE + AGGREGATE_OPTIONS ); }); }); @@ -1868,7 +1869,7 @@ describe('Database', function () { ); expect(matchStage).to.deep.equals({ $match: {} }); expect(serviceProvider.aggregateDb.firstCall.args[2]).to.deep.equal( - READ_PREFERENCE + AGGREGATE_OPTIONS ); }); }); @@ -1890,7 +1891,7 @@ describe('Database', function () { ); expect(matchStage).to.deep.equals({ $match: {} }); expect(serviceProvider.aggregateDb.firstCall.args[2]).to.deep.equal( - READ_PREFERENCE + AGGREGATE_OPTIONS ); }); }); @@ -1914,7 +1915,7 @@ describe('Database', function () { ); expect(matchStage).to.deep.equals({ $match: {} }); expect(serviceProvider.aggregateDb.firstCall.args[2]).to.deep.equal( - READ_PREFERENCE + AGGREGATE_OPTIONS ); }); } @@ -1945,7 +1946,7 @@ describe('Database', function () { $match: { waitingForLock: true }, }); expect(serviceProvider.aggregateDb.firstCall.args[2]).to.deep.equal( - READ_PREFERENCE + AGGREGATE_OPTIONS ); }); diff --git a/packages/shell-api/src/database.ts b/packages/shell-api/src/database.ts index 137782ef0..4688b521e 100644 --- a/packages/shell-api/src/database.ts +++ b/packages/shell-api/src/database.ts @@ -1063,7 +1063,10 @@ export default class Database extends ShellApiWithMongoClass { } const adminDb = this.getSiblingDB('admin'); - const aggregateOptions = { $readPreference: { mode: 'primaryPreferred' } }; + const aggregateOptions = { + $readPreference: { mode: 'primaryPreferred' }, + bsonRegExp: true, + }; try { const cursor = await adminDb.aggregate(pipeline, aggregateOptions); From 91b6ff20e42151f0f4e0fd3234b4eddc2260eb13 Mon Sep 17 00:00:00 2001 From: gagik Date: Tue, 1 Oct 2024 16:04:41 +0200 Subject: [PATCH 02/21] Add e2e test --- .../e2e-tests/test/e2e-current-op.spec.ts | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 packages/e2e-tests/test/e2e-current-op.spec.ts diff --git a/packages/e2e-tests/test/e2e-current-op.spec.ts b/packages/e2e-tests/test/e2e-current-op.spec.ts new file mode 100644 index 000000000..709d87937 --- /dev/null +++ b/packages/e2e-tests/test/e2e-current-op.spec.ts @@ -0,0 +1,84 @@ +import { expect } from 'chai'; +import { + skipIfApiStrict, + startSharedTestServer, +} from '../../../testing/integration-testing-hooks'; +import { TestShell } from './test-shell'; + +describe('e2e currentOp', function () { + skipIfApiStrict(); + afterEach(TestShell.cleanup); + + const testServer = startSharedTestServer(); + + context('with 2 shells', function () { + let helperShell: TestShell; + let currentOpShell: TestShell; + + const OPERATION_TIME = 1_000; + const CURRENT_OP_WAIT_TIME = 100; + this.timeout(OPERATION_TIME * 2); + + beforeEach(async function () { + helperShell = TestShell.start({ + args: [await testServer.connectionString()], + }); + currentOpShell = TestShell.start({ + args: [await testServer.connectionString()], + }); + await helperShell.waitForPrompt(); + + // Insert a dummy object so find commands will actually run with the delay. + await helperShell.executeLine('db.coll.insertOne({})'); + }); + + it('should return the correct operation', async function () { + const regexOperation = helperShell.executeLine( + `db.coll.find({$where: function() { sleep(${OPERATION_TIME}) }}).projection({test: 1})` + ); + helperShell.assertNoErrors(); + await currentOpShell.executeLine(`sleep(${CURRENT_OP_WAIT_TIME})`); + let currentOpCall = await currentOpShell.executeLine(`db.currentOp()`); + + currentOpShell.assertNoErrors(); + expect(currentOpCall).to.include("find: 'coll'"); + expect(currentOpCall).to.include( + `filter: { '$where': Code('function() { sleep(${OPERATION_TIME}) }') }` + ); + expect(currentOpCall).to.include('projection: { test: 1 }'); + + console.log(currentOpCall); + + await regexOperation; + + currentOpCall = await currentOpShell.executeLine(`db.currentOp()`); + + currentOpShell.assertNoErrors(); + expect(currentOpCall).not.to.include("find: 'coll'"); + expect(currentOpCall).not.to.include( + `filter: { '$where': Code('function() { sleep(${OPERATION_TIME}) }') }` + ); + expect(currentOpCall).not.to.include('projection: { test: 1 }'); + }); + + it('should work when the operation contains regex', async function () { + const regExpString = '^(?i)\\Qchho0842\\E'; + + void helperShell.executeLine( + `db.coll.find({$where: function() { sleep(${OPERATION_TIME}) }}).projection({re: BSONRegExp('${regExpString}')})` + ); + helperShell.assertNoErrors(); + + await currentOpShell.executeLine(`sleep(${CURRENT_OP_WAIT_TIME})`); + + const currentOpCall = await currentOpShell.executeLine(`db.currentOp()`); + currentOpShell.assertNoErrors(); + + const regExpStringWithoutEscapes = regExpString.replace(/\\/g, ''); + + expect(currentOpCall).to.include( + `projection: { re: BSONRegExp('${regExpStringWithoutEscapes}', '') }` + ); + }); + }); +}); From 8339acdd21d01ea95de7ed592409b40fc515304c Mon Sep 17 00:00:00 2001 From: gagik Date: Wed, 2 Oct 2024 09:42:57 +0200 Subject: [PATCH 03/21] Use simplification example --- packages/e2e-tests/test/e2e-current-op.spec.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/e2e-tests/test/e2e-current-op.spec.ts b/packages/e2e-tests/test/e2e-current-op.spec.ts index 709d87937..29bf56583 100644 --- a/packages/e2e-tests/test/e2e-current-op.spec.ts +++ b/packages/e2e-tests/test/e2e-current-op.spec.ts @@ -62,7 +62,9 @@ describe('e2e currentOp', function () { }); it('should work when the operation contains regex', async function () { - const regExpString = '^(?i)\\Qchho0842\\E'; + const regExpString = '^(?i)\\\\Qchho0842\\E'; + // The currentOp return simplifies unnecessary escapes such as \E + const simplifiedRegExpString = '^(?i)\\\\Qchho0842E'; void helperShell.executeLine( `db.coll.find({$where: function() { sleep(${OPERATION_TIME}) }}).projection({re: BSONRegExp('${regExpString}')})` @@ -74,10 +76,8 @@ describe('e2e currentOp', function () { const currentOpCall = await currentOpShell.executeLine(`db.currentOp()`); currentOpShell.assertNoErrors(); - const regExpStringWithoutEscapes = regExpString.replace(/\\/g, ''); - expect(currentOpCall).to.include( - `projection: { re: BSONRegExp('${regExpStringWithoutEscapes}', '') }` + `projection: { re: BSONRegExp('${simplifiedRegExpString}', '') }` ); }); }); From 7fa09e7094491e689b8ea2c8806cd82f450bfbaa Mon Sep 17 00:00:00 2001 From: gagik Date: Wed, 2 Oct 2024 09:43:50 +0200 Subject: [PATCH 04/21] better wording --- packages/e2e-tests/test/e2e-current-op.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/e2e-tests/test/e2e-current-op.spec.ts b/packages/e2e-tests/test/e2e-current-op.spec.ts index 29bf56583..973510b1b 100644 --- a/packages/e2e-tests/test/e2e-current-op.spec.ts +++ b/packages/e2e-tests/test/e2e-current-op.spec.ts @@ -63,7 +63,7 @@ describe('e2e currentOp', function () { it('should work when the operation contains regex', async function () { const regExpString = '^(?i)\\\\Qchho0842\\E'; - // The currentOp return simplifies unnecessary escapes such as \E + // The values from currentOp removes redundant escapes such as \E const simplifiedRegExpString = '^(?i)\\\\Qchho0842E'; void helperShell.executeLine( From 97cbf552fd280f69796c9fae2d4e24ccb207bcf8 Mon Sep 17 00:00:00 2001 From: gagik Date: Wed, 2 Oct 2024 12:39:34 +0200 Subject: [PATCH 05/21] Remove console log --- packages/e2e-tests/test/e2e-current-op.spec.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/e2e-tests/test/e2e-current-op.spec.ts b/packages/e2e-tests/test/e2e-current-op.spec.ts index 973510b1b..a57d1fab0 100644 --- a/packages/e2e-tests/test/e2e-current-op.spec.ts +++ b/packages/e2e-tests/test/e2e-current-op.spec.ts @@ -47,8 +47,6 @@ describe('e2e currentOp', function () { ); expect(currentOpCall).to.include('projection: { test: 1 }'); - console.log(currentOpCall); - await regexOperation; currentOpCall = await currentOpShell.executeLine(`db.currentOp()`); From fc4ca7624bdd10d51a8756b3ad067b975dc7b01d Mon Sep 17 00:00:00 2001 From: Gagik Amaryan Date: Wed, 2 Oct 2024 12:59:20 +0200 Subject: [PATCH 06/21] Reduce operation time --- packages/e2e-tests/test/e2e-current-op.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/e2e-tests/test/e2e-current-op.spec.ts b/packages/e2e-tests/test/e2e-current-op.spec.ts index a57d1fab0..a4ceba826 100644 --- a/packages/e2e-tests/test/e2e-current-op.spec.ts +++ b/packages/e2e-tests/test/e2e-current-op.spec.ts @@ -15,7 +15,7 @@ describe('e2e currentOp', function () { let helperShell: TestShell; let currentOpShell: TestShell; - const OPERATION_TIME = 1_000; + const OPERATION_TIME = 500; const CURRENT_OP_WAIT_TIME = 100; this.timeout(OPERATION_TIME * 2); From e5d469b878270209853f192ac4d4551088a5677a Mon Sep 17 00:00:00 2001 From: gagik Date: Wed, 2 Oct 2024 16:06:21 +0200 Subject: [PATCH 07/21] Revert time change --- packages/e2e-tests/test/e2e-current-op.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/e2e-tests/test/e2e-current-op.spec.ts b/packages/e2e-tests/test/e2e-current-op.spec.ts index a4ceba826..a57d1fab0 100644 --- a/packages/e2e-tests/test/e2e-current-op.spec.ts +++ b/packages/e2e-tests/test/e2e-current-op.spec.ts @@ -15,7 +15,7 @@ describe('e2e currentOp', function () { let helperShell: TestShell; let currentOpShell: TestShell; - const OPERATION_TIME = 500; + const OPERATION_TIME = 1_000; const CURRENT_OP_WAIT_TIME = 100; this.timeout(OPERATION_TIME * 2); From c119b1ad40277de5d391af26ed43184349dcf424 Mon Sep 17 00:00:00 2001 From: gagik Date: Fri, 4 Oct 2024 11:53:58 +0200 Subject: [PATCH 08/21] Use the new startTestShell --- packages/e2e-tests/test/e2e-current-op.spec.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/e2e-tests/test/e2e-current-op.spec.ts b/packages/e2e-tests/test/e2e-current-op.spec.ts index a57d1fab0..05f5e9d7d 100644 --- a/packages/e2e-tests/test/e2e-current-op.spec.ts +++ b/packages/e2e-tests/test/e2e-current-op.spec.ts @@ -3,11 +3,10 @@ import { skipIfApiStrict, startSharedTestServer, } from '../../../testing/integration-testing-hooks'; -import { TestShell } from './test-shell'; +import type { TestShell } from './test-shell'; describe('e2e currentOp', function () { skipIfApiStrict(); - afterEach(TestShell.cleanup); const testServer = startSharedTestServer(); @@ -20,10 +19,10 @@ describe('e2e currentOp', function () { this.timeout(OPERATION_TIME * 2); beforeEach(async function () { - helperShell = TestShell.start({ + helperShell = this.startTestShell({ args: [await testServer.connectionString()], }); - currentOpShell = TestShell.start({ + currentOpShell = this.startTestShell({ args: [await testServer.connectionString()], }); await helperShell.waitForPrompt(); From edf8e258f609f0edc5b41f1cc9cfbba759b51197 Mon Sep 17 00:00:00 2001 From: gagik Date: Fri, 4 Oct 2024 15:12:45 +0200 Subject: [PATCH 09/21] await both prompts --- packages/e2e-tests/test/e2e-current-op.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/e2e-tests/test/e2e-current-op.spec.ts b/packages/e2e-tests/test/e2e-current-op.spec.ts index 05f5e9d7d..357633530 100644 --- a/packages/e2e-tests/test/e2e-current-op.spec.ts +++ b/packages/e2e-tests/test/e2e-current-op.spec.ts @@ -26,6 +26,7 @@ describe('e2e currentOp', function () { args: [await testServer.connectionString()], }); await helperShell.waitForPrompt(); + await currentOpShell.waitForPrompt(); // Insert a dummy object so find commands will actually run with the delay. await helperShell.executeLine('db.coll.insertOne({})'); From af2c696d64cf775cdc0b02f72cfbd4c419a37f46 Mon Sep 17 00:00:00 2001 From: gagik Date: Mon, 7 Oct 2024 11:17:24 +0200 Subject: [PATCH 10/21] Increase timeout --- packages/e2e-tests/test/e2e-current-op.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/e2e-tests/test/e2e-current-op.spec.ts b/packages/e2e-tests/test/e2e-current-op.spec.ts index 357633530..df82b9a00 100644 --- a/packages/e2e-tests/test/e2e-current-op.spec.ts +++ b/packages/e2e-tests/test/e2e-current-op.spec.ts @@ -16,7 +16,7 @@ describe('e2e currentOp', function () { const OPERATION_TIME = 1_000; const CURRENT_OP_WAIT_TIME = 100; - this.timeout(OPERATION_TIME * 2); + this.timeout(OPERATION_TIME * 5); beforeEach(async function () { helperShell = this.startTestShell({ From 1c09b22cba8bc60cef47490bbd84fa94c44a188b Mon Sep 17 00:00:00 2001 From: Gagik Amaryan Date: Mon, 7 Oct 2024 12:07:03 +0200 Subject: [PATCH 11/21] Update packages/e2e-tests/test/e2e-current-op.spec.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kræn Hansen --- packages/e2e-tests/test/e2e-current-op.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/e2e-tests/test/e2e-current-op.spec.ts b/packages/e2e-tests/test/e2e-current-op.spec.ts index df82b9a00..390f8889b 100644 --- a/packages/e2e-tests/test/e2e-current-op.spec.ts +++ b/packages/e2e-tests/test/e2e-current-op.spec.ts @@ -14,7 +14,7 @@ describe('e2e currentOp', function () { let helperShell: TestShell; let currentOpShell: TestShell; - const OPERATION_TIME = 1_000; + const OPERATION_TIME = CURRENT_OP_WAIT_TIME * 2; const CURRENT_OP_WAIT_TIME = 100; this.timeout(OPERATION_TIME * 5); From 12092ee4ba6defacfcd859f229b27c1126f229c7 Mon Sep 17 00:00:00 2001 From: gagik Date: Mon, 7 Oct 2024 12:25:54 +0200 Subject: [PATCH 12/21] Clean up tests --- packages/e2e-tests/test/e2e-current-op.spec.ts | 8 ++++---- packages/shell-api/src/database.ts | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/e2e-tests/test/e2e-current-op.spec.ts b/packages/e2e-tests/test/e2e-current-op.spec.ts index 390f8889b..49d643ce5 100644 --- a/packages/e2e-tests/test/e2e-current-op.spec.ts +++ b/packages/e2e-tests/test/e2e-current-op.spec.ts @@ -14,8 +14,8 @@ describe('e2e currentOp', function () { let helperShell: TestShell; let currentOpShell: TestShell; - const OPERATION_TIME = CURRENT_OP_WAIT_TIME * 2; const CURRENT_OP_WAIT_TIME = 100; + const OPERATION_TIME = CURRENT_OP_WAIT_TIME * 2; this.timeout(OPERATION_TIME * 5); beforeEach(async function () { @@ -32,8 +32,8 @@ describe('e2e currentOp', function () { await helperShell.executeLine('db.coll.insertOne({})'); }); - it('should return the correct operation', async function () { - const regexOperation = helperShell.executeLine( + it('should return the current operation and clear when it is complete', async function () { + const currentCommand = helperShell.executeLine( `db.coll.find({$where: function() { sleep(${OPERATION_TIME}) }}).projection({test: 1})` ); helperShell.assertNoErrors(); @@ -47,7 +47,7 @@ describe('e2e currentOp', function () { ); expect(currentOpCall).to.include('projection: { test: 1 }'); - await regexOperation; + await currentCommand; currentOpCall = await currentOpShell.executeLine(`db.currentOp()`); diff --git a/packages/shell-api/src/database.ts b/packages/shell-api/src/database.ts index 4688b521e..9a198a0ce 100644 --- a/packages/shell-api/src/database.ts +++ b/packages/shell-api/src/database.ts @@ -1065,6 +1065,8 @@ export default class Database extends ShellApiWithMongoClass { const adminDb = this.getSiblingDB('admin'); const aggregateOptions = { $readPreference: { mode: 'primaryPreferred' }, + // Regex patterns should be instances of BSONRegExp + // as there can be issues during conversion otherwise. bsonRegExp: true, }; @@ -1427,7 +1429,7 @@ export default class Database extends ShellApiWithMongoClass { CommonErrors.CommandFailed ); } - for (const cmdDescription of Object.values(result.commands) as Document[]) { + for (const cmdDescription of Object.values(result.commands)) { if ('slaveOk' in cmdDescription) { cmdDescription.secondaryOk = cmdDescription.slaveOk; delete cmdDescription.slaveOk; From ec8863928c3c718a7622389dcc02c48596b7cf7a Mon Sep 17 00:00:00 2001 From: gagik Date: Mon, 7 Oct 2024 13:19:19 +0200 Subject: [PATCH 13/21] Move to e2e.spec and make nicer JS escape --- .../e2e-tests/test/e2e-current-op.spec.ts | 82 ------------------- packages/e2e-tests/test/e2e.spec.ts | 77 +++++++++++++++++ packages/e2e-tests/test/util-helpers.ts | 3 + 3 files changed, 80 insertions(+), 82 deletions(-) delete mode 100644 packages/e2e-tests/test/e2e-current-op.spec.ts create mode 100644 packages/e2e-tests/test/util-helpers.ts diff --git a/packages/e2e-tests/test/e2e-current-op.spec.ts b/packages/e2e-tests/test/e2e-current-op.spec.ts deleted file mode 100644 index 49d643ce5..000000000 --- a/packages/e2e-tests/test/e2e-current-op.spec.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { expect } from 'chai'; -import { - skipIfApiStrict, - startSharedTestServer, -} from '../../../testing/integration-testing-hooks'; -import type { TestShell } from './test-shell'; - -describe('e2e currentOp', function () { - skipIfApiStrict(); - - const testServer = startSharedTestServer(); - - context('with 2 shells', function () { - let helperShell: TestShell; - let currentOpShell: TestShell; - - const CURRENT_OP_WAIT_TIME = 100; - const OPERATION_TIME = CURRENT_OP_WAIT_TIME * 2; - this.timeout(OPERATION_TIME * 5); - - beforeEach(async function () { - helperShell = this.startTestShell({ - args: [await testServer.connectionString()], - }); - currentOpShell = this.startTestShell({ - args: [await testServer.connectionString()], - }); - await helperShell.waitForPrompt(); - await currentOpShell.waitForPrompt(); - - // Insert a dummy object so find commands will actually run with the delay. - await helperShell.executeLine('db.coll.insertOne({})'); - }); - - it('should return the current operation and clear when it is complete', async function () { - const currentCommand = helperShell.executeLine( - `db.coll.find({$where: function() { sleep(${OPERATION_TIME}) }}).projection({test: 1})` - ); - helperShell.assertNoErrors(); - await currentOpShell.executeLine(`sleep(${CURRENT_OP_WAIT_TIME})`); - let currentOpCall = await currentOpShell.executeLine(`db.currentOp()`); - - currentOpShell.assertNoErrors(); - expect(currentOpCall).to.include("find: 'coll'"); - expect(currentOpCall).to.include( - `filter: { '$where': Code('function() { sleep(${OPERATION_TIME}) }') }` - ); - expect(currentOpCall).to.include('projection: { test: 1 }'); - - await currentCommand; - - currentOpCall = await currentOpShell.executeLine(`db.currentOp()`); - - currentOpShell.assertNoErrors(); - expect(currentOpCall).not.to.include("find: 'coll'"); - expect(currentOpCall).not.to.include( - `filter: { '$where': Code('function() { sleep(${OPERATION_TIME}) }') }` - ); - expect(currentOpCall).not.to.include('projection: { test: 1 }'); - }); - - it('should work when the operation contains regex', async function () { - const regExpString = '^(?i)\\\\Qchho0842\\E'; - // The values from currentOp removes redundant escapes such as \E - const simplifiedRegExpString = '^(?i)\\\\Qchho0842E'; - - void helperShell.executeLine( - `db.coll.find({$where: function() { sleep(${OPERATION_TIME}) }}).projection({re: BSONRegExp('${regExpString}')})` - ); - helperShell.assertNoErrors(); - - await currentOpShell.executeLine(`sleep(${CURRENT_OP_WAIT_TIME})`); - - const currentOpCall = await currentOpShell.executeLine(`db.currentOp()`); - currentOpShell.assertNoErrors(); - - expect(currentOpCall).to.include( - `projection: { re: BSONRegExp('${simplifiedRegExpString}', '') }` - ); - }); - }); -}); diff --git a/packages/e2e-tests/test/e2e.spec.ts b/packages/e2e-tests/test/e2e.spec.ts index dc58693b9..cfc3f2b56 100644 --- a/packages/e2e-tests/test/e2e.spec.ts +++ b/packages/e2e-tests/test/e2e.spec.ts @@ -21,6 +21,7 @@ import { createServer as createHTTPServer } from 'http'; import { once } from 'events'; import type { AddressInfo } from 'net'; const { EJSON } = bson; +import { sleep } from './util-helpers'; const jsContextFlagCombinations: `--jsContext=${'plain-vm' | 'repl'}`[][] = [ [], @@ -1938,4 +1939,80 @@ describe('e2e', function () { shell.assertContainsOutput('610'); }); }); + + describe('currentOp', function () { + context('with 2 shells', function () { + let helperShell: TestShell; + let currentOpShell: TestShell; + + const CURRENT_OP_WAIT_TIME = 100; + const OPERATION_TIME = CURRENT_OP_WAIT_TIME * 2; + + beforeEach(async function () { + helperShell = this.startTestShell({ + args: [await testServer.connectionString()], + }); + currentOpShell = this.startTestShell({ + args: [await testServer.connectionString()], + }); + await helperShell.waitForPrompt(); + await currentOpShell.waitForPrompt(); + + // Insert a dummy object so find commands will actually run with the delay. + await helperShell.executeLine('db.coll.insertOne({})'); + }); + + it('should return the current operation and clear when it is complete', async function () { + const currentCommand = helperShell.executeLine( + `db.coll.find({$where: function() { sleep(${OPERATION_TIME}) }}).projection({test: 1})` + ); + helperShell.assertNoErrors(); + await sleep(CURRENT_OP_WAIT_TIME); + let currentOpCall = await currentOpShell.executeLine(`db.currentOp()`); + + currentOpShell.assertNoErrors(); + expect(currentOpCall).to.include("find: 'coll'"); + expect(currentOpCall).to.include( + `filter: { '$where': Code('function() { sleep(${OPERATION_TIME}) }') }` + ); + expect(currentOpCall).to.include('projection: { test: 1 }'); + + await currentCommand; + + currentOpCall = await currentOpShell.executeLine(`db.currentOp()`); + + currentOpShell.assertNoErrors(); + expect(currentOpCall).not.to.include("find: 'coll'"); + expect(currentOpCall).not.to.include( + `filter: { '$where': Code('function() { sleep(${OPERATION_TIME}) }') }` + ); + expect(currentOpCall).not.to.include('projection: { test: 1 }'); + }); + + it('should work when the operation contains regex', async function () { + const regExpString = String.raw`^(?i)\Qchho0842\E`; + + // Stringify the reg exp and drop the quotation marks. + // Meant to account for JS escaping behavior and to compare with output later. + const stringifiedRegExpString = `${JSON.stringify(regExpString)}`.slice( + 1, + -1 + ); + + void helperShell.executeLine( + `db.coll.find({$where: function() { sleep(${OPERATION_TIME}) }}).projection({re: BSONRegExp('${stringifiedRegExpString}')})` + ); + helperShell.assertNoErrors(); + + await sleep(CURRENT_OP_WAIT_TIME); + + const currentOpCall = await currentOpShell.executeLine( + `db.currentOp()` + ); + currentOpShell.assertNoErrors(); + + expect(currentOpCall).to.include(stringifiedRegExpString); + }); + }); + }); }); diff --git a/packages/e2e-tests/test/util-helpers.ts b/packages/e2e-tests/test/util-helpers.ts new file mode 100644 index 000000000..0d7f188e1 --- /dev/null +++ b/packages/e2e-tests/test/util-helpers.ts @@ -0,0 +1,3 @@ +export function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} From 30814979061ddf7f2a0b786e4130f1aa5831d4a5 Mon Sep 17 00:00:00 2001 From: gagik Date: Mon, 7 Oct 2024 13:26:12 +0200 Subject: [PATCH 14/21] Revert autoformat change --- packages/shell-api/src/database.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shell-api/src/database.ts b/packages/shell-api/src/database.ts index 9a198a0ce..1765c9299 100644 --- a/packages/shell-api/src/database.ts +++ b/packages/shell-api/src/database.ts @@ -1429,7 +1429,7 @@ export default class Database extends ShellApiWithMongoClass { CommonErrors.CommandFailed ); } - for (const cmdDescription of Object.values(result.commands)) { + for (const cmdDescription of Object.values(result.commands) as Document[]) { if ('slaveOk' in cmdDescription) { cmdDescription.secondaryOk = cmdDescription.slaveOk; delete cmdDescription.slaveOk; From 0417c4ae384b1feef0bfdda60cb3ce7bc4661472 Mon Sep 17 00:00:00 2001 From: gagik Date: Mon, 7 Oct 2024 13:50:20 +0200 Subject: [PATCH 15/21] Specify sleep type --- packages/e2e-tests/test/util-helpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/e2e-tests/test/util-helpers.ts b/packages/e2e-tests/test/util-helpers.ts index 0d7f188e1..421bda080 100644 --- a/packages/e2e-tests/test/util-helpers.ts +++ b/packages/e2e-tests/test/util-helpers.ts @@ -1,3 +1,3 @@ -export function sleep(ms: number) { +export function sleep(ms: number): Promise { return new Promise((resolve) => setTimeout(resolve, ms)); } From 270a98f048a6937f3dc900cf513a7bb5908169f9 Mon Sep 17 00:00:00 2001 From: gagik Date: Mon, 7 Oct 2024 14:51:58 +0200 Subject: [PATCH 16/21] Less strict output matching --- packages/e2e-tests/test/e2e.spec.ts | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/packages/e2e-tests/test/e2e.spec.ts b/packages/e2e-tests/test/e2e.spec.ts index cfc3f2b56..f2f10839d 100644 --- a/packages/e2e-tests/test/e2e.spec.ts +++ b/packages/e2e-tests/test/e2e.spec.ts @@ -1964,29 +1964,23 @@ describe('e2e', function () { it('should return the current operation and clear when it is complete', async function () { const currentCommand = helperShell.executeLine( - `db.coll.find({$where: function() { sleep(${OPERATION_TIME}) }}).projection({test: 1})` + `db.coll.find({$where: function() { sleep(${OPERATION_TIME}) }}).projection({testProjection: 1})` ); helperShell.assertNoErrors(); await sleep(CURRENT_OP_WAIT_TIME); let currentOpCall = await currentOpShell.executeLine(`db.currentOp()`); currentOpShell.assertNoErrors(); - expect(currentOpCall).to.include("find: 'coll'"); - expect(currentOpCall).to.include( - `filter: { '$where': Code('function() { sleep(${OPERATION_TIME}) }') }` - ); - expect(currentOpCall).to.include('projection: { test: 1 }'); + expect(currentOpCall).to.include(`sleep(${OPERATION_TIME})`); + expect(currentOpCall).to.include('testProjection'); await currentCommand; currentOpCall = await currentOpShell.executeLine(`db.currentOp()`); currentOpShell.assertNoErrors(); - expect(currentOpCall).not.to.include("find: 'coll'"); - expect(currentOpCall).not.to.include( - `filter: { '$where': Code('function() { sleep(${OPERATION_TIME}) }') }` - ); - expect(currentOpCall).not.to.include('projection: { test: 1 }'); + expect(currentOpCall).not.to.include(`sleep(${OPERATION_TIME})`); + expect(currentOpCall).not.to.include('testProjection'); }); it('should work when the operation contains regex', async function () { From 8d276371cfb2740c9c538007857df0c3608b8311 Mon Sep 17 00:00:00 2001 From: gagik Date: Mon, 7 Oct 2024 15:25:10 +0200 Subject: [PATCH 17/21] Bump wait time --- packages/e2e-tests/test/e2e.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/e2e-tests/test/e2e.spec.ts b/packages/e2e-tests/test/e2e.spec.ts index f2f10839d..5fcfaf605 100644 --- a/packages/e2e-tests/test/e2e.spec.ts +++ b/packages/e2e-tests/test/e2e.spec.ts @@ -1945,7 +1945,7 @@ describe('e2e', function () { let helperShell: TestShell; let currentOpShell: TestShell; - const CURRENT_OP_WAIT_TIME = 100; + const CURRENT_OP_WAIT_TIME = 200; const OPERATION_TIME = CURRENT_OP_WAIT_TIME * 2; beforeEach(async function () { From 74aa0e0092656e7296f46f7a1a743d02cf01f2f7 Mon Sep 17 00:00:00 2001 From: gagik Date: Tue, 8 Oct 2024 10:24:17 +0200 Subject: [PATCH 18/21] test log output --- packages/e2e-tests/test/e2e.spec.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/e2e-tests/test/e2e.spec.ts b/packages/e2e-tests/test/e2e.spec.ts index 5fcfaf605..1e4ecf11a 100644 --- a/packages/e2e-tests/test/e2e.spec.ts +++ b/packages/e2e-tests/test/e2e.spec.ts @@ -1971,7 +1971,9 @@ describe('e2e', function () { let currentOpCall = await currentOpShell.executeLine(`db.currentOp()`); currentOpShell.assertNoErrors(); - expect(currentOpCall).to.include(`sleep(${OPERATION_TIME})`); + + // TODO: Remove this + console.log(currentOpCall); expect(currentOpCall).to.include('testProjection'); await currentCommand; @@ -1979,7 +1981,6 @@ describe('e2e', function () { currentOpCall = await currentOpShell.executeLine(`db.currentOp()`); currentOpShell.assertNoErrors(); - expect(currentOpCall).not.to.include(`sleep(${OPERATION_TIME})`); expect(currentOpCall).not.to.include('testProjection'); }); From cbe2864cfc30ba20d53156329fc289f6023ff567 Mon Sep 17 00:00:00 2001 From: gagik Date: Tue, 8 Oct 2024 11:25:51 +0200 Subject: [PATCH 19/21] check if higher wait time help --- packages/e2e-tests/test/e2e.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/e2e-tests/test/e2e.spec.ts b/packages/e2e-tests/test/e2e.spec.ts index 1e4ecf11a..af7d25813 100644 --- a/packages/e2e-tests/test/e2e.spec.ts +++ b/packages/e2e-tests/test/e2e.spec.ts @@ -1945,7 +1945,7 @@ describe('e2e', function () { let helperShell: TestShell; let currentOpShell: TestShell; - const CURRENT_OP_WAIT_TIME = 200; + const CURRENT_OP_WAIT_TIME = 1000; const OPERATION_TIME = CURRENT_OP_WAIT_TIME * 2; beforeEach(async function () { From b4c96a817a09253b278928a2f181bf6f150d0c98 Mon Sep 17 00:00:00 2001 From: gagik Date: Tue, 8 Oct 2024 15:43:50 +0200 Subject: [PATCH 20/21] Revert diagnostic changes --- packages/e2e-tests/test/e2e.spec.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/e2e-tests/test/e2e.spec.ts b/packages/e2e-tests/test/e2e.spec.ts index af7d25813..a32fd078a 100644 --- a/packages/e2e-tests/test/e2e.spec.ts +++ b/packages/e2e-tests/test/e2e.spec.ts @@ -1945,7 +1945,7 @@ describe('e2e', function () { let helperShell: TestShell; let currentOpShell: TestShell; - const CURRENT_OP_WAIT_TIME = 1000; + const CURRENT_OP_WAIT_TIME = 100; const OPERATION_TIME = CURRENT_OP_WAIT_TIME * 2; beforeEach(async function () { @@ -1972,8 +1972,6 @@ describe('e2e', function () { currentOpShell.assertNoErrors(); - // TODO: Remove this - console.log(currentOpCall); expect(currentOpCall).to.include('testProjection'); await currentCommand; From e94306d4930d878f2f6584b136add53007911686 Mon Sep 17 00:00:00 2001 From: gagik Date: Tue, 8 Oct 2024 16:26:15 +0200 Subject: [PATCH 21/21] Bump wait time --- packages/e2e-tests/test/e2e.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/e2e-tests/test/e2e.spec.ts b/packages/e2e-tests/test/e2e.spec.ts index a32fd078a..43971d67c 100644 --- a/packages/e2e-tests/test/e2e.spec.ts +++ b/packages/e2e-tests/test/e2e.spec.ts @@ -1945,7 +1945,7 @@ describe('e2e', function () { let helperShell: TestShell; let currentOpShell: TestShell; - const CURRENT_OP_WAIT_TIME = 100; + const CURRENT_OP_WAIT_TIME = 400; const OPERATION_TIME = CURRENT_OP_WAIT_TIME * 2; beforeEach(async function () {