Skip to content

Commit 674a404

Browse files
committed
Sync to latest change stream tests
There is one behavioral change in these tests: to treat CursorNotFound errors as resumable. The reason there is no corresponding change in the driver is because it was already doing this, incorrectly it turns out. But now it turns it that it is the correct thing to do. JAVA-3781 JAVA-3776
1 parent 7b9a753 commit 674a404

File tree

4 files changed

+219
-66
lines changed

4 files changed

+219
-66
lines changed

driver-core/src/test/resources/change-streams/README.rst

Lines changed: 84 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ The definition of MATCH or MATCHES in the Spec Test Runner is as follows:
6363

6464
- MATCH takes two values, ``expected`` and ``actual``
6565
- Notation is "Assert [actual] MATCHES [expected]
66-
- Assertion passes if ``expected`` is a subset of ``actual``, with the values ``42`` and ``"42"`` acting as placeholders for "any value"
66+
- Assertion passes if ``expected`` is a subset of ``actual``, with the value ``42`` acting as placeholders for "any value"
6767

6868
Pseudocode implementation of ``actual`` MATCHES ``expected``:
6969

@@ -93,7 +93,10 @@ Spec Test Runner
9393

9494
Before running the tests
9595

96-
- Create a MongoClient ``globalClient``, and connect to the server
96+
- Create a MongoClient ``globalClient``, and connect to the server.
97+
When executing tests against a sharded cluster, ``globalClient`` must only connect to one mongos. This is because tests
98+
that set failpoints will only work consistently if both the ``configureFailPoint`` and failing commands are sent to the
99+
same mongos.
97100

98101
For each YAML file, for each element in ``tests``:
99102

@@ -110,13 +113,10 @@ For each YAML file, for each element in ``tests``:
110113

111114
- Create a new MongoClient ``client``
112115
- Begin monitoring all APM events for ``client``. (If the driver uses global listeners, filter out all events that do not originate with ``client``). Filter out any "internal" commands (e.g. ``isMaster``)
113-
- Using ``client``, create a changeStream ``changeStream`` against the specified ``target``. Use ``changeStreamPipeline`` and ``changeStreamOptions`` if they are non-empty
114-
- Using ``globalClient``, run every operation in ``operations`` in serial against the server
115-
- Wait until either:
116-
117-
- An error occurs
118-
- All operations have been successful AND the changeStream has received as many changes as there are in ``result.success``
119-
116+
- Using ``client``, create a changeStream ``changeStream`` against the specified ``target``. Use ``changeStreamPipeline`` and ``changeStreamOptions`` if they are non-empty. Capture any error.
117+
- If there was no error, use ``globalClient`` and run every operation in ``operations`` in serial against the server until all operations have been executed or an error is thrown. Capture any error.
118+
- If there was no error and ``result.error`` is set, iterate ``changeStream`` once and capture any error.
119+
- If there was no error and ``result.success`` is non-empty, iterate ``changeStream`` until it returns as many changes as there are elements in the ``result.success`` array or an error is thrown. Capture any error.
120120
- Close ``changeStream``
121121
- If there was an error:
122122

@@ -131,8 +131,8 @@ For each YAML file, for each element in ``tests``:
131131
- If there are any ``expectations``
132132

133133
- For each (``expected``, ``idx``) in ``expectations``
134-
135-
- Assert that ``actual[idx]`` MATCHES ``expected``
134+
- If ``actual[idx]`` is a ``killCursors`` event, skip it and move to ``actual[idx+1]``.
135+
- Else assert that ``actual[idx]`` MATCHES ``expected``
136136

137137
- Close the MongoClient ``client``
138138

@@ -142,20 +142,86 @@ After running all tests
142142
- Drop database ``database_name``
143143
- Drop database ``database2_name``
144144

