async def test_join_cleanup_external2(): """ Ensure that when the scope is done, all tasks have been cleaned properly. """ done = False scope = Scope() async def job(): nonlocal done try: await asyncio.sleep(10) finally: done = True async def runner(scope): async with scope: scope << job() task = asyncio.ensure_future(runner(scope)) # Wait a bit so that everyone is started and blocked await asyncio.sleep(0.2) # Now: scope should be joining, pending on job assert not done # Cancel the scope and await the scope scope.cancel() await scope # As soon as scope is done, we should have cleaned up job assert done await task
async def test_join_cleanup(): """ Ensure that when the scope is done, all tasks have been cleaned properly. """ done = False async def job(): nonlocal done try: await asyncio.sleep(10) finally: done = True scope = Scope() # will run 0.2 seconds scope << job() await asyncio.sleep(0.1) scope.cancel() await scope assert done
async def test_fork_dead(): """ Try to fork a dead scope. """ scope = Scope() async with scope: pass with pytest.raises(AssertionError): _ = scope.fork()
async def test_join_cancel(wait): """ """ parent = Scope() await asyncio.sleep(0.1) parent.cancel() if wait: await parent else: await asyncio.wait_for(parent, 1)
async def test_nested_cancel_wait(): """ """ parent = Scope() child = parent.fork() child << run10() await asyncio.sleep(0.1) child.cancel() parent.cancel() await asyncio.wait_for(asyncio.shield(parent), 1)
async def test_join_task_cancelled_no_env(wait): """Test joining a task, but cancelled""" n = Scope(timeout=1) t = n.spawn(run10()) t.cancel() with pytest.raises(asyncio.CancelledError): await t n.finalize() if wait: await asyncio.wait_for(n, 2) else: await n
async def test_nested_fork_raises_catch(): """ Two nested Nurseries, but completely unrelated. Remember that we cannot do magic (yet). As long as the inner code is blocking and not related to the surrounding Scope, The outer timeout will be stuck! """ before = time.time() async def bomb(): await asyncio.sleep(0.2) raise ValueError('boom!') with pytest.raises(TimeoutError): async with Scope(timeout=0.5) as parent: parent.spawn(run10(), name='run10') inner = parent.fork() inner.spawn(bomb()) with pytest.raises(ValueError): # This should prevent bubbling await inner after = time.time() assert (after - before) > 0.4
async def test_join_cleanup_external(): """ Ensure that when the scope is done, all tasks have been cleaned properly. """ done = False async def job(): nonlocal done try: await asyncio.sleep(10) finally: done = True async def cleaner(scope): await asyncio.sleep(0.2) scope.cancel() scope = Scope() c = asyncio.ensure_future(cleaner(scope)) async with scope: scope << job() await c assert done
async def test_nested_fork_timeout_sibling(): """ Two nested Nurseries, but completely unrelated. Remember that we cannot do magic (yet). As long as the inner code is blocking and not related to the surrounding Scope, The outer timeout will be stuck! """ before = time.time() async def fork_my_parent(scope, timeout: float = 0): async with scope.fork(timeout=timeout) as inner: inner.spawn(run10()) with pytest.raises(TimeoutError): async with Scope() as parent: parent.spawn(run10()) # First long one parent.spawn(fork_my_parent(parent)) # Second will timeout soon parent.spawn(fork_my_parent(parent, timeout=0.1)) after = time.time() assert (after - before) < 0.2
async def test_join_task_raises_no_env(): """Test joining a task, but raises""" before = time.time() n = Scope(timeout=1) t = n.spawn(raiser()) with pytest.raises(ValueError): # Catching the error here prevents bubbling await t n.finalize() await n after = time.time() assert (after - before) < 0.3
async def test_join_cleanup_fast(): """ Ensure that when the scope is done, all tasks have been cleaned properly. """ done = 0 async def job(): nonlocal done try: await asyncio.sleep(10) finally: await asyncio.sleep(0.2) done += 1 before = time.time() async with Scope() as s: for _ in range(10): s << job() await asyncio.sleep(0.1) s.cancel() after = time.time() # assert 0.1 < (after - before) < 0.3 assert done == 10
async def test_cancel_finally_cancel(): """ Cancelled internally, twice """ async def cleaner(): await asyncio.sleep(0.2) raise ValueError('boom') scope = Scope() with pytest.raises(ValueError): try: async with scope: scope << cleaner() finally: scope.cancel()
async def test_join_not_waited_but_clean(): """ Ensure that when the scope is done, all tasks not awaited are cancelled without waiting. But also check that tasks are properly finalised (cancelled and awaited) """ before = time.time() done = False async def background(): nonlocal done try: while True: await asyncio.sleep(1) except asyncio.CancelledError: done = True with pytest.raises(TimeoutError): async with Scope(timeout=0.2) as scope: scope.spawn(background(), awaited=False) scope << asyncio.sleep(0.2) after = time.time() assert 0.1 < (after - before) < 0.3 assert done is True
async def test_nested_cancel_join(wait): """ """ parent = Scope() child = parent.fork() child << run10() await asyncio.sleep(0.1) child.cancel() parent.cancel() if wait: await parent else: await asyncio.wait_for(parent, 1)
async def test_nested_unrelated(): """ Two nested Nurseries, outer will timeout before inner. This should be handled properly now. """ before = time.time() with pytest.raises(TimeoutError): async with Scope(timeout=0.2): async with Scope(timeout=0.5) as inner: """ A completely different """ inner.spawn(run10()) after = time.time() assert (after - before) < 0.4, 'for now...'
async def test_join_task_cancelled(): """Test joining a task, but cancelled""" async with Scope(timeout=1) as n: t = n.spawn(run10()) t.cancel() with pytest.raises(asyncio.CancelledError): await t
async def sub(): old = Scope.get_current() assert old == n async with old.fork() as new: assert Scope.get_current() == new async def test_old(): assert Scope.get_current() == old async def test_new(): assert Scope.get_current() == new await test_new() await asyncio.ensure_future(test_new()) new << test_new() old << test_old()
async def test_cancel_double(): """ Cancelled externally, twice """ async def cleaner(scope): await asyncio.sleep(0.2) scope.cancel() # Should we raise something in case of double close? scope.cancel() scope = Scope() task = asyncio.ensure_future(cleaner(scope)) async with scope: scope << run10() await task assert scope.done() and scope.exception() is None
async def test_join_forever(): """Test joining a task, then joining forever""" n = Scope(timeout=0.5) # will run 0.2 seconds n << trivial() with pytest.raises(TimeoutError): # We join forever: this will stay alive even if the trivial task is done! await n
async def test_timeout(): """Simple timeout""" before = time.time() with pytest.raises(TimeoutError): async with Scope(timeout=0.1) as n: n.spawn(run10()) after = time.time() assert (after - before) < 0.5
async def test_cancel_double_exception(): """ Cancelled externally, twice, with exception """ async def cleaner(scope): await asyncio.sleep(0.2) scope.cancel(ValueError('boom')) # Should we raise something in case of double close? scope.cancel(ValueError('boom')) scope = Scope() task = asyncio.ensure_future(cleaner(scope)) with pytest.raises(ValueError): async with scope: scope << run10() await task assert scope.done() and isinstance(scope.exception(), ValueError)
async def test_timeout_override(): """Override timeout value""" before = time.time() with pytest.raises(TimeoutError): async with Scope(timeout=5) as n: n.spawn(run10()) n.timeout = 0.1 after = time.time() assert (after - before) < 0.5
async def test_internal_cancel(): """Test an internal cancellation""" before = time.time() async with Scope() as n: n.spawn(run10()) await asyncio.sleep(0.2) n.cancel() after = time.time() assert (after - before) < 0.5
async def test_join_task_raises_wait_for(): """Test joining a task, but raises""" before = time.time() async with Scope(timeout=1) as n: t = n.spawn(raiser()) with pytest.raises(ValueError): # Catching the error here prevents bubbling await asyncio.wait_for(t, 10) after = time.time() assert (after - before) < 0.3
async def test_cancel_double_internal(): """ Cancelled internally, twice """ async def cleaner(): await asyncio.sleep(0.2) Scope.get_current().cancel() # Should we raise something in case of double close? Scope.get_current().cancel() async with Scope() as scope: scope << cleaner()
async def test_join_not_waited_alone(): """ Ensure that when the scope is done, all tasks not awaited are cancelled without waiting """ before = time.time() async with Scope() as scope: scope.spawn(run10(), awaited=False) after = time.time() assert (after - before) < 0.1
async def test_nested_fork_timeout_parent(): """ Two nested Nurseries, inner one generated by parent """ before = time.time() with pytest.raises(TimeoutError): async with Scope(timeout=0.1) as parent: async with parent.fork() as inner: inner.spawn(run10()) after = time.time() assert (after - before) < 0.2
async def test_master_raises(awaited): """ Raise an exception from a task This is independent of awaited flag """ async def raiser(): await asyncio.sleep(0.01) raise ValueError('boom') with pytest.raises(ValueError): async with Scope() as n: n.spawn(run10()) n.spawn(raiser(), master=True, awaited=awaited)
async def test_cancel_double_internal_exception(): """ Cancelled internally, twice, with exception """ async def cleaner(): await asyncio.sleep(0.2) Scope.get_current().cancel(ValueError('boom')) # Should we raise something in case of double close? Scope.get_current().cancel(ValueError('boom')) with pytest.raises(ValueError): async with Scope() as scope: scope << cleaner()
async def test_executor(): """Test simple task running in an executor""" before = time.time() def job(): time.sleep(0.2) return 42 async with Scope(timeout=1) as n: t = n.spawn(asyncio.get_event_loop().run_in_executor(None, job)) assert 42 == await t after = time.time() assert (after - before) < 0.3