Skip to content

Commit

Permalink
RUST-2069 Convert retryable writes construction tests to spec tests (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
isabelatkinson authored Nov 15, 2024
1 parent bf724a4 commit b821bb8
Show file tree
Hide file tree
Showing 30 changed files with 1,105 additions and 266 deletions.
244 changes: 103 additions & 141 deletions src/test/spec/json/retryable-writes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,18 @@ cluster because the fail point is not supported by mongos.
The tests exercise the following scenarios:

- Single-statement write operations
- Each test expecting a write result will encounter at-most one network error for the write command. Retry attempts
should return without error and allow operation to succeed. Observation of the collection state will assert that the
write occurred at-most once.
- Each test expecting an error will encounter successive network errors for the write command. Observation of the
collection state will assert that the write was never committed on the server.
- Each test expecting a write result will encounter at-most one network error for the write command. Retry attempts
should return without error and allow operation to succeed. Observation of the collection state will assert that
the write occurred at-most once.
- Each test expecting an error will encounter successive network errors for the write command. Observation of the
collection state will assert that the write was never committed on the server.
- Multi-statement write operations
- Each test expecting a write result will encounter at-most one network error for some write command(s) in the batch.
Retry attempts should return without error and allow the batch to ultimately succeed. Observation of the collection
state will assert that each write occurred at-most once.
- Each test expecting an error will encounter successive network errors for some write command in the batch. The batch
will ultimately fail with an error, but observation of the collection state will assert that the failing write was
never committed on the server. We may observe that earlier writes in the batch occurred at-most once.
- Each test expecting a write result will encounter at-most one network error for some write command(s) in the batch.
Retry attempts should return without error and allow the batch to ultimately succeed. Observation of the
collection state will assert that each write occurred at-most once.
- Each test expecting an error will encounter successive network errors for some write command in the batch. The batch
will ultimately fail with an error, but observation of the collection state will assert that the failing write was
never committed on the server. We may observe that earlier writes in the batch occurred at-most once.

We cannot test a scenario where the first and second attempts both encounter network errors but the write does actually
commit during one of those attempts. This is because (1) the fail point only triggers when a write would be committed
Expand Down Expand Up @@ -63,42 +63,9 @@ insert command (because all documents in the first command will be processed in
or delete that is split into two commands, the `skip` should be set to the number of statements in the first command to
allow the fail point to trigger on the second command.

## Command Construction Tests

Drivers should also assert that command documents are properly constructed with or without a transaction ID, depending
on whether the write operation is supported.
[Command Logging and Monitoring](../../command-logging-and-monitoring/command-logging-and-monitoring.rst) may be used to
check for the presence of a `txnNumber` field in the command document. Note that command documents may always include an
`lsid` field per the [Driver Session](../../sessions/driver-sessions.md) specification.

These tests may be run against both a replica set and shard cluster.

Drivers should test that transaction IDs are never included in commands for unsupported write operations:

- Write commands with unacknowledged write concerns (e.g. `{w: 0}`)
- Unsupported single-statement write operations
- `updateMany()`
- `deleteMany()`
- Unsupported multi-statement write operations
- `bulkWrite()` that includes `UpdateMany` or `DeleteMany`
- Unsupported write commands
- `aggregate` with write stage (e.g. `$out`, `$merge`)

Drivers should test that transactions IDs are always included in commands for supported write operations:

- Supported single-statement write operations
- `insertOne()`
- `updateOne()`
- `replaceOne()`
- `deleteOne()`
- `findOneAndDelete()`
- `findOneAndReplace()`
- `findOneAndUpdate()`
- Supported multi-statement write operations
- `insertMany()` with `ordered=true`
- `insertMany()` with `ordered=false`
- `bulkWrite()` with `ordered=true` (no `UpdateMany` or `DeleteMany`)
- `bulkWrite()` with `ordered=false` (no `UpdateMany` or `DeleteMany`)
## ~~Command Construction Tests~~

The command construction prose tests have been removed in favor of command event assertions in the unified format tests.

## Prose Tests

Expand All @@ -109,7 +76,7 @@ The following tests ensure that retryable writes work properly with replica sets
For this test, execute a write operation, such as `insertOne`, which should generate an exception. Assert that the error
message is the replacement error message:

```
```text
This MongoDB deployment does not support retryable writes. Please add
retryWrites=false to your connection string.
```
Expand All @@ -127,23 +94,23 @@ This test MUST be implemented by any driver that implements the CMAP specificati
This test requires MongoDB 4.3.4+ for both the `errorLabels` and `blockConnection` fail point options.

1. Create a client with maxPoolSize=1 and retryWrites=true. If testing against a sharded deployment, be sure to connect
to only a single mongos.
to only a single mongos.

2. Enable the following failpoint:

```javascript
{
configureFailPoint: "failCommand",
mode: { times: 1 },
data: {
failCommands: ["insert"],
errorCode: 91,
blockConnection: true,
blockTimeMS: 1000,
errorLabels: ["RetryableWriteError"]
}
}
```
```javascript
{
configureFailPoint: "failCommand",
mode: { times: 1 },
data: {
failCommands: ["insert"],
errorCode: 91,
blockConnection: true,
blockTimeMS: 1000,
errorLabels: ["RetryableWriteError"]
}
}
```

3. Start two threads and attempt to perform an `insertOne` simultaneously on both.

Expand Down Expand Up @@ -175,47 +142,47 @@ test to cover the same sequence of events.

2. Configure a fail point with error code `91` (ShutdownInProgress):

```javascript
{
configureFailPoint: "failCommand",
mode: {times: 1},
data: {
failCommands: ["insert"],
errorLabels: ["RetryableWriteError"],
writeConcernError: { code: 91 }
}
}
```
```javascript
{
configureFailPoint: "failCommand",
mode: {times: 1},
data: {
failCommands: ["insert"],
errorLabels: ["RetryableWriteError"],
writeConcernError: { code: 91 }
}
}
```

3. Via the command monitoring CommandSucceededEvent, configure a fail point with error code `10107` (NotWritablePrimary)
and a NoWritesPerformed label:

```javascript
{
configureFailPoint: "failCommand",
mode: {times: 1},
data: {
failCommands: ["insert"],
errorCode: 10107,
errorLabels: ["RetryableWriteError", "NoWritesPerformed"]
}
}
```

Drivers SHOULD only configure the `10107` fail point command if the the succeeded event is for the `91` error
configured in step 2.
and a NoWritesPerformed label:

```javascript
{
configureFailPoint: "failCommand",
mode: {times: 1},
data: {
failCommands: ["insert"],
errorCode: 10107,
errorLabels: ["RetryableWriteError", "NoWritesPerformed"]
}
}
```

Drivers SHOULD only configure the `10107` fail point command if the the succeeded event is for the `91` error
configured in step 2.

4. Attempt an `insertOne` operation on any record for any database and collection. For the resulting error, assert that
the associated error code is `91`.
the associated error code is `91`.

5. Disable the fail point:

```javascript
{
configureFailPoint: "failCommand",
mode: "off"
}
```
```javascript
{
configureFailPoint: "failCommand",
mode: "off"
}
```

### 4. Test that in a sharded cluster writes are retried on a different mongos when one is available.

Expand All @@ -229,24 +196,24 @@ This test MUST be executed against a sharded cluster that has at least two mongo
> coverage tool, etc.

1. Create two clients `s0` and `s1` that each connect to a single mongos from the sharded cluster. They must not connect
to the same mongos.
to the same mongos.

2. Configure the following fail point for both `s0` and `s1`:

```javascript
{
configureFailPoint: "failCommand",
mode: { times: 1 },
data: {
failCommands: ["insert"],
errorCode: 6,
errorLabels: ["RetryableWriteError"]
}
}
```
```javascript
{
configureFailPoint: "failCommand",
mode: { times: 1 },
data: {
failCommands: ["insert"],
errorCode: 6,
errorLabels: ["RetryableWriteError"]
}
}
```

3. Create a client `client` with `retryWrites=true` that connects to the cluster using the same two mongoses as `s0` and
`s1`.
`s1`.

4. Enable failed command event monitoring for `client`.

Expand All @@ -270,72 +237,67 @@ debugger, code coverage tool, etc.

2. Configure the following fail point for `s0`:

```javascript
{
configureFailPoint: "failCommand",
mode: { times: 1 },
data: {
failCommands: ["insert"],
errorCode: 6,
errorLabels: ["RetryableWriteError"],
closeConnection: true
}
}
```
```javascript
{
configureFailPoint: "failCommand",
mode: { times: 1 },
data: {
failCommands: ["insert"],
errorCode: 6,
errorLabels: ["RetryableWriteError"],
closeConnection: true
}
}
```

3. Create a client `client` with `directConnection=false` (when not set by default) and `retryWrites=true` that connects
to the cluster using the same single mongos as `s0`.
to the cluster using the same single mongos as `s0`.

4. Enable succeeded and failed command event monitoring for `client`.

5. Execute an `insert` command with `client`. Assert that the command succeeded.

6. Assert that exactly one failed command event and one succeeded command event occurred. Assert that both events
occurred on the same mongos.
occurred on the same mongos.

7. Disable the fail point on `s0`.

## Changelog

- 2024-10-29: Convert command construction tests to unified format.

- 2024-05-30: Migrated from reStructuredText to Markdown.

- 2024-02-27: Convert legacy retryable writes tests to unified format.

- 2024-02-21: Update prose test 4 and 5 to workaround SDAM behavior preventing\
execution of deprioritization code
paths.
- 2024-02-21: Update prose test 4 and 5 to workaround SDAM behavior preventing execution of deprioritization code paths.

- 2024-01-05: Fix typo in prose test title.

- 2024-01-03: Note server version requirements for fail point options and revise\
tests to specify the `errorLabels`
option at the top-level instead of within `writeConcernError`.
- 2024-01-03: Note server version requirements for fail point options and revise tests to specify the `errorLabels`
option at the top-level instead of within `writeConcernError`.

- 2023-08-26: Add prose tests for retrying in a sharded cluster.

- 2022-08-30: Add prose test verifying correct error handling for errors with\
the NoWritesPerformed label, which is to
return the original error.
- 2022-08-30: Add prose test verifying correct error handling for errors with the NoWritesPerformed label, which is to
return the original error.

- 2022-04-22: Clarifications to `serverless` and `useMultipleMongoses`.

- 2021-08-27: Add `serverless` to `runOn`. Clarify behavior of\
`useMultipleMongoses` for `LoadBalanced` topologies.
- 2021-08-27: Add `serverless` to `runOn`. Clarify behavior of `useMultipleMongoses` for `LoadBalanced` topologies.

- 2021-04-23: Add `load-balanced` to test topology requirements.

- 2021-03-24: Add prose test verifying `PoolClearedErrors` are retried.

- 2019-10-21: Add `errorLabelsContain` and `errorLabelsContain` fields to\
`result`
- 2019-10-21: Add `errorLabelsContain` and `errorLabelsContain` fields to `result`

- 2019-08-07: Add Prose Tests section

- 2019-06-07: Mention $merge stage for aggregate alongside $out

- 2019-03-01: Add top-level `runOn` field to denote server version and/or\
topology requirements requirements for the
test file. Removes the `minServerVersion` and `maxServerVersion` top-level fields, which are now expressed within
`runOn` elements.
- 2019-03-01: Add top-level `runOn` field to denote server version and/or topology requirements requirements for the
test file. Removes the `minServerVersion` and `maxServerVersion` top-level fields, which are now expressed within
`runOn` elements.

Add test-level `useMultipleMongoses` field.
Add test-level `useMultipleMongoses` field.
Loading

0 comments on commit b821bb8

Please sign in to comment.