diff options
author | Jack Mulrow <jack.mulrow@mongodb.com> | 2018-09-28 14:12:16 -0400 |
---|---|---|
committer | Jack Mulrow <jack.mulrow@mongodb.com> | 2018-10-09 09:39:08 -0400 |
commit | d2d7dbadcc008a484218321666aae44b75964787 (patch) | |
tree | 6d5167a57fd3d446144d8dc08f078dfbbfbd52f6 /src/mongo/s/transaction_router_test.cpp | |
parent | 1e03955cdab995fed6672d75a6a4544a9771a279 (diff) | |
download | mongo-d2d7dbadcc008a484218321666aae44b75964787.tar.gz |
SERVER-37210 Mongos should implicitly abort transactions on unhandled errors
Diffstat (limited to 'src/mongo/s/transaction_router_test.cpp')
-rw-r--r-- | src/mongo/s/transaction_router_test.cpp | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/src/mongo/s/transaction_router_test.cpp b/src/mongo/s/transaction_router_test.cpp index 6dcc8795f4f..b0da4b30af0 100644 --- a/src/mongo/s/transaction_router_test.cpp +++ b/src/mongo/s/transaction_router_test.cpp @@ -1241,5 +1241,130 @@ TEST_F(TransactionRouterTest, OnViewResolutionErrorClearsAllNewParticipants) { ASSERT_TRUE(secondShardCmd["startTransaction"].trueValue()); } +TEST_F(TransactionRouterTest, ImplicitAbortIsNoopWithNoParticipants) { + TxnNumber txnNum{3}; + + auto opCtx = operationContext(); + opCtx->setLogicalSessionId(makeLogicalSessionIdForTest()); + opCtx->setTxnNumber(txnNum); + ScopedRouterSession scopedSession(opCtx); + + auto txnRouter = TransactionRouter::get(opCtx); + txnRouter->beginOrContinueTxn(opCtx, txnNum, true); + + // Should not throw. + txnRouter->implicitlyAbortTransaction(opCtx); +} + +TEST_F(TransactionRouterTest, ImplicitAbortForSingleParticipant) { + LogicalSessionId lsid(makeLogicalSessionIdForTest()); + TxnNumber txnNum{3}; + + auto opCtx = operationContext(); + opCtx->setLogicalSessionId(lsid); + opCtx->setTxnNumber(txnNum); + + ScopedRouterSession scopedSession(opCtx); + auto txnRouter = TransactionRouter::get(opCtx); + + txnRouter->beginOrContinueTxn(opCtx, txnNum, true); + txnRouter->attachTxnFieldsIfNeeded(shard1, {}); + + auto future = + launchAsync([&] { return txnRouter->implicitlyAbortTransaction(operationContext()); }); + + onCommandForPoolExecutor([&](const RemoteCommandRequest& request) { + ASSERT_EQ(hostAndPort1, request.target); + ASSERT_EQ("admin", request.dbname); + + auto cmdName = request.cmdObj.firstElement().fieldNameStringData(); + ASSERT_EQ(cmdName, "abortTransaction"); + + checkSessionDetails(request.cmdObj, lsid, txnNum, true); + + return BSON("ok" << 1); + }); + + future.timed_get(kFutureTimeout); +} + +TEST_F(TransactionRouterTest, ImplicitAbortForMultipleParticipants) { + LogicalSessionId lsid(makeLogicalSessionIdForTest()); + TxnNumber txnNum{3}; + + auto opCtx = operationContext(); + opCtx->setLogicalSessionId(lsid); + opCtx->setTxnNumber(txnNum); + + ScopedRouterSession scopedSession(opCtx); + auto txnRouter = TransactionRouter::get(opCtx); + + txnRouter->beginOrContinueTxn(opCtx, txnNum, true); + txnRouter->attachTxnFieldsIfNeeded(shard1, {}); + txnRouter->attachTxnFieldsIfNeeded(shard2, {}); + + auto future = + launchAsync([&] { return txnRouter->implicitlyAbortTransaction(operationContext()); }); + + onCommandForPoolExecutor([&](const RemoteCommandRequest& request) { + ASSERT_EQ(hostAndPort1, request.target); + ASSERT_EQ("admin", request.dbname); + + auto cmdName = request.cmdObj.firstElement().fieldNameStringData(); + ASSERT_EQ(cmdName, "abortTransaction"); + + checkSessionDetails(request.cmdObj, lsid, txnNum, true); + + return BSON("ok" << 1); + }); + + onCommandForPoolExecutor([&](const RemoteCommandRequest& request) { + ASSERT_EQ(hostAndPort2, request.target); + ASSERT_EQ("admin", request.dbname); + + auto cmdName = request.cmdObj.firstElement().fieldNameStringData(); + ASSERT_EQ(cmdName, "abortTransaction"); + + checkSessionDetails(request.cmdObj, lsid, txnNum, boost::none); + + return BSON("ok" << 1); + }); + + future.timed_get(kFutureTimeout); +} + +TEST_F(TransactionRouterTest, ImplicitAbortIgnoresErrors) { + LogicalSessionId lsid(makeLogicalSessionIdForTest()); + TxnNumber txnNum{3}; + + auto opCtx = operationContext(); + opCtx->setLogicalSessionId(lsid); + opCtx->setTxnNumber(txnNum); + + ScopedRouterSession scopedSession(opCtx); + auto txnRouter = TransactionRouter::get(opCtx); + + txnRouter->beginOrContinueTxn(opCtx, txnNum, true); + txnRouter->attachTxnFieldsIfNeeded(shard1, {}); + + auto future = + launchAsync([&] { return txnRouter->implicitlyAbortTransaction(operationContext()); }); + + onCommandForPoolExecutor([&](const RemoteCommandRequest& request) { + ASSERT_EQ(hostAndPort1, request.target); + ASSERT_EQ("admin", request.dbname); + + auto cmdName = request.cmdObj.firstElement().fieldNameStringData(); + ASSERT_EQ(cmdName, "abortTransaction"); + + checkSessionDetails(request.cmdObj, lsid, txnNum, true); + + return BSON("ok" << 0); + }); + + // Shouldn't throw. + future.timed_get(kFutureTimeout); +} + } // unnamed namespace } // namespace mongo |