-
-
Notifications
You must be signed in to change notification settings - Fork 325
/
Copy pathtest_sync.py
128 lines (90 loc) · 3.48 KB
/
test_sync.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import asyncio
import time
from collections.abc import AsyncGenerator
from unittest.mock import AsyncMock, patch
import pytest
from zarr.sync import SyncError, SyncMixin, _get_lock, _get_loop, sync
from zarr.testing.utils import IS_WASM
pytestmark = pytest.mark.skipif(IS_WASM, reason="Can't test async code in WASM")
@pytest.fixture(params=[True, False])
def sync_loop(request) -> asyncio.AbstractEventLoop | None:
if request.param is True:
return _get_loop()
if request.param is False:
return None
def test_get_loop() -> None:
# test that calling _get_loop() twice returns the same loop
loop = _get_loop()
loop2 = _get_loop()
assert loop is loop2
def test_get_lock() -> None:
# test that calling _get_lock() twice returns the same lock
lock = _get_lock()
lock2 = _get_lock()
assert lock is lock2
def test_sync(sync_loop: asyncio.AbstractEventLoop | None) -> None:
foo = AsyncMock(return_value="foo")
assert sync(foo(), loop=sync_loop) == "foo"
foo.assert_awaited_once()
def test_sync_raises(sync_loop: asyncio.AbstractEventLoop | None) -> None:
foo = AsyncMock(side_effect=ValueError("foo-bar"))
with pytest.raises(ValueError, match="foo-bar"):
sync(foo(), loop=sync_loop)
foo.assert_awaited_once()
def test_sync_timeout() -> None:
duration = 0.002
async def foo() -> None:
time.sleep(duration)
with pytest.raises(asyncio.TimeoutError):
sync(foo(), timeout=duration / 2)
def test_sync_raises_if_no_coroutine(sync_loop: asyncio.AbstractEventLoop | None) -> None:
def foo() -> str:
return "foo"
with pytest.raises(TypeError):
sync(foo(), loop=sync_loop)
@pytest.mark.filterwarnings("ignore:coroutine.*was never awaited")
def test_sync_raises_if_loop_is_closed() -> None:
loop = _get_loop()
foo = AsyncMock(return_value="foo")
with patch.object(loop, "is_closed", return_value=True):
with pytest.raises(RuntimeError):
sync(foo(), loop=loop)
foo.assert_not_awaited()
@pytest.mark.filterwarnings("ignore:coroutine.*was never awaited")
def test_sync_raises_if_calling_sync_from_within_a_running_loop(
sync_loop: asyncio.AbstractEventLoop | None,
) -> None:
def foo() -> str:
# technically, this should be an async function but doing that
# yields a warning because it is never awaited by the inner function
return "foo"
async def bar() -> str:
return sync(foo(), loop=sync_loop)
with pytest.raises(SyncError):
sync(bar(), loop=sync_loop)
@pytest.mark.filterwarnings("ignore:coroutine.*was never awaited")
def test_sync_raises_if_loop_is_invalid_type() -> None:
foo = AsyncMock(return_value="foo")
with pytest.raises(TypeError):
sync(foo(), loop=1)
foo.assert_not_awaited()
def test_sync_mixin(sync_loop) -> None:
class AsyncFoo:
def __init__(self) -> None:
pass
async def foo(self) -> str:
return "foo"
async def bar(self) -> AsyncGenerator:
for i in range(10):
yield i
class SyncFoo(SyncMixin):
def __init__(self, async_foo: AsyncFoo) -> None:
self._async_foo = async_foo
def foo(self) -> str:
return self._sync(self._async_foo.foo())
def bar(self) -> list[int]:
return self._sync_iter(self._async_foo.bar())
async_foo = AsyncFoo()
foo = SyncFoo(async_foo)
assert foo.foo() == "foo"
assert foo.bar() == list(range(10))