Skip to content

Commit 54fc538

Browse files
committed
fix(test): replace caplog with spy list in test_spec_parser to fix xdist flakiness
With xdist, log records from other parametrized cases on the same worker could leak into caplog, causing intermittent assertion failures in test_expressions. Replace the logging-based assertion with a spy callable that records variable_hook calls in a test-local list.
1 parent d22be8b commit 54fc538

1 file changed

Lines changed: 23 additions & 21 deletions

File tree

tests/test_spec_parser.py

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
import asyncio
2-
import logging
2+
from typing import TYPE_CHECKING
33

44
import pytest
55
from statemachine.spec_parser import Functions
66
from statemachine.spec_parser import operator_mapping
77
from statemachine.spec_parser import parse_boolean_expr
88

9-
logger = logging.getLogger(__name__)
10-
DEBUG = logging.DEBUG
9+
if TYPE_CHECKING:
10+
from collections.abc import Callable
1111

1212

13-
def variable_hook(var_name):
13+
def variable_hook(
14+
var_name: str,
15+
spy: "Callable[[str], None] | None" = None,
16+
) -> "Callable":
1417
values = {
1518
"frodo_has_ring": True,
1619
"sauron_alive": False,
@@ -30,7 +33,8 @@ def variable_hook(var_name):
3033
}
3134

3235
def decorated(*args, **kwargs):
33-
logger.debug(f"variable_hook({var_name})")
36+
if spy is not None:
37+
spy(var_name)
3438
return values.get(var_name, False)
3539

3640
decorated.__name__ = var_name
@@ -171,16 +175,15 @@ def decorated(*args, **kwargs):
171175
("height > 1 and height < 2", True, ["height", "height"]),
172176
],
173177
)
174-
def test_expressions(expression, expected, caplog, hooks_called):
175-
caplog.set_level(logging.DEBUG, logger="tests")
178+
def test_expressions(expression, expected, hooks_called):
179+
calls: list[str] = []
176180

177-
parsed_expr = parse_boolean_expr(expression, variable_hook, operator_mapping)
178-
assert parsed_expr() is expected, expression
181+
def hook(name):
182+
return variable_hook(name, spy=calls.append)
179183

180-
if hooks_called:
181-
assert caplog.record_tuples == [
182-
("tests.test_spec_parser", DEBUG, f"variable_hook({hook})") for hook in hooks_called
183-
]
184+
parsed_expr = parse_boolean_expr(expression, hook, operator_mapping)
185+
assert parsed_expr() is expected, expression
186+
assert calls == hooks_called
184187

185188

186189
def test_negating_compound_false_expression():
@@ -377,16 +380,15 @@ def test_mixed_sync_async_expressions(expression, expected):
377380

378381

379382
@pytest.mark.xfail(reason="TODO: Optimize so that expressios are evaluated only once")
380-
def test_should_evaluate_values_only_once(expression, expected, caplog, hooks_called):
381-
caplog.set_level(logging.DEBUG, logger="tests")
383+
def test_should_evaluate_values_only_once(expression, expected, hooks_called):
384+
calls: list[str] = []
382385

383-
parsed_expr = parse_boolean_expr(expression, variable_hook, operator_mapping)
384-
assert parsed_expr() is expected, expression
386+
def hook(name):
387+
return variable_hook(name, spy=calls.append)
385388

386-
if hooks_called:
387-
assert caplog.record_tuples == [
388-
("tests.test_spec_parser", DEBUG, f"variable_hook({hook})") for hook in hooks_called
389-
]
389+
parsed_expr = parse_boolean_expr(expression, hook, operator_mapping)
390+
assert parsed_expr() is expected, expression
391+
assert calls == hooks_called
390392

391393

392394
def test_functions_get_unknown_raises():

0 commit comments

Comments
 (0)