@@ -398,6 +398,81 @@ test_write_command_disconnect (void *ctx)
398
398
}
399
399
400
400
401
+ /* Test for CDRIVER-3306 - Do not assume non-empty server reply implies stream
402
+ * is still valid */
403
+ static void
404
+ test_cluster_command_notmaster (void )
405
+ {
406
+ mock_server_t * server ;
407
+ mongoc_uri_t * uri ;
408
+ mongoc_client_t * client ;
409
+ mongoc_collection_t * collection ;
410
+ mongoc_bulk_operation_t * bulk ;
411
+ bson_t * doc ;
412
+ uint32_t i ;
413
+ bson_error_t error ;
414
+ future_t * future ;
415
+ request_t * request ;
416
+ bson_t reply ;
417
+
418
+ if (!TestSuite_CheckMockServerAllowed ()) {
419
+ return ;
420
+ }
421
+
422
+ server = mock_server_new ();
423
+ mock_server_run (server );
424
+
425
+ /* server is "recovering": not master, not secondary */
426
+ mock_server_auto_ismaster (server ,
427
+ "{'ok': 1,"
428
+ " 'maxWireVersion': %d,"
429
+ " 'ismaster': false,"
430
+ " 'secondary': false,"
431
+ " 'setName': 'rs',"
432
+ " 'hosts': ['%s']}" ,
433
+ WIRE_VERSION_OP_MSG - 1 ,
434
+ mock_server_get_host_and_port (server ));
435
+
436
+ uri = mongoc_uri_copy (mock_server_get_uri (server ));
437
+ mongoc_uri_set_option_as_utf8 (uri , "replicaSet" , "rs" );
438
+
439
+ client = mongoc_client_new_from_uri (uri );
440
+
441
+ collection = mongoc_client_get_collection (client , "db" , "test" );
442
+ /* use an unordered bulk write, so it attempts to continue on error */
443
+ bulk = mongoc_collection_create_bulk_operation_with_opts (
444
+ collection , tmp_bson ("{'ordered': false}" ));
445
+ /* Set a "hint" aka "server id" to force the write to be directed to the
446
+ * non-primary */
447
+ mongoc_bulk_operation_set_hint (bulk , 1 );
448
+ doc = tmp_bson ("{'foo': 1}" );
449
+ /* Have enough inserts to ensure some batch splits */
450
+ for (i = 0 ; i < 10001 ; i ++ ) {
451
+ mongoc_bulk_operation_insert_with_opts (bulk , doc , NULL , & error );
452
+ }
453
+ /* If CDRIVER-3306 is still present, then this operation will trigger a
454
+ * segfault; once the below non-empty reply is received from the mock
455
+ * server, the stream will be invalidated but the non-empty reply will be
456
+ * interpreted as meaning it is OK to proceed with the other operations */
457
+ future = future_bulk_operation_execute (bulk , & reply , & error );
458
+
459
+ request = mock_server_receives_request (server );
460
+ mock_server_replies_simple (
461
+ request , "{ 'code': 10107, 'errmsg': 'not master', 'ok': 0 }" );
462
+ ASSERT (future_wait (future ));
463
+
464
+ mongoc_client_destroy (client );
465
+ mongoc_collection_destroy (collection );
466
+ mongoc_bulk_operation_destroy (bulk );
467
+ bson_destroy (& reply );
468
+ request_destroy (request );
469
+ future_destroy (future );
470
+ mongoc_uri_destroy (uri );
471
+ mock_server_destroy (server );
472
+
473
+ }
474
+
475
+
401
476
typedef struct {
402
477
int calls ;
403
478
bson_t * cluster_time ;
@@ -1793,6 +1868,9 @@ test_cluster_install (TestSuite *suite)
1793
1868
TestSuite_AddMockServerTest (suite ,
1794
1869
"/Cluster/command/timeout/pooled" ,
1795
1870
test_cluster_command_timeout_pooled );
1871
+ TestSuite_AddMockServerTest (suite ,
1872
+ "/Cluster/command/notmaster" ,
1873
+ test_cluster_command_notmaster );
1796
1874
TestSuite_AddFull (suite ,
1797
1875
"/Cluster/write_command/disconnect" ,
1798
1876
test_write_command_disconnect ,
0 commit comments