Skip to content

Commit a3afd7e

Browse files
committed
test: add regression test for issue #509 example
1 parent bb5320d commit a3afd7e

1 file changed

Lines changed: 65 additions & 0 deletions

File tree

tests/testcases/test_issue509.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"""
2+
3+
### Issue 509
4+
5+
A StateChart that exercises the example given on issue
6+
#[509](https://github.com/fgmacedo/python-statemachine/issues/509).
7+
8+
When multiple async coroutines send events concurrently, each caller should
9+
receive its own event's result or exception — not another caller's.
10+
11+
Original problem: fn2 triggers a validator exception, but fn1 receives it instead.
12+
"""
13+
14+
import asyncio
15+
16+
import pytest
17+
18+
from statemachine import State
19+
from statemachine import StateChart
20+
21+
22+
class Issue509SC(StateChart):
23+
error_on_execution = False
24+
25+
INITIAL = State(initial=True)
26+
FINAL = State()
27+
28+
noop = INITIAL.to(FINAL, on="do_nothing")
29+
noop2 = INITIAL.to(FINAL, on="do_nothing", validators="raise_exception") | FINAL.to.itself(
30+
on="do_nothing", validators="raise_exception"
31+
)
32+
33+
async def do_nothing(self, name):
34+
await asyncio.sleep(0.1)
35+
return f"Did nothing via {name}"
36+
37+
def raise_exception(self):
38+
raise ValueError("noop2 is not allowed")
39+
40+
41+
@pytest.mark.asyncio()
42+
async def test_issue509_exception_routed_to_correct_caller():
43+
test = Issue509SC()
44+
await test.activate_initial_state()
45+
46+
results = {}
47+
48+
async def fn1():
49+
results["fn1"] = await test.send("noop", "fn1")
50+
51+
async def fn2():
52+
try:
53+
await test.send("noop2", "fn2")
54+
results["fn2"] = "no error"
55+
except ValueError as e:
56+
results["fn2"] = f"caught: {e}"
57+
58+
task1 = asyncio.create_task(fn1())
59+
task2 = asyncio.create_task(fn2())
60+
await asyncio.gather(task1, task2)
61+
62+
# fn1 should get its own result, not fn2's exception
63+
assert results["fn1"] == "Did nothing via fn1"
64+
# fn2 should catch the ValueError from its own validator
65+
assert results["fn2"] == "caught: noop2 is not allowed"

0 commit comments

Comments
 (0)