Skip to content

Commit 9d13f11

Browse files
committed
[SEA-NodeJS] tests: ordered PEM markers + poll-loop terminal close (P1.3/P1.5 coverage)
Locks the round-2 fixes the review flagged as untested: - PEM customCaCert rejects out-of-order / BEGIN-only / END-only blobs (ordered regex, not two independent substring checks). - The async poll loop best-effort close()s the kernel statement on every server-driven terminal error (Cancelled/Closed/Unknown), proving no handle leak. All round-2 behaviours additionally verified end-to-end against a live warehouse (insecure-combo warn, async-Failed SQL error + close, Thrift rowLimit warn). Co-authored-by: Isaac Signed-off-by: Madhavendra Rathore <madhavendra.rathore@databricks.com>
1 parent 0422f27 commit 9d13f11

2 files changed

Lines changed: 23 additions & 0 deletions

File tree

tests/unit/sea/connectionOptions.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,17 @@ describe('SeaAuth TLS options (buildSeaTlsOptions)', () => {
9393
expect(() => buildSeaTlsOptions(opts({ customCaCert: 'not-a-pem' }))).to.throw(HiveDriverError, /PEM certificate/);
9494
});
9595

96+
it('rejects out-of-order / partial PEM markers (ordered match, not two substrings)', () => {
97+
// END-before-BEGIN, BEGIN-only, and END-only must all fail — a blob that
98+
// merely *contains* both literals (e.g. a proxy-intercept page) is not a cert.
99+
const reversed = '-----END CERTIFICATE-----\nMIIB...\n-----BEGIN CERTIFICATE-----';
100+
const beginOnly = '-----BEGIN CERTIFICATE-----\nMIIB...\n';
101+
const endOnly = 'MIIB...\n-----END CERTIFICATE-----';
102+
for (const bad of [reversed, beginOnly, endOnly]) {
103+
expect(() => buildSeaTlsOptions(opts({ customCaCert: bad })), bad).to.throw(HiveDriverError, /PEM certificate/);
104+
}
105+
});
106+
96107
it('rejects an empty Buffer', () => {
97108
expect(() => buildSeaTlsOptions(opts({ customCaCert: Buffer.alloc(0) }))).to.throw(HiveDriverError, /empty/);
98109
});

tests/unit/sea/execution.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,18 @@ describe('SeaOperationBackend — async (submitStatement) path', () => {
952952
expect((thrown as OperationStateError).errorCode).to.equal(OperationStateErrorCode.Canceled);
953953
});
954954

955+
it('best-effort close()s the kernel statement on a server-driven terminal error (no leak)', async () => {
956+
// P1.5: the poll loop must release the statement handle on terminal errors,
957+
// not just throw (otherwise the kernel-side statement leaks until session close).
958+
for (const state of ['Cancelled', 'Closed', 'Unknown']) {
959+
const stmt = new FakeAsyncStatement(state);
960+
const op = makeAsyncOp(stmt);
961+
// eslint-disable-next-line no-await-in-loop
962+
await op.waitUntilReady().catch(() => undefined);
963+
expect(stmt.closed, `closed after ${state}`).to.equal(true);
964+
}
965+
});
966+
955967
it('waitUntilReady() throws OperationStateError(Closed) on a server-side Closed statement', async () => {
956968
const op = makeAsyncOp(new FakeAsyncStatement('Closed'));
957969
let thrown: unknown;

0 commit comments

Comments
 (0)