2121from bson import InvalidDocument , SON
2222from bson .py3compat import string_type
2323from pymongo import MongoClient
24+ from pymongo .common import partition_node
2425from pymongo .errors import BulkWriteError , InvalidOperation , OperationFailure
25- from test import client_context , unittest , host , port , IntegrationTest
26+ from test import (client_context ,
27+ unittest ,
28+ host ,
29+ port ,
30+ IntegrationTest ,
31+ SkipTest )
2632from test .utils import oid_generated_on_client , remove_all_users
2733
2834
@@ -909,6 +915,36 @@ class TestBulkWriteConcern(BulkTestBase):
909915 def setUpClass (cls ):
910916 super (TestBulkWriteConcern , cls ).setUpClass ()
911917 cls .w = client_context .w
918+ cls .secondary = None
919+ if cls .w > 1 :
920+ for member in client_context .ismaster ['hosts' ]:
921+ if member != client_context .ismaster ['primary' ]:
922+ cls .secondary = MongoClient (* partition_node (member ))
923+ break
924+
925+ # We tested wtimeout errors by specifying a write concern greater than
926+ # the number of members, but in MongoDB 2.7.8+ this causes a different
927+ # sort of error, "Not enough data-bearing nodes". In recent servers we
928+ # use a failpoint to pause replication on a secondary.
929+ cls .need_replication_stopped = client_context .version .at_least (2 , 7 , 8 )
930+
931+ def cause_wtimeout (self , batch ):
932+ if self .need_replication_stopped :
933+ if not client_context .test_commands_enabled :
934+ raise SkipTest ("Test commands must be enabled." )
935+
936+ self .secondary .admin .command ('configureFailPoint' ,
937+ 'rsSyncApplyStop' ,
938+ mode = 'alwaysOn' )
939+
940+ try :
941+ return batch .execute ({'w' : self .w , 'wtimeout' : 1 })
942+ finally :
943+ self .secondary .admin .command ('configureFailPoint' ,
944+ 'rsSyncApplyStop' ,
945+ mode = 'off' )
946+ else :
947+ return batch .execute ({'w' : self .w + 1 , 'wtimeout' : 1 })
912948
913949 @client_context .require_version_min (1 , 8 , 2 )
914950 def test_fsync_and_j (self ):
@@ -932,7 +968,7 @@ def test_write_concern_failure_ordered(self):
932968 # Replication wtimeout is a 'soft' error.
933969 # It shouldn't stop batch processing.
934970 try :
935- batch . execute ({ 'w' : self .w + 1 , 'wtimeout' : 1 } )
971+ self .cause_wtimeout ( batch )
936972 except BulkWriteError as exc :
937973 result = exc .details
938974 self .assertEqual (exc .code , 65 )
@@ -969,7 +1005,7 @@ def test_write_concern_failure_ordered(self):
9691005 batch .insert ({'a' : 1 })
9701006 batch .insert ({'a' : 2 })
9711007 try :
972- batch . execute ({ 'w' : self .w + 1 , 'wtimeout' : 1 } )
1008+ self .cause_wtimeout ( batch )
9731009 except BulkWriteError as exc :
9741010 result = exc .details
9751011 self .assertEqual (exc .code , 65 )
@@ -1011,7 +1047,7 @@ def test_write_concern_failure_unordered(self):
10111047 # Replication wtimeout is a 'soft' error.
10121048 # It shouldn't stop batch processing.
10131049 try :
1014- batch . execute ({ 'w' : self .w + 1 , 'wtimeout' : 1 } )
1050+ self .cause_wtimeout ( batch )
10151051 except BulkWriteError as exc :
10161052 result = exc .details
10171053 self .assertEqual (exc .code , 65 )
@@ -1038,7 +1074,7 @@ def test_write_concern_failure_unordered(self):
10381074 batch .insert ({'a' : 1 })
10391075 batch .insert ({'a' : 2 })
10401076 try :
1041- batch . execute ({ 'w' : self .w + 1 , 'wtimeout' : 1 } )
1077+ self .cause_wtimeout ( batch )
10421078 except BulkWriteError as exc :
10431079 result = exc .details
10441080 self .assertEqual (exc .code , 65 )
0 commit comments