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._process_events = mock.Mock() | ||||
|         delay = 0.1 | ||||
|         delay = 0.100 | ||||
| 
 | ||||
|         when = self.loop.time() + delay | ||||
|         self.loop.call_at(when, cb) | ||||
|  | @ -282,10 +282,7 @@ def cb(): | |||
|         dt = self.loop.time() - t0 | ||||
| 
 | ||||
|         # 50 ms: maximum granularity of the event loop | ||||
|         self.assertGreaterEqual(dt, delay - 0.050, dt) | ||||
|         # tolerate a difference of +800 ms because some Python buildbots | ||||
|         # are really slow | ||||
|         self.assertLessEqual(dt, 0.9, dt) | ||||
|         self.assertGreaterEqual(dt, delay - test_utils.CLOCK_RES) | ||||
|         with self.assertRaises(TypeError, msg="when cannot be None"): | ||||
|             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). | ||||
| 
 | ||||
|     def test_run_until_complete(self): | ||||
|         delay = 0.100 | ||||
|         t0 = self.loop.time() | ||||
|         self.loop.run_until_complete(asyncio.sleep(0.1)) | ||||
|         t1 = self.loop.time() | ||||
|         self.assertTrue(0.08 <= t1-t0 <= 0.8, t1-t0) | ||||
|         self.loop.run_until_complete(asyncio.sleep(delay)) | ||||
|         dt = self.loop.time() - t0 | ||||
|         self.assertGreaterEqual(dt, delay - test_utils.CLOCK_RES) | ||||
| 
 | ||||
|     def test_run_until_complete_stopped(self): | ||||
| 
 | ||||
|  | @ -1717,7 +1718,6 @@ def _run_once(): | |||
|         self.loop._run_once = _run_once | ||||
| 
 | ||||
|         async def wait(): | ||||
|             loop = self.loop | ||||
|             await asyncio.sleep(1e-2) | ||||
|             await asyncio.sleep(1e-4) | ||||
|             await asyncio.sleep(1e-6) | ||||
|  |  | |||
|  | @ -46,7 +46,6 @@ async def test_nested_timeouts(self): | |||
|         self.assertTrue(cm2.expired()) | ||||
| 
 | ||||
|     async def test_waiter_cancelled(self): | ||||
|         loop = asyncio.get_running_loop() | ||||
|         cancelled = False | ||||
|         with self.assertRaises(TimeoutError): | ||||
|             async with asyncio.timeout(0.01): | ||||
|  | @ -59,39 +58,26 @@ async def test_waiter_cancelled(self): | |||
| 
 | ||||
|     async def test_timeout_not_called(self): | ||||
|         loop = asyncio.get_running_loop() | ||||
|         t0 = loop.time() | ||||
|         async with asyncio.timeout(10) as cm: | ||||
|             await asyncio.sleep(0.01) | ||||
|         t1 = loop.time() | ||||
| 
 | ||||
|         self.assertFalse(cm.expired()) | ||||
|         # 2 sec for slow CI boxes | ||||
|         self.assertLess(t1-t0, 2) | ||||
|         self.assertGreater(cm.when(), t1) | ||||
| 
 | ||||
|     async def test_timeout_disabled(self): | ||||
|         loop = asyncio.get_running_loop() | ||||
|         t0 = loop.time() | ||||
|         async with asyncio.timeout(None) as cm: | ||||
|             await asyncio.sleep(0.01) | ||||
|         t1 = loop.time() | ||||
| 
 | ||||
|         self.assertFalse(cm.expired()) | ||||
|         self.assertIsNone(cm.when()) | ||||
|         # 2 sec for slow CI boxes | ||||
|         self.assertLess(t1-t0, 2) | ||||
| 
 | ||||
|     async def test_timeout_at_disabled(self): | ||||
|         loop = asyncio.get_running_loop() | ||||
|         t0 = loop.time() | ||||
|         async with asyncio.timeout_at(None) as cm: | ||||
|             await asyncio.sleep(0.01) | ||||
|         t1 = loop.time() | ||||
| 
 | ||||
|         self.assertFalse(cm.expired()) | ||||
|         self.assertIsNone(cm.when()) | ||||
|         # 2 sec for slow CI boxes | ||||
|         self.assertLess(t1-t0, 2) | ||||
| 
 | ||||
|     async def test_timeout_zero(self): | ||||
|         loop = asyncio.get_running_loop() | ||||
|  | @ -101,8 +87,6 @@ async def test_timeout_zero(self): | |||
|                 await asyncio.sleep(10) | ||||
|         t1 = loop.time() | ||||
|         self.assertTrue(cm.expired()) | ||||
|         # 2 sec for slow CI boxes | ||||
|         self.assertLess(t1-t0, 2) | ||||
|         self.assertTrue(t0 <= cm.when() <= t1) | ||||
| 
 | ||||
|     async def test_timeout_zero_sleep_zero(self): | ||||
|  | @ -113,8 +97,6 @@ async def test_timeout_zero_sleep_zero(self): | |||
|                 await asyncio.sleep(0) | ||||
|         t1 = loop.time() | ||||
|         self.assertTrue(cm.expired()) | ||||
|         # 2 sec for slow CI boxes | ||||
|         self.assertLess(t1-t0, 2) | ||||
|         self.assertTrue(t0 <= cm.when() <= t1) | ||||
| 
 | ||||
