Spaces:
Build error
Build error
import asyncio | |
import pytest | |
from openhands.utils.async_utils import ( | |
AsyncException, | |
call_async_from_sync, | |
call_sync_from_async, | |
wait_all, | |
) | |
async def test_await_all(): | |
# Mock function demonstrating some calculation - always takes a minimum of 0.1 seconds | |
async def dummy(value: int): | |
await asyncio.sleep(0.1) | |
return value * 2 | |
# wait for 10 calculations - serially this would take 1 second | |
coro = wait_all(dummy(i) for i in range(10)) | |
# give the task only 0.3 seconds to complete (This verifies they occur in parallel) | |
task = asyncio.create_task(coro) | |
await asyncio.wait([task], timeout=0.3) | |
# validate the results (We need to sort because they can return in any order) | |
results = list(await task) | |
expected = [i * 2 for i in range(10)] | |
assert expected == results | |
async def test_await_all_single_exception(): | |
# Mock function demonstrating some calculation - always takes a minimum of 0.1 seconds | |
async def dummy(value: int): | |
await asyncio.sleep(0.1) | |
if value == 1: | |
raise ValueError('Invalid value 1') # Throw an exception on every odd value | |
return value * 2 | |
# expect an exception to be raised. | |
with pytest.raises(ValueError, match='Invalid value 1'): | |
await wait_all(dummy(i) for i in range(10)) | |
async def test_await_all_multi_exception(): | |
# Mock function demonstrating some calculation - always takes a minimum of 0.1 seconds | |
async def dummy(value: int): | |
await asyncio.sleep(0.1) | |
if value & 1: | |
raise ValueError( | |
f'Invalid value {value}' | |
) # Throw an exception on every odd value | |
return value * 2 | |
# expect an exception to be raised. | |
with pytest.raises(AsyncException): | |
await wait_all(dummy(i) for i in range(10)) | |
async def test_await_all_timeout(): | |
result = 0 | |
# Mock function updates a nonlocal variable after a delay | |
async def dummy(value: int): | |
nonlocal result | |
await asyncio.sleep(0.2) | |
result += value | |
# expect an exception to be raised. | |
with pytest.raises(asyncio.TimeoutError): | |
await wait_all((dummy(i) for i in range(10)), 0.1) | |
# Wait and then check the shared result - this makes sure that pending tasks were cancelled. | |
asyncio.sleep(0.2) | |
assert result == 0 | |
async def test_call_sync_from_async(): | |
def dummy(value: int = 2): | |
return value * 2 | |
result = await call_sync_from_async(dummy) | |
assert result == 4 | |
result = await call_sync_from_async(dummy, 3) | |
assert result == 6 | |
result = await call_sync_from_async(dummy, value=5) | |
assert result == 10 | |
async def test_call_sync_from_async_error(): | |
def dummy(): | |
raise ValueError() | |
with pytest.raises(ValueError): | |
await call_sync_from_async(dummy) | |
def test_call_async_from_sync(): | |
async def dummy(value: int): | |
return value * 2 | |
result = call_async_from_sync(dummy, 0, 3) | |
assert result == 6 | |
def test_call_async_from_sync_error(): | |
async def dummy(value: int): | |
raise ValueError() | |
with pytest.raises(ValueError): | |
call_async_from_sync(dummy, 0, 3) | |
def test_call_async_from_sync_background_tasks(): | |
events = [] | |
async def bg_task(): | |
# This background task should finish after the dummy task | |
events.append('bg_started') | |
asyncio.sleep(0.2) | |
events.append('bg_finished') | |
async def dummy(value: int): | |
events.append('dummy_started') | |
# This coroutine kicks off a background task | |
asyncio.create_task(bg_task()) | |
events.append('dummy_started') | |
call_async_from_sync(dummy, 0, 3) | |
# We check that the function did not return until all coroutines completed | |
# (Even though some of these were started as background tasks) | |
expected = ['dummy_started', 'dummy_started', 'bg_started', 'bg_finished'] | |
assert expected == events | |