Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/cmap/command_monitoring_events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export class CommandSucceededEvent {
commandName: string;
reply: unknown;
serviceId?: ObjectId;
databaseName: string;
/** @internal */
name = COMMAND_SUCCEEDED;

Expand Down Expand Up @@ -127,6 +128,7 @@ export class CommandSucceededEvent {
this.duration = calculateDurationInMs(started);
this.reply = maybeRedact(commandName, cmd, extractReply(reply));
this.serverConnectionId = serverConnectionId;
this.databaseName = command.databaseName;
}

/* @internal */
Expand Down Expand Up @@ -154,6 +156,7 @@ export class CommandFailedEvent {
commandName: string;
failure: Error;
serviceId?: ObjectId;
databaseName: string;
/** @internal */
name = COMMAND_FAILED;

Expand Down Expand Up @@ -186,6 +189,7 @@ export class CommandFailedEvent {
this.duration = calculateDurationInMs(started);
this.failure = maybeRedact(commandName, cmd, error) as Error;
this.serverConnectionId = serverConnectionId;
this.databaseName = command.databaseName;
}

/* @internal */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { expect } from 'chai';
import { once } from 'events';
import { createServer, type Server } from 'net';

import { getCSFLEKMSProviders } from '../../csfle-kms-providers';
import { type MongoClient } from '../../mongodb';
import { ClientSideEncryptionFilter } from '../../tools/runner/filters/client_encryption_filter';
import { getEncryptExtraOptions } from '../../tools/utils';

describe('20. Bypass creating mongocryptd client when shared library is loaded', function () {
let server: Server;
let hasConnection = false;
let client: MongoClient;

beforeEach(function () {
if (!ClientSideEncryptionFilter.cryptShared) {
this.currentTest.skipReason =
'test requires that the crypt shared be loaded into the current process.';
this.skip();
}

// Start a new thread (referred to as listenerThread)
// On listenerThread, create a TcpListener on 127.0.0.1 endpoint and port 27021. Start the listener and wait for establishing connections. If any connection is established, then signal about this to the main thread.
// Drivers MAY pass a different port if they expect their testing infrastructure to be using port 27021. Pass a port that should be free.
// In Node, we don't need to create a separate thread for the server.
server = createServer({});
server.listen(27021);
server.on('connection', () => (hasConnection = true));

// Create a MongoClient configured with auto encryption (referred to as client_encrypted)
// Configure the required options. Use the local KMS provider as follows:
// { "local": { "key": <base64 decoding of LOCAL_MASTERKEY> } }
// Configure with the keyVaultNamespace set to keyvault.datakeys.
// Configure the following extraOptions:
// {
// "mongocryptdURI": "mongodb://localhost:27021/?serverSelectionTimeoutMS=1000"
// }
client = this.configuration.newClient(
{},
{
autoEncryption: {
kmsProviders: { local: getCSFLEKMSProviders().local },
keyVaultNamespace: 'keyvault.datakeys',
extraOptions: {
cryptSharedLibPath: getEncryptExtraOptions().cryptSharedLibPath,
mongocryptdURI: 'mongodb://localhost:27021'
}
}
}
);
});

afterEach(async function () {
server && (await once(server.close(), 'close'));
await client?.close();
});

it(
'does not create or use a mongocryptd client when the shared library is loaded',
{
requires: {
clientSideEncryption: true
}
},
async function () {
// Use client_encrypted to insert the document {"unencrypted": "test"} into db.coll.
await client.db('db').collection('coll').insertOne({ unencrypted: 'test' });

// Expect no signal from listenerThread.
expect(hasConnection).to.be.false;

// Note: this assertion is not in the spec test. However, unlike other drivers, Node's client
// does not connect when instantiated. So, we won't receive any TCP connections to the
// server if the mongocryptd client is only instantiated. This assertion captures the
// spirit of this test, causing it to fail if we do instantiate a client. I left the
// TCP server in, although it isn't necessary for Node's test, just because its nice to have
// in case Node's client behavior ever changes.
expect(client.autoEncrypter._mongocryptdClient).to.be.undefined;
}
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"description": "expectedCommandEvent-commandFailedEvent-databaseName-type",
"schemaVersion": "1.15",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandFailedEvent": {
"databaseName": 0
}
}
]
}
]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
description: "expectedCommandEvent-commandFailedEvent-databaseName-type"

