Skip to content

Commit 99ded3a

Browse files
committed
chore: try fixing tests
1 parent 54c59df commit 99ded3a

File tree

5 files changed

+67
-28
lines changed

5 files changed

+67
-28
lines changed

src/client-side-encryption/state_machine.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
} from '../bson';
1313
import { type ProxyOptions } from '../cmap/connection';
1414
import { CursorTimeoutContext } from '../cursor/abstract_cursor';
15-
import { type ListCollectionsCursor } from '../cursor/list_collections_cursor';
1615
import { getSocks, type SocksLib } from '../deps';
1716
import { MongoOperationTimeoutError } from '../error';
1817
import { type MongoClient, type MongoClientOptions } from '../mongo_client';
@@ -207,11 +206,19 @@ export class StateMachine {
207206
const mongocryptdManager = executor._mongocryptdManager;
208207
let result: Uint8Array | null = null;
209208

210-
while (context.state !== MONGOCRYPT_CTX_DONE && context.state !== MONGOCRYPT_CTX_ERROR) {
209+
// Typescript treats getters just like properties: Once you've tested it for equality
210+
// it cannot change. Which is exactly the opposite of what we use state and status for.
211+
// Every call to at least `addMongoOperationResponse` and `finalize` can change the state.
212+
// These wrappers let us write code more naturally and not add compiler exceptions
213+
// to conditions checks inside the state machine.
214+
const getStatus = () => context.status;
215+
const getState = () => context.state;
216+
217+
while (getState() !== MONGOCRYPT_CTX_DONE && getState() !== MONGOCRYPT_CTX_ERROR) {
211218
options.signal?.throwIfAborted();
212-
debug(`[context#${context.id}] ${stateToString.get(context.state) || context.state}`);
219+
debug(`[context#${context.id}] ${stateToString.get(getState()) || getState()}`);
213220

214-
switch (context.state) {
221+
switch (getState()) {
215222
case MONGOCRYPT_CTX_NEED_MONGO_COLLINFO: {
216223
const filter = deserialize(context.nextMongoOperation());
217224
if (!metaDataClient) {
@@ -229,8 +236,11 @@ export class StateMachine {
229236

230237
for await (const collInfo of collInfoCursor) {
231238
context.addMongoOperationResponse(serialize(collInfo));
239+
if (getState() === MONGOCRYPT_CTX_ERROR) break;
232240
}
233241

242+
if (getState() === MONGOCRYPT_CTX_ERROR) break;
243+
234244
context.finishMongoOperation();
235245
break;
236246
}
@@ -286,22 +296,21 @@ export class StateMachine {
286296

287297
case MONGOCRYPT_CTX_READY: {
288298
const finalizedContext = context.finalize();
289-
// @ts-expect-error finalize can change the state, check for error
290-
if (context.state === MONGOCRYPT_CTX_ERROR) {
291-
const message = context.status.message || 'Finalization error';
299+
if (getState() === MONGOCRYPT_CTX_ERROR) {
300+
const message = getStatus().message || 'Finalization error';
292301
throw new MongoCryptError(message);
293302
}
294303
result = finalizedContext;
295304
break;
296305
}
297306

298307
default:
299-
throw new MongoCryptError(`Unknown state: ${context.state}`);
308+
throw new MongoCryptError(`Unknown state: ${getState()}`);
300309
}
301310
}
302311

303-
if (context.state === MONGOCRYPT_CTX_ERROR || result == null) {
304-
const message = context.status.message;
312+
if (getState() === MONGOCRYPT_CTX_ERROR || result == null) {
313+
const message = getStatus().message;
305314
if (!message) {
306315
debug(
307316
`unidentifiable error in MongoCrypt - received an error status from \`libmongocrypt\` but received no error message.`
@@ -535,7 +544,7 @@ export class StateMachine {
535544
ns: string,
536545
filter: Document,
537546
options?: { timeoutContext?: TimeoutContext } & Abortable
538-
): ListCollectionsCursor<CollectionInfo> {
547+
): AsyncIterable<CollectionInfo> {
539548
const { db } = MongoDBCollectionNamespace.fromString(ns);
540549

541550
const cursor = client.db(db).listCollections(filter, {

test/integration/client-side-encryption/client_side_encryption.prose.25.lookup.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ const newEncryptedClient = ({ configuration }: { configuration: TestConfiguratio
4242
}
4343
);
4444

45-
describe('$lookup support', function () {
45+
describe('$lookup support', defaultMetadata, function () {
4646
before(async function () {
4747
let client: MongoClient, encryptedClient: MongoClient;
4848
try {

test/integration/client-side-encryption/driver.test.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,11 +1047,19 @@ describe('CSOT', function () {
10471047
});
10481048

10491049
it('the command should fail due to a timeout error', metadata, async function () {
1050-
const { duration, result: error } = await measureDuration(() =>
1051-
stateMachine
1052-
.fetchCollectionInfo(encryptedClient, 'test.test', { a: 1 }, timeoutContext())
1053-
.catch(e => e)
1054-
);
1050+
const { duration, result: error } = await measureDuration(async () => {
1051+
try {
1052+
const cursor = stateMachine.fetchCollectionInfo(
1053+
encryptedClient,
1054+
'test.test',
1055+
{ a: 1 },
1056+
timeoutContext()
1057+
);
1058+
for await (const doc of cursor) void doc;
1059+
} catch (error) {
1060+
return error;
1061+
}
1062+
});
10551063
expect(error).to.be.instanceOf(MongoOperationTimeoutError);
10561064
expect(duration).to.be.within(timeoutMS - 100, timeoutMS + 100);
10571065
});
@@ -1074,7 +1082,8 @@ describe('CSOT', function () {
10741082
});
10751083

10761084
it('the command succeeds', metadata, async function () {
1077-
await stateMachine.fetchCollectionInfo(encryptedClient, 'test.test', { a: 1 });
1085+
const cursor = stateMachine.fetchCollectionInfo(encryptedClient, 'test.test', { a: 1 });
1086+
for await (const doc of cursor) void doc;
10781087
});
10791088
}
10801089
);

test/unit/client-side-encryption/auto_encrypter.test.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { MongocryptdManager } from '../../../src/client-side-encryption/mongocry
1111
import { StateMachine } from '../../../src/client-side-encryption/state_machine';
1212
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
1313
import { MongoClient } from '../../../src/mongo_client';
14-
import { BSON, type DataKey } from '../../mongodb';
14+
import { BSON, type DataKey, type Db, ListCollectionsCursor } from '../../mongodb';
1515
import * as requirements from './requirements.helper';
1616

1717
const bson = BSON;
@@ -63,7 +63,11 @@ describe('AutoEncrypter', function () {
6363
return Promise.resolve();
6464
});
6565

66-
sandbox.stub(StateMachine.prototype, 'fetchCollectionInfo').resolves(MOCK_COLLINFO_RESPONSE);
66+
sandbox.stub(StateMachine.prototype, 'fetchCollectionInfo').returns(
67+
(async function* () {
68+
while (true) yield MOCK_COLLINFO_RESPONSE;
69+
})()
70+
);
6771

6872
sandbox.stub(StateMachine.prototype, 'markCommand').callsFake(() => {
6973
if (ENABLE_LOG_TEST) {

test/unit/client-side-encryption/state_machine.test.ts

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -580,11 +580,21 @@ describe('StateMachine', function () {
580580
serverSelectionTimeoutMS: 30000
581581
});
582582
await sleep(300);
583-
await stateMachine
584-
.fetchCollectionInfo(client, 'keyVault', BSON.serialize({ a: 1 }), {
585-
timeoutContext: context
586-
})
587-
.catch(e => squashError(e));
583+
584+
try {
585+
const cursor = stateMachine.fetchCollectionInfo(
586+
client,
587+
'keyVault',
588+
BSON.serialize({ a: 1 }),
589+
{
590+
timeoutContext: context
591+
}
592+
);
593+
for await (const doc of cursor) void doc;
594+
} catch {
595+
// ignore
596+
}
597+
588598
const [_filter, { timeoutContext }] = listCollectionsSpy.getCalls()[0].args;
589599
expect(timeoutContext).to.exist;
590600
expect(timeoutContext.timeoutContext).to.equal(context);
@@ -596,9 +606,16 @@ describe('StateMachine', function () {
596606
'when StateMachine.fetchCollectionInfo() is not passed a `CSOTimeoutContext`',
597607
function () {
598608
it('no timeoutContext is provided to listCollections', async function () {
599-
await stateMachine
600-
.fetchCollectionInfo(client, 'keyVault', BSON.serialize({ a: 1 }))
601-
.catch(e => squashError(e));
609+
try {
610+
const cursor = stateMachine.fetchCollectionInfo(
611+
client,
612+
'keyVault',
613+
BSON.serialize({ a: 1 })
614+
);
615+
for await (const doc of cursor) void doc;
616+
} catch {
617+
// ignore
618+
}
602619
const [_filter, { timeoutContext }] = listCollectionsSpy.getCalls()[0].args;
603620
expect(timeoutContext).not.to.exist;
604621
});

0 commit comments

Comments
 (0)