summaryrefslogtreecommitdiff
path: root/src/mongo/s/transaction_router_test.cpp
diff options
context:
space:
mode:
authorJack Mulrow <jack.mulrow@mongodb.com>2018-09-28 14:12:16 -0400
committerJack Mulrow <jack.mulrow@mongodb.com>2018-10-09 09:39:08 -0400
commitd2d7dbadcc008a484218321666aae44b75964787 (patch)
tree6d5167a57fd3d446144d8dc08f078dfbbfbd52f6 /src/mongo/s/transaction_router_test.cpp
parent1e03955cdab995fed6672d75a6a4544a9771a279 (diff)
downloadmongo-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.cpp125
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