Skip to content

DRIVERS-2985: Allow on-demand client metadata updates after MongoClient initialization. #1798

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 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
18 changes: 15 additions & 3 deletions source/mongodb-handshake/handshake.md
Original file line number Diff line number Diff line change
Expand Up @@ -405,10 +405,21 @@ class DriverInfoOptions {
}
```

Note that how these options are provided to a driver is left up to the implementer.
Note that how these options are provided to a driver during `MongoClient` initialization is left up to the implementer.

If provided, these options MUST NOT replace the values used for metadata generation. The provided options MUST be
appended to their respective fields, and be delimited by a `|` character. For example, when
### Metadata updates after MongoClient initialization

Drivers MUST provide an API that allows appending `DriverInfoOptions` to a MongoClient instance after initialization.

After client metadata update, drivers MUST apply updated metadata to newly created connections. Drivers MUST NOT apply
updated metadata to already established connections, nor create new connections solely for the purpose of transferring
updated metadata.

### Appending metadata

If `DriverInfoOptions` are provided during or after MongoClient initialization, these options MUST NOT replace any
existing metadata values, including driver-generated metadata and previously provided options. The provided options MUST
be appended to their respective fields, and be delimited by a `|` character. For example, when
[Motor](https://www.mongodb.com/docs/drivers/motor/) wraps PyMongo, the following fields are updated to include Motor's
"driver info":

Expand Down Expand Up @@ -534,6 +545,7 @@ support the `hello` command, the `helloOk: true` argument is ignored and the leg

## Changelog

- 2025-05-07: Add requirement to allow appending to client metadata after MongoClient initialization.
- 2024-11-05: Move handshake prose tests from spec file to prose test file.
- 2024-10-09: Clarify that FaaS and container metadata must both be populated when both are present.
- 2024-08-16: Migrated from reStructuredText to Markdown.
Expand Down
125 changes: 125 additions & 0 deletions source/mongodb-handshake/tests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,128 @@ the following sets of environment variables:
2. Create and connect a `Connection` object that connects to the server that returns the mocked response.

3. Assert that no error is raised.

## Client Metadata Update Prose Tests

The driver **MAY** implement the following tests. Drivers that do not emit events for commands issued as part of the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this a MAY?

Copy link
Member Author

@vbabanin vbabanin May 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The prose tests assume interaction via the public API. However, iff the public API is just a thin wrapper around internal components, and those components may already expose functionality to intercept commands (i.e., without requiring a backdoor), testing against internal layers may cover most functionality, assuming the public API’s interaction with the internals remains stable over time. The “MAY” implies that the implementer can choose the trade-off between the complexity of introducing a backdoor for public API prose testing vs internal component testing. I’ve removed “MAY” to avoid over-assuming.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. @ShaneHarvey what do you think about this? Are these reasonable tests to require for all drivers?

handshake with the server will need to create a test-only backdoor mechanism to intercept the handshake `hello` command
for verification purposes.

### Test 1: Test that the driver updates metadata

Drivers should verify that metadata provided after `MongoClient` initialization is appended, not replaced, and is
visible in the `hello` command of new connections.

There are multiple test cases parameterized with `DriverInfoOptions` to be appended after `MongoClient` initialization.
Before each test case, perform the setup.

#### Setup

1. Create a `MongoClient` instance with the following:

- `maxIdleTimeMS` set to `1ms`

- Wrapping library metadata:

| Field | Value |
| -------- | ---------------- |
| name | library |
| version | 1.2 |
| platform | Library Platform |

2. Send a `ping` command to the server and verify:

- The command succeeds.
- The wrapping library metadata is appended to the respective `client.driver` fields of the `hello` command.
- Save intercepted `client` document as `initialClientMetadata`.

3. Wait 5ms for the connection to become idle.

#### Parameterized test cases

**Case 1**

| Field | Value |
| -------- | ------------------ |
| name | framework |
| version | 2.0 |
| platform | Framework Platform |

**Case 2**

| Field | Value |
| -------- | --------- |
| name | framework |
| version | 2.0 |
| platform | null |

**Case 3**

| Field | Value |
| -------- | ------------------ |
| name | framework |
| version | null |
| platform | Framework Platform |

**Case 4**

| Field | Value |
| -------- | --------- |
| name | framework |
| version | null |
| platform | null |

#### Running a test case

1. Append the `DriverInfoOptions` from the selected test case to the `MongoClient` metadata.

2. Send a `ping` command to the server and verify:

- The command succeeds.

- The framework metadata is appended to the existing `DriverInfoOptions` in the `client.driver` fields of the `hello`
command, with values separated by a pipe `|`.

- `client.driver.name`:
- If test case's name is non-null: `library|<name>`
- Otherwise, the field remains unchanged: `library`
- `client.driver.version`:
- If test case's version is non-null: `1.2|<version>`
- Otherwise, the field remains unchanged: `1.2`
- `client.driver.platform`:
- If test case's platform is non-null: `Library Platform|<platform>`
- Otherwise, the field remains unchanged: `Library Platform`

- All other subfields in the `client` document remain unchanged from `initialClientMetadata`.

### Test 2: Test that metadata is not updated on established connections

Drivers should verify that appending metadata after `MongoClient` initialization does **not** close existing
connections, and that no new `hello` command is sent.

1. Create a `MongoClient` instance with wrapping library metadata:

| Field | Value |
| -------- | ---------------- |
| name | library |
| version | 1.2 |
| platform | Library Platform |

2. Send a `ping` command to the server and verify:

- The command succeeds.
- The wrapping library metadata is appended to the respective `client.driver` fields of the `hello` command.

3. Append the following `DriverInfoOptions` to the `MongoClient` metadata:

| Field | Value |
| -------- | ------------------ |
| name | framework |
| version | 2.0 |
| platform | Framework Platform |

4. Send a `ping` command to the server and verify:

- The command succeeds.
- No `hello` command is sent.
- No `ConnectionClosedEvent` is emitted.
Loading