@@ -1887,11 +1887,11 @@ test_resume_cases (void)
1887
1887
1888
1888
/* only 'startAfter' specified. */
1889
1889
/* - if no doc recv'ed, use the startAfter option for the original aggregate
1890
- * but resumeAfter with the same value when resuming. */
1890
+ * whether or not we are resuming. */
1891
1891
_test_resume ("{" OPT_SA "}" ,
1892
1892
OPT_SA "," NO_OPT_OP "," NO_OPT_RA "," ,
1893
1893
"" ,
1894
- OPT_RA "," NO_OPT_OP "," NO_OPT_SA "," ,
1894
+ OPT_SA "," NO_OPT_OP "," NO_OPT_RA "," ,
1895
1895
"" );
1896
1896
/* - if doc recv'ed and iterated, use the doc's resume token. */
1897
1897
_test_resume ("{" OPT_SA "}" ,
@@ -1902,13 +1902,14 @@ test_resume_cases (void)
1902
1902
1903
1903
/* 'resumeAfter', 'startAfter', and 'startAtOperationTime' are all specified.
1904
1904
* All should be passed (although the server currently returns an error). */
1905
- /* - if no doc recv'ed, use the resumeAfter option . */
1905
+ /* - if no doc recv'ed, use startAfter . */
1906
1906
_test_resume ("{" OPT_RA "," OPT_SA "," OPT_OP "}" ,
1907
1907
OPT_RA "," OPT_SA "," OPT_OP "," ,
1908
1908
"" ,
1909
- OPT_RA "," NO_OPT_OP "," NO_OPT_SA "," ,
1909
+ OPT_SA "," NO_OPT_OP "," NO_OPT_RA "," ,
1910
1910
"" );
1911
- /* - if doc recv'ed and iterated, use the doc's resume token. */
1911
+ /* - if one doc recv'ed and iterated, use resumeAfter with doc's resume
1912
+ * token. */
1912
1913
_test_resume ("{" OPT_RA "," OPT_SA "," OPT_OP "}" ,
1913
1914
OPT_RA "," OPT_SA "," OPT_OP "," ,
1914
1915
DOC ,
@@ -1924,6 +1925,7 @@ test_resume_cases_with_post_batch_resume_token (void)
1924
1925
{
1925
1926
#define CURSOR_PBR "'postBatchResumeToken': {'resume': 'pbr'}"
1926
1927
#define PBR_RA "'resumeAfter': {'resume': 'pbr'}"
1928
+ #define PBR_SA "'startAfter': {'resume': 'pbr'}"
1927
1929
1928
1930
/* test features:
1929
1931
* - whether the change stream returns a document before resuming.
@@ -1937,55 +1939,59 @@ test_resume_cases_with_post_batch_resume_token (void)
1937
1939
* last document in the batch (if _test_resume() iterates to that point). */
1938
1940
1939
1941
/* no options specified. */
1940
- /* - if no doc recv'ed, use postBatchResumeToken. */
1942
+ /* - if no doc recv'ed, use resumeAfter with postBatchResumeToken. */
1941
1943
_test_resume ("{}" ,
1942
1944
NO_OPT_OP "," NO_OPT_RA "," NO_OPT_SA "," ,
1943
1945
"" ,
1944
1946
PBR_RA "," NO_OPT_OP "," NO_OPT_SA "," ,
1945
1947
"," CURSOR_PBR );
1946
- /* - if one doc recv'ed and iterated, use postBatchResumeToken. */
1948
+ /* - if one doc recv'ed and iterated, use resumeAfter with
1949
+ * postBatchResumeToken. */
1947
1950
_test_resume ("{}" ,
1948
1951
NO_OPT_OP "," NO_OPT_RA "," NO_OPT_SA "," ,
1949
1952
DOC ,
1950
1953
PBR_RA "," NO_OPT_OP "," NO_OPT_SA "," ,
1951
1954
"," CURSOR_PBR );
1952
1955
1953
1956
/* only 'startAtOperationTime' specified. */
1954
- /* - if no doc recv'ed, use postBatchResumeToken. */
1957
+ /* - if no doc recv'ed, use resumeAfter with postBatchResumeToken. */
1955
1958
_test_resume ("{" OPT_OP "}" ,
1956
1959
OPT_OP "," NO_OPT_RA "," NO_OPT_SA "," ,
1957
1960
"" ,
1958
1961
PBR_RA "," NO_OPT_OP "," NO_OPT_SA "," ,
1959
1962
"," CURSOR_PBR );
1960
- /* - if one doc recv'ed and iterated, use postBatchResumeToken. */
1963
+ /* - if one doc recv'ed and iterated, use resumeAfter with
1964
+ * postBatchResumeToken. */
1961
1965
_test_resume ("{" OPT_OP "}" ,
1962
1966
OPT_OP "," NO_OPT_RA "," NO_OPT_SA "," ,
1963
1967
DOC ,
1964
1968
PBR_RA "," NO_OPT_OP "," NO_OPT_SA "," ,
1965
1969
"," CURSOR_PBR );
1966
1970
1967
1971
/* only 'resumeAfter' specified. */
1968
- /* - if no doc recv'ed, use postBatchResumeToken. */
1972
+ /* - if no doc recv'ed, use resumeAfter with postBatchResumeToken. */
1969
1973
_test_resume ("{" OPT_RA "}" ,
1970
1974
OPT_RA "," NO_OPT_OP "," NO_OPT_SA "," ,
1971
1975
"" ,
1972
1976
PBR_RA "," NO_OPT_OP "," NO_OPT_SA "," ,
1973
1977
"," CURSOR_PBR );
1974
- /* - if one doc recv'ed and iterated, use postBatchResumeToken. */
1978
+ /* - if one doc recv'ed and iterated, use resumeAfter with
1979
+ * postBatchResumeToken. */
1975
1980
_test_resume ("{" OPT_RA "}" ,
1976
1981
OPT_RA "," NO_OPT_OP "," NO_OPT_SA "," ,
1977
1982
DOC ,
1978
1983
PBR_RA "," NO_OPT_OP "," NO_OPT_SA "," ,
1979
1984
"," CURSOR_PBR );
1980
1985
1981
1986
/* only 'startAfter' specified. */
1982
- /* - if no doc recv'ed, use postBatchResumeToken. */
1987
+ /* - if no doc recv'ed, use startAfter with postBatchResumeToken. */
1983
1988
_test_resume ("{" OPT_SA "}" ,
1984
1989
OPT_SA "," NO_OPT_OP "," NO_OPT_RA "," ,
1985
1990
"" ,
1986
- PBR_RA "," NO_OPT_OP "," NO_OPT_SA "," ,
1991
+ PBR_SA "," NO_OPT_OP "," NO_OPT_RA "," ,
1987
1992
"," CURSOR_PBR );
1988
- /* - if one doc recv'ed and iterated, use postBatchResumeToken. */
1993
+ /* - if one doc recv'ed and iterated, use resumeAfter with
1994
+ * postBatchResumeToken. */
1989
1995
_test_resume ("{" OPT_SA "}" ,
1990
1996
OPT_SA "," NO_OPT_OP "," NO_OPT_RA "," ,
1991
1997
DOC ,
@@ -1994,13 +2000,14 @@ test_resume_cases_with_post_batch_resume_token (void)
1994
2000
1995
2001
/* 'resumeAfter', 'startAfter', and 'startAtOperationTime' are all specified.
1996
2002
* All should be passed (although the server currently returns an error). */
1997
- /* - if no doc recv'ed, use postBatchResumeToken. */
2003
+ /* - if no doc recv'ed, use startAfter with postBatchResumeToken. */
1998
2004
_test_resume ("{" OPT_RA "," OPT_SA "," OPT_OP "}" ,
1999
2005
OPT_RA "," OPT_SA "," OPT_OP "," ,
2000
2006
"" ,
2001
- PBR_RA "," NO_OPT_OP "," NO_OPT_SA "," ,
2007
+ PBR_SA "," NO_OPT_OP "," NO_OPT_RA "," ,
2002
2008
"," CURSOR_PBR );
2003
- /* - if one doc recv'ed and iterated, use postBatchResumeToken. */
2009
+ /* - if one doc recv'ed and iterated, use resumeAfter with
2010
+ * postBatchResumeToken. */
2004
2011
_test_resume ("{" OPT_RA "," OPT_SA "," OPT_OP "}" ,
2005
2012
OPT_RA "," OPT_SA "," OPT_OP "," ,
2006
2013
DOC ,
@@ -2311,6 +2318,156 @@ prose_test_14 (void *test_ctx)
2311
2318
}
2312
2319
2313
2320
2321
+ void
2322
+ prose_test_17 (void )
2323
+ {
2324
+ mock_server_t * server ;
2325
+ request_t * request ;
2326
+ future_t * future ;
2327
+ mongoc_client_t * client ;
2328
+ mongoc_collection_t * coll ;
2329
+ mongoc_change_stream_t * stream ;
2330
+ const bson_t * next_doc = NULL ;
2331
+
2332
+ server = mock_server_with_autoismaster (WIRE_VERSION_MAX );
2333
+ mock_server_run (server );
2334
+ client = mongoc_client_new_from_uri (mock_server_get_uri (server ));
2335
+
2336
+ coll = mongoc_client_get_collection (client , "db" , "coll" );
2337
+ /* Pass an arbitrary document as the resume token, like {'x': 1} */
2338
+ future = future_collection_watch (
2339
+ coll , tmp_bson ("{}" ), tmp_bson ("{'startAfter': {'x': 1}}" ));
2340
+
2341
+ request = mock_server_receives_msg (
2342
+ server ,
2343
+ MONGOC_QUERY_NONE ,
2344
+ tmp_bson ("{ 'aggregate': 'coll', 'pipeline' : [ { '$changeStream': { "
2345
+ "'startAfter': {'x': 1} , 'resumeAfter': { '$exists': false }, "
2346
+ "'startAtOperationTime': { '$exists': false } } } ]}" ));
2347
+
2348
+ mock_server_replies_simple (
2349
+ request ,
2350
+ "{'cursor': {'id': 123, 'ns': 'db.coll', 'firstBatch': []}, 'ok': 1 }" );
2351
+
2352
+ request_destroy (request );
2353
+
2354
+ stream = future_get_mongoc_change_stream_ptr (future );
2355
+ ASSERT (stream );
2356
+ future_destroy (future );
2357
+
2358
+ future = future_change_stream_next (stream , & next_doc );
2359
+
2360
+ request = mock_server_receives_msg (
2361
+ server ,
2362
+ MONGOC_QUERY_NONE ,
2363
+ tmp_bson ("{ 'getMore': {'$numberLong': '123'}, 'collection': 'coll' }" ));
2364
+
2365
+ mock_server_replies_simple (
2366
+ request , "{ 'code': 10107, 'errmsg': 'not master', 'ok': 0 }" );
2367
+
2368
+ request_destroy (request );
2369
+
2370
+ /* Resume occurs. */
2371
+ request = mock_server_receives_msg (
2372
+ server ,
2373
+ MONGOC_QUERY_NONE ,
2374
+ tmp_bson ("{ 'aggregate': 'coll', 'pipeline': [ { "
2375
+ "'$changeStream': { 'startAfter': {'x': 1}, 'resumeAfter': { "
2376
+ "'$exists': false }, 'startAtOperationTime': { '$exists': "
2377
+ "false } } "
2378
+ "}]}" ));
2379
+
2380
+ /* Reply with a 0 cursor ID to prevent a killCursors command. */
2381
+ mock_server_replies_simple (
2382
+ request ,
2383
+ "{'cursor': {'id': 0, 'ns': 'db.coll', 'firstBatch': []}, 'ok': 1 }" );
2384
+ request_destroy (request );
2385
+ BSON_ASSERT (!future_get_bool (future ));
2386
+ future_destroy (future );
2387
+ mongoc_change_stream_destroy (stream );
2388
+
2389
+ mongoc_collection_destroy (coll );
2390
+ mongoc_client_destroy (client );
2391
+ mock_server_destroy (server );
2392
+ }
2393
+
2394
+
2395
+ void
2396
+ prose_test_18 (void )
2397
+ {
2398
+ mock_server_t * server ;
2399
+ request_t * request ;
2400
+ future_t * future ;
2401
+ mongoc_client_t * client ;
2402
+ mongoc_collection_t * coll ;
2403
+ mongoc_change_stream_t * stream ;
2404
+ const bson_t * next_doc = NULL ;
2405
+
2406
+ server = mock_server_with_autoismaster (WIRE_VERSION_MAX );
2407
+ mock_server_run (server );
2408
+ client = mongoc_client_new_from_uri (mock_server_get_uri (server ));
2409
+
2410
+ coll = mongoc_client_get_collection (client , "db" , "coll" );
2411
+ /* Pass an arbitrary document as the resume token, like {'x': 1} */
2412
+ future = future_collection_watch (
2413
+ coll , tmp_bson ("{}" ), tmp_bson ("{'startAfter': {'x': 1}}" ));
2414
+
2415
+ request = mock_server_receives_msg (
2416
+ server ,
2417
+ MONGOC_QUERY_NONE ,
2418
+ tmp_bson ("{ 'aggregate': 'coll', 'pipeline' : [ { '$changeStream': { "
2419
+ "'startAfter': {'x': 1}, 'resumeAfter': { '$exists': false }, "
2420
+ "'startAtOperationTime': { '$exists': false } } } ]}" ));
2421
+
2422
+ mock_server_replies_simple (request ,
2423
+ "{'cursor': {'id': 123, 'ns': "
2424
+ "'db.coll', 'firstBatch': [{'_id': "
2425
+ "{'y': 1}}]}, 'ok': 1 }" );
2426
+
2427
+ request_destroy (request );
2428
+ stream = future_get_mongoc_change_stream_ptr (future );
2429
+ ASSERT (stream );
2430
+ future_destroy (future );
2431
+
2432
+ /* The first call to mongoc_change_stream_next returns the batched document.
2433
+ */
2434
+ mongoc_change_stream_next (stream , & next_doc );
2435
+
2436
+ future = future_change_stream_next (stream , & next_doc );
2437
+
2438
+ request = mock_server_receives_msg (
2439
+ server ,
2440
+ MONGOC_QUERY_NONE ,
2441
+ tmp_bson ("{ 'getMore': {'$numberLong': '123'}, 'collection': 'coll' }" ));
2442
+
2443
+ mock_server_replies_simple (
2444
+ request , "{ 'code': 10107, 'errmsg': 'not master', 'ok': 0 }" );
2445
+
2446
+ request_destroy (request );
2447
+
2448
+ request = mock_server_receives_msg (
2449
+ server ,
2450
+ MONGOC_QUERY_NONE ,
2451
+ tmp_bson ("{ 'aggregate': 'coll', 'pipeline': [ { "
2452
+ "'$changeStream': { 'resumeAfter': {'y': 1}, 'startAfter': { "
2453
+ "'$exists': false }, 'startAtOperationTime': { '$exists': "
2454
+ "false } } "
2455
+ "}]}" ));
2456
+ /* Reply with a 0 cursor ID to prevent a killCursors command. */
2457
+ mock_server_replies_simple (
2458
+ request ,
2459
+ "{'cursor': {'id': 0, 'ns': 'db.coll', 'firstBatch': []}, 'ok': 1 }" );
2460
+ request_destroy (request );
2461
+ BSON_ASSERT (!future_get_bool (future ));
2462
+ future_destroy (future );
2463
+ mongoc_change_stream_destroy (stream );
2464
+
2465
+ mongoc_collection_destroy (coll );
2466
+ mongoc_client_destroy (client );
2467
+ mock_server_destroy (server );
2468
+ }
2469
+
2470
+
2314
2471
void
2315
2472
test_change_stream_install (TestSuite * suite )
2316
2473
{
@@ -2469,6 +2626,11 @@ test_change_stream_install (TestSuite *suite)
2469
2626
NULL ,
2470
2627
test_framework_skip_if_mongos ,
2471
2628
test_framework_skip_if_not_rs_version_7 );
2629
+ TestSuite_AddMockServerTest (
2630
+ suite , "/change_streams/prose_test_17" , prose_test_17 );
2631
+ TestSuite_AddMockServerTest (
2632
+ suite , "/change_streams/prose_test_18" , prose_test_18 );
2633
+
2472
2634
2473
2635
test_framework_resolve_path (JSON_DIR "/change_streams" , resolved );
2474
2636
install_json_test_suite (suite , resolved , & test_change_stream_spec_cb );
0 commit comments