diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2cf15a9838..7e35063af6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -387,6 +387,11 @@ If you are running one of the `no-responder` tests, omit the `run-server` step. To run any of the test suites with minimum supported dependencies, pass `--test-min-deps` to `just setup-tests`. +## Testing time-dependent operations + +- `test.utils_shared.delay` - One can trigger an arbitrarily long-running operation on the server using this delay utility + in combination with a `$where` operation. Use this to test behaviors around timeouts or signals. + ## Adding a new test suite - If adding new tests files that should only be run for that test suite, add a pytest marker to the file and add diff --git a/test/utils_shared.py b/test/utils_shared.py index 72fb943fc1..70a195215a 100644 --- a/test/utils_shared.py +++ b/test/utils_shared.py @@ -377,7 +377,50 @@ def oid_generated_on_process(oid): def delay(sec): - return """function() { sleep(%f * 1000); return true; }""" % sec + """Along with a ``$where`` operator, this triggers an arbitrarily long-running + operation on the server. + + This can be useful in time-sensitive tests (e.g., timeouts, signals). + Note that you must have at least one document in the collection or the + server may decide not to sleep at all. + + Example + ------- + + .. code-block:: python + + db.coll.insert_one({"x": 1}) + db.test.find_one({"x": 1}) + # {'x': 1, '_id': ObjectId('54f4e12bfba5220aa4d6dee8')} + + # The following will wait 2.5 seconds before returning. + db.test.find_one({"$where": delay(2.5)}) + # {'x': 1, '_id': ObjectId('54f4e12bfba5220aa4d6dee8')} + + Using ``delay`` to provoke a KeyboardInterrupt + ---------------------------------------------- + + .. code-block:: python + + import signal + + # Raise KeyboardInterrupt in 1 second + def sigalarm(num, frame): + raise KeyboardInterrupt + + + signal.signal(signal.SIGALRM, sigalarm) + signal.alarm(1) + + raised = False + try: + clxn.find_one({"$where": delay(1.5)}) + except KeyboardInterrupt: + raised = True + + assert raised + """ + return "function() { sleep(%f * 1000); return true; }" % sec def camel_to_snake(camel):