|
16 | 16 |
|
17 | 17 | package com.google.cloud.spanner;
|
18 | 18 |
|
19 |
| -import static com.google.cloud.spanner.MockSpannerTestUtil.SELECT1; |
20 | 19 | import static com.google.common.truth.Truth.assertThat;
|
21 | 20 | import static org.junit.Assert.fail;
|
22 | 21 |
|
|
37 | 36 | import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult;
|
38 | 37 | import com.google.cloud.spanner.TransactionRunner.TransactionCallable;
|
39 | 38 | import com.google.cloud.spanner.TransactionRunnerImpl.TransactionContextImpl;
|
| 39 | +import com.google.common.base.Predicate; |
40 | 40 | import com.google.common.base.Throwables;
|
41 | 41 | import com.google.common.collect.ImmutableList;
|
42 | 42 | import com.google.common.util.concurrent.MoreExecutors;
|
@@ -204,6 +204,7 @@ public void setUp() throws IOException {
|
204 | 204 | public void tearDown() throws Exception {
|
205 | 205 | spanner.close();
|
206 | 206 | mockSpanner.reset();
|
| 207 | +mockSpanner.clearRequests(); |
207 | 208 | }
|
208 | 209 |
|
209 | 210 | @Test
|
@@ -1348,6 +1349,69 @@ public Void run(TransactionContext transaction) throws Exception {
|
1348 | 1349 | assertThat(countRequests(CommitRequest.class)).isEqualTo(0);
|
1349 | 1350 | }
|
1350 | 1351 |
|
| 1352 | +@Test |
| 1353 | +public void testCloseResultSetWhileRequestInFlight() { |
| 1354 | +DatabaseClient client = spanner.getDatabaseClient(DatabaseId.of("p", "i", "d")); |
| 1355 | +final ExecutorService service = Executors.newSingleThreadExecutor(); |
| 1356 | +try { |
| 1357 | +client |
| 1358 | +.readWriteTransaction() |
| 1359 | +.run( |
| 1360 | +new TransactionCallable<Void>() { |
| 1361 | +@Override |
| 1362 | +public Void run(TransactionContext transaction) throws Exception { |
| 1363 | +final ResultSet rs = transaction.executeQuery(SELECT1); |
| 1364 | +// Prevent the server from executing the query. |
| 1365 | +mockSpanner.freeze(); |
| 1366 | +service.submit( |
| 1367 | +new Runnable() { |
| 1368 | +@Override |
| 1369 | +public void run() { |
| 1370 | +// This call will be stuck on the server until the mock server is |
| 1371 | +// unfrozen. |
| 1372 | +rs.next(); |
| 1373 | +} |
| 1374 | +}); |
| 1375 | + |
| 1376 | +// Close the result set while the request is in flight. |
| 1377 | +mockSpanner.waitForRequestsToContain( |
| 1378 | +new Predicate<AbstractMessage>() { |
| 1379 | +@Override |
| 1380 | +public boolean apply(AbstractMessage input) { |
| 1381 | +return input instanceof ExecuteSqlRequest |
| 1382 | +&& ((ExecuteSqlRequest) input).getTransaction().hasBegin(); |
| 1383 | +} |
| 1384 | +}, |
| 1385 | +100L); |
| 1386 | +rs.close(); |
| 1387 | +// The next statement should now fail before it is sent to the server because the |
| 1388 | +// first statement failed to return a transaction while the result set was still |
| 1389 | +// open. |
| 1390 | +mockSpanner.unfreeze(); |
| 1391 | +try { |
| 1392 | +transaction.executeUpdate(UPDATE_STATEMENT); |
| 1393 | +fail("missing expected exception"); |
| 1394 | +} catch (SpannerException e) { |
| 1395 | +assertThat(e.getErrorCode()).isEqualTo(ErrorCode.FAILED_PRECONDITION); |
| 1396 | +assertThat(e.getMessage()) |
| 1397 | +.contains("ResultSet was closed before a transaction id was returned"); |
| 1398 | +} |
| 1399 | +return null; |
| 1400 | +} |
| 1401 | +}); |
| 1402 | +fail("missing expected exception"); |
| 1403 | +} catch (SpannerException e) { |
| 1404 | +// The commit request will also fail, which means that the entire transaction will fail. |
| 1405 | +assertThat(e.getErrorCode()).isEqualTo(ErrorCode.FAILED_PRECONDITION); |
| 1406 | +assertThat(e.getMessage()) |
| 1407 | +.contains("ResultSet was closed before a transaction id was returned"); |
| 1408 | +} |
| 1409 | +service.shutdown(); |
| 1410 | +assertThat(countRequests(BeginTransactionRequest.class)).isEqualTo(0); |
| 1411 | +assertThat(countRequests(ExecuteSqlRequest.class)).isEqualTo(1); |
| 1412 | +assertThat(countRequests(CommitRequest.class)).isEqualTo(0); |
| 1413 | +} |
| 1414 | + |
1351 | 1415 | private int countRequests(Class<? extends AbstractMessage> requestType) {
|
1352 | 1416 | int count = 0;
|
1353 | 1417 | for (AbstractMessage msg : mockSpanner.getRequests()) {
|
|
0 commit comments