blob: e15ee39427a7054fe628c24c9ebe5dd41baa09ae [file] [log] [blame]
Mark Hammond3b959db2002-04-19 00:11:32 +00001# Some simple Queue module tests, plus some failure conditions
Tim Petersafe52972004-08-20 02:37:25 +00002# to ensure the Queue locks remain stable.
Mark Hammond3b959db2002-04-19 00:11:32 +00003import Queue
4import sys
5import threading
6import time
7
Barry Warsaw04f357c2002-07-23 19:04:11 +00008from test.test_support import verify, TestFailed, verbose
Mark Hammond3b959db2002-04-19 00:11:32 +00009
Tim Petersafe52972004-08-20 02:37:25 +000010QUEUE_SIZE = 5
Mark Hammond3b959db2002-04-19 00:11:32 +000011
Raymond Hettingerda3caed2008-01-14 21:39:24 +000012def qfull(q):
13 return q.maxsize > 0 and q.qsize() == q.maxsize
14
Tim Petersafe52972004-08-20 02:37:25 +000015# A thread to run a function that unclogs a blocked Queue.
Mark Hammond3b959db2002-04-19 00:11:32 +000016class _TriggerThread(threading.Thread):
17 def __init__(self, fn, args):
18 self.fn = fn
19 self.args = args
20 self.startedEvent = threading.Event()
21 threading.Thread.__init__(self)
Tim Petersafe52972004-08-20 02:37:25 +000022
Mark Hammond3b959db2002-04-19 00:11:32 +000023 def run(self):
Tim Peters8d7626c2004-08-20 03:27:12 +000024 # The sleep isn't necessary, but is intended to give the blocking
25 # function in the main thread a chance at actually blocking before
26 # we unclog it. But if the sleep is longer than the timeout-based
27 # tests wait in their blocking functions, those tests will fail.
28 # So we give them much longer timeout values compared to the
29 # sleep here (I aimed at 10 seconds for blocking functions --
30 # they should never actually wait that long - they should make
31 # progress as soon as we call self.fn()).
32 time.sleep(0.1)
Mark Hammond3b959db2002-04-19 00:11:32 +000033 self.startedEvent.set()
34 self.fn(*self.args)
35
Tim Peters8d7626c2004-08-20 03:27:12 +000036# Execute a function that blocks, and in a separate thread, a function that
Tim Petersafe52972004-08-20 02:37:25 +000037# triggers the release. Returns the result of the blocking function.
Tim Peters8d7626c2004-08-20 03:27:12 +000038# Caution: block_func must guarantee to block until trigger_func is
39# called, and trigger_func must guarantee to change queue state so that
40# block_func can make enough progress to return. In particular, a
41# block_func that just raises an exception regardless of whether trigger_func
42# is called will lead to timing-dependent sporadic failures, and one of
43# those went rarely seen but undiagnosed for years. Now block_func
44# must be unexceptional. If block_func is supposed to raise an exception,
45# call _doExceptionalBlockingTest() instead.
Tim Petersa1d004a2002-11-15 19:08:50 +000046def _doBlockingTest(block_func, block_args, trigger_func, trigger_args):
Mark Hammond3b959db2002-04-19 00:11:32 +000047 t = _TriggerThread(trigger_func, trigger_args)
48 t.start()
Tim Peters8d7626c2004-08-20 03:27:12 +000049 result = block_func(*block_args)
50 # If block_func returned before our thread made the call, we failed!
51 if not t.startedEvent.isSet():
52 raise TestFailed("blocking function '%r' appeared not to block" %
53 block_func)
54 t.join(10) # make sure the thread terminates
55 if t.isAlive():
56 raise TestFailed("trigger function '%r' appeared to not return" %
57 trigger_func)
58 return result
59
60# Call this instead if block_func is supposed to raise an exception.
61def _doExceptionalBlockingTest(block_func, block_args, trigger_func,
62 trigger_args, expected_exception_class):
63 t = _TriggerThread(trigger_func, trigger_args)
64 t.start()
Mark Hammond3b959db2002-04-19 00:11:32 +000065 try:
Tim Peters8d7626c2004-08-20 03:27:12 +000066 try:
67 block_func(*block_args)
68 except expected_exception_class:
69 raise
70 else:
71 raise TestFailed("expected exception of kind %r" %
72 expected_exception_class)
Mark Hammond3b959db2002-04-19 00:11:32 +000073 finally:
Tim Peters8d7626c2004-08-20 03:27:12 +000074 t.join(10) # make sure the thread terminates
Mark Hammond3b959db2002-04-19 00:11:32 +000075 if t.isAlive():
Tim Petersa1d004a2002-11-15 19:08:50 +000076 raise TestFailed("trigger function '%r' appeared to not return" %
77 trigger_func)
Tim Peters8d7626c2004-08-20 03:27:12 +000078 if not t.startedEvent.isSet():
79 raise TestFailed("trigger thread ended but event never set")
Mark Hammond3b959db2002-04-19 00:11:32 +000080
81# A Queue subclass that can provoke failure at a moment's notice :)
82class FailingQueueException(Exception):
83 pass
84
85class FailingQueue(Queue.Queue):
86 def __init__(self, *args):
87 self.fail_next_put = False
88 self.fail_next_get = False
89 Queue.Queue.__init__(self, *args)
90 def _put(self, item):
91 if self.fail_next_put:
92 self.fail_next_put = False
Collin Winter3add4d72007-08-29 23:37:32 +000093 raise FailingQueueException("You Lose")
Mark Hammond3b959db2002-04-19 00:11:32 +000094 return Queue.Queue._put(self, item)
95 def _get(self):
96 if self.fail_next_get:
97 self.fail_next_get = False
Collin Winter3add4d72007-08-29 23:37:32 +000098 raise FailingQueueException("You Lose")
Mark Hammond3b959db2002-04-19 00:11:32 +000099 return Queue.Queue._get(self)
100
101def FailingQueueTest(q):
Raymond Hettingerda3caed2008-01-14 21:39:24 +0000102 if q.qsize():
Collin Winter3add4d72007-08-29 23:37:32 +0000103 raise RuntimeError("Call this function with an empty queue")
Tim Petersafe52972004-08-20 02:37:25 +0000104 for i in range(QUEUE_SIZE-1):
Mark Hammond3b959db2002-04-19 00:11:32 +0000105 q.put(i)
Mark Hammond3b959db2002-04-19 00:11:32 +0000106 # Test a failing non-blocking put.
Martin v. Löwis77ac4292002-10-15 15:11:13 +0000107 q.fail_next_put = True
Mark Hammond3b959db2002-04-19 00:11:32 +0000108 try:
109 q.put("oops", block=0)
110 raise TestFailed("The queue didn't fail when it should have")
111 except FailingQueueException:
112 pass
Martin v. Löwis77ac4292002-10-15 15:11:13 +0000113 q.fail_next_put = True
114 try:
115 q.put("oops", timeout=0.1)
116 raise TestFailed("The queue didn't fail when it should have")
117 except FailingQueueException:
118 pass
Mark Hammond3b959db2002-04-19 00:11:32 +0000119 q.put("last")
Raymond Hettingerda3caed2008-01-14 21:39:24 +0000120 verify(qfull(q), "Queue should be full")
Mark Hammond3b959db2002-04-19 00:11:32 +0000121 # Test a failing blocking put
Martin v. Löwis77ac4292002-10-15 15:11:13 +0000122 q.fail_next_put = True
Mark Hammond3b959db2002-04-19 00:11:32 +0000123 try:
Tim Petersafe52972004-08-20 02:37:25 +0000124 _doBlockingTest(q.put, ("full",), q.get, ())
Mark Hammond3b959db2002-04-19 00:11:32 +0000125 raise TestFailed("The queue didn't fail when it should have")
126 except FailingQueueException:
127 pass
128 # Check the Queue isn't damaged.
129 # put failed, but get succeeded - re-add
130 q.put("last")
Martin v. Löwis77ac4292002-10-15 15:11:13 +0000131 # Test a failing timeout put
132 q.fail_next_put = True
133 try:
Tim Peters8d7626c2004-08-20 03:27:12 +0000134 _doExceptionalBlockingTest(q.put, ("full", True, 10), q.get, (),
135 FailingQueueException)
Martin v. Löwis77ac4292002-10-15 15:11:13 +0000136 raise TestFailed("The queue didn't fail when it should have")
137 except FailingQueueException:
138 pass
139 # Check the Queue isn't damaged.
140 # put failed, but get succeeded - re-add
141 q.put("last")
Raymond Hettingerda3caed2008-01-14 21:39:24 +0000142 verify(qfull(q), "Queue should be full")
Mark Hammond3b959db2002-04-19 00:11:32 +0000143 q.get()
Raymond Hettingerda3caed2008-01-14 21:39:24 +0000144 verify(not qfull(q), "Queue should not be full")
Mark Hammond3b959db2002-04-19 00:11:32 +0000145 q.put("last")
Raymond Hettingerda3caed2008-01-14 21:39:24 +0000146 verify(qfull(q), "Queue should be full")
Mark Hammond3b959db2002-04-19 00:11:32 +0000147 # Test a blocking put
148 _doBlockingTest( q.put, ("full",), q.get, ())
149 # Empty it
Tim Petersafe52972004-08-20 02:37:25 +0000150 for i in range(QUEUE_SIZE):
Mark Hammond3b959db2002-04-19 00:11:32 +0000151 q.get()
Raymond Hettingerda3caed2008-01-14 21:39:24 +0000152 verify(not q.qsize(), "Queue should be empty")
Mark Hammond3b959db2002-04-19 00:11:32 +0000153 q.put("first")
154 q.fail_next_get = True
155 try:
156 q.get()
157 raise TestFailed("The queue didn't fail when it should have")
158 except FailingQueueException:
159 pass
Raymond Hettingerda3caed2008-01-14 21:39:24 +0000160 verify(q.qsize(), "Queue should not be empty")
Martin v. Löwis77ac4292002-10-15 15:11:13 +0000161 q.fail_next_get = True
162 try:
163 q.get(timeout=0.1)
164 raise TestFailed("The queue didn't fail when it should have")
165 except FailingQueueException:
166 pass
Raymond Hettingerda3caed2008-01-14 21:39:24 +0000167 verify(q.qsize(), "Queue should not be empty")
Mark Hammond3b959db2002-04-19 00:11:32 +0000168 q.get()
Raymond Hettingerda3caed2008-01-14 21:39:24 +0000169 verify(not q.qsize(), "Queue should be empty")
Mark Hammond3b959db2002-04-19 00:11:32 +0000170 q.fail_next_get = True
171 try:
Tim Peters8d7626c2004-08-20 03:27:12 +0000172 _doExceptionalBlockingTest(q.get, (), q.put, ('empty',),
173 FailingQueueException)
Mark Hammond3b959db2002-04-19 00:11:32 +0000174 raise TestFailed("The queue didn't fail when it should have")
175 except FailingQueueException:
176 pass
177 # put succeeded, but get failed.
Raymond Hettingerda3caed2008-01-14 21:39:24 +0000178 verify(q.qsize(), "Queue should not be empty")
Mark Hammond3b959db2002-04-19 00:11:32 +0000179 q.get()
Raymond Hettingerda3caed2008-01-14 21:39:24 +0000180 verify(not q.qsize(), "Queue should be empty")
Mark Hammond3b959db2002-04-19 00:11:32 +0000181
182def SimpleQueueTest(q):
Raymond Hettingerda3caed2008-01-14 21:39:24 +0000183 if q.qsize():
Collin Winter3add4d72007-08-29 23:37:32 +0000184 raise RuntimeError("Call this function with an empty queue")
Mark Hammond3b959db2002-04-19 00:11:32 +0000185 # I guess we better check things actually queue correctly a little :)
186 q.put(111)
Christian Heimes679db4a2008-01-18 09:56:22 +0000187 q.put(333)
Mark Hammond3b959db2002-04-19 00:11:32 +0000188 q.put(222)
Christian Heimes679db4a2008-01-18 09:56:22 +0000189 target_order = dict(Queue = [111, 333, 222],
190 LifoQueue = [222, 333, 111],
191 PriorityQueue = [111, 222, 333])
192 actual_order = [q.get(), q.get(), q.get()]
193 verify(actual_order == target_order[q.__class__.__name__],
Tim Petersa1d004a2002-11-15 19:08:50 +0000194 "Didn't seem to queue the correct data!")
Tim Petersafe52972004-08-20 02:37:25 +0000195 for i in range(QUEUE_SIZE-1):
Mark Hammond3b959db2002-04-19 00:11:32 +0000196 q.put(i)
Raymond Hettingerda3caed2008-01-14 21:39:24 +0000197 verify(q.qsize(), "Queue should not be empty")
198 verify(not qfull(q), "Queue should not be full")
Christian Heimes679db4a2008-01-18 09:56:22 +0000199 last = 2*QUEUE_SIZE
200 full = 3*2*QUEUE_SIZE
201 q.put(last)
Raymond Hettingerda3caed2008-01-14 21:39:24 +0000202 verify(qfull(q), "Queue should be full")
Mark Hammond3b959db2002-04-19 00:11:32 +0000203 try:
Christian Heimes679db4a2008-01-18 09:56:22 +0000204 q.put(full, block=0)
Mark Hammond3b959db2002-04-19 00:11:32 +0000205 raise TestFailed("Didn't appear to block with a full queue")
206 except Queue.Full:
207 pass
Martin v. Löwis77ac4292002-10-15 15:11:13 +0000208 try:
Christian Heimes679db4a2008-01-18 09:56:22 +0000209 q.put(full, timeout=0.01)
Martin v. Löwis77ac4292002-10-15 15:11:13 +0000210 raise TestFailed("Didn't appear to time-out with a full queue")
211 except Queue.Full:
212 pass
Mark Hammond3b959db2002-04-19 00:11:32 +0000213 # Test a blocking put
Christian Heimes679db4a2008-01-18 09:56:22 +0000214 _doBlockingTest(q.put, (full,), q.get, ())
215 _doBlockingTest(q.put, (full, True, 10), q.get, ())
Mark Hammond3b959db2002-04-19 00:11:32 +0000216 # Empty it
Tim Petersafe52972004-08-20 02:37:25 +0000217 for i in range(QUEUE_SIZE):
Mark Hammond3b959db2002-04-19 00:11:32 +0000218 q.get()
Raymond Hettingerda3caed2008-01-14 21:39:24 +0000219 verify(not q.qsize(), "Queue should be empty")
Mark Hammond3b959db2002-04-19 00:11:32 +0000220 try:
221 q.get(block=0)
222 raise TestFailed("Didn't appear to block with an empty queue")
223 except Queue.Empty:
224 pass
Martin v. Löwis77ac4292002-10-15 15:11:13 +0000225 try:
Tim Peters8d7626c2004-08-20 03:27:12 +0000226 q.get(timeout=0.01)
Martin v. Löwis77ac4292002-10-15 15:11:13 +0000227 raise TestFailed("Didn't appear to time-out with an empty queue")
228 except Queue.Empty:
229 pass
Mark Hammond3b959db2002-04-19 00:11:32 +0000230 # Test a blocking get
Tim Petersa1d004a2002-11-15 19:08:50 +0000231 _doBlockingTest(q.get, (), q.put, ('empty',))
Tim Peters8d7626c2004-08-20 03:27:12 +0000232 _doBlockingTest(q.get, (True, 10), q.put, ('empty',))
Mark Hammond3b959db2002-04-19 00:11:32 +0000233
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000234cum = 0
235cumlock = threading.Lock()
236
237def worker(q):
238 global cum
239 while True:
240 x = q.get()
241 if x is None:
242 q.task_done()
243 return
244 cumlock.acquire()
245 try:
246 cum += x
247 finally:
248 cumlock.release()
249 q.task_done()
250
251def QueueJoinTest(q):
252 global cum
253 cum = 0
254 for i in (0,1):
255 threading.Thread(target=worker, args=(q,)).start()
Guido van Rossum805365e2007-05-07 22:24:25 +0000256 for i in range(100):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000257 q.put(i)
258 q.join()
259 verify(cum==sum(range(100)), "q.join() did not block until all tasks were done")
Christian Heimes679db4a2008-01-18 09:56:22 +0000260 q.put(None) # instruct the threads to close
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000261 q.join() # verify that you can join twice
262
263def QueueTaskDoneTest(q):
264 try:
265 q.task_done()
266 except ValueError:
267 pass
268 else:
269 raise TestFailed("Did not detect task count going negative")
270
Mark Hammond3b959db2002-04-19 00:11:32 +0000271def test():
Christian Heimes679db4a2008-01-18 09:56:22 +0000272 for Q in Queue.Queue, Queue.LifoQueue, Queue.PriorityQueue:
273 q = Q()
274 QueueTaskDoneTest(q)
275 QueueJoinTest(q)
276 QueueJoinTest(q)
277 QueueTaskDoneTest(q)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000278
Christian Heimes679db4a2008-01-18 09:56:22 +0000279 q = Q(QUEUE_SIZE)
280 # Do it a couple of times on the same queue
281 SimpleQueueTest(q)
282 SimpleQueueTest(q)
283 if verbose:
284 print("Simple Queue tests seemed to work for", Q.__name__)
285
Tim Petersafe52972004-08-20 02:37:25 +0000286 q = FailingQueue(QUEUE_SIZE)
Mark Hammond3b959db2002-04-19 00:11:32 +0000287 FailingQueueTest(q)
288 FailingQueueTest(q)
289 if verbose:
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000290 print("Failing Queue tests seemed to work")
Mark Hammond3b959db2002-04-19 00:11:32 +0000291
292test()