Skip to content

Commit 13918bc

Browse files
committed
tests for error scenario
Signed-off-by: Sreekanth <prsreekanth920@gmail.com>
1 parent 7d4f82f commit 13918bc

1 file changed

Lines changed: 62 additions & 0 deletions

File tree

packages/pynumaflow/tests/reducestreamer/test_async_reduce_err.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import threading
44
import unittest
55
from collections.abc import AsyncIterable
6+
from unittest.mock import MagicMock
67
import grpc
78
from grpc.aio._server import Server
89

@@ -16,6 +17,7 @@
1617
Metadata,
1718
)
1819
from pynumaflow.proto.reducer import reduce_pb2, reduce_pb2_grpc
20+
from pynumaflow.reducestreamer.servicer.async_servicer import AsyncReduceStreamServicer
1921
from pynumaflow.shared.asynciter import NonBlockingIterator
2022
from tests.testing_utils import (
2123
mock_message,
@@ -217,6 +219,66 @@ def __stub(self):
217219
return reduce_pb2_grpc.ReduceStub(_channel)
218220

219221

222+
async def _emit_one_handler(keys, datums, output, md):
223+
"""Handler that emits one message eagerly, then blocks reading remaining datums."""
224+
await output.put(Message(b"result", keys=keys))
225+
async for _ in datums:
226+
pass
227+
228+
229+
def test_cancelled_error_in_consumer_loop():
230+
"""athrow(CancelledError) at the yield point exercises the except CancelledError branch."""
231+
servicer = AsyncReduceStreamServicer(_emit_one_handler)
232+
shutdown_event = asyncio.Event()
233+
servicer.set_shutdown_event(shutdown_event)
234+
request, _ = start_request(multiple_window=False)
235+
236+
async def _run():
237+
async def requests():
238+
yield request
239+
await asyncio.sleep(999)
240+
241+
gen = servicer.ReduceFn(requests(), MagicMock())
242+
# Drive the pipeline until the handler's message is yielded.
243+
await gen.__anext__()
244+
# Simulate task cancellation (e.g. SIGTERM) at the yield point.
245+
try:
246+
await gen.athrow(asyncio.CancelledError())
247+
except StopAsyncIteration:
248+
pass
249+
250+
asyncio.run(_run())
251+
assert shutdown_event.is_set()
252+
assert servicer._error is None
253+
254+
255+
def test_base_exception_in_consumer_loop():
256+
"""athrow(ValueError) at the yield point exercises the except BaseException branch."""
257+
servicer = AsyncReduceStreamServicer(_emit_one_handler)
258+
shutdown_event = asyncio.Event()
259+
servicer.set_shutdown_event(shutdown_event)
260+
request, _ = start_request(multiple_window=False)
261+
262+
async def _run():
263+
async def requests():
264+
yield request
265+
await asyncio.sleep(999)
266+
267+
ctx = MagicMock()
268+
gen = servicer.ReduceFn(requests(), ctx)
269+
await gen.__anext__()
270+
try:
271+
await gen.athrow(ValueError("boom"))
272+
except StopAsyncIteration:
273+
pass
274+
return ctx
275+
276+
ctx = asyncio.run(_run())
277+
assert shutdown_event.is_set()
278+
assert isinstance(servicer._error, ValueError)
279+
ctx.set_code.assert_called_once_with(grpc.StatusCode.INTERNAL)
280+
281+
220282
if __name__ == "__main__":
221283
logging.basicConfig(level=logging.DEBUG)
222284
unittest.main()

0 commit comments

Comments
 (0)