From a846579e3aa6e3b8c0bb5cd03a01f89ba2862ac0 Mon Sep 17 00:00:00 2001 From: Paula Stachova Date: Wed, 31 Jan 2024 16:34:59 +0100 Subject: [PATCH] fix(shell-api): improve error message on reading from secondary via runCommand MONGOSH-1679 (#1805) * fix: improve error message on reading from secondary via runCommand * test: add tests * Update packages/shell-api/src/mongo-errors.ts Co-authored-by: Anna Henningsen * Update packages/shell-api/src/database.ts Co-authored-by: Anna Henningsen * explicit type * adjust all messages --------- Co-authored-by: Anna Henningsen --- packages/shell-api/src/database.spec.ts | 17 +++++++++++++++++ packages/shell-api/src/database.ts | 16 ++++++++++++---- packages/shell-api/src/mongo-errors.spec.ts | 13 ++++++++++++- packages/shell-api/src/mongo-errors.ts | 6 ++++-- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/packages/shell-api/src/database.spec.ts b/packages/shell-api/src/database.spec.ts index 2e4eac09b..193730ec3 100644 --- a/packages/shell-api/src/database.spec.ts +++ b/packages/shell-api/src/database.spec.ts @@ -31,6 +31,8 @@ import { MongoshUnimplementedError, } from '@mongosh/errors'; import type { ClientEncryption } from './field-level-encryption'; +import type { MongoServerError } from 'mongodb'; + chai.use(sinonChai); describe('Database', function () { @@ -323,6 +325,21 @@ describe('Database', function () { } ); }); + + it('rephrases the "NotPrimaryNoSecondaryOk" error', async function () { + const originalError: Partial = { + message: 'old message', + codeName: 'NotPrimaryNoSecondaryOk', + code: 13435, + }; + serviceProvider.runCommandWithCheck.rejects(originalError); + const caughtError = await database + .runCommand({ someCommand: 'someCollection' }) + .catch((e) => e); + expect(caughtError.message).to.contain( + 'e.g. db.runCommand({ command }, { readPreference: "secondaryPreferred" })' + ); + }); }); describe('adminCommand', function () { diff --git a/packages/shell-api/src/database.ts b/packages/shell-api/src/database.ts index 2dee29051..842cb4628 100644 --- a/packages/shell-api/src/database.ts +++ b/packages/shell-api/src/database.ts @@ -365,11 +365,19 @@ export default class Database extends ShellApiWithMongoClass { cmd = { [cmd]: 1 }; } - const hiddenCommands = new RegExp(HIDDEN_COMMANDS); - if (!Object.keys(cmd).some((k) => hiddenCommands.test(k))) { - this._emitDatabaseApiCall('runCommand', { cmd, options }); + try { + const hiddenCommands = new RegExp(HIDDEN_COMMANDS); + if (!Object.keys(cmd).some((k) => hiddenCommands.test(k))) { + this._emitDatabaseApiCall('runCommand', { cmd, options }); + } + return await this._runCommand(cmd, options); + } catch (error: any) { + if (error.codeName === 'NotPrimaryNoSecondaryOk') { + const message = `not primary - consider passing the readPreference option e.g. db.runCommand({ command }, { readPreference: "secondaryPreferred" })`; + (error as Error).message = message; + } + throw error; } - return this._runCommand(cmd, options); } /** diff --git a/packages/shell-api/src/mongo-errors.spec.ts b/packages/shell-api/src/mongo-errors.spec.ts index cfb807fc4..3b028f277 100644 --- a/packages/shell-api/src/mongo-errors.spec.ts +++ b/packages/shell-api/src/mongo-errors.spec.ts @@ -61,6 +61,17 @@ describe('mongo-errors', function () { expect(r.code).to.equal(13435); expect(r.message).to.contain('setReadPref'); }); + + it('does not rephrase a NotPrimaryNoSecondaryOk error with db.runCommand example', function () { + const e = new MongoError( + 'not primary - consider passing the readPreference option e.g. db.runCommand({ command }, { readPreference: "secondaryPreferred" })' + ); + e.code = 13435; + const r = rephraseMongoError(e); + expect(r).to.equal(e); + expect(r.code).to.equal(13435); + expect(r.message).not.to.contain('setReadPref'); + }); }); }); @@ -101,7 +112,7 @@ describe('mongo-errors', function () { expect.fail('expected error'); } catch (e: any) { expect(e).to.equal(error); - expect(e.message).to.contain('not primary and secondaryOk=false'); + expect(e.message).to.contain('not primary'); expect(e.message).to.contain('db.getMongo().setReadPref()'); expect(e.message).to.contain('readPreference'); } diff --git a/packages/shell-api/src/mongo-errors.ts b/packages/shell-api/src/mongo-errors.ts index d6dd3b5ee..7a068588f 100644 --- a/packages/shell-api/src/mongo-errors.ts +++ b/packages/shell-api/src/mongo-errors.ts @@ -9,8 +9,10 @@ const ERROR_REPHRASES: MongoErrorRephrase[] = [ { // NotPrimaryNoSecondaryOk (also used for old terminology) code: 13435, - replacement: - 'not primary and secondaryOk=false - consider using db.getMongo().setReadPref() or readPreference in the connection string', + replacement: (message) => + message.includes('db.runCommand') + ? message + : 'not primary - consider using db.getMongo().setReadPref() or readPreference in the connection string', }, ];