mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 21:51:50 +00:00 
			
		
		
		
	gh-110088, gh-109878: Fix test_asyncio timeouts (#110092)
Fix test_asyncio timeouts: don't measure the maximum duration, a test should not measure a CI performance. Only measure the minimum duration when a task has a timeout or delay. Add CLOCK_RES to test_asyncio.utils.
This commit is contained in:
		
							parent
							
								
									e27adc68cc
								
							
						
					
					
						commit
						db0a258e79
					
				
					 7 changed files with 19 additions and 54 deletions
				
			
		|  | @ -273,7 +273,7 @@ def cb(): | ||||||
|             self.loop.stop() |             self.loop.stop() | ||||||
| 
 | 
 | ||||||
|         self.loop._process_events = mock.Mock() |         self.loop._process_events = mock.Mock() | ||||||
|         delay = 0.1 |         delay = 0.100 | ||||||
| 
 | 
 | ||||||
|         when = self.loop.time() + delay |         when = self.loop.time() + delay | ||||||
|         self.loop.call_at(when, cb) |         self.loop.call_at(when, cb) | ||||||
|  | @ -282,10 +282,7 @@ def cb(): | ||||||
|         dt = self.loop.time() - t0 |         dt = self.loop.time() - t0 | ||||||
| 
 | 
 | ||||||
|         # 50 ms: maximum granularity of the event loop |         # 50 ms: maximum granularity of the event loop | ||||||
|         self.assertGreaterEqual(dt, delay - 0.050, dt) |         self.assertGreaterEqual(dt, delay - test_utils.CLOCK_RES) | ||||||
|         # tolerate a difference of +800 ms because some Python buildbots |  | ||||||
|         # are really slow |  | ||||||
|         self.assertLessEqual(dt, 0.9, dt) |  | ||||||
|         with self.assertRaises(TypeError, msg="when cannot be None"): |         with self.assertRaises(TypeError, msg="when cannot be None"): | ||||||
|             self.loop.call_at(None, cb) |             self.loop.call_at(None, cb) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -293,10 +293,11 @@ async def coro2(): | ||||||
|     # 15.6 msec, we use fairly long sleep times here (~100 msec). |     # 15.6 msec, we use fairly long sleep times here (~100 msec). | ||||||
| 
 | 
 | ||||||
|     def test_run_until_complete(self): |     def test_run_until_complete(self): | ||||||
|  |         delay = 0.100 | ||||||
|         t0 = self.loop.time() |         t0 = self.loop.time() | ||||||
|         self.loop.run_until_complete(asyncio.sleep(0.1)) |         self.loop.run_until_complete(asyncio.sleep(delay)) | ||||||
|         t1 = self.loop.time() |         dt = self.loop.time() - t0 | ||||||
|         self.assertTrue(0.08 <= t1-t0 <= 0.8, t1-t0) |         self.assertGreaterEqual(dt, delay - test_utils.CLOCK_RES) | ||||||
| 
 | 
 | ||||||
|     def test_run_until_complete_stopped(self): |     def test_run_until_complete_stopped(self): | ||||||
| 
 | 
 | ||||||
|  | @ -1717,7 +1718,6 @@ def _run_once(): | ||||||
|         self.loop._run_once = _run_once |         self.loop._run_once = _run_once | ||||||
| 
 | 
 | ||||||
|         async def wait(): |         async def wait(): | ||||||
|             loop = self.loop |  | ||||||
|             await asyncio.sleep(1e-2) |             await asyncio.sleep(1e-2) | ||||||
|             await asyncio.sleep(1e-4) |             await asyncio.sleep(1e-4) | ||||||
|             await asyncio.sleep(1e-6) |             await asyncio.sleep(1e-6) | ||||||
|  |  | ||||||
|  | @ -46,7 +46,6 @@ async def test_nested_timeouts(self): | ||||||
|         self.assertTrue(cm2.expired()) |         self.assertTrue(cm2.expired()) | ||||||
| 
 | 
 | ||||||
|     async def test_waiter_cancelled(self): |     async def test_waiter_cancelled(self): | ||||||
|         loop = asyncio.get_running_loop() |  | ||||||
|         cancelled = False |         cancelled = False | ||||||
|         with self.assertRaises(TimeoutError): |         with self.assertRaises(TimeoutError): | ||||||
|             async with asyncio.timeout(0.01): |             async with asyncio.timeout(0.01): | ||||||
|  | @ -59,39 +58,26 @@ async def test_waiter_cancelled(self): | ||||||
| 
 | 
 | ||||||
|     async def test_timeout_not_called(self): |     async def test_timeout_not_called(self): | ||||||
|         loop = asyncio.get_running_loop() |         loop = asyncio.get_running_loop() | ||||||
|         t0 = loop.time() |  | ||||||
|         async with asyncio.timeout(10) as cm: |         async with asyncio.timeout(10) as cm: | ||||||
|             await asyncio.sleep(0.01) |             await asyncio.sleep(0.01) | ||||||
|         t1 = loop.time() |         t1 = loop.time() | ||||||
| 
 | 
 | ||||||
|         self.assertFalse(cm.expired()) |         self.assertFalse(cm.expired()) | ||||||
|         # 2 sec for slow CI boxes |  | ||||||
|         self.assertLess(t1-t0, 2) |  | ||||||
|         self.assertGreater(cm.when(), t1) |         self.assertGreater(cm.when(), t1) | ||||||
| 
 | 
 | ||||||
|     async def test_timeout_disabled(self): |     async def test_timeout_disabled(self): | ||||||
|         loop = asyncio.get_running_loop() |  | ||||||
|         t0 = loop.time() |  | ||||||
|         async with asyncio.timeout(None) as cm: |         async with asyncio.timeout(None) as cm: | ||||||
|             await asyncio.sleep(0.01) |             await asyncio.sleep(0.01) | ||||||
|         t1 = loop.time() |  | ||||||
| 
 | 
 | ||||||
|         self.assertFalse(cm.expired()) |         self.assertFalse(cm.expired()) | ||||||
|         self.assertIsNone(cm.when()) |         self.assertIsNone(cm.when()) | ||||||
|         # 2 sec for slow CI boxes |  | ||||||
|         self.assertLess(t1-t0, 2) |  | ||||||
| 
 | 
 | ||||||
|     async def test_timeout_at_disabled(self): |     async def test_timeout_at_disabled(self): | ||||||
|         loop = asyncio.get_running_loop() |  | ||||||
|         t0 = loop.time() |  | ||||||
|         async with asyncio.timeout_at(None) as cm: |         async with asyncio.timeout_at(None) as cm: | ||||||
|             await asyncio.sleep(0.01) |             await asyncio.sleep(0.01) | ||||||
|         t1 = loop.time() |  | ||||||
| 
 | 
 | ||||||
|         self.assertFalse(cm.expired()) |         self.assertFalse(cm.expired()) | ||||||
|         self.assertIsNone(cm.when()) |         self.assertIsNone(cm.when()) | ||||||
|         # 2 sec for slow CI boxes |  | ||||||
|         self.assertLess(t1-t0, 2) |  | ||||||
| 
 | 
 | ||||||
|     async def test_timeout_zero(self): |     async def test_timeout_zero(self): | ||||||
|         loop = asyncio.get_running_loop() |         loop = asyncio.get_running_loop() | ||||||
|  | @ -101,8 +87,6 @@ async def test_timeout_zero(self): | ||||||
|                 await asyncio.sleep(10) |                 await asyncio.sleep(10) | ||||||
|         t1 = loop.time() |         t1 = loop.time() | ||||||
|         self.assertTrue(cm.expired()) |         self.assertTrue(cm.expired()) | ||||||
|         # 2 sec for slow CI boxes |  | ||||||
|         self.assertLess(t1-t0, 2) |  | ||||||
|         self.assertTrue(t0 <= cm.when() <= t1) |         self.assertTrue(t0 <= cm.when() <= t1) | ||||||
| 
 | 
 | ||||||
|     async def test_timeout_zero_sleep_zero(self): |     async def test_timeout_zero_sleep_zero(self): | ||||||
|  | @ -113,8 +97,6 @@ async def test_timeout_zero_sleep_zero(self): | ||||||
|                 await asyncio.sleep(0) |                 await asyncio.sleep(0) | ||||||
|         t1 = loop.time() |         t1 = loop.time() | ||||||
|         self.assertTrue(cm.expired()) |         self.assertTrue(cm.expired()) | ||||||
|         # 2 sec for slow CI boxes |  | ||||||
|         self.assertLess(t1-t0, 2) |  | ||||||
|         self.assertTrue(t0 <= cm.when() <= t1) |         self.assertTrue(t0 <= cm.when() <= t1) | ||||||
| 
 | 
 | ||||||
|     async def test_timeout_in_the_past_sleep_zero(self): |     async def test_timeout_in_the_past_sleep_zero(self): | ||||||
|  | @ -125,8 +107,6 @@ async def test_timeout_in_the_past_sleep_zero(self): | ||||||
|                 await asyncio.sleep(0) |                 await asyncio.sleep(0) | ||||||
|         t1 = loop.time() |         t1 = loop.time() | ||||||
|         self.assertTrue(cm.expired()) |         self.assertTrue(cm.expired()) | ||||||
|         # 2 sec for slow CI boxes |  | ||||||
|         self.assertLess(t1-t0, 2) |  | ||||||
|         self.assertTrue(t0 >= cm.when() <= t1) |         self.assertTrue(t0 >= cm.when() <= t1) | ||||||
| 
 | 
 | ||||||
|     async def test_foreign_exception_passed(self): |     async def test_foreign_exception_passed(self): | ||||||
|  |  | ||||||
|  | @ -66,17 +66,12 @@ async def test_wait_for_timeout_less_then_0_or_0_future_done(self): | ||||||
|         fut = loop.create_future() |         fut = loop.create_future() | ||||||
|         fut.set_result('done') |         fut.set_result('done') | ||||||
| 
 | 
 | ||||||
|         t0 = loop.time() |  | ||||||
|         ret = await asyncio.wait_for(fut, 0) |         ret = await asyncio.wait_for(fut, 0) | ||||||
|         t1 = loop.time() |  | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(ret, 'done') |         self.assertEqual(ret, 'done') | ||||||
|         self.assertTrue(fut.done()) |         self.assertTrue(fut.done()) | ||||||
|         self.assertLess(t1 - t0, 0.1) |  | ||||||
| 
 | 
 | ||||||
|     async def test_wait_for_timeout_less_then_0_or_0_coroutine_do_not_started(self): |     async def test_wait_for_timeout_less_then_0_or_0_coroutine_do_not_started(self): | ||||||
|         loop = asyncio.get_running_loop() |  | ||||||
| 
 |  | ||||||
|         foo_started = False |         foo_started = False | ||||||
| 
 | 
 | ||||||
|         async def foo(): |         async def foo(): | ||||||
|  | @ -84,12 +79,9 @@ async def foo(): | ||||||
|             foo_started = True |             foo_started = True | ||||||
| 
 | 
 | ||||||
|         with self.assertRaises(asyncio.TimeoutError): |         with self.assertRaises(asyncio.TimeoutError): | ||||||
|             t0 = loop.time() |  | ||||||
|             await asyncio.wait_for(foo(), 0) |             await asyncio.wait_for(foo(), 0) | ||||||
|         t1 = loop.time() |  | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(foo_started, False) |         self.assertEqual(foo_started, False) | ||||||
|         self.assertLess(t1 - t0, 0.1) |  | ||||||
| 
 | 
 | ||||||
|     async def test_wait_for_timeout_less_then_0_or_0(self): |     async def test_wait_for_timeout_less_then_0_or_0(self): | ||||||
|         loop = asyncio.get_running_loop() |         loop = asyncio.get_running_loop() | ||||||
|  | @ -113,18 +105,14 @@ async def foo(): | ||||||
|                 await started |                 await started | ||||||
| 
 | 
 | ||||||
|                 with self.assertRaises(asyncio.TimeoutError): |                 with self.assertRaises(asyncio.TimeoutError): | ||||||
|                     t0 = loop.time() |  | ||||||
|                     await asyncio.wait_for(fut, timeout) |                     await asyncio.wait_for(fut, timeout) | ||||||
|                 t1 = loop.time() |  | ||||||
| 
 | 
 | ||||||
|                 self.assertTrue(fut.done()) |                 self.assertTrue(fut.done()) | ||||||
|                 # it should have been cancelled due to the timeout |                 # it should have been cancelled due to the timeout | ||||||
|                 self.assertTrue(fut.cancelled()) |                 self.assertTrue(fut.cancelled()) | ||||||
|                 self.assertEqual(foo_running, False) |                 self.assertEqual(foo_running, False) | ||||||
|                 self.assertLess(t1 - t0, 0.1) |  | ||||||
| 
 | 
 | ||||||
|     async def test_wait_for(self): |     async def test_wait_for(self): | ||||||
|         loop = asyncio.get_running_loop() |  | ||||||
|         foo_running = None |         foo_running = None | ||||||
| 
 | 
 | ||||||
|         async def foo(): |         async def foo(): | ||||||
|  | @ -139,13 +127,10 @@ async def foo(): | ||||||
|         fut = asyncio.create_task(foo()) |         fut = asyncio.create_task(foo()) | ||||||
| 
 | 
 | ||||||
|         with self.assertRaises(asyncio.TimeoutError): |         with self.assertRaises(asyncio.TimeoutError): | ||||||
|             t0 = loop.time() |  | ||||||
|             await asyncio.wait_for(fut, 0.1) |             await asyncio.wait_for(fut, 0.1) | ||||||
|         t1 = loop.time() |  | ||||||
|         self.assertTrue(fut.done()) |         self.assertTrue(fut.done()) | ||||||
|         # it should have been cancelled due to the timeout |         # it should have been cancelled due to the timeout | ||||||
|         self.assertTrue(fut.cancelled()) |         self.assertTrue(fut.cancelled()) | ||||||
|         self.assertLess(t1 - t0, support.SHORT_TIMEOUT) |  | ||||||
|         self.assertEqual(foo_running, False) |         self.assertEqual(foo_running, False) | ||||||
| 
 | 
 | ||||||
|     async def test_wait_for_blocking(self): |     async def test_wait_for_blocking(self): | ||||||
|  |  | ||||||
|  | @ -163,29 +163,25 @@ def test_wait_for_handle(self): | ||||||
| 
 | 
 | ||||||
|         # Wait for unset event with 0.5s timeout; |         # Wait for unset event with 0.5s timeout; | ||||||
|         # result should be False at timeout |         # result should be False at timeout | ||||||
|         fut = self.loop._proactor.wait_for_handle(event, 0.5) |         timeout = 0.5 | ||||||
|  |         fut = self.loop._proactor.wait_for_handle(event, timeout) | ||||||
|         start = self.loop.time() |         start = self.loop.time() | ||||||
|         done = self.loop.run_until_complete(fut) |         done = self.loop.run_until_complete(fut) | ||||||
|         elapsed = self.loop.time() - start |         elapsed = self.loop.time() - start | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(done, False) |         self.assertEqual(done, False) | ||||||
|         self.assertFalse(fut.result()) |         self.assertFalse(fut.result()) | ||||||
|         # bpo-31008: Tolerate only 450 ms (at least 500 ms expected), |         self.assertGreaterEqual(elapsed, timeout - test_utils.CLOCK_RES) | ||||||
|         # because of bad clock resolution on Windows |  | ||||||
|         self.assertTrue(0.45 <= elapsed <= 0.9, elapsed) |  | ||||||
| 
 | 
 | ||||||
|         _overlapped.SetEvent(event) |         _overlapped.SetEvent(event) | ||||||
| 
 | 
 | ||||||
|         # Wait for set event; |         # Wait for set event; | ||||||
|         # result should be True immediately |         # result should be True immediately | ||||||
|         fut = self.loop._proactor.wait_for_handle(event, 10) |         fut = self.loop._proactor.wait_for_handle(event, 10) | ||||||
|         start = self.loop.time() |  | ||||||
|         done = self.loop.run_until_complete(fut) |         done = self.loop.run_until_complete(fut) | ||||||
|         elapsed = self.loop.time() - start |  | ||||||
| 
 | 
 | ||||||
|         self.assertEqual(done, True) |         self.assertEqual(done, True) | ||||||
|         self.assertTrue(fut.result()) |         self.assertTrue(fut.result()) | ||||||
|         self.assertTrue(0 <= elapsed < 0.3, elapsed) |  | ||||||
| 
 | 
 | ||||||
|         # asyncio issue #195: cancelling a done _WaitHandleFuture |         # asyncio issue #195: cancelling a done _WaitHandleFuture | ||||||
|         # must not crash |         # must not crash | ||||||
|  | @ -199,11 +195,8 @@ def test_wait_for_handle_cancel(self): | ||||||
|         # CancelledError should be raised immediately |         # CancelledError should be raised immediately | ||||||
|         fut = self.loop._proactor.wait_for_handle(event, 10) |         fut = self.loop._proactor.wait_for_handle(event, 10) | ||||||
|         fut.cancel() |         fut.cancel() | ||||||
|         start = self.loop.time() |  | ||||||
|         with self.assertRaises(asyncio.CancelledError): |         with self.assertRaises(asyncio.CancelledError): | ||||||
|             self.loop.run_until_complete(fut) |             self.loop.run_until_complete(fut) | ||||||
|         elapsed = self.loop.time() - start |  | ||||||
|         self.assertTrue(0 <= elapsed < 0.1, elapsed) |  | ||||||
| 
 | 
 | ||||||
|         # asyncio issue #195: cancelling a _WaitHandleFuture twice |         # asyncio issue #195: cancelling a _WaitHandleFuture twice | ||||||
|         # must not crash |         # must not crash | ||||||
|  |  | ||||||
|  | @ -36,6 +36,12 @@ | ||||||
| from test.support import threading_helper | from test.support import threading_helper | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | # Use the maximum known clock resolution (gh-75191, gh-110088): Windows | ||||||
|  | # GetTickCount64() has a resolution of 15.6 ms.  Use 20 ms to tolerate rounding | ||||||
|  | # issues. | ||||||
|  | CLOCK_RES = 0.020 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| def data_file(*filename): | def data_file(*filename): | ||||||
|     fullname = os.path.join(support.TEST_HOME_DIR, *filename) |     fullname = os.path.join(support.TEST_HOME_DIR, *filename) | ||||||
|     if os.path.isfile(fullname): |     if os.path.isfile(fullname): | ||||||
|  |  | ||||||
|  | @ -0,0 +1,4 @@ | ||||||
|  | Fix test_asyncio timeouts: don't measure the maximum duration, a test should | ||||||
|  | not measure a CI performance. Only measure the minimum duration when a task has | ||||||
|  | a timeout or delay. Add ``CLOCK_RES`` to ``test_asyncio.utils``. Patch by | ||||||
|  | Victor Stinner. | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Victor Stinner
						Victor Stinner