diff --git a/src/operations/execute_operation.ts b/src/operations/execute_operation.ts index b2951170ada..6e1b569a7dd 100644 --- a/src/operations/execute_operation.ts +++ b/src/operations/execute_operation.ts @@ -119,7 +119,14 @@ export async function executeOperation< const readPreference = operation.readPreference ?? ReadPreference.primary; const inTransaction = !!session?.inTransaction(); - if (inTransaction && !readPreference.equals(ReadPreference.primary)) { + const hasReadAspect = operation.hasAspect(Aspect.READ_OPERATION); + const hasWriteAspect = operation.hasAspect(Aspect.WRITE_OPERATION); + + if ( + inTransaction && + !readPreference.equals(ReadPreference.primary) && + (hasReadAspect || operation.commandName === 'runCommand') + ) { throw new MongoTransactionError( `Read preference in a transaction must be primary, not: ${readPreference.mode}` ); @@ -177,8 +184,6 @@ export async function executeOperation< supportsRetryableWrites(server) && operation.canRetryWrite; - const hasReadAspect = operation.hasAspect(Aspect.READ_OPERATION); - const hasWriteAspect = operation.hasAspect(Aspect.WRITE_OPERATION); const willRetry = (hasReadAspect && willRetryRead) || (hasWriteAspect && willRetryWrite); if (hasWriteAspect && willRetryWrite) { diff --git a/src/sessions.ts b/src/sessions.ts index 7ef4c3ba22c..e9dc6a396b5 100644 --- a/src/sessions.ts +++ b/src/sessions.ts @@ -194,7 +194,7 @@ export class ClientSession extends TypedEventEmitter { this.operationTime = undefined; this.owner = options.owner; - this.defaultTransactionOptions = Object.assign({}, options.defaultTransactionOptions); + this.defaultTransactionOptions = { ...options.defaultTransactionOptions }; this.transaction = new Transaction(); } diff --git a/test/integration/transactions/transactions.spec.test.ts b/test/integration/transactions/transactions.spec.test.ts index a6ed914349f..22dd4ddd802 100644 --- a/test/integration/transactions/transactions.spec.test.ts +++ b/test/integration/transactions/transactions.spec.test.ts @@ -4,8 +4,6 @@ import { loadSpecTests } from '../../spec'; import { runUnifiedSuite } from '../../tools/unified-spec-runner/runner'; const SKIPPED_TESTS = [ - // TODO(NODE-5925) - secondary read preference not allowed in transactions. - 'readPreference inherited from defaultTransactionOptions', // TODO(NODE-5924) - Fix modification of readConcern object post message send. 'readConcern local in defaultTransactionOptions', 'defaultTransactionOptions override client options', @@ -17,7 +15,7 @@ const SKIPPED_TESTS = [ describe('Transactions Spec Unified Tests', function () { runUnifiedSuite(loadSpecTests(path.join('transactions', 'unified')), test => { return SKIPPED_TESTS.includes(test.description) - ? 'TODO(NODE-5924/NODE-5925): Skipping failing transaction tests' + ? 'TODO(NODE-5924): Skipping failing transaction tests' : false; }); }); diff --git a/test/tools/unified-spec-runner/entities.ts b/test/tools/unified-spec-runner/entities.ts index e36afdc5d16..4b7e4f55b14 100644 --- a/test/tools/unified-spec-runner/entities.ts +++ b/test/tools/unified-spec-runner/entities.ts @@ -620,9 +620,8 @@ export class EntitiesMap extends Map { WriteConcern.fromOptions(defaultOptions); } if (defaultOptions.readPreference) { - options.defaultTransactionOptions.readPreference = ReadPreference.fromOptions( - defaultOptions.readPreference - ); + options.defaultTransactionOptions.readPreference = + ReadPreference.fromOptions(defaultOptions); } if (typeof defaultOptions.maxCommitTimeMS === 'number') { options.defaultTransactionOptions.maxCommitTimeMS = defaultOptions.maxCommitTimeMS;