Merged
Show file tree
Hide file tree
Changes from 1 commit
Show all changes
23 commits
Select commit Hold shift + click to select a range
9fb15fe
feat: inline begin tx with first statement
olavloiteJul 8, 2020
6b8d9dc
feat: support inlining BeginTransaction
olavloiteJul 8, 2020
59ff2aa
fix: invalid dml statement can still return tx id
olavloiteJul 8, 2020
4d4446f
bench: add benchmarks for inline begin
olavloiteJul 16, 2020
48a5db5
feat: add inline begin for async runner
olavloiteJul 17, 2020
261c911
test: add additional tests and ITs
olavloiteJul 17, 2020
af50669
test: add tests for error during tx
olavloiteJul 30, 2020
f30334e
test: use statement with same error code on emulator
olavloiteJul 30, 2020
a4d2e76
test: skip test on emulator
olavloiteJul 30, 2020
1817afa
test: constraint error causes transaction to be invalidated
olavloiteJul 30, 2020
61cc207
fix: retry transaction if first statements fails and had BeginTransac…
olavloiteJul 31, 2020
3bdff48
fix: handle aborted exceptions
olavloiteJul 31, 2020
057839f
Merge branch 'master' into inline-begin-tx
olavloiteSep 16, 2020
b3148a0
test: add additional tests for corner cases
olavloiteSep 16, 2020
f508bdb
feat: use single-use tx for idem-potent mutations
olavloiteSep 16, 2020
d9e938f
fix: remove check for idempotent mutations
olavloiteSep 17, 2020
8a28f61
Merge branch 'master' into inline-begin-tx
olavloiteSep 28, 2020
bec71d7
Merge branch 'master' into inline-begin-tx
olavloiteOct 5, 2020
07346f0
chore: remove commented code
olavloiteOct 6, 2020
2768f69
feat!: remove session pool preparing (#515)
olavloiteOct 21, 2020
b816a66
Merge branch 'master' into inline-begin-tx
olavloiteOct 21, 2020
24ea415
chore: run formatter
olavloiteOct 21, 2020
28277ff
test: fix integration test that relied on data from other test case
olavloiteOct 21, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Failed to load files.
Previous commit
Next commit
test: add tests for error during tx
  • Loading branch information
@olavloite
olavloite committedJul 30, 2020
commit af5066978406e106c72a113d2547f6b9309d12ad
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,10 @@
import com.google.protobuf.AbstractMessage;
import com.google.protobuf.ListValue;
import com.google.spanner.v1.BeginTransactionRequest;
import com.google.spanner.v1.CommitRequest;
import com.google.spanner.v1.ExecuteSqlRequest;
import com.google.spanner.v1.ResultSetMetadata;
import com.google.spanner.v1.RollbackRequest;
import com.google.spanner.v1.StructType;
import com.google.spanner.v1.StructType.Field;
import com.google.spanner.v1.TypeCode;
Expand DownExpand Up@@ -284,6 +287,63 @@ public Long run(TransactionContext transaction) throws Exception {
assertThat(countTransactionsStarted()).isEqualTo(2);
}

@Test
public void testInlinedBeginTxWithUncaughtError() {
DatabaseClient client =
spanner.getDatabaseClient(DatabaseId.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"));
try {
client
.readWriteTransaction()
.run(
new TransactionCallable<Long>() {
@Override
public Long run(TransactionContext transaction) throws Exception {
return transaction.executeUpdate(INVALID_UPDATE_STATEMENT);
}
});
fail("missing expected exception");
} catch (SpannerException e) {
assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT);
}
// The first update will start a transaction, but then fail the update statement. This will
// start a transaction on the mock server, but that transaction will never be returned to the
// client.
assertThat(countRequests(BeginTransactionRequest.class)).isEqualTo(0);
assertThat(countRequests(CommitRequest.class)).isEqualTo(0);
assertThat(countRequests(ExecuteSqlRequest.class)).isEqualTo(1);
// No rollback request will be initiated because the client does not receive any transaction id.
assertThat(countRequests(RollbackRequest.class)).isEqualTo(0);
assertThat(countTransactionsStarted()).isEqualTo(1);
}

@Test
public void testInlinedBeginTxWithUncaughtErrorAfterSuccessfulBegin() {
DatabaseClient client =
spanner.getDatabaseClient(DatabaseId.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"));
try {
client
.readWriteTransaction()
.run(
new TransactionCallable<Long>() {
@Override
public Long run(TransactionContext transaction) throws Exception {
// This statement will start a transaction.
transaction.executeUpdate(UPDATE_STATEMENT);
// This statement will fail and cause a rollback as the exception is not caught.
return transaction.executeUpdate(INVALID_UPDATE_STATEMENT);
}
});
fail("missing expected exception");
} catch (SpannerException e) {
assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT);
}
assertThat(countRequests(BeginTransactionRequest.class)).isEqualTo(0);
assertThat(countRequests(CommitRequest.class)).isEqualTo(0);
assertThat(countRequests(ExecuteSqlRequest.class)).isEqualTo(2);
assertThat(countRequests(RollbackRequest.class)).isEqualTo(1);
assertThat(countTransactionsStarted()).isEqualTo(1);
}

@Test
public void testInlinedBeginTxWithParallelQueries() {
final int numQueries = 100;
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -28,6 +28,7 @@
import com.google.cloud.spanner.BatchReadOnlyTransaction;
import com.google.cloud.spanner.Database;
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.ErrorCode;
import com.google.cloud.spanner.IntegrationTestEnv;
import com.google.cloud.spanner.Key;
Expand All@@ -45,6 +46,8 @@
import com.google.cloud.spanner.TimestampBound;
import com.google.cloud.spanner.TransactionContext;
import com.google.cloud.spanner.TransactionRunner;
import com.google.cloud.spanner.TransactionRunner.TransactionCallable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.SettableFuture;
import com.google.common.util.concurrent.Uninterruptibles;
Expand DownExpand Up@@ -111,6 +114,7 @@ public void setupClient() {

@After
public void closeClient() {
client.writeAtLeastOnce(ImmutableList.of(Mutation.delete("T", KeySet.all())));
spanner.close();
}

Expand DownExpand Up@@ -548,4 +552,68 @@ public Void run(TransactionContext transaction) throws SpannerException {
}
});
}