schemaVersion: "1.15"

createEntities:
- client:
id: &client0 "client0"

tests:
- description: "foo"
operations: []
expectEvents:
- client: *client0
events:
- commandFailedEvent:
databaseName: 0
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"description": "expectedCommandEvent-commandSucceededEvent-databaseName-type",
"schemaVersion": "1.15",
"createEntities": [
{
"client": {
"id": "client0"
}
}
],
"tests": [
{
"description": "foo",
"operations": [],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandSucceededEvent": {
"databaseName": 0
}
}
]
}
]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
description: "expectedCommandEvent-commandSucceededEvent-databaseName-type"

schemaVersion: "1.15"

createEntities:
- client:
id: &client0 "client0"

tests:
- description: "foo"
operations: []
expectEvents:
- client: *client0
events:
- commandSucceededEvent:
databaseName: 0
44 changes: 27 additions & 17 deletions test/tools/unified-spec-runner/match.ts
Original file line number Diff line number Diff line change
Expand Up @@ -461,54 +461,64 @@ function compareCommandStartedEvents(
if (expected!.commandName) {
expect(
expected!.commandName,
`expected ${prefix}.commandName to equal ${expected!.commandName} but received ${
actual.commandName
`expected ${prefix}.commandName to equal ${expected!.commandName} but received ${actual.commandName
}`
).to.equal(actual.commandName);
}
if (expected!.databaseName) {
expect(
expected!.databaseName,
`expected ${prefix}.databaseName to equal ${expected!.databaseName} but received ${
actual.databaseName
`expected ${prefix}.databaseName to equal ${expected!.databaseName} but received ${actual.databaseName
}`
).to.equal(actual.databaseName);
}
}

function compareCommandSucceededEvents(
actual: CommandSucceededEvent,
expected: ExpectedCommandEvent['commandSucceededEvent'],
expected: NonNullable<ExpectedCommandEvent['commandSucceededEvent']>,
entities: EntitiesMap,
prefix: string
) {
if (expected!.reply) {
resultCheck(actual.reply as Document, expected!.reply, entities, [prefix]);
if (expected.reply) {
resultCheck(actual.reply as Document, expected.reply, entities, [prefix]);
}
if (expected!.commandName) {
if (expected.commandName) {
expect(
expected!.commandName,
`expected ${prefix}.commandName to equal ${expected!.commandName} but received ${
actual.commandName
expected.commandName,
`expected ${prefix}.commandName to equal ${expected.commandName} but received ${actual.commandName
}`
).to.equal(actual.commandName);
}
if (expected.databaseName) {
expect(
expected.databaseName,
`expected ${prefix}.databaseName to equal ${expected.databaseName} but received ${actual.databaseName
}`
).to.equal(actual.databaseName);
}
}

function compareCommandFailedEvents(
actual: CommandFailedEvent,
expected: ExpectedCommandEvent['commandFailedEvent'],
entities: EntitiesMap,
expected: NonNullable<ExpectedCommandEvent['commandFailedEvent']>,
_entities: EntitiesMap,
prefix: string
) {
if (expected!.commandName) {
if (expected.commandName) {
expect(
expected!.commandName,
`expected ${prefix}.commandName to equal ${expected!.commandName} but received ${
actual.commandName
expected.commandName,
`expected ${prefix}.commandName to equal ${expected.commandName} but received ${actual.commandName
}`
).to.equal(actual.commandName);
}
if (expected.databaseName) {
expect(
expected.databaseName,
`expected ${prefix}.databaseName to equal ${expected.databaseName} but received ${actual.databaseName
}`
).to.equal(actual.databaseName);
}
}

function expectInstanceOf<T extends new (...args: any[]) => any>(
Expand Down
2 changes: 2 additions & 0 deletions test/tools/unified-spec-runner/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,10 +312,12 @@ export interface ExpectedCommandEvent {
commandSucceededEvent?: {
reply?: Document;
commandName?: string;
databaseName?: string;
hasServerConnectionId?: boolean;
};
commandFailedEvent?: {
commandName?: string;
databaseName?: string;
hasServerConnectionId?: boolean;
};
}
Expand Down