|     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) | ||||
|         t1 = loop.time() | ||||
|         self.assertTrue(cm.expired()) | ||||
|         # 2 sec for slow CI boxes | ||||
|         self.assertLess(t1-t0, 2) | ||||
|         self.assertTrue(t0 >= cm.when() <= t1) | ||||
| 
 | ||||
|     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.set_result('done') | ||||
| 
 | ||||
|         t0 = loop.time() | ||||
|         ret = await asyncio.wait_for(fut, 0) | ||||
|         t1 = loop.time() | ||||
| 
 | ||||
|         self.assertEqual(ret, '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): | ||||
|         loop = asyncio.get_running_loop() | ||||
| 
 | ||||
|         foo_started = False | ||||
| 
 | ||||
|         async def foo(): | ||||
|  | @ -84,12 +79,9 @@ async def foo(): | |||
|             foo_started = True | ||||
| 
 | ||||
|         with self.assertRaises(asyncio.TimeoutError): | ||||
|             t0 = loop.time() | ||||
|             await asyncio.wait_for(foo(), 0) | ||||
|         t1 = loop.time() | ||||
| 
 | ||||
|         self.assertEqual(foo_started, False) | ||||
|         self.assertLess(t1 - t0, 0.1) | ||||
| 
 | ||||
|     async def test_wait_for_timeout_less_then_0_or_0(self): | ||||
|         loop = asyncio.get_running_loop() | ||||
|  | @ -113,18 +105,14 @@ async def foo(): | |||
|                 await started | ||||
| 
 | ||||
|                 with self.assertRaises(asyncio.TimeoutError): | ||||
|                     t0 = loop.time() | ||||
|                     await asyncio.wait_for(fut, timeout) | ||||
|                 t1 = loop.time() | ||||
| 
 | ||||
|                 self.assertTrue(fut.done()) | ||||
|                 # it should have been cancelled due to the timeout | ||||
|                 self.assertTrue(fut.cancelled()) | ||||
|                 self.assertEqual(foo_running, False) | ||||
|                 self.assertLess(t1 - t0, 0.1) | ||||
| 
 | ||||
|     async def test_wait_for(self): | ||||
|         loop = asyncio.get_running_loop() | ||||
|         foo_running = None | ||||
| 
 | ||||
|         async def foo(): | ||||
|  | @ -139,13 +127,10 @@ async def foo(): | |||
|         fut = asyncio.create_task(foo()) | ||||
| 
 | ||||
|         with self.assertRaises(asyncio.TimeoutError): | ||||
|             t0 = loop.time() | ||||
|             await asyncio.wait_for(fut, 0.1) | ||||
|         t1 = loop.time() | ||||
|         self.assertTrue(fut.done()) | ||||
|         # it should have been cancelled due to the timeout | ||||
|         self.assertTrue(fut.cancelled()) | ||||
|         self.assertLess(t1 - t0, support.SHORT_TIMEOUT) | ||||
|         self.assertEqual(foo_running, False) | ||||
| 
 | ||||
|     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; | ||||
|         # 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() | ||||
|         done = self.loop.run_until_complete(fut) | ||||
|         elapsed = self.loop.time() - start | ||||
| 
 | ||||
|         self.assertEqual(done, False) | ||||
|         self.assertFalse(fut.result()) | ||||
|         # bpo-31008: Tolerate only 450 ms (at least 500 ms expected), | ||||
|         # because of bad clock resolution on Windows | ||||
|         self.assertTrue(0.45 <= elapsed <= 0.9, elapsed) | ||||
|         self.assertGreaterEqual(elapsed, timeout - test_utils.CLOCK_RES) | ||||
| 
 | ||||
|         _overlapped.SetEvent(event) | ||||
| 
 | ||||
|         # Wait for set event; | ||||
|         # result should be True immediately | ||||
|         fut = self.loop._proactor.wait_for_handle(event, 10) | ||||
|         start = self.loop.time() | ||||
|         done = self.loop.run_until_complete(fut) | ||||
|         elapsed = self.loop.time() - start | ||||
| 
 | ||||
|         self.assertEqual(done, True) | ||||
|         self.assertTrue(fut.result()) | ||||
|         self.assertTrue(0 <= elapsed < 0.3, elapsed) | ||||
| 
 | ||||
|         # asyncio issue #195: cancelling a done _WaitHandleFuture | ||||
|         # must not crash | ||||
|  | @ -199,11 +195,8 @@ def test_wait_for_handle_cancel(self): | |||
|         # CancelledError should be raised immediately | ||||
|         fut = self.loop._proactor.wait_for_handle(event, 10) | ||||
|         fut.cancel() | ||||
|         start = self.loop.time() | ||||
|         with self.assertRaises(asyncio.CancelledError): | ||||
|             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 | ||||
|         # must not crash | ||||
|  |  | |||
|  | @ -36,6 +36,12 @@ | |||
| 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): | ||||
|     fullname = os.path.join(support.TEST_HOME_DIR, *filename) | ||||
|     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