@Test
public void testTxWithCaughtError() {
long updateCount =
client
.readWriteTransaction()
.run(
new TransactionCallable<Long>() {
@Override
public Long run(TransactionContext transaction) throws Exception {
try {
transaction.executeUpdate(
Statement.of("UPDATE NonExistingTable SET Foo=1 WHERE Bar=2"));
fail("missing expected exception");
} catch (SpannerException e) {
assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT);
}
return transaction.executeUpdate(
Statement.of("INSERT INTO T (K, V) VALUES ('One', 1)"));
}
});
assertThat(updateCount).isEqualTo(1L);
}

@Test
public void testTxWithUncaughtError() {
try {
client
.readWriteTransaction()
.run(
new TransactionCallable<Long>() {
@Override
public Long run(TransactionContext transaction) throws Exception {
return transaction.executeUpdate(
Statement.of("UPDATE NonExistingTable SET Foo=1 WHERE Bar=2"));
}
});
fail("missing expected exception");
} catch (SpannerException e) {
assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT);
}
}

@Test
public void testTxWithUncaughtErrorAfterSuccessfulBegin() {
DatabaseClient client =
spanner.getDatabaseClient(DatabaseId.of("[PROJECT]", "[INSTANCE]", "[DATABASE]"));
try {
client
.readWriteTransaction()
.run(
new TransactionCallable<Long>() {
@Override
public Long run(TransactionContext transaction) throws Exception {
transaction.executeUpdate(Statement.of("INSERT INTO T (K, V) VALUES ('One', 1)"));
return transaction.executeUpdate(
Statement.of("UPDATE NonExistingTable SET Foo=1 WHERE Bar=2"));
}
});
fail("missing expected exception");
} catch (SpannerException e) {
assertThat(e.getErrorCode()).isEqualTo(ErrorCode.INVALID_ARGUMENT);
}
}
}