Skip to content

Commit 006ca6a

Browse files
committed
test: commit retry logic
1 parent 30b6669 commit 006ca6a

File tree

2 files changed

+102
-4
lines changed

2 files changed

+102
-4
lines changed

test/mockserver/mockspanner.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,6 @@ export class MockSpanner {
325325
string,
326326
protobuf.Session
327327
>();
328-
private multiplexedSession: boolean | undefined;
329328
private begin: boolean;
330329
private transactionCounters: Map<string, number> = new Map<string, number>();
331330
private transactions: Map<string, protobuf.Transaction> = new Map<
@@ -473,7 +472,6 @@ export class MockSpanner {
473472
createTime: now(),
474473
});
475474
this.sessions.set(name, session);
476-
this.multiplexedSession = multiplexed;
477475
return session;
478476
}
479477

@@ -695,13 +693,14 @@ export class MockSpanner {
695693
}
696694
}
697695
const res = this.statementResults.get(call.request!.sql);
696+
const session = this.sessions.get(call.request!.session);
698697
if (res) {
699698
if (call.request!.transaction?.begin) {
700699
const txn = this._updateTransaction(
701700
call.request!.session,
702701
call.request!.transaction.begin,
703702
);
704-
const precommitToken = this.multiplexedSession
703+
const precommitToken = session?.multiplexed
705704
? protobuf.MultiplexedSessionPrecommitToken.create({
706705
precommitToken: Buffer.from('mock-precommit-token'),
707706
seqNum: randomInt(1, 1000),
@@ -1012,13 +1011,14 @@ export class MockSpanner {
10121011
);
10131012
const key = `${call.request!.table}|${keySet}`;
10141013
const res = this.readRequestResults.get(key);
1014+
const session = this.sessions.get(call.request!.session);
10151015
if (res) {
10161016
if (call.request!.transaction?.begin) {
10171017
const txn = this._updateTransaction(
10181018
call.request!.session,
10191019
call.request!.transaction.begin,
10201020
);
1021-
const precommitToken = this.multiplexedSession
1021+
const precommitToken = session?.multiplexed
10221022
? protobuf.MultiplexedSessionPrecommitToken.create({
10231023
precommitToken: Buffer.from('mock-precommit-token'),
10241024
seqNum: randomInt(1, 1000),

test/spanner.ts

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2099,6 +2099,12 @@ describe('Spanner with mock server', () => {
20992099
'false';
21002100
});
21012101

2102+
after(() => {
2103+
process.env.GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS = 'false';
2104+
process.env.GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_PARTITIONED_OPS =
2105+
'false';
2106+
});
2107+
21022108
it('should execute the transaction(database.runPartitionedUpdate) successfully using regular/pool session', done => {
21032109
const database = newTestDatabase({min: 1, max: 1});
21042110
const pool = (database.sessionFactory_ as SessionFactory)
@@ -2127,6 +2133,12 @@ describe('Spanner with mock server', () => {
21272133
'true';
21282134
});
21292135

2136+
after(() => {
2137+
process.env.GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS = 'false';
2138+
process.env.GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_PARTITIONED_OPS =
2139+
'false';
2140+
});
2141+
21302142
it('should execute the transaction(database.runPartitionedUpdate) successfully using regular/pool session', done => {
21312143
const database = newTestDatabase({min: 1, max: 1});
21322144
const pool = (database.sessionFactory_ as SessionFactory)
@@ -2154,6 +2166,12 @@ describe('Spanner with mock server', () => {
21542166
'true';
21552167
});
21562168

2169+
after(() => {
2170+
process.env.GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS = 'false';
2171+
process.env.GOOGLE_CLOUD_SPANNER_MULTIPLEXED_SESSIONS_PARTITIONED_OPS =
2172+
'false';
2173+
});
2174+
21572175
it('should execute the transaction(database.runPartitionedUpdate) successfully using multiplexed session', done => {
21582176
const database = newTestDatabase({min: 1, max: 1});
21592177
const pool = (database.sessionFactory_ as SessionFactory)
@@ -4452,6 +4470,86 @@ describe('Spanner with mock server', () => {
44524470
});
44534471
});
44544472
});
4473+
4474+
// test(s) for commit retry logic
4475+
describe('Transaction Commit Retry Logic', () => {
4476+
let commitCallCount = 0;
4477+
let capturedCommitRequests: any[] = [];
4478+
4479+
it('should retry commit only once with a precommit token', async () => {
4480+
commitCallCount = 0;
4481+
capturedCommitRequests = [];
4482+
4483+
const database = newTestDatabase({min: 1, max: 1});
4484+
const fakeRetryToken = Buffer.from('mock-retry-token-123');
4485+
4486+
const commitRetryResponse = {
4487+
MultiplexedSessionRetry: 'precommitToken',
4488+
precommitToken: {
4489+
precommitToken: fakeRetryToken,
4490+
seqNum: 1,
4491+
},
4492+
commitTimestamp: mock.now(),
4493+
};
4494+
4495+
const commitSuccessResponse = {
4496+
commitTimestamp: mock.now(),
4497+
};
4498+
4499+
await database.runTransactionAsync(async tx => {
4500+
// mock commit request
4501+
tx.request = (config: any, callback: Function) => {
4502+
const cb = callback as (err: any, response: any) => void;
4503+
4504+
if (config.method !== 'commit') return;
4505+
4506+
commitCallCount++;
4507+
capturedCommitRequests.push(config.reqOpts);
4508+
4509+
if (commitCallCount === 1) {
4510+
cb(null, commitRetryResponse);
4511+
} else {
4512+
cb(null, commitSuccessResponse);
4513+
}
4514+
};
4515+
4516+
// perform read
4517+
await tx!.run(selectSql);
4518+
4519+
// perform mutations
4520+
await tx.upsert('foo', [
4521+
{id: 1, name: 'One'},
4522+
{id: 2, name: 'Two'},
4523+
]);
4524+
4525+
// make a call to commit
4526+
await tx.commit();
4527+
4528+
// assert that retry heppen only once
4529+
assert.strictEqual(
4530+
commitCallCount,
4531+
2,
4532+
'The mock commit method should have been called exactly twice.',
4533+
);
4534+
const firstRequest = capturedCommitRequests[0];
4535+
// assert that during the first request to commit
4536+
// the precommitToken was missing
4537+
assert.ok(
4538+
!firstRequest.precommitToken,
4539+
'The first commit request should not have a precommitToken.',
4540+
);
4541+
const secondRequest = capturedCommitRequests[1];
4542+
// assert that during the second request to commit
4543+
// the precommitToken was present
4544+
assert.deepStrictEqual(
4545+
secondRequest.precommitToken,
4546+
commitRetryResponse.precommitToken,
4547+
'The second commit request should have the precommitToken from the retry response.',
4548+
);
4549+
});
4550+
await database.close();
4551+
});
4552+
});
44554553
});
44564554
});
44574555

0 commit comments

Comments
 (0)