Skip to content

Commit 4404280

Browse files
committed
Add tests for more negative tests
1 parent 8a8e485 commit 4404280

File tree

2 files changed

+174
-1
lines changed

2 files changed

+174
-1
lines changed

observability-test/spanner.ts

Lines changed: 173 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1253,7 +1253,7 @@ describe('E2E traces with async/await', async () => {
12531253
});
12541254
});
12551255

1256-
describe("Negative case: database.run('SELECT 1p')", async () => {
1256+
describe('Negative cases', async () => {
12571257
let server: grpc.Server;
12581258
let spanner: Spanner;
12591259
let database: Database;
@@ -1266,6 +1266,10 @@ describe("Negative case: database.run('SELECT 1p')", async () => {
12661266
const messageBadSelect1p = `Missing whitespace between literal and alias [at 1:9]
12671267
SELECT 1p
12681268
^`;
1269+
const insertAlreadyExistentDataSql =
1270+
"INSERT INTO Singers(firstName, SingerId) VALUES('Foo', 1)";
1271+
const messageBadInsertAlreadyExistent =
1272+
'Failed to insert row with primary key ({pk#SingerId:1}) due to previously existing row';
12691273

12701274
beforeEach(async () => {
12711275
traceExporter = new InMemorySpanExporter();
@@ -1292,6 +1296,15 @@ SELECT 1p
12921296
selectSql1p,
12931297
mock.StatementResult.error(serverErr)
12941298
);
1299+
1300+
const insertAlreadyExistentErr = {
1301+
message: messageBadInsertAlreadyExistent,
1302+
code: grpc.status.ALREADY_EXISTS,
1303+
} as mock.MockError;
1304+
spannerMock.putStatementResult(
1305+
insertAlreadyExistentDataSql,
1306+
mock.StatementResult.error(insertAlreadyExistentErr)
1307+
);
12951308
});
12961309

12971310
afterEach(async () => {
@@ -1305,6 +1318,9 @@ SELECT 1p
13051318
function assertRunBadSyntaxExpectations() {
13061319
traceExporter.forceFlush();
13071320
const spans = traceExporter.getFinishedSpans();
1321+
spans.sort((spanA, spanB) => {
1322+
return spanA.startTime < spanB.startTime;
1323+
});
13081324

13091325
const actualSpanNames: string[] = [];
13101326
const actualEventNames: string[] = [];
@@ -1453,4 +1469,160 @@ SELECT 1p
14531469
done();
14541470
});
14551471
});
1472+
1473+
function assertDatabaseRunPlusAwaitTransactionForAlreadyExistentData() {
1474+
traceExporter.forceFlush();
1475+
const spans = traceExporter.getFinishedSpans();
1476+
spans.sort((spanA, spanB) => {
1477+
return spanA.startTime < spanB.startTime;
1478+
});
1479+
1480+
const actualSpanNames: string[] = [];
1481+
const actualEventNames: string[] = [];
1482+
spans.forEach(span => {
1483+
actualSpanNames.push(span.name);
1484+
span.events.forEach(event => {
1485+
actualEventNames.push(event.name);
1486+
});
1487+
});
1488+
1489+
const expectedSpanNames = [
1490+
'CloudSpanner.Database.batchCreateSessions',
1491+
'CloudSpanner.SessionPool.createSessions',
1492+
'CloudSpanner.Snapshot.runStream',
1493+
'CloudSpanner.Snapshot.run',
1494+
'CloudSpanner.Snapshot.begin',
1495+
'CloudSpanner.Snapshot.begin',
1496+
'CloudSpanner.Transaction.commit',
1497+
'CloudSpanner.Transaction.commit',
1498+
'CloudSpanner.Database.runTransaction',
1499+
];
1500+
assert.deepStrictEqual(
1501+
expectedSpanNames,
1502+
actualSpanNames,
1503+
`span names mismatch:\n\tGot: ${actualSpanNames}\n\tWant: ${expectedSpanNames}`
1504+
);
1505+
1506+
// We need to ensure a strict relationship between the spans.
1507+
// |-Database.runTransaction |-------------------------------------|
1508+
// |-Snapshot.run |------------------------|
1509+
// |-Snapshot.runStream |---------------------|
1510+
// |-Transaction.commit |--------|
1511+
// |-Snapshot.begin |------|
1512+
// |-Snapshot.commit |-----|
1513+
const spanDatabaseRunTransaction = spans[spans.length - 1];
1514+
assert.deepStrictEqual(
1515+
spanDatabaseRunTransaction.name,
1516+
'CloudSpanner.Database.runTransaction',
1517+
`${actualSpanNames}`
1518+
);
1519+
const spanTransactionCommit0 = spans[spans.length - 2];
1520+
assert.strictEqual(
1521+
spanTransactionCommit0.name,
1522+
'CloudSpanner.Transaction.commit'
1523+
);
1524+
assert.deepStrictEqual(
1525+
spanTransactionCommit0.parentSpanId,
1526+
spanDatabaseRunTransaction.spanContext().spanId,
1527+
'Expected that Database.runTransaction is the parent to Transaction.commmit'
1528+
);
1529+
const spanSnapshotRun = spans[3];
1530+
assert.strictEqual(spanSnapshotRun.name, 'CloudSpanner.Snapshot.run');
1531+
assert.deepStrictEqual(
1532+
spanSnapshotRun.parentSpanId,
1533+
spanDatabaseRunTransaction.spanContext().spanId,
1534+
'Expected that Database.runTransaction is the parent to Snapshot.run'
1535+
);
1536+
const wantSpanErr = '6 ALREADY_EXISTS: ' + messageBadInsertAlreadyExistent;
1537+
assert.deepStrictEqual(
1538+
spanSnapshotRun.status.code,
1539+
SpanStatusCode.ERROR,
1540+
'Unexpected status code'
1541+
);
1542+
assert.deepStrictEqual(
1543+
spanSnapshotRun.status.message,
1544+
wantSpanErr,
1545+
'Unexpexcted error message'
1546+
);
1547+
1548+
const databaseBatchCreateSessionsSpan = spans[0];
1549+
assert.strictEqual(
1550+
databaseBatchCreateSessionsSpan.name,
1551+
'CloudSpanner.Database.batchCreateSessions'
1552+
);
1553+
const sessionPoolCreateSessionsSpan = spans[1];
1554+
assert.strictEqual(
1555+
sessionPoolCreateSessionsSpan.name,
1556+
'CloudSpanner.SessionPool.createSessions'
1557+
);
1558+
assert.ok(
1559+
sessionPoolCreateSessionsSpan.spanContext().traceId,
1560+
'Expecting a defined sessionPoolCreateSessions traceId'
1561+
);
1562+
assert.deepStrictEqual(
1563+
sessionPoolCreateSessionsSpan.spanContext().traceId,
1564+
databaseBatchCreateSessionsSpan.spanContext().traceId,
1565+
'Expected the same traceId'
1566+
);
1567+
assert.deepStrictEqual(
1568+
databaseBatchCreateSessionsSpan.parentSpanId,
1569+
sessionPoolCreateSessionsSpan.spanContext().spanId,
1570+
'Expected that sessionPool.createSessions is the parent to db.batchCreassionSessions'
1571+
);
1572+
1573+
// Assert that despite all being exported, SessionPool.createSessions
1574+
// is not in the same trace as runStream, createSessions is invoked at
1575+
// Spanner Client instantiation, thus before database.run is invoked.
1576+
assert.notEqual(
1577+
sessionPoolCreateSessionsSpan.spanContext().traceId,
1578+
spanDatabaseRunTransaction.spanContext().traceId,
1579+
'Did not expect the same traceId'
1580+
);
1581+
// Finally check for the collective expected event names.
1582+
const expectedEventNames = [
1583+
'Requesting 25 sessions',
1584+
'Creating 25 sessions',
1585+
'Requested for 25 sessions returned 25',
1586+
'Begin Transaction',
1587+
'Transaction Creation Done',
1588+
'Begin Transaction',
1589+
'Transaction Creation Done',
1590+
'Starting Commit',
1591+
'Commit Done',
1592+
'Acquiring session',
1593+
'Waiting for a session to become available',
1594+
'Acquired session',
1595+
];
1596+
assert.deepStrictEqual(
1597+
actualEventNames,
1598+
expectedEventNames,
1599+
`Unexpected events:\n\tGot: ${actualEventNames}\n\tWant: ${expectedEventNames}`
1600+
);
1601+
}
1602+
1603+
it('runTransaction with async/await for INSERT with existent data + transaction.commit', done => {
1604+
const instance = spanner.instance('instance');
1605+
const database = instance.database('database');
1606+
1607+
const update = {
1608+
sql: insertAlreadyExistentDataSql,
1609+
};
1610+
database.runTransaction(async (err, transaction) => {
1611+
if (err) {
1612+
console.error(err);
1613+
return;
1614+
}
1615+
try {
1616+
await transaction!.run(update);
1617+
await new Promise(resolve => setTimeout(resolve, 400));
1618+
} catch (err) {
1619+
} finally {
1620+
await transaction!.commit();
1621+
await new Promise(resolve => setTimeout(resolve, 2800));
1622+
provider.forceFlush();
1623+
assertDatabaseRunPlusAwaitTransactionForAlreadyExistentData();
1624+
done();
1625+
}
1626+
});
1627+
});
14561628
});

src/database.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3259,6 +3259,7 @@ class Database extends common.GrpcServiceObject {
32593259
setSpanError(span, err!);
32603260
}
32613261
await runFn!(err, resp);
3262+
span.end();
32623263
},
32633264
options
32643265
);

0 commit comments

Comments
 (0)