Skip to content

Commit 7f455fc

Browse files
authored
RUST-2046 Fix flaky afterClusterTime test (#1209)
1 parent b54837f commit 7f455fc

File tree

4 files changed

+270
-286
lines changed

4 files changed

+270
-286
lines changed

src/operation.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ mod insert;
1818
pub(crate) mod list_collections;
1919
pub(crate) mod list_databases;
2020
mod list_indexes;
21+
#[cfg(feature = "in-use-encryption")]
2122
mod raw_output;
2223
pub(crate) mod run_command;
2324
pub(crate) mod run_cursor_command;

src/test/spec/json/sessions/README.md

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
# Driver Session Tests
2+
3+
______________________________________________________________________
4+
5+
## Introduction
6+
7+
The YAML and JSON files in this directory are platform-independent tests meant to exercise a driver's implementation of
8+
sessions. These tests utilize the [Unified Test Format](../../unified-test-format/unified-test-format.md).
9+
10+
### Snapshot session tests
11+
12+
The default snapshot history window on the server is 5 minutes. Running the test in debug mode, or in any other slow
13+
configuration may lead to `SnapshotTooOld` errors. Drivers can work around this issue by increasing the server's
14+
`minSnapshotHistoryWindowInSeconds` parameter, for example:
15+
16+
```python
17+
client.admin.command('setParameter', 1, minSnapshotHistoryWindowInSeconds=600)
18+
```
19+
20+
### Testing against servers that do not support sessions
21+
22+
Since all regular 3.6+ servers support sessions, the prose tests which test for session non-support SHOULD use a
23+
mongocryptd server as the test server (available with server versions 4.2+); however, if future versions of mongocryptd
24+
support sessions or if mongocryptd is not a viable option for the driver implementing these tests, another server MAY be
25+
substituted as long as it does not return a non-null value for `logicalSessionTimeoutMinutes`; in the event that no such
26+
server is readily available, a mock server may be used as a last resort.
27+
28+
As part of the test setup for these cases, create a `MongoClient` pointed at the test server with the options specified
29+
in the test case and verify that the test server does NOT define a value for `logicalSessionTimeoutMinutes` by sending a
30+
hello command and checking the response.
31+
32+
## Prose tests
33+
34+
### 1. Setting both `snapshot` and `causalConsistency` to true is not allowed
35+
36+
Snapshot sessions tests require server of version 5.0 or higher and replica set or a sharded cluster deployment.
37+
38+
- `client.startSession(snapshot = true, causalConsistency = true)`
39+
- Assert that an error was raised by driver
40+
41+
### 2. Pool is LIFO
42+
43+
This test applies to drivers with session pools.
44+
45+
- Call `MongoClient.startSession` twice to create two sessions, let us call them `A` and `B`.
46+
- Call `A.endSession`, then `B.endSession`.
47+
- Call `MongoClient.startSession`: the resulting session must have the same session ID as `B`.
48+
- Call `MongoClient.startSession` again: the resulting session must have the same session ID as `A`.
49+
50+
### 3. `$clusterTime` in commands
51+
52+
- Turn `heartbeatFrequencyMS` up to a very large number.
53+
- Register a command-started and a command-succeeded APM listener. If the driver has no APM support, inspect
54+
commands/replies in another idiomatic way, such as monkey-patching or a mock server.
55+
- Send a `ping` command to the server with the generic `runCommand` method.
56+
- Assert that the command passed to the command-started listener includes `$clusterTime` if and only if `maxWireVersion`
57+
> = 6.
58+
- Record the `$clusterTime`, if any, in the reply passed to the command-succeeded APM listener.
59+
- Send another `ping` command.
60+
- Assert that `$clusterTime` in the command passed to the command-started listener, if any, equals the `$clusterTime` in
61+
the previous server reply. (Turning `heartbeatFrequencyMS` up prevents an intervening heartbeat from advancing the
62+
`$clusterTime` between these final two steps.)
63+
64+
Repeat the above for:
65+
66+
- An aggregate command from the `aggregate` helper method
67+
- A find command from the `find` helper method
68+
- An insert command from the `insert_one` helper method
69+
70+
### 4. Explicit and implicit session arguments
71+
72+
- Register a command-started APM listener. If the driver has no APM support, inspect commands in another idiomatic way,
73+
such as monkey-patching or a mock server.
74+
- Create `client1`
75+
- Get `database` from `client1`
76+
- Get `collection` from `database`
77+
- Start `session` from `client1`
78+
- Call `collection.insertOne(session,...)`
79+
- Assert that the command passed to the command-started listener contained the session `lsid` from `session`.
80+
- Call `collection.insertOne(,...)` (*without* a session argument)
81+
- Assert that the command passed to the command-started listener contained a session `lsid`.
82+
83+
Repeat the above for all methods that take a session parameter.
84+
85+
### 5. Session argument is for the right client
86+
87+
- Create `client1` and `client2`
88+
- Get `database` from `client1`
89+
- Get `collection` from `database`
90+
- Start `session` from `client2`
91+
- Call `collection.insertOne(session,...)`
92+
- Assert that an error was reported because `session` was not started from `client1`
93+
94+
Repeat the above for all methods that take a session parameter.
95+
96+
### 6. No further operations can be performed using a session after `endSession` has been called
97+
98+
- Start a `session`
99+
- End the `session`
100+
- Call `collection.InsertOne(session, ...)`
101+
- Assert that the proper error was reported
102+
103+
Repeat the above for all methods that take a session parameter.
104+
105+
If your driver implements a platform dependent idiomatic disposal pattern, test that also (if the idiomatic disposal
106+
pattern calls `endSession` it would be sufficient to only test the disposal pattern since that ends up calling
107+
`endSession`).
108+
109+
### 7. Authenticating as multiple users suppresses implicit sessions
110+
111+
Skip this test if your driver does not allow simultaneous authentication with multiple users.
112+
113+
- Authenticate as two users
114+
- Call `findOne` with no explicit session
115+
- Capture the command sent to the server
116+
- Assert that the command sent to the server does not have an `lsid` field
117+
118+
### 8. Client-side cursor that exhausts the results on the initial query immediately returns the implicit session to the pool
119+
120+
- Insert two documents into a collection
121+
- Execute a find operation on the collection and iterate past the first document
122+
- Assert that the implicit session is returned to the pool. This can be done in several ways:
123+
- Track in-use count in the server session pool and assert that the count has dropped to zero
124+
- Track the lsid used for the find operation (e.g. with APM) and then do another operation and assert that the same
125+
lsid is used as for the find operation.
126+
127+
### 9. Client-side cursor that exhausts the results after a `getMore` immediately returns the implicit session to the pool
128+
129+
- Insert five documents into a collection
130+
- Execute a find operation on the collection with batch size of 3
131+
- Iterate past the first four documents, forcing the final `getMore` operation
132+
- Assert that the implicit session is returned to the pool prior to iterating past the last document
133+
134+
### 10. No remaining sessions are checked out after each functional test
135+
136+
At the end of every individual functional test of the driver, there SHOULD be an assertion that there are no remaining
137+
sessions checked out from the pool. This may require changes to existing tests to ensure that they close any explicit
138+
client sessions and any unexhausted cursors.
139+
140+
### 11. For every combination of topology and readPreference, ensure that `find` and `getMore` both send the same session id
141+
142+
- Insert three documents into a collection
143+
- Execute a `find` operation on the collection with a batch size of 2
144+
- Assert that the server receives a non-zero lsid
145+
- Iterate through enough documents (3) to force a `getMore`
146+
- Assert that the server receives a non-zero lsid equal to the lsid that `find` sent.
147+
148+
### 12. Session pool can be cleared after forking without calling `endSession`
149+
150+
Skip this test if your driver does not allow forking.
151+
152+
- Create ClientSession
153+
- Record its lsid
154+
- Delete it (so the lsid is pushed into the pool)
155+
- Fork
156+
- In the parent, create a ClientSession and assert its lsid is the same.
157+
- In the child, create a ClientSession and assert its lsid is different.
158+
159+
### 13. Existing sessions are not checked into a cleared pool after forking
160+
161+
Skip this test if your driver does not allow forking.
162+
163+
- Create ClientSession
164+
- Record its lsid
165+
- Fork
166+
- In the parent, return the ClientSession to the pool, create a new ClientSession, and assert its lsid is the same.
167+
- In the child, return the ClientSession to the pool, create a new ClientSession, and assert its lsid is different.
168+
169+
### 14. Implicit sessions only allocate their server session after a successful connection checkout
170+
171+
- Create a MongoClient with the following options: `maxPoolSize=1` and `retryWrites=true`. If testing against a sharded
172+
deployment, the test runner MUST ensure that the MongoClient connects to only a single mongos host.
173+
- Attach a command started listener that collects each command's lsid
174+
- Initiate the following concurrent operations
175+
- `insertOne({ }),`
176+
- `deleteOne({ }),`
177+
- `updateOne({ }, { $set: { a: 1 } }),`
178+
- `bulkWrite([{ updateOne: { filter: { }, update: { $set: { a: 1 } } } }]),`
179+
- `findOneAndDelete({ }),`
180+
- `findOneAndUpdate({ }, { $set: { a: 1 } }),`
181+
- `findOneAndReplace({ }, { a: 1 }),`
182+
- `find().toArray()`
183+
- Wait for all operations to complete successfully
184+
- Assert the following across at least 5 retries of the above test:
185+
- Drivers MUST assert that exactly one session is used for all operations at least once across the retries of this
186+
test.
187+
- Note that it's possible, although rare, for >1 server session to be used because the session is not released until
188+
after the connection is checked in.
189+
- Drivers MUST assert that the number of allocated sessions is strictly less than the number of concurrent operations
190+
in every retry of this test. In this instance it would be less than (but NOT equal to) 8.
191+
192+
### 15. `lsid` is added inside `$query` when using OP_QUERY
193+
194+
This test only applies to drivers that have not implemented OP_MSG and still use OP_QUERY.
195+
196+
- For a command to a mongos that includes a readPreference, verify that the `lsid` on query commands is added inside the
197+
`$query` field, and NOT as a top-level field.
198+
199+
### 16. Authenticating as a second user after starting a session results in a server error
200+
201+
This test only applies to drivers that allow authentication to be changed on the fly.
202+
203+
- Authenticate as the first user
204+
- Start a session by calling `startSession`
205+
- Authenticate as a second user
206+
- Call `findOne` using the session as an explicit session
207+
- Assert that the driver returned an error because multiple users are authenticated
208+
209+
### 17. Driver verifies that the session is owned by the current user
210+
211+
This test only applies to drivers that allow authentication to be changed on the fly.
212+
213+
- Authenticate as user A
214+
- Start a session by calling `startSession`
215+
- Logout user A
216+
- Authenticate as user B
217+
- Call `findOne` using the session as an explicit session
218+
- Assert that the driver returned an error because the session is owned by a different user
219+
220+
### 18. Implicit session is ignored if connection does not support sessions
221+
222+
Refer to [Testing against servers that do not support sessions](#testing-against-servers-that-do-not-support-sessions)
223+
and configure a `MongoClient` with command monitoring enabled.
224+
225+
- Send a read command to the server (e.g., `findOne`), ignoring any errors from the server response
226+
- Check the corresponding `commandStarted` event: verify that `lsid` is not set
227+
- Send a write command to the server (e.g., `insertOne`), ignoring any errors from the server response
228+
- Check the corresponding `commandStarted` event: verify that lsid is not set
229+
230+
### 19. Explicit session raises an error if connection does not support sessions
231+
232+
Refer to [Testing against servers that do not support sessions](#testing-against-servers-that-do-not-support-sessions)
233+
and configure a `MongoClient` with default options.
234+
235+
- Create a new explicit session by calling `startSession` (this MUST NOT error)
236+
- Attempt to send a read command to the server (e.g., `findOne`) with the explicit session passed in
237+
- Assert that a client-side error is generated indicating that sessions are not supported
238+
- Attempt to send a write command to the server (e.g., `insertOne`) with the explicit session passed in
239+
- Assert that a client-side error is generated indicating that sessions are not supported
240+
241+
## Changelog
242+
243+
- 2024-05-08: Migrated from reStructuredText to Markdown.
244+
- 2019-05-15: Initial version.
245+
- 2021-06-15: Added snapshot-session tests. Introduced legacy and unified folders.
246+
- 2021-07-30: Use numbering for prose test
247+
- 2022-02-11: Convert legacy tests to unified format
248+
- 2022-06-13: Relocate prose test from spec document and apply new ordering
249+
- 2023-02-24: Fix formatting and add new prose tests 18 and 19

0 commit comments

Comments
 (0)