1====================
2Driver Session Tests
3====================
4
5.. contents::
6
7----
8
9Introduction
10============
11
12The YAML and JSON files in this directory are platform-independent tests
13meant to exercise a driver's implementation of sessions. These tests utilize the
14`Unified Test Format <../../unified-test-format/unified-test-format.rst>`__.
15
16Several prose tests, which are not easily expressed in YAML, are also presented
17in the Driver Sessions Spec. Those tests will need to be manually implemented
18by each driver.
19
20Snapshot session tests
21======================
22Snapshot sessions tests require server of version 5.0 or higher and
23replica set or a sharded cluster deployment.
24Default snapshot history window on the server is 5 minutes. Running the test in debug mode, or in any other slow configuration
25may lead to `SnapshotTooOld` errors. Drivers can work around this issue by increasing the server's `minSnapshotHistoryWindowInSeconds` parameter, for example:
26
27.. code:: python
28
29 client.admin.command('setParameter', 1, minSnapshotHistoryWindowInSeconds=60)
30
31Prose tests
32```````````
33
341. Setting both ``snapshot`` and ``causalConsistency`` to true is not allowed
35~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
36
37* ``client.startSession(snapshot = true, causalConsistency = true)``
38* Assert that an error was raised by driver
39
402. Pool is LIFO
41~~~~~~~~~~~~~~~
42
43This 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
503. ``$clusterTime`` in commands
51~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
52
53* Turn ``heartbeatFrequencyMS`` up to a very large number.
54* Register a command-started and a command-succeeded APM listener. If the driver has no APM support, inspect 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`` >= 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 the previous server reply. (Turning ``heartbeatFrequencyMS`` up prevents an intervening heartbeat from advancing the ``$clusterTime`` between these final two steps.)
60
61Repeat the above for:
62
63* An aggregate command from the ``aggregate`` helper method
64* A find command from the ``find`` helper method
65* An insert command from the ``insert_one`` helper method
66
674. Explicit and implicit session arguments
68~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
69
70* Register a command-started APM listener. If the driver has no APM support, inspect commands in another idiomatic way, such as monkey-patching or a mock server.
71* Create ``client1``
72* Get ``database`` from ``client1``
73* Get ``collection`` from ``database``
74* Start ``session`` from ``client1``
75* Call ``collection.insertOne(session,...)``
76* Assert that the command passed to the command-started listener contained the session ``lsid`` from ``session``.
77* Call ``collection.insertOne(,...)`` (*without* a session argument)
78* Assert that the command passed to the command-started listener contained a session ``lsid``.
79
80Repeat the above for all methods that take a session parameter.
81
825. Session argument is for the right client
83~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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
92Repeat the above for all methods that take a session parameter.
93
946. No further operations can be performed using a session after ``endSession`` has been called
95~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
96
97* Start a ``session``
98* End the ``session``
99* Call ``collection.InsertOne(session, ...)``
100* Assert that the proper error was reported
101
102Repeat the above for all methods that take a session parameter.
103
104If your driver implements a platform dependent idiomatic disposal pattern, test
105that also (if the idiomatic disposal pattern calls ``endSession`` it would be
106sufficient to only test the disposal pattern since that ends up calling
107``endSession``).
108
1097. Authenticating as multiple users suppresses implicit sessions
110~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
111
112Skip this test if your driver does not allow simultaneous authentication with multiple users.
113
114* Authenticate as two users
115* Call ``findOne`` with no explicit session
116* Capture the command sent to the server
117* Assert that the command sent to the server does not have an ``lsid`` field
118
1198. Client-side cursor that exhausts the results on the initial query immediately returns the implicit session to the pool
120~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
121
122* Insert two documents into a collection
123* Execute a find operation on the collection and iterate past the first document
124* Assert that the implicit session is returned to the pool. This can be done in several ways:
125
126 * Track in-use count in the server session pool and assert that the count has dropped to zero
127 * Track the lsid used for the find operation (e.g. with APM) and then do another operation and
128 assert that the same lsid is used as for the find operation.
129
1309. Client-side cursor that exhausts the results after a ``getMore`` immediately returns the implicit session to the pool
131~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
132
133* Insert five documents into a collection
134* Execute a find operation on the collection with batch size of 3
135* Iterate past the first four documents, forcing the final ``getMore`` operation
136* Assert that the implicit session is returned to the pool prior to iterating past the last document
137
13810. No remaining sessions are checked out after each functional test
139~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
140
141At the end of every individual functional test of the driver, there SHOULD be an
142assertion that there are no remaining sessions checked out from the pool. This
143may require changes to existing tests to ensure that they close any explicit
144client sessions and any unexhausted cursors.
145
14611. For every combination of topology and readPreference, ensure that ``find`` and ``getMore`` both send the same session id
147~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
148
149* Insert three documents into a collection
150* Execute a ``find`` operation on the collection with a batch size of 2
151* Assert that the server receives a non-zero lsid
152* Iterate through enough documents (3) to force a ``getMore``
153* Assert that the server receives a non-zero lsid equal to the lsid that ``find`` sent.
154
15512. Session pool can be cleared after forking without calling ``endSession``
156~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
157
158Skip this test if your driver does not allow forking.
159
160* Create ClientSession
161* Record its lsid
162* Delete it (so the lsid is pushed into the pool)
163* Fork
164* In the parent, create a ClientSession and assert its lsid is the same.
165* In the child, create a ClientSession and assert its lsid is different.
166
16713. Existing sessions are not checked into a cleared pool after forking
168~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
169
170Skip this test if your driver does not allow forking.
171
172* Create ClientSession
173* Record its lsid
174* Fork
175* In the parent, return the ClientSession to the pool, create a new ClientSession, and assert its lsid is the same.
176* In the child, return the ClientSession to the pool, create a new ClientSession, and assert its lsid is different.
177
17814. Implicit sessions only allocate their server session after a successful connection checkout
179~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
180
181* Create a MongoClient with the following options: ``maxPoolSize=1`` and ``retryWrites=true``. If testing against a sharded deployment, the test runner MUST ensure that the MongoClient connects to only a single mongos host.
182* Attach a command started listener that collects each command's lsid
183* Initiate the following concurrent operations
184
185 * ``insertOne({ }),``
186 * ``deleteOne({ }),``
187 * ``updateOne({ }, { $set: { a: 1 } }),``
188 * ``bulkWrite([{ updateOne: { filter: { }, update: { $set: { a: 1 } } } }]),``
189 * ``findOneAndDelete({ }),``
190 * ``findOneAndUpdate({ }, { $set: { a: 1 } }),``
191 * ``findOneAndReplace({ }, { a: 1 }),``
192 * ``find().toArray()``
193
194* Wait for all operations to complete successfully
195* Assert the following across at least 5 retries of the above test:
196
197 * Drivers MUST assert that exactly one session is used for all operations at
198 least once across the retries of this test.
199 * Note that it's possible, although rare, for >1 server session to be used
200 because the session is not released until after the connection is checked in.
201 * Drivers MUST assert that the number of allocated sessions is strictly less
202 than the number of concurrent operations in every retry of this test. In
203 this instance it would be less than (but NOT equal to) 8.
204
20515. ``lsid`` is added inside ``$query`` when using OP_QUERY
206~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
207
208This test only applies to drivers that have not implemented OP_MSG and still use OP_QUERY.
209
210* For a command to a mongos that includes a readPreference, verify that the
211 ``lsid`` on query commands is added inside the ``$query`` field, and NOT as a
212 top-level field.
213
21416. Authenticating as a second user after starting a session results in a server error
215~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
216
217This test only applies to drivers that allow authentication to be changed on the fly.
218
219* Authenticate as the first user
220* Start a session by calling ``startSession``
221* Authenticate as a second user
222* Call ``findOne`` using the session as an explicit session
223* Assert that the driver returned an error because multiple users are authenticated
224
22517. Driver verifies that the session is owned by the current user
226~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
227
228This test only applies to drivers that allow authentication to be changed on the fly.
229
230* Authenticate as user A
231* Start a session by calling ``startSession``
232* Logout user A
233* Authenticate as user B
234* Call ``findOne`` using the session as an explicit session
235* Assert that the driver returned an error because the session is owned by a different user
236
237Changelog
238=========
239
240:2019-05-15: Initial version.
241:2021-06-15: Added snapshot-session tests. Introduced legacy and unified folders.
242:2021-07-30: Use numbering for prose test
243:2022-02-11: Convert legacy tests to unified format
244:2022-06-13: Relocate prose test from spec document and apply new ordering
View as plain text