145+
Iterating the Change Stream
146+
---------------------------
147+
148+
Although synchronous drivers must provide a `non-blocking mode of iteration <../change-streams.rst#not-blocking-on-iteration>`_, asynchronous drivers may not have such a mechanism. Those drivers with only a blocking mode of iteration should be careful not to iterate the change stream unnecessarily, as doing so could cause the test runner to block indefinitely. For this reason, the test runner procedure above advises drivers to take a conservative approach to iteration.
149+
150+
If the test expects an error and one was not thrown by either creating the change stream or executing the test's operations, iterating the change stream once allows for an error to be thrown by a ``getMore`` command. If the test does not expect any error, the change stream should be iterated only until it returns as many result documents as are expected by the test.
151+
152+
Testing on Sharded Clusters
153+
---------------------------
154+
155+
When writing data on sharded clusters, majority-committed data does not always show up in the response of the first
156+
``getMore`` command after the data is written. This is because in sharded clusters, no data from shard A may be returned
157+
until all other shard reports an entry that sorts after the change in shard A.
158+
159+
To account for this, drivers MUST NOT rely on change stream documents in certain batches. For example, if expecting two
160+
documents in a change stream, these may not be part of the same ``getMore`` response, or even be produced in two
161+
subsequent ``getMore`` responses. Drivers MUST allow for a ``getMore`` to produce empty batches when testing on a
162+
sharded cluster. By default, this can take up to 10 seconds, but can be controlled by enabling the ``writePeriodicNoops``
163+
server parameter and configuring the ``periodNoopIntervalSecs`` parameter. Choosing lower values allows for running
164+
change stream tests with smaller timeouts.
145165

146166
Prose Tests
147167
===========
148168

149-
The following tests have not yet been automated, but MUST still be tested
169+
The following tests have not yet been automated, but MUST still be tested. All tests SHOULD be run on both replica sets and sharded clusters unless otherwise specified:
150170

151171
#. ``ChangeStream`` must continuously track the last seen ``resumeToken``
152-
#. ``ChangeStream`` will throw an exception if the server response is missing the resume token
153-
#. ``ChangeStream`` will automatically resume one time on a resumable error (including `not master`) with the initial pipeline and options, except for the addition/update of a ``resumeToken``.
154-
#. ``ChangeStream`` will not attempt to resume on any error encountered while executing an ``aggregate`` command.
155-
#. ``ChangeStream`` will not attempt to resume after encountering error code 11601 (Interrupted), 136 (CappedPositionLost), or 237 (CursorKilled) while executing a ``getMore`` command.
172+
#. ``ChangeStream`` will throw an exception if the server response is missing the resume token (if wire version is < 8, this is a driver-side error; for 8+, this is a server-side error)
173+
#. After receiving a ``resumeToken``, ``ChangeStream`` will automatically resume one time on a resumable error with the initial pipeline and options, except for the addition/update of a ``resumeToken``.
174+
#. ``ChangeStream`` will not attempt to resume on any error encountered while executing an ``aggregate`` command. Note that retryable reads may retry ``aggregate`` commands. Drivers should be careful to distinguish retries from resume attempts. Alternatively, drivers may specify `retryReads=false` or avoid using a [retryable error](../../retryable-reads/retryable-reads.rst#retryable-error) for this test.
175+
#. **Removed**
156176
#. ``ChangeStream`` will perform server selection before attempting to resume, using initial ``readPreference``
157177
#. Ensure that a cursor returned from an aggregate command with a cursor id and an initial empty batch is not closed on the driver side.
158178
#. The ``killCursors`` command sent during the "Resume Process" must not be allowed to throw an exception.
159-
#. ``$changeStream`` stage for ``ChangeStream`` against a server ``>=4.0`` that has not received any results yet MUST include a ``startAtOperationTime`` option when resuming a changestream.
160-
#. ``ChangeStream`` will resume after a ``killCursors`` command is issued for its child cursor.
179+
#. ``$changeStream`` stage for ``ChangeStream`` against a server ``>=4.0`` and ``<4.0.7`` that has not received any results yet MUST include a ``startAtOperationTime`` option when resuming a change stream.
180+
#. **Removed**
181+
#. For a ``ChangeStream`` under these conditions:
182+
183+
- Running against a server ``>=4.0.7``.
184+
- The batch is empty or has been iterated to the last document.
185+
186+
Expected result:
187+
188+
- ``getResumeToken`` must return the ``postBatchResumeToken`` from the current command response.
189+
190+
#. For a ``ChangeStream`` under these conditions:
191+
192+
- Running against a server ``<4.0.7``.
193+
- The batch is empty or has been iterated to the last document.
194+
195+
Expected result:
196+
197+
- ``getResumeToken`` must return the ``_id`` of the last document returned if one exists.
198+
- ``getResumeToken`` must return ``resumeAfter`` from the initial aggregate if the option was specified.
199+
- If ``resumeAfter`` was not specified, the ``getResumeToken`` result must be empty.
200+
201+
#. For a ``ChangeStream`` under these conditions:
202+
203+
- The batch is not empty.
204+
- The batch has been iterated up to but not including the last element.
205+
206+
Expected result:
207+
208+
- ``getResumeToken`` must return the ``_id`` of the previous document returned.
209+
210+
#. For a ``ChangeStream`` under these conditions:
211+
212+
- The batch is not empty.
213+
- The batch hasn’t been iterated at all.
214+
- Only the initial ``aggregate`` command has been executed.
215+
216+
Expected result:
217+
218+
- ``getResumeToken`` must return ``startAfter`` from the initial aggregate if the option was specified.
219+
- ``getResumeToken`` must return ``resumeAfter`` from the initial aggregate if the option was specified.
220+
- If neither the ``startAfter`` nor ``resumeAfter`` options were specified, the ``getResumeToken`` result must be empty.
221+
222+
Note that this test cannot be run against sharded topologies because in that case the initial ``aggregate`` command only establishes cursors on the shards and always returns an empty ``firstBatch``.
161223

