Skip to content

Commit 3cb8cb9

Browse files
authored
CSHARP-4052: Convert sessions spec tests to unified test format (#1641)
1 parent 8414926 commit 3cb8cb9

23 files changed

+1973
-1678
lines changed
+262
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
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+
- Register a command-started and a command-succeeded APM listener. If the driver has no APM support, inspect
53+
commands/replies in another idiomatic way, such as monkey-patching or a mock server.
54+
- Send a `ping` command to the server with the generic `runCommand` method.
55+
- Assert that the command passed to the command-started listener includes `$clusterTime` if and only if `maxWireVersion`
56+
> = 6.
57+
- Record the `$clusterTime`, if any, in the reply passed to the command-succeeded APM listener.
58+
- Send another `ping` command.
59+
- Assert that `$clusterTime` in the command passed to the command-started listener, if any, equals the `$clusterTime` in
60+
the previous server reply.
61+
62+
Repeat the above for:
63+
64+
- An aggregate command from the `aggregate` helper method
65+
- A find command from the `find` helper method
66+
- An insert command from the `insert_one` helper method
67+
68+
### 4. Explicit and implicit session arguments
69+
70+
- Register a command-started APM listener. If the driver has no APM support, inspect commands in another idiomatic way,
71+
such as monkey-patching or a mock server.
72+
- Create `client1`
73+
- Get `database` from `client1`
74+
- Get `collection` from `database`
75+
- Start `session` from `client1`
76+
- Call `collection.insertOne(session,...)`
77+
- Assert that the command passed to the command-started listener contained the session `lsid` from `session`.
78+
- Call `collection.insertOne(,...)` (*without* a session argument)
79+
- Assert that the command passed to the command-started listener contained a session `lsid`.
80+
81+
Repeat the above for all methods that take a session parameter.
82+
83+
### 5. Session argument is for the right client
84+
85+
- Create `client1` and `client2`
86+
- Get `database` from `client1`
87+
- Get `collection` from `database`
88+
- Start `session` from `client2`
89+
- Call `collection.insertOne(session,...)`
90+
- Assert that an error was reported because `session` was not started from `client1`
91+
92+
Repeat the above for all methods that take a session parameter.
93+
94+
### 6. No further operations can be performed using a session after `endSession` has been called
95+
96+
- Start a `session`
97+
- End the `session`
98+
- Call `collection.InsertOne(session, ...)`
99+
- Assert that the proper error was reported
100+
101+
Repeat the above for all methods that take a session parameter.
102+
103+
If your driver implements a platform dependent idiomatic disposal pattern, test that also (if the idiomatic disposal
104+
pattern calls `endSession` it would be sufficient to only test the disposal pattern since that ends up calling
105+
`endSession`).
106+
107+
### 7. Authenticating as multiple users suppresses implicit sessions
108+
109+
Skip this test if your driver does not allow simultaneous authentication with multiple users.
110+
111+
- Authenticate as two users
112+
- Call `findOne` with no explicit session
113+
- Capture the command sent to the server
114+
- Assert that the command sent to the server does not have an `lsid` field
115+
116+
### 8. Client-side cursor that exhausts the results on the initial query immediately returns the implicit session to the pool
117+
118+
- Insert two documents into a collection
119+
- Execute a find operation on the collection and iterate past the first document
120+
- Assert that the implicit session is returned to the pool. This can be done in several ways:
121+
- Track in-use count in the server session pool and assert that the count has dropped to zero
122+
- Track the lsid used for the find operation (e.g. with APM) and then do another operation and assert that the same
123+
lsid is used as for the find operation.
124+
125+
### 9. Client-side cursor that exhausts the results after a `getMore` immediately returns the implicit session to the pool
126+
127+
- Insert five documents into a collection
128+
- Execute a find operation on the collection with batch size of 3
129+
- Iterate past the first four documents, forcing the final `getMore` operation
130+
- Assert that the implicit session is returned to the pool prior to iterating past the last document
131+
132+
### 10. No remaining sessions are checked out after each functional test
133+
134+
At the end of every individual functional test of the driver, there SHOULD be an assertion that there are no remaining
135+
sessions checked out from the pool. This may require changes to existing tests to ensure that they close any explicit
136+
client sessions and any unexhausted cursors.
137+
138+
### 11. For every combination of topology and readPreference, ensure that `find` and `getMore` both send the same session id
139+
140+
- Insert three documents into a collection
141+
- Execute a `find` operation on the collection with a batch size of 2
142+
- Assert that the server receives a non-zero lsid
143+
- Iterate through enough documents (3) to force a `getMore`
144+
- Assert that the server receives a non-zero lsid equal to the lsid that `find` sent.
145+
146+
### 12. Session pool can be cleared after forking without calling `endSession`
147+
148+
Skip this test if your driver does not allow forking.
149+
150+
- Create ClientSession
151+
- Record its lsid
152+
- Delete it (so the lsid is pushed into the pool)
153+
- Fork
154+
- In the parent, create a ClientSession and assert its lsid is the same.
155+
- In the child, create a ClientSession and assert its lsid is different.
156+
157+
### 13. Existing sessions are not checked into a cleared pool after forking
158+
159+
Skip this test if your driver does not allow forking.
160+
161+
- Create ClientSession
162+
- Record its lsid
163+
- Fork
164+
- In the parent, return the ClientSession to the pool, create a new ClientSession, and assert its lsid is the same.
165+
- In the child, return the ClientSession to the pool, create a new ClientSession, and assert its lsid is different.
166+
167+
### 14. Implicit sessions only allocate their server session after a successful connection checkout
168+
169+
- Create a MongoClient with the following options: `maxPoolSize=1` and `retryWrites=true`. If testing against a sharded
170+
deployment, the test runner MUST ensure that the MongoClient connects to only a single mongos host.
171+
- Attach a command started listener that collects each command's lsid
172+
- Initiate the following concurrent operations
173+
- `insertOne({ }),`
174+
- `deleteOne({ }),`
175+
- `updateOne({ }, { $set: { a: 1 } }),`
176+
- `bulkWrite([{ updateOne: { filter: { }, update: { $set: { a: 1 } } } }]),`
177+
- `findOneAndDelete({ }),`
178+
- `findOneAndUpdate({ }, { $set: { a: 1 } }),`
179+
- `findOneAndReplace({ }, { a: 1 }),`
180+
- `find().toArray()`
181+
- Wait for all operations to complete successfully
182+
- Assert the following across at least 5 retries of the above test:
183+
- Drivers MUST assert that exactly one session is used for all operations at least once across the retries of this
184+
test.
185+
- Note that it's possible, although rare, for >1 server session to be used because the session is not released until
186+
after the connection is checked in.
187+
- Drivers MUST assert that the number of allocated sessions is strictly less than the number of concurrent operations
188+
in every retry of this test. In this instance it would be less than (but NOT equal to) 8.
189+
190+
### 15. `lsid` is added inside `$query` when using OP_QUERY
191+
192+
This test only applies to drivers that have not implemented OP_MSG and still use OP_QUERY.
193+
194+
- For a command to a mongos that includes a readPreference, verify that the `lsid` on query commands is added inside the
195+
`$query` field, and NOT as a top-level field.
196+
197+
### 16. Authenticating as a second user after starting a session results in a server error
198+
199+
This test only applies to drivers that allow authentication to be changed on the fly.
200+
201+
- Authenticate as the first user
202+
- Start a session by calling `startSession`
203+
- Authenticate as a second user
204+
- Call `findOne` using the session as an explicit session
205+
- Assert that the driver returned an error because multiple users are authenticated
206+
207+
### 17. Driver verifies that the session is owned by the current user
208+
209+
This test only applies to drivers that allow authentication to be changed on the fly.
210+
211+
- Authenticate as user A
212+
- Start a session by calling `startSession`
213+
- Logout user A
214+
- Authenticate as user B
215+
- Call `findOne` using the session as an explicit session
216+
- Assert that the driver returned an error because the session is owned by a different user
217+
218+
### 18. Implicit session is ignored if connection does not support sessions
219+
220+
Refer to [Testing against servers that do not support sessions](#testing-against-servers-that-do-not-support-sessions)
221+
and configure a `MongoClient` with command monitoring enabled.
222+
223+
- Send a read command to the server (e.g., `findOne`), ignoring any errors from the server response
224+
- Check the corresponding `commandStarted` event: verify that `lsid` is not set
225+
- Send a write command to the server (e.g., `insertOne`), ignoring any errors from the server response
226+
- Check the corresponding `commandStarted` event: verify that lsid is not set
227+
228+
### 19. Explicit session raises an error if connection does not support sessions
229+
230+
Refer to [Testing against servers that do not support sessions](#testing-against-servers-that-do-not-support-sessions)
231+
and configure a `MongoClient` with default options.
232+
233+
- Create a new explicit session by calling `startSession` (this MUST NOT error)
234+
- Attempt to send a read command to the server (e.g., `findOne`) with the explicit session passed in
235+
- Assert that a client-side error is generated indicating that sessions are not supported
236+
- Attempt to send a write command to the server (e.g., `insertOne`) with the explicit session passed in
237+
- Assert that a client-side error is generated indicating that sessions are not supported
238+
239+
### 20. Drivers do not gossip `$clusterTime` on SDAM commands.
240+
241+
- Skip this test when connected to a deployment that does not support cluster times
242+
- Create a client, C1, directly connected to a writable server and a small heartbeatFrequencyMS
243+
- `c1 = MongoClient(directConnection=True, heartbeatFrequencyMS=10)`
244+
- Run a ping command using C1 and record the `$clusterTime` in the response, as `clusterTime`.
245+
- `clusterTime = c1.admin.command({"ping": 1})["$clusterTime"]`
246+
- Using a separate client, C2, run an insert to advance the cluster time
247+
- `c2.test.test.insert_one({"advance": "$clusterTime"})`
248+
- Next, wait until the client C1 processes the next pair of SDAM heartbeat started + succeeded events.
249+
- If possible, assert the SDAM heartbeats do not send `$clusterTime`
250+
- Run a ping command using C1 and assert that `$clusterTime` sent is the same as the `clusterTime` recorded earlier.
251+
This assertion proves that C1's `$clusterTime` was not advanced by gossiping through SDAM.
252+
253+
## Changelog
254+
255+
- 2025-02-24: Test drivers do not gossip $clusterTime on SDAM.
256+
- 2024-05-08: Migrated from reStructuredText to Markdown.
257+
- 2019-05-15: Initial version.
258+
- 2021-06-15: Added snapshot-session tests. Introduced legacy and unified folders.
259+
- 2021-07-30: Use numbering for prose test
260+
- 2022-02-11: Convert legacy tests to unified format
261+
- 2022-06-13: Relocate prose test from spec document and apply new ordering
262+
- 2023-02-24: Fix formatting and add new prose tests 18 and 19

specifications/sessions/tests/README.rst

-104
This file was deleted.

0 commit comments

Comments
 (0)