@@ -74,6 +74,23 @@ MATCHER_P(BatchCreateSessionsRequestHasDatabase, database,
74
74
return arg.database () == database.FullName ();
75
75
}
76
76
77
+ // Matches a spanner::Transaction that is marked "is_bad()"
78
+ MATCHER (HasBadSession, " bound to a session that's marked bad" ) {
79
+ return internal::Visit (
80
+ arg, [&](internal::SessionHolder& session,
81
+ google::spanner::v1::TransactionSelector&, std::int64_t ) {
82
+ if (!session) {
83
+ *result_listener << " has no session" ;
84
+ return false ;
85
+ }
86
+ if (!session->is_bad ()) {
87
+ *result_listener << " session expected to be bad, but was not" ;
88
+ return false ;
89
+ }
90
+ return true ;
91
+ });
92
+ }
93
+
77
94
// Helper to set the Transaction's ID.
78
95
void SetTransactionId (Transaction& txn, std::string tid) {
79
96
internal::Visit (
@@ -1285,6 +1302,8 @@ TEST(ConnectionImplTest, CommitGetSession_TooManyTransientFailures) {
1285
1302
TEST (ConnectionImplTest, CommitGetSession_Retry) {
1286
1303
auto mock = std::make_shared<spanner_testing::MockSpannerStub>();
1287
1304
1305
+ spanner_proto::Transaction txn;
1306
+ txn.set_id (" 1234567890" );
1288
1307
auto db = Database (" dummy_project" , " dummy_instance" , " dummy_database_id" );
1289
1308
auto conn = MakeLimitedRetryConnection (db, mock);
1290
1309
EXPECT_CALL (*mock, BatchCreateSessions (_, _))
@@ -1300,21 +1319,78 @@ TEST(ConnectionImplTest, CommitGetSession_Retry) {
1300
1319
EXPECT_EQ (db.FullName (), request.database ());
1301
1320
return MakeSessionsResponse ({" test-session-name" });
1302
1321
});
1322
+ EXPECT_CALL (*mock, BeginTransaction (_, _)).WillOnce (Return (txn));
1303
1323
EXPECT_CALL (*mock, Commit (_, _))
1304
- .WillOnce ([](grpc::ClientContext&,
1305
- spanner_proto::CommitRequest const & request) {
1324
+ .WillOnce ([&txn ](grpc::ClientContext&,
1325
+ spanner_proto::CommitRequest const & request) {
1306
1326
EXPECT_EQ (" test-session-name" , request.session ());
1307
- EXPECT_TRUE ( request.has_single_use_transaction ());
1327
+ EXPECT_EQ (txn. id (), request.transaction_id ());
1308
1328
return Status (StatusCode::kPermissionDenied , " uh-oh in Commit" );
1309
1329
});
1310
1330
auto commit = conn->Commit ({MakeReadWriteTransaction (), {}});
1311
1331
EXPECT_EQ (StatusCode::kPermissionDenied , commit.status ().code ());
1312
1332
EXPECT_THAT (commit.status ().message (), HasSubstr (" uh-oh in Commit" ));
1313
1333
}
1314
1334
1335
+ TEST (ConnectionImplTest, CommitBeginTransaction_Retry) {
1336
+ auto mock = std::make_shared<spanner_testing::MockSpannerStub>();
1337
+
1338
+ spanner_proto::Transaction txn;
1339
+ txn.set_id (" 1234567890" );
1340
+ auto db = Database (" dummy_project" , " dummy_instance" , " dummy_database_id" );
1341
+ auto conn = MakeLimitedRetryConnection (db, mock);
1342
+ EXPECT_CALL (*mock, BatchCreateSessions (_, _))
1343
+ .WillOnce (
1344
+ [&db](grpc::ClientContext&,
1345
+ spanner_proto::BatchCreateSessionsRequest const & request) {
1346
+ EXPECT_EQ (db.FullName (), request.database ());
1347
+ return MakeSessionsResponse ({" test-session-name" });
1348
+ });
1349
+ EXPECT_CALL (*mock, BeginTransaction (_, _))
1350
+ .WillOnce (Return (Status (StatusCode::kUnavailable , " try-again" )))
1351
+ .WillOnce (Return (txn));
1352
+ EXPECT_CALL (*mock, Commit (_, _))
1353
+ .WillOnce ([&txn](grpc::ClientContext&,
1354
+ spanner_proto::CommitRequest const & request) {
1355
+ EXPECT_EQ (" test-session-name" , request.session ());
1356
+ EXPECT_EQ (txn.id (), request.transaction_id ());
1357
+ spanner_proto::CommitResponse response;
1358
+ *response.mutable_commit_timestamp () =
1359
+ internal::ToProto (Timestamp{std::chrono::seconds (123 )});
1360
+ return response;
1361
+ });
1362
+
1363
+ auto commit = conn->Commit ({MakeReadWriteTransaction (), {}});
1364
+ EXPECT_STATUS_OK (commit);
1365
+ EXPECT_EQ (Timestamp (std::chrono::seconds (123 )), commit->commit_timestamp );
1366
+ }
1367
+
1368
+ TEST (ConnectionImplTest, CommitBeginTransaction_SessionNotFound) {
1369
+ auto mock = std::make_shared<spanner_testing::MockSpannerStub>();
1370
+ auto db = Database (" dummy_project" , " dummy_instance" , " dummy_database_id" );
1371
+ auto conn = MakeLimitedRetryConnection (db, mock);
1372
+ EXPECT_CALL (*mock, BatchCreateSessions (_, _))
1373
+ .WillOnce (
1374
+ [&db](grpc::ClientContext&,
1375
+ spanner_proto::BatchCreateSessionsRequest const & request) {
1376
+ EXPECT_EQ (db.FullName (), request.database ());
1377
+ return MakeSessionsResponse ({" test-session-name" });
1378
+ });
1379
+ EXPECT_CALL (*mock, BeginTransaction (_, _))
1380
+ .WillOnce (Return (Status (StatusCode::kNotFound , " Session not found" )));
1381
+ auto txn = MakeReadWriteTransaction ();
1382
+ auto commit = conn->Commit ({txn, {}});
1383
+ EXPECT_FALSE (commit.ok ());
1384
+ auto status = commit.status ();
1385
+ EXPECT_TRUE (IsSessionNotFound (status)) << status;
1386
+ EXPECT_THAT (txn, HasBadSession ());
1387
+ }
1388
+
1315
1389
TEST (ConnectionImplTest, CommitCommit_PermanentFailure) {
1316
1390
auto mock = std::make_shared<spanner_testing::MockSpannerStub>();
1317
1391
1392
+ spanner_proto::Transaction txn;
1393
+ txn.set_id (" 1234567890" );
1318
1394
auto db = Database (" dummy_project" , " dummy_instance" , " dummy_database_id" );
1319
1395
auto conn = MakeLimitedRetryConnection (db, mock);
1320
1396
EXPECT_CALL (*mock, BatchCreateSessions (_, _))
@@ -1324,11 +1400,12 @@ TEST(ConnectionImplTest, CommitCommit_PermanentFailure) {
1324
1400
EXPECT_EQ (db.FullName (), request.database ());
1325
1401
return MakeSessionsResponse ({" test-session-name" });
1326
1402
});
1403
+ EXPECT_CALL (*mock, BeginTransaction (_, _)).WillOnce (Return (txn));
1327
1404
EXPECT_CALL (*mock, Commit (_, _))
1328
- .WillOnce ([](grpc::ClientContext&,
1329
- spanner_proto::CommitRequest const & request) {
1405
+ .WillOnce ([&txn ](grpc::ClientContext&,
1406
+ spanner_proto::CommitRequest const & request) {
1330
1407
EXPECT_EQ (" test-session-name" , request.session ());
1331
- EXPECT_TRUE ( request.has_single_use_transaction ());
1408
+ EXPECT_EQ (txn. id (), request.transaction_id ());
1332
1409
return Status (StatusCode::kPermissionDenied , " uh-oh in Commit" );
1333
1410
});
1334
1411
auto commit = conn->Commit ({MakeReadWriteTransaction (), {}});
@@ -1339,6 +1416,8 @@ TEST(ConnectionImplTest, CommitCommit_PermanentFailure) {
1339
1416
TEST (ConnectionImplTest, CommitCommit_TooManyTransientFailures) {
1340
1417
auto mock = std::make_shared<spanner_testing::MockSpannerStub>();
1341
1418
1419
+ spanner_proto::Transaction txn;
1420
+ txn.set_id (" 1234567890" );
1342
1421
auto db = Database (" dummy_project" , " dummy_instance" , " dummy_database_id" );
1343
1422
auto conn = MakeLimitedRetryConnection (db, mock);
1344
1423
EXPECT_CALL (*mock, BatchCreateSessions (_, _))
@@ -1348,11 +1427,12 @@ TEST(ConnectionImplTest, CommitCommit_TooManyTransientFailures) {
1348
1427
EXPECT_EQ (db.FullName (), request.database ());
1349
1428
return MakeSessionsResponse ({" test-session-name" });
1350
1429
});
1430
+ EXPECT_CALL (*mock, BeginTransaction (_, _)).WillOnce (Return (txn));
1351
1431
EXPECT_CALL (*mock, Commit (_, _))
1352
- .WillOnce ([](grpc::ClientContext&,
1353
- spanner_proto::CommitRequest const & request) {
1432
+ .WillOnce ([&txn ](grpc::ClientContext&,
1433
+ spanner_proto::CommitRequest const & request) {
1354
1434
EXPECT_EQ (" test-session-name" , request.session ());
1355
- EXPECT_TRUE ( request.has_single_use_transaction ());
1435
+ EXPECT_EQ (txn. id (), request.transaction_id ());
1356
1436
return Status (StatusCode::kPermissionDenied , " uh-oh in Commit" );
1357
1437
});
1358
1438
auto commit = conn->Commit ({MakeReadWriteTransaction (), {}});
@@ -1398,34 +1478,6 @@ TEST(ConnectionImplTest, CommitCommit_IdempotentTransientSuccess) {
1398
1478
EXPECT_EQ (Timestamp (std::chrono::seconds (123 )), commit->commit_timestamp );
1399
1479
}
1400
1480
1401
- TEST (ConnectionImplTest, CommitCommit_NonIdempotentTransientFailure) {
1402
- auto mock = std::make_shared<spanner_testing::MockSpannerStub>();
1403
-
1404
- auto db = Database (" dummy_project" , " dummy_instance" , " dummy_database_id" );
1405
- auto conn = MakeConnection (db, {mock});
1406
- EXPECT_CALL (*mock, BatchCreateSessions (_, _))
1407
- .WillOnce (
1408
- [&db](grpc::ClientContext&,
1409
- spanner_proto::BatchCreateSessionsRequest const & request) {
1410
- EXPECT_EQ (db.FullName (), request.database ());
1411
- return MakeSessionsResponse ({" test-session-name" });
1412
- });
1413
- EXPECT_CALL (*mock, Commit (_, _))
1414
- .WillOnce ([](grpc::ClientContext&,
1415
- spanner_proto::CommitRequest const & request) {
1416
- EXPECT_EQ (" test-session-name" , request.session ());
1417
- return Status (StatusCode::kUnavailable , " try-again in Commit" );
1418
- });
1419
-
1420
- // Create a transaction without an id, that makes `Commit()` non-idempotent,
1421
- // so the transient failure should not be retried.
1422
- auto txn = MakeReadWriteTransaction ();
1423
-
1424
- auto commit = conn->Commit ({txn, {}});
1425
- EXPECT_EQ (StatusCode::kUnavailable , commit.status ().code ());
1426
- EXPECT_THAT (commit.status ().message (), HasSubstr (" try-again in Commit" ));
1427
- }
1428
-
1429
1481
TEST (ConnectionImplTest, CommitSuccessWithTransactionId) {
1430
1482
auto mock = std::make_shared<spanner_testing::MockSpannerStub>();
1431
1483
@@ -2034,22 +2086,6 @@ TEST(ConnectionImplTest, TransactionOutlivesConnection) {
2034
2086
conn.reset ();
2035
2087
}
2036
2088
2037
- MATCHER (HasBadSession, " bound to a session that's marked bad" ) {
2038
- return internal::Visit (
2039
- arg, [&](internal::SessionHolder& session,
2040
- google::spanner::v1::TransactionSelector&, std::int64_t ) {
2041
- if (!session) {
2042
- *result_listener << " has no session" ;
2043
- return false ;
2044
- }
2045
- if (!session->is_bad ()) {
2046
- *result_listener << " session expected to be bad, but was not" ;
2047
- return false ;
2048
- }
2049
- return true ;
2050
- });
2051
- }
2052
-
2053
2089
TEST (ConnectionImplTest, Read_SessionNotFound) {
2054
2090
auto mock = std::make_shared<spanner_testing::MockSpannerStub>();
2055
2091
EXPECT_CALL (*mock, BatchCreateSessions (_, _))
0 commit comments