Repository navigation
Expand file tree
/
Copy pathpytest.ini
More file actions
82 lines (81 loc) · 4.73 KB
/
Copy pathpytest.ini
File metadata and controls
82 lines (81 loc) · 4.73 KB
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
[pytest]
# An xfail that starts passing is a failure, not a silent pass. Without this,
# a stale marker keeps reporting green as XPASS and the xfail/xpass profile
# stops being a usable signal — which is how three markers went stale here,
# two of them masking fixtures that wrote to a rolled-back transaction and
# asserted against other tests' leftovers. Both remaining markers were checked
# against this setting; use `strict=False` on a marker that genuinely needs it.
xfail_strict = true
# A coroutine created and then dropped is scheduled work that silently never
# ran. That is a live failure mode here rather than a theoretical one:
# ``run_contradiction_detection`` is a sync function returning an awaitable,
# eager on purpose, so a caller that returns or raises between the call and its
# ``track_task(...)`` loses contradiction detection with nothing logged
# anywhere. This gate is the only signal that would show it.
#
# BOTH lines are required and each is INERT alone — measured, not assumed. The
# first turns the warning into an exception inside the coroutine's ``__del__``,
# where exceptions are never propagated: CPython routes it to
# ``sys.unraisablehook`` and pytest re-reports it as a warning. The second is
# what turns that re-report into a failure. With only one of the two, the
# offending test passes.
#
# ``AsyncMockMixin`` is excluded because that is a mock's OWN internal
# coroutine rather than this codebase's work. Four tests in
# ``test_crystallization_must_not_wedge.py`` shed one from a bare
# ``AsyncMock()``; in the case traced to production the ``await`` is present
# (``crystallizer_service.py:942``), and the exact mechanism was NOT
# established — this is recorded as an exclusion, not as a diagnosis. What the
# exclusion costs is a missing ``await`` on a call whose callee is mocked,
# where that mock's own ``assert_awaited_once`` is the better check anyway; a
# missing ``await`` on real code still reports that function's own name and
# still fails here.
#
# No ':' may appear in a message pattern, because the filter string is split on
# it — hence "ignored in.*coroutine object" and not the literal
# "ignored in: <coroutine object".
#
# When this fails, the named test is often NOT the culprit: the warning fires
# when the coroutine is collected, which can be a later test than the one that
# created it (a reference held by a mock's ``call_args`` routinely outlives its
# test). Find the real creator by re-running the suspect files with
# PYTHONTRACEMALLOC=25, which adds the allocation traceback to the report.
# Scope that to a handful of files: suite-wide it reached 1% in six minutes.
# Two things NOT to reach for when this fails. An autouse fixture that disposes
# of stray coroutines would make the gate permanently green -- it cannot tell a
# test double's leftover from a production drop, which is the whole distinction
# being gated. And a per-test ``filterwarnings`` marker does not reliably exempt
# anything, because the failure is attributed to whichever test was running at
# collection time rather than the one that created the coroutine.
filterwarnings =
error:coroutine '(?!AsyncMockMixin)[^']*' was never awaited:RuntimeWarning
error:Exception ignored in.*coroutine object:pytest.PytestUnraisableExceptionWarning
asyncio_mode = auto
asyncio_default_fixture_loop_scope = session
asyncio_default_test_loop_scope = session
testpaths = tests
pythonpath = core-api/src core-storage-api/src core-worker/src .
# Benchmarks are opt-in. All 16 ``benchmark``-marked tests assert a fixed
# wall-clock budget around pure CPU work — 13 assertions across 5 files, the
# tightest 10μs (``test_visibility.py``) and 5μs/call
# (``test_p5_p6_benchmarks.py``). Elapsed time on a shared machine is not a
# property of the code: this suite runs ~5,700 tests in ~2 minutes with heavy
# concurrent database work, so those budgets measure contention. Concretely,
# ``test_cluster_1000_pairs`` failed 2 of 6 full-suite runs while measuring
# 3,794μs against its 50,000μs budget in isolation — a 13x margin. Nothing was
# slow; the machine was busy.
#
# Deselected rather than loosened: a budget chosen to survive a saturated runner
# catches only a catastrophic regression and is still flaky at the tail. These
# numbers are meaningful on a quiet machine, which is where to take them:
#
# uv run pytest tests/ -m benchmark -s
#
# A ``-m`` on the command line replaces this one, so that works as written.
# Correctness of the code they exercise stays in the ordinary suite — e.g.
# ``_build_clusters`` has ``test_p5_crystallizer.py::TestBuildClusters``.
addopts = -m "not benchmark"
markers =
unit: pure algorithmic tests (no DB required)
integration: tests requiring PostgreSQL + pgvector
benchmark: latency measurement tests — opt-in, see addopts above