diff --git a/source/mongodb-handshake/handshake.md b/source/mongodb-handshake/handshake.md index aa5574718e..24c6eea50d 100644 --- a/source/mongodb-handshake/handshake.md +++ b/source/mongodb-handshake/handshake.md @@ -185,8 +185,8 @@ Drivers MUST NOT provide a default value for this key. This value is required and is not application configurable. -The internal driver name. For drivers written on-top of other core drivers, the underlying driver will typically expose -a function to append additional name to this field. +The internal driver name. For drivers written on-top of other core drivers, the `appendMetadata()` method can be used to +add package information to an existing MongoClient. Example: @@ -200,7 +200,7 @@ Example: This value is required and is not application configurable. The internal driver version. The version formatting is not defined. For drivers written on-top of other core drivers, -the underlying driver will typically expose a function to append additional name to this field. +the `appendMetadata()` method can be used to add package information to an existing MongoClient. Example: @@ -405,6 +405,10 @@ class DriverInfoOptions { } ``` +Two `DriverInfoOptions` objects are considered equal if they would result in the same metadata in the client handshake. +In practice, this means if a field is the empty string (`""`), treat it as unset. Assert that each field is strictly +equal with case sensitive string comparison. + Note that how these options are provided to a driver during `MongoClient` initialization is left up to the implementer. ### Metadata updates after MongoClient initialization @@ -442,6 +446,12 @@ be appended to their respective fields, and be delimited by a `|` character. For } ``` +Some client libraries provide APIs that accept a pre-initialized MongoClient as an argument. In these circumstances, it +is possible for multiple library objects to be associated with the same MongoClient, which could result in the same +metadata being appended multiple times. Drivers MUST ensure that any duplicate `DriverInfoOptions` objects provided to a +MongoClient or appended to a MongoClient do not result in additional metadata being appended. See +[Supporting Wrapping Libraries](#supporting-wrapping-libraries). + **NOTE:** All strings provided as part of the driver info MUST NOT contain the delimiter used for metadata concatention. Drivers MUST throw an error if any of these strings contains that character. @@ -553,6 +563,7 @@ support the `hello` command, the `helloOk: true` argument is ignored and the leg ## Changelog +- 2025-09-04: Clarify that drivers do not append the same metadata multiple times. - 2025-06-09: 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. diff --git a/source/mongodb-handshake/tests/README.md b/source/mongodb-handshake/tests/README.md index 848c6351fd..d88a49fa92 100644 --- a/source/mongodb-handshake/tests/README.md +++ b/source/mongodb-handshake/tests/README.md @@ -142,13 +142,13 @@ Before each test case, perform the setup. - `client.driver.version`: - If test case's version is non-null: `1.2|` - Otherwise, the field remains unchanged: `1.2` - - `client.driver.platform`: + - `client.platform`: - If test case's platform is non-null: `Library Platform|` - Otherwise, the field remains unchanged: `Library Platform` - All other subfields in the `client` document remain unchanged from `initialClientMetadata`. -## Test 2: Multiple Successive Metadata Updates +### Test 2: Multiple Successive Metadata Updates Drivers should verify that after `MongoClient` initialization, metadata can be updated multiple times, not replaced, and is visible in the `hello` command of new connections. @@ -156,7 +156,7 @@ is visible in the `hello` command of new connections. There are multiple test cases parameterized with `DriverInfoOptions` to be appended after a previous metadata update. Before each test case, perform the setup. -### Setup +#### Setup 1. Create a `MongoClient` instance with: @@ -176,7 +176,7 @@ Before each test case, perform the setup. 5. Wait 5ms for the connection to become idle. -#### Parameterized test cases +##### Parameterized test cases | Case | Name | Version | Platform | | ---- | --------- | ------- | ------------------ | @@ -185,7 +185,7 @@ Before each test case, perform the setup. | 3 | framework | null | Framework Platform | | 4 | framework | null | null | -#### Running a test case +##### Running a test case 1. Append the `DriverInfoOptions` from the selected test case to the `MongoClient` metadata. @@ -202,8 +202,287 @@ Before each test case, perform the setup. - `client.driver.version`: - If test case's version is non-null: `1.2|` - Otherwise, the field remains unchanged: `1.2` - - `client.driver.platform`: + - `client.platform`: - If test case's platform is non-null: `Library Platform|` - Otherwise, the field remains unchanged: `Library Platform` - All other subfields in the `client` document remain unchanged from `updatedClientMetadata`. + +### Test 3: Multiple Successive Metadata Updates with Duplicate Data + +There are multiple test cases parameterized with `DriverInfoOptions` to be appended after a previous metadata update. +Before each test case, perform the setup. + +#### Setup + +1. Create a `MongoClient` instance with: + + - `maxIdleTimeMS` set to `1ms` + +2. Append the following `DriverInfoOptions` to the `MongoClient` metadata: + + | Field | Value | + | -------- | ---------------- | + | name | library | + | version | 1.2 | + | platform | Library Platform | + +3. Send a `ping` command to the server and verify that the command succeeds. + +4. Save intercepted `client` document as `updatedClientMetadata`. + +5. Wait 5ms for the connection to become idle. + +##### Parameterized test cases + +| Case | Name | Version | Platform | +| ---- | --------- | ------- | ------------------ | +| 1 | library | 1.2 | Library Platform | +| 2 | framework | 1.2 | Library Platform | +| 3 | library | 2.0 | Library Platform | +| 4 | library | 1.2 | Framework Platform | +| 5 | framework | 2.0 | Library Platform | +| 6 | framework | 1.2 | Framework Platform | +| 7 | library | 2.0 | Framework Platform | + +##### 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 `|`. To simplify assertions in these tests, strip out the default driver + info that is automatically added by the driver (ex: `metadata.name.split('|').slice(1).join('|')`). + + - If the test case's DriverInfo is identical to the driver info from setup step 2 (test case 1): + - Assert `metadata.driver.name` is equal to `library` + - Assert `metadata.driver.version` is equal to `1.2` + - Assert `metadata.platform` is equal to `LibraryPlatform` + - Otherwise: + - Assert `metadata.driver.name` is equal to `library|` + - Assert `metadata.driver.version` is equal to `1.2|` + - Assert `metadata.platform` is equal to `LibraryPlatform|` + + - All other subfields in the `client` document remain unchanged from `updatedClientMetadata`. + +### Test 4: Multiple Metadata Updates with Duplicate Data + +1. Create a `MongoClient` instance with: + + - `maxIdleTimeMS` set to `1ms` + +2. Append the following `DriverInfoOptions` to the `MongoClient` metadata: + + | Field | Value | + | -------- | ---------------- | + | name | library | + | version | 1.2 | + | platform | Library Platform | + +3. Send a `ping` command to the server and verify that the command succeeds. + +4. Wait 5ms for the connection to become idle. + +5. Append the following `DriverInfoOptions` to the `MongoClient` metadata: + + | Field | Value | + | -------- | ------------------ | + | name | framework | + | version | 2.0 | + | platform | Framework Platform | + +6. Send a `ping` command to the server and verify that the command succeeds. + +7. Save intercepted `client` document as `clientMetadata`. + +8. Wait 5ms for the connection to become idle. + +9. Append the following `DriverInfoOptions` to the `MongoClient` metadata: + + | Field | Value | + | -------- | ---------------- | + | name | library | + | version | 1.2 | + | platform | Library Platform | + +10. Send a `ping` command to the server and verify that the command succeeds. + +11. Save intercepted `client` document as `updatedClientMetadata`. + +12. Assert that `clientMetadata` is identical to `updatedClientMetadata`. + +### Test 5: Metadata is not appended if identical to initial metadata + +1. Create a `MongoClient` instance with: + + - `maxIdleTimeMS` set to `1ms` + - `driverInfo` set to the following: + + | Field | Value | + | -------- | ---------------- | + | name | library | + | version | 1.2 | + | platform | Library Platform | + +2. Send a `ping` command to the server and verify that the command succeeds. + +3. Save intercepted `client` document as `clientMetadata`. + +4. Wait 5ms for the connection to become idle. + +5. Append the following `DriverInfoOptions` to the `MongoClient` metadata: + + | Field | Value | + | -------- | ---------------- | + | name | library | + | version | 1.2 | + | platform | Library Platform | + +6. Send a `ping` command to the server and verify that the command succeeds. + +7. Save intercepted `client` document as `updatedClientMetadata`. + +8. Assert that `clientMetadata` is identical to `updatedClientMetadata`. + +### Test 6: Metadata is not appended if identical to initial metadata (separated by non-identical metadata) + +1. Create a `MongoClient` instance with: + + - `maxIdleTimeMS` set to `1ms` + - `driverInfo` set to the following: + + | Field | Value | + | -------- | ---------------- | + | name | library | + | version | 1.2 | + | platform | Library Platform | + +2. Send a `ping` command to the server and verify that the command succeeds. + +3. Wait 5ms for the connection to become idle. + +4. Append the following `DriverInfoOptions` to the `MongoClient` metadata: + + | Field | Value | + | -------- | ---------------- | + | name | framework | + | version | 1.2 | + | platform | Library Platform | + +5. Send a `ping` command to the server and verify that the command succeeds. + +6. Save intercepted `client` document as `clientMetadata`. + +7. Wait 5ms for the connection to become idle. + +8. Append the following `DriverInfoOptions` to the `MongoClient` metadata: + + | Field | Value | + | -------- | ---------------- | + | name | library | + | version | 1.2 | + | platform | Library Platform | + +9. Send a `ping` command to the server and verify that the command succeeds. + +10. Save intercepted `client` document as `updatedClientMetadata`. + +11. Assert that `clientMetadata` is identical to `updatedClientMetadata`. + +### Test 7: Empty strings are considered unset when appending duplicate metadata + +Drivers should verify that after `MongoClient` initialization, metadata can be updated multiple times, not replaced, and +is visible in the `hello` command of new connections. + +There are multiple test cases parameterized with `DriverInfoOptions` to be appended after a previous metadata update. +Before each test case, perform the setup. + +##### Parameterized test cases + +###### Initial metadata + +| Case | Name | Version | Platform | +| ---- | ------- | ------- | ---------------- | +| 1 | null | 1.2 | Library Platform | +| 2 | library | null | Library Platform | +| 3 | library | 1.2 | null | + +###### Appended Metadata + +| Case | Name | Version | Platform | +| ---- | ------- | ------- | ---------------- | +| 1 | "" | 1.2 | Library Platform | +| 2 | library | "" | Library Platform | +| 3 | library | 1.2 | "" | + +##### Running a test case + +1. Create a `MongoClient` instance with: + + - `maxIdleTimeMS` set to `1ms` + +2. Append the `DriverInfoOptions` from the selected test case from the initial metadata section. + +3. Send a `ping` command to the server and verify that the command succeeds. + +4. Save intercepted `client` document as `initialClientMetadata`. + +5. Wait 5ms for the connection to become idle. + +6. Append the `DriverInfoOptions` from the selected test case from the appended metadata section. + +7. Send a `ping` command to the server and verify the command succeeds. + +8. Store the response as `updatedClientMetadata`. + +9. Assert that `initialClientMetadata` is identical to `updatedClientMetadata`. + +### Test 8: Empty strings are considered unset when appending metadata identical to initial metadata + +Drivers should verify that after `MongoClient` initialization, metadata can be updated multiple times, not replaced, and +is visible in the `hello` command of new connections. + +There are multiple test cases parameterized with `DriverInfoOptions` to be appended after a previous metadata update. +Before each test case, perform the setup. + +##### Parameterized test cases + +###### Initial metadata + +| Case | Name | Version | Platform | +| ---- | ------- | ------- | ---------------- | +| 1 | null | 1.2 | Library Platform | +| 2 | library | null | Library Platform | +| 3 | library | 1.2 | null | + +###### Appended Metadata + +| Case | Name | Version | Platform | +| ---- | ------- | ------- | ---------------- | +| 1 | "" | 1.2 | Library Platform | +| 2 | library | "" | Library Platform | +| 3 | library | 1.2 | "" | + +##### Running a test case + +1. Create a `MongoClient` instance with: + + - `maxIdleTimeMS` set to `1ms` + - `driverInfo` set to the `DriverInfoOptions` from the selected test case from the initial metadata section. + +2. Send a `ping` command to the server and verify that the command succeeds. + +3. Save intercepted `client` document as `initialClientMetadata`. + +4. Wait 5ms for the connection to become idle. + +5. Append the `DriverInfoOptions` from the selected test case from the appended metadata section. + +6. Send a `ping` command to the server and verify the command succeeds. + +7. Store the response as `updatedClientMetadata`. + +8. Assert that `initialClientMetadata` is identical to `updatedClientMetadata`.