|
16 | 16 |
|
17 | 17 | import datetime
|
18 | 18 | import os
|
19 |
| -import threading |
| 19 | +import signal |
20 | 20 | import socket
|
21 | 21 | import sys
|
22 |
| -import time |
23 | 22 | import thread
|
| 23 | +import threading |
| 24 | +import time |
24 | 25 | import unittest
|
25 | 26 | import warnings
|
26 | 27 |
|
@@ -935,31 +936,53 @@ def test_interrupt_signal(self):
|
935 | 936 | db.drop_collection('foo')
|
936 | 937 | db.foo.insert({'_id': 1})
|
937 | 938 |
|
938 |
| - def interrupter(): |
939 |
| - # Raises KeyboardInterrupt in the main thread |
940 |
| - time.sleep(0.25) |
941 |
| - thread.interrupt_main() |
942 |
| - |
943 |
| - thread.start_new_thread(interrupter, ()) |
944 |
| - |
945 |
| - raised = False |
| 939 | + old_signal_handler = None |
946 | 940 | try:
|
947 |
| - # Will be interrupted by a KeyboardInterrupt. |
948 |
| - db.foo.find({'$where': where}).next() |
949 |
| - except KeyboardInterrupt: |
950 |
| - raised = True |
951 |
| - |
952 |
| - # Can't use self.assertRaises() because it doesn't catch system |
953 |
| - # exceptions |
954 |
| - self.assertTrue(raised, "Didn't raise expected KeyboardInterrupt") |
955 |
| - |
956 |
| - # Raises AssertionError due to PYTHON-294 -- Mongo's response to the |
957 |
| - # previous find() is still waiting to be read on the socket, so the |
958 |
| - # request id's don't match. |
959 |
| - self.assertEqual( |
960 |
| - {'_id': 1}, |
961 |
| - db.foo.find().next() |
962 |
| - ) |
| 941 | + # Platform-specific hacks for raising a KeyboardInterrupt on the |
| 942 | + # main thread while find() is in-progress: On Windows, SIGALRM is |
| 943 | + # unavailable so we use a second thread. In our Evergreen setup on |
| 944 | + # Linux, the thread technique causes an error in the test at |
| 945 | + # sock.recv(): TypeError: 'int' object is not callable |
| 946 | + # We don't know what causes this, so we hack around it. |
| 947 | + |
| 948 | + if sys.platform == 'win32': |
| 949 | + def interrupter(): |
| 950 | + # Raises KeyboardInterrupt in the main thread |
| 951 | + time.sleep(0.25) |
| 952 | + thread.interrupt_main() |
| 953 | + |
| 954 | + thread.start_new_thread(interrupter, ()) |
| 955 | + else: |
| 956 | + # Convert SIGALRM to SIGINT -- it's hard to schedule a SIGINT |
| 957 | + # for one second in the future, but easy to schedule SIGALRM. |
| 958 | + def sigalarm(num, frame): |
| 959 | + raise KeyboardInterrupt |
| 960 | + |
| 961 | + old_signal_handler = signal.signal(signal.SIGALRM, sigalarm) |
| 962 | + signal.alarm(1) |
| 963 | + |
| 964 | + raised = False |
| 965 | + try: |
| 966 | + # Will be interrupted by a KeyboardInterrupt. |
| 967 | + db.foo.find({'$where': where}).next() |
| 968 | + except KeyboardInterrupt: |
| 969 | + raised = True |
| 970 | + |
| 971 | + # Can't use self.assertRaises() because it doesn't catch system |
| 972 | + # exceptions |
| 973 | + self.assertTrue(raised, "Didn't raise expected KeyboardInterrupt") |
| 974 | + |
| 975 | + # Raises AssertionError due to PYTHON-294 -- Mongo's response to |
| 976 | + # the previous find() is still waiting to be read on the socket, |
| 977 | + # so the request id's don't match. |
| 978 | + self.assertEqual( |
| 979 | + {'_id': 1}, |
| 980 | + db.foo.find().next() |
| 981 | + ) |
| 982 | + finally: |
| 983 | + if old_signal_handler: |
| 984 | + signal.signal(signal.SIGALRM, old_signal_handler) |
| 985 | + |
963 | 986 |
|
964 | 987 | def test_operation_failure_without_request(self):
|
965 | 988 | # Ensure MongoClient doesn't close socket after it gets an error
|
|
0 commit comments