224+
#. **Removed**
225+
#. **Removed**
226+
#. ``$changeStream`` stage for ``ChangeStream`` started with ``startAfter`` against a server ``>=4.1.1`` that has not received any results yet MUST include a ``startAfter`` option and MUST NOT include a ``resumeAfter`` option when resuming a change stream.
227+
#. ``$changeStream`` stage for ``ChangeStream`` started with ``startAfter`` against a server ``>=4.1.1`` that has received at least one result MUST include a ``resumeAfter`` option and MUST NOT include a ``startAfter`` option when resuming a change stream.

driver-core/src/test/resources/change-streams/change-streams-errors.json

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -102,15 +102,12 @@
102102
],
103103
"result": {
104104
"error": {
105-
"code": 280,
106-
"errorLabels": [
107-
"NonResumableChangeStreamError"
108-
]
105+
"code": 280
109106
}
110107
}
111108
},
112109
{
113-
"description": "change stream errors on MaxTimeMSExpired",
110+
"description": "change stream errors on ElectionInProgress",
114111
"minServerVersion": "4.2",
115112
"failPoint": {
116113
"configureFailPoint": "failCommand",
@@ -121,7 +118,7 @@
121118
"failCommands": [
122119
"getMore"
123120
],
124-
"errorCode": 50,
121+
"errorCode": 216,
125122
"closeConnection": false
126123
}
127124
},
@@ -130,13 +127,7 @@
130127
"replicaset",
131128
"sharded"
132129
],
133-
"changeStreamPipeline": [
134-
{
135-
"$project": {
136-
"_id": 0
137-
}
138-
}
139-
],
130+
"changeStreamPipeline": [],
140131
"changeStreamOptions": {},
141132
"operations": [
142133
{
@@ -152,7 +143,7 @@
152143
],
153144
"result": {
154145
"error": {
155-
"code": 50
146+
"code": 216
156147
}
157148
}
158149
}

driver-core/src/test/resources/change-streams/change-streams-resume-errorLabels.json

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
{
5454
"command_started_event": {
5555
"command": {
56-
"getMore": "42",
56+
"getMore": 42,
5757
"collection": "test"
5858
},
5959
"command_name": "getMore",
@@ -146,7 +146,7 @@
146146
{
147147
"command_started_event": {
148148
"command": {
149-
"getMore": "42",
149+
"getMore": 42,
150150
"collection": "test"
151151
},
152152
"command_name": "getMore",
@@ -239,7 +239,7 @@
239239
{
240240
"command_started_event": {
241241
"command": {
242-
"getMore": "42",
242+
"getMore": 42,
243243
"collection": "test"
244244
},
245245
"command_name": "getMore",
@@ -332,7 +332,7 @@
332332
{
333333
"command_started_event": {
334334
"command": {
335-
"getMore": "42",
335+
"getMore": 42,
336336
"collection": "test"
337337
},
338338
"command_name": "getMore",
@@ -425,7 +425,7 @@
425425
{
426426
"command_started_event": {
427427
"command": {
428-
"getMore": "42",
428+
"getMore": 42,
429429
"collection": "test"
430430
},
431431
"command_name": "getMore",
@@ -518,7 +518,7 @@
518518
{
519519
"command_started_event": {
520520
"command": {
521-
"getMore": "42",
521+
"getMore": 42,
522522
"collection": "test"
523523
},
524524
"command_name": "getMore",
@@ -611,7 +611,7 @@
611611
{
612612
"command_started_event": {
613613
"command": {
614-
"getMore": "42",
614+
"getMore": 42,
615615
"collection": "test"
616616
},
617617
"command_name": "getMore",
@@ -704,7 +704,7 @@
704704
{
705705
"command_started_event": {
706706
"command": {
707-
"getMore": "42",
707+
"getMore": 42,
708708
"collection": "test"
709709
},
710710
"command_name": "getMore",
@@ -797,7 +797,7 @@
797797
{
798798
"command_started_event": {
799799
"command": {
800-
"getMore": "42",
800+
"getMore": 42,
801801
"collection": "test"
802802
},
803803
"command_name": "getMore",
@@ -890,7 +890,7 @@
890890
{
891891
"command_started_event": {
892892
"command": {
893-
"getMore": "42",
893+
"getMore": 42,
894894
"collection": "test"
895895
},
896896
"command_name": "getMore",
@@ -983,7 +983,7 @@
983983
{
984984
"command_started_event": {
985985
"command": {
986-
"getMore": "42",
986+
"getMore": 42,
987987
"collection": "test"
988988
},
989989
"command_name": "getMore",
@@ -1076,7 +1076,7 @@
10761076
{
10771077
"command_started_event": {
10781078
"command": {
1079-
"getMore": "42",
1079+
"getMore": 42,
10801080
"collection": "test"
10811081
},
10821082
"command_name": "getMore",
@@ -1169,7 +1169,7 @@
11691169
{
11701170
"command_started_event": {
11711171
"command": {
1172-
"getMore": "42",
1172+
"getMore": 42,
11731173
"collection": "test"
11741174
},
11751175
"command_name": "getMore",
@@ -1262,7 +1262,7 @@
12621262
{
12631263
"command_started_event": {
12641264
"command": {
1265-
"getMore": "42",
1265+
"getMore": 42,
12661266
"collection": "test"
12671267
},
12681268
"command_name": "getMore",
@@ -1355,7 +1355,7 @@
13551355
{
13561356
"command_started_event": {
13571357
"command": {
1358-
"getMore": "42",
1358+
"getMore": 42,
13591359
"collection": "test"
13601360
},
13611361
"command_name": "getMore",
@@ -1448,7 +1448,7 @@
14481448
{
14491449
"command_started_event": {
14501450
"command": {
1451-
"getMore": "42",
1451+
"getMore": 42,
14521452
"collection": "test"
14531453
},
14541454
"command_name": "getMore",
@@ -1547,7 +1547,7 @@
15471547
{
15481548
"command_started_event": {
15491549
"command": {
1550-
"getMore": "42",
1550+
"getMore": 42,
15511551
"collection": "test"
15521552
},
15531553
"command_name": "getMore",

0 commit comments

Comments
 (0)