1616import os
1717import pathlib
1818import sys
19+ from time import perf_counter
20+ from unittest .mock import patch
21+
22+ from pymongo .errors import OperationFailure
1923
2024sys .path [0 :0 ] = ["" ]
2125
@@ -41,10 +45,57 @@ def setUpClass(cls) -> None:
4145 async def asyncSetUp (self ) -> None :
4246 await super ().asyncSetUp ()
4347 self .listener .reset ()
48+ self .app_name = self .__class__ .__name__ .lower ()
4449 self .client = await self .async_rs_or_single_client (
45- event_listeners = [self .listener ], retryWrites = False
50+ event_listeners = [self .listener ], retryWrites = False , appName = self . app_name
4651 )
4752
53+ @patch ("random.random" )
54+ async def test_01_operation_retry_uses_exponential_backoff (self , random_func ):
55+ # Drivers should test that retries do not occur immediately when a SystemOverloadedError is encountered.
56+
57+ # 1. let `client` be a `MongoClient`
58+ client = self .client
59+
60+ # 2. let `collection` be a collection
61+ collection = client .test .test
62+
63+ # 3. Now, run transactions without backoff:
64+
65+ # a. Configure the random number generator used for jitter to always return `0` -- this effectively disables backoff.
66+ random_func .return_value = 0
67+
68+ # b. Configure the following failPoint:
69+ fail_point = dict (
70+ mode = "alwaysOn" ,
71+ data = dict (
72+ failCommands = ["insert" ],
73+ errorCode = 2 ,
74+ errorLabels = ["SystemOverloadedError" , "RetryableError" ],
75+ appName = self .app_name ,
76+ ),
77+ )
78+ async with self .fail_point (fail_point ):
79+ # c. Execute the following command. Expect that the command errors. Measure the duration of the command execution.
80+ start0 = perf_counter ()
81+ with self .assertRaises (OperationFailure ):
82+ await collection .insert_one ({"a" : 1 })
83+ end0 = perf_counter ()
84+
85+ # d. Configure the random number generator used for jitter to always return `1`.
86+ random_func .return_value = 1
87+
88+ # e. Execute step c again.
89+ start1 = perf_counter ()
90+ with self .assertRaises (OperationFailure ):
91+ await collection .insert_one ({"a" : 1 })
92+ end1 = perf_counter ()
93+
94+ # f. Compare the two time between the two runs.
95+ # The sum of 5 backoffs is 3.1 seconds. There is a 1-second window to account for potential variance between the two
96+ # runs.
97+ self .assertTrue (abs ((end1 - start1 ) - (end0 - start0 + 3.1 )) < 1 )
98+
4899
49100# Location of JSON test specifications.
50101if _IS_SYNC :
0 commit comments