litellm/tests/unit/test_check_test_quality.py
devin-ai-integration[bot] 7efce7f8e0
test(integration): give chaos and timing tests a harness API and gate raw signals (#46031)
* test(integration): give chaos and timing tests a harness API and gate raw signals

Chaos tests killed and suspended proxy workers with raw os.kill and psutil
calls and bounded elapsed time with fixed literals, so they raced the uvicorn
worker healthcheck and failed on slow CI boxes

OwnedProxy now offers kill_worker and replacing_worker, which return only once
a replacement answers readiness with its own pid, and suspended, which is
refused unless the proxy was launched with a lenient worker healthcheck.
timing.py bounds durations against a measured control or the injected delay.
run.py measures the proxy import time once and derives readiness deadlines and
the per-test timeout from it, writing boot-calibration.json

check_test_quality.py adds TQ010 (raw process signals) and TQ011 (elapsed time
asserted under a numeric literal) for tests/integration outside _support, and
every call site is migrated so both report zero with no suppressions

* test(integration): steer the assistants wire burst onto both workers

The mixed-status burst assumed the OS would spread 48 connections across both workers and failed when one worker took them all. Each half is now sent while the other worker is suspended, and the test asserts an exact 24 and 24 split

* test(integration): restore product-enforced timing bounds lost in the migration

Some TQ011 migrations dropped or loosened a bound whose time is the behaviour
under test. The websocket session cap only kept its floor, so a cap closing at
300 s would have passed, and several timeouts were bounded by the injected stall
instead of the configured product value

assert_enforced_within bounds an elapsed time by the configured value plus
explicit slack, with an optional floor. The websocket cap, the MCP validation
timeout, the guardrail litellm_params timeout, the prisma command timeouts, the
baseline projection lock timeout and the key metadata statement timeout use it.
The device code refusal keeps its 15 s margin, and the langfuse retried prompt
fetch is now bounded by a cold fetch of a steady prompt as well as by the
ignored retry-after

* fix(tests): wait for the supervisor to reap killed workers and fix real-kill migrations

The lenient worker healthcheck was the whole case budget, so uvicorn's supervisor sat
in a ping on the killed worker for up to that long before respawning it. It now uses
the graceful stop budget, and a worker kill returns only after the victim is reaped,
so pooled connections no longer race the dead worker's socket.

Several tests on main picked the multiprocessing resource tracker as their victim and
never killed a worker. Now that they kill a real one, presidio counts streams cut by
the death, delete_model waits for the config reload that removes a deleted model from
a replacement worker, and the wedged coordination Redis test kills before the wedge
and waits for every parked publish to fail before resuming Redis.

The redis cluster test imports the harness through the tests package so it collects
in the unit job, and the per-model fallback rig exposes the owned proxy it now needs.

* test(observability): only require S3 deliveries the killed worker could not have buffered

A real SIGKILL drops the victim's unflushed batch, so requests it already answered can't be expected to land. The test now requires every request served after the replacement to land, some of the surviving worker's burst share to land, and nothing unsent to land

---------

Co-authored-by: Yuneng Jiang <yuneng@berri.ai>
2026-10-12 05:27:33 -07:00

811 lines
27 KiB
Python

"""Tests for scripts/check_test_quality.py.
Every rule is exercised on a snippet that violates it and on one that does not, so
dropping a rule, widening it, or inverting the suppression check makes a test fail.
The helper-resolution cases are the regression for the false positives the rule
produced against tests/e2e, where the assertions live in a shared helper rather than
in the test body.
"""
import importlib.util
import os
import subprocess
import sys
from pathlib import Path
from types import MappingProxyType
from typing import Final
import pytest
_REPO_ROOT = Path(__file__).resolve().parents[2]
_MODULE_PATH = _REPO_ROOT / "scripts" / "check_test_quality.py"
_spec = importlib.util.spec_from_file_location("check_test_quality", _MODULE_PATH)
checker = importlib.util.module_from_spec(_spec)
# @dataclass(slots=True) rebuilds its class through sys.modules[__module__], so the
# module has to be registered before exec_module runs or Scope fails to construct.
sys.modules[_spec.name] = checker
_spec.loader.exec_module(checker)
def _codes(tmp_path, source):
snippet = tmp_path / "test_snippet.py"
snippet.write_text(source, encoding="utf-8")
return [v.code for v in checker.check_file(snippet)]
def test_zero_assert_test_is_flagged(tmp_path):
assert _codes(tmp_path, "def test_nothing():\n compute()\n") == ["TQ001"]
def test_plain_assert_statement_clears_the_rule(tmp_path):
assert _codes(tmp_path, "def test_value():\n assert compute() == 3\n") == []
def test_pytest_raises_counts_as_an_assertion(tmp_path):
source = "import pytest\n\n\ndef test_raises():\n with pytest.raises(ValueError):\n compute()\n"
assert _codes(tmp_path, source) == []
def test_unittest_style_assertion_counts(tmp_path):
source = "class TestThing:\n def test_equal(self):\n self.assertEqual(compute(), 3)\n"
assert _codes(tmp_path, source) == []
def test_bare_assert_helper_call_counts(tmp_path):
source = "def test_denied():\n assert_auth_denied(call(), 'missing header')\n"
assert _codes(tmp_path, source) == []
def test_assertion_inside_a_module_local_helper_clears_the_rule(tmp_path):
source = (
"def _drive_and_check(client):\n"
" assert client.status == 429\n"
"\n"
"\n"
"def test_budget_blocks(client):\n"
" _drive_and_check(client)\n"
)
assert _codes(tmp_path, source) == []
def test_helper_chain_is_followed_transitively(tmp_path):
source = (
"def _inner(x):\n"
" assert x == 1\n"
"\n"
"\n"
"def _outer(x):\n"
" _inner(x)\n"
"\n"
"\n"
"def test_chain():\n"
" _outer(1)\n"
)
assert _codes(tmp_path, source) == []
def test_a_same_named_helper_in_another_class_does_not_clear_the_rule(tmp_path):
source = (
"class TestAsserting:\n"
" def _check(self):\n"
" assert compute() == 3\n"
"\n"
" def test_ok(self):\n"
" self._check()\n"
"\n"
"\n"
"class TestNotAsserting:\n"
" def _check(self):\n"
" compute()\n"
"\n"
" def test_nothing(self):\n"
" self._check()\n"
)
assert _codes(tmp_path, source) == ["TQ001"]
def test_self_call_resolves_to_the_enclosing_class(tmp_path):
source = (
"class TestOne:\n"
" def _check(self):\n"
" assert compute() == 3\n"
"\n"
" def test_ok(self):\n"
" self._check()\n"
)
assert _codes(tmp_path, source) == []
def test_a_method_named_like_a_module_helper_does_not_shadow_it(tmp_path):
source = (
"def _check():\n"
" assert compute() == 3\n"
"\n"
"\n"
"class TestThing:\n"
" def _check(self):\n"
" compute()\n"
"\n"
" def test_bare_name_uses_the_module_helper(self):\n"
" _check()\n"
"\n"
" def test_self_uses_the_method(self):\n"
" self._check()\n"
)
assert _codes(tmp_path, source) == ["TQ001"]
def test_helper_without_assertions_does_not_clear_the_rule(tmp_path):
source = (
"def _just_calls(client):\n"
" client.go()\n"
"\n"
"\n"
"def test_nothing_anywhere(client):\n"
" _just_calls(client)\n"
)
assert _codes(tmp_path, source) == ["TQ001"]
def test_mutually_recursive_helpers_terminate(tmp_path):
source = (
"def _a(x):\n"
" _b(x)\n"
"\n"
"\n"
"def _b(x):\n"
" _a(x)\n"
"\n"
"\n"
"def test_cycle():\n"
" _a(1)\n"
)
assert _codes(tmp_path, source) == ["TQ001"]
def test_non_test_function_is_not_collected(tmp_path):
assert _codes(tmp_path, "def helper_without_asserts():\n compute()\n") == []
def test_class_with_a_constructor_is_not_collected(tmp_path):
source = (
"class TestLegacy:\n"
" def __init__(self):\n"
" self.x = 1\n"
"\n"
" def test_nothing(self):\n"
" compute()\n"
)
assert _codes(tmp_path, source) == []
def test_mock_echo_is_flagged(tmp_path):
source = (
"from unittest.mock import patch\n"
"\n"
"\n"
"def test_echo():\n"
" with patch('litellm.completion') as mock_completion:\n"
" run()\n"
" mock_completion.assert_called_once()\n"
)
assert _codes(tmp_path, source) == ["TQ002"]
def test_call_args_inspection_is_mock_echo(tmp_path):
source = (
"from unittest.mock import patch\n"
"\n"
"\n"
"def test_echo():\n"
" with patch('litellm.completion') as mock_completion:\n"
" run()\n"
" assert mock_completion.call_args[1]['model'] == 'gpt-4o'\n"
)
assert _codes(tmp_path, source) == ["TQ002"]
def test_patch_decorator_counts_as_installing_a_patch(tmp_path):
source = (
"from unittest import mock\n"
"\n"
"\n"
"@mock.patch('litellm.completion')\n"
"def test_echo(mock_completion):\n"
" run()\n"
" mock_completion.assert_called_once()\n"
)
assert _codes(tmp_path, source) == ["TQ002"]
def test_patching_but_asserting_the_output_is_not_mock_echo(tmp_path):
source = (
"from unittest.mock import patch\n"
"\n"
"\n"
"def test_output():\n"
" with patch('litellm.completion') as mock_completion:\n"
" result = run()\n"
" mock_completion.assert_called_once()\n"
" assert result.choices[0].message.content == 'pong'\n"
)
assert _codes(tmp_path, source) == []
def test_asserting_without_patching_is_not_mock_echo(tmp_path):
source = "def test_plain():\n m = build()\n assert m.called\n"
assert _codes(tmp_path, source) == []
def test_a_test_with_no_assertions_is_tq001_not_tq002(tmp_path):
source = (
"from unittest.mock import patch\n"
"\n"
"\n"
"def test_nothing():\n"
" with patch('litellm.completion'):\n"
" run()\n"
)
assert _codes(tmp_path, source) == ["TQ001"]
def test_sys_path_insert_is_flagged(tmp_path):
assert _codes(tmp_path, "import sys\n\nsys.path.insert(0, '..')\n") == ["TQ003"]
def test_sys_path_read_is_not_flagged(tmp_path):
assert _codes(tmp_path, "import sys\n\nprint(sys.path)\n") == []
def test_raw_environ_write_is_flagged(tmp_path):
assert _codes(tmp_path, "import os\n\nos.environ['KEY'] = 'v'\n") == ["TQ004"]
def test_bare_environ_write_is_flagged(tmp_path):
assert _codes(tmp_path, "from os import environ\n\nenviron['KEY'] = 'v'\n") == ["TQ004"]
def test_environ_read_is_not_flagged(tmp_path):
assert _codes(tmp_path, "import os\n\nvalue = os.environ.get('KEY')\n") == []
def test_monkeypatch_setenv_is_not_flagged(tmp_path):
source = "def test_env(monkeypatch):\n monkeypatch.setenv('KEY', 'v')\n assert read() == 'v'\n"
assert _codes(tmp_path, source) == []
def test_litellm_global_write_is_flagged(tmp_path):
assert _codes(tmp_path, "import litellm\n\nlitellm.drop_params = True\n") == ["TQ005"]
def test_litellm_augmented_global_write_is_flagged(tmp_path):
assert _codes(tmp_path, "import litellm\n\nlitellm.num_retries += 1\n") == ["TQ005"]
def test_litellm_attribute_read_is_not_flagged(tmp_path):
assert _codes(tmp_path, "import litellm\n\nvalue = litellm.drop_params\n") == []
def test_unrelated_attribute_write_is_not_flagged(tmp_path):
assert _codes(tmp_path, "config.drop_params = True\n") == []
def test_suppression_with_a_reason_clears_the_violation(tmp_path):
source = "import sys\n\nsys.path.insert(0, '..') # test-quality-ok: vendored path is required here\n"
assert _codes(tmp_path, source) == []
def test_suppression_without_a_reason_does_not_suppress(tmp_path):
assert _codes(tmp_path, "import sys\n\nsys.path.insert(0, '..') # test-quality-ok:\n") == ["TQ003"]
def test_suppression_on_another_line_does_not_suppress(tmp_path):
source = "import sys # test-quality-ok: this reason sits on the wrong line\n\nsys.path.insert(0, '..')\n"
assert _codes(tmp_path, source) == ["TQ003"]
def test_unparseable_source_degrades_to_tq000(tmp_path):
assert _codes(tmp_path, "def test_broken(:\n pass\n") == ["TQ000"]
def test_every_violation_renders_as_path_line_code_message():
rendered = checker.Violation(Path("tests/test_x.py"), 7, "TQ001", "nothing asserted").render()
assert rendered == "tests/test_x.py:7: TQ001 nothing asserted"
_DIRECT_GATE = """import os
import pytest
def test_live_call():
if not os.getenv("ACME_API_KEY"):
pytest.skip("no key")
assert call() == "ok"
"""
_BOUND_GATE = """import os
import pytest
def test_live_call():
api_key = os.getenv("ACME_API_KEY")
if not api_key:
pytest.skip("no key")
assert call() == "ok"
"""
_MEMBERSHIP_GATE = """import os
import pytest
def test_live_call():
if "ACME_API_KEY" not in os.environ:
pytest.skip("no key")
assert call() == "ok"
"""
def test_a_skip_gated_on_a_missing_credential_is_flagged(tmp_path):
assert _codes(tmp_path, _DIRECT_GATE) == ["TQ006"]
def test_the_gate_is_followed_through_the_local_it_was_bound_to(tmp_path):
assert _codes(tmp_path, _BOUND_GATE) == ["TQ006"]
def test_a_membership_test_against_os_environ_gates_just_the_same(tmp_path):
assert _codes(tmp_path, _MEMBERSHIP_GATE) == ["TQ006"]
def test_a_skip_gated_on_something_that_is_not_a_credential_is_left_alone(tmp_path):
source = _DIRECT_GATE.replace("ACME_API_KEY", "CI_RUNNER_OS")
assert _codes(tmp_path, source) == []
def test_reading_a_credential_without_skipping_on_it_is_left_alone(tmp_path):
source = 'import os\n\n\ndef test_live_call():\n assert call(os.getenv("ACME_API_KEY")) == "ok"\n'
assert _codes(tmp_path, source) == []
def test_a_skip_outside_the_credential_branch_is_left_alone(tmp_path):
source = (
"import os\n"
"import pytest\n"
"\n"
"\n"
"def test_live_call():\n"
' if not os.getenv("ACME_API_KEY"):\n'
" configure()\n"
' pytest.skip("unconditional")\n'
' assert call() == "ok"\n'
)
assert _codes(tmp_path, source) == []
def test_the_credential_skip_is_suppressible_like_every_other_rule(tmp_path):
source = _DIRECT_GATE.replace(
'pytest.skip("no key")',
'pytest.skip("no key") # test-quality-ok: the live suite owns this one',
)
assert _codes(tmp_path, source) == []
def test_a_skip_taken_when_the_credential_is_present_is_left_alone(tmp_path):
source = _DIRECT_GATE.replace('if not os.getenv("ACME_API_KEY")', 'if os.getenv("ACME_API_KEY")')
assert _codes(tmp_path, source) == []
def test_a_none_comparison_reads_as_absence(tmp_path):
source = _BOUND_GATE.replace("if not api_key:", "if api_key is None:")
assert _codes(tmp_path, source) == ["TQ006"]
def test_a_membership_test_without_the_negation_is_left_alone(tmp_path):
source = _MEMBERSHIP_GATE.replace('"ACME_API_KEY" not in os.environ', '"ACME_API_KEY" in os.environ')
assert _codes(tmp_path, source) == []
_SNAPSHOT_CONFTEST = """import litellm
import pytest
@pytest.fixture(autouse=True)
def restore_globals():
original_state = {}
original_state["drop_params"] = litellm.drop_params
for attr in ("api_base", "num_retries"):
original_state[attr] = getattr(litellm, attr)
yield
for attr, value in original_state.items():
setattr(litellm, attr, value)
"""
def _conftest_codes(tmp_path, source, name="conftest.py"):
snippet = tmp_path / name
snippet.write_text(source, encoding="utf-8")
return [v.code for v in checker.check_file(snippet)]
def test_every_snapshotted_global_is_counted_once(tmp_path):
assert _conftest_codes(tmp_path, _SNAPSHOT_CONFTEST) == ["TQ007", "TQ007", "TQ007"]
def test_the_names_come_from_the_loop_tuple_as_well_as_the_direct_keys(tmp_path):
snippet = tmp_path / "conftest.py"
snippet.write_text(_SNAPSHOT_CONFTEST, encoding="utf-8")
reported = [v.message.split("`")[1] for v in checker.check_file(snippet)]
assert sorted(reported) == ["litellm.api_base", "litellm.drop_params", "litellm.num_retries"]
def test_the_same_global_saved_twice_counts_once(tmp_path):
source = _SNAPSHOT_CONFTEST.replace(
'("api_base", "num_retries")', '("api_base", "num_retries", "drop_params")'
)
assert _conftest_codes(tmp_path, source) == ["TQ007", "TQ007", "TQ007"]
def test_the_rule_only_looks_at_conftest_files(tmp_path):
assert _conftest_codes(tmp_path, _SNAPSHOT_CONFTEST, name="test_snapshot.py") == []
def test_a_conftest_that_snapshots_nothing_is_clean(tmp_path):
source = "import pytest\n\n\n@pytest.fixture\ndef client():\n return object()\n"
assert _conftest_codes(tmp_path, source) == []
def test_a_snapshot_entry_is_suppressible_with_a_reason(tmp_path):
source = _SNAPSHOT_CONFTEST.replace(
'original_state["drop_params"] = litellm.drop_params',
'original_state["drop_params"] = litellm.drop_params # test-quality-ok: owned by the SDK config surface',
)
assert _conftest_codes(tmp_path, source) == ["TQ007", "TQ007"]
_NAMED_MAPPING_CONFTEST = """import litellm
import pytest
_SCALAR_DEFAULTS = {
"num_retries": None,
"set_verbose": False,
}
_EXTRA_ATTRS = ("api_base", "drop_params")
@pytest.fixture(autouse=True)
def restore_globals():
original_state = {}
for attr in _SCALAR_DEFAULTS:
original_state[attr] = getattr(litellm, attr)
for attr in _EXTRA_ATTRS:
original_state[attr] = getattr(litellm, attr)
yield
for attr, value in original_state.items():
setattr(litellm, attr, value)
"""
def test_a_save_loop_over_a_module_level_dict_counts_its_keys(tmp_path):
# The two largest inventories in the repo name their list instead of spelling it
# out, so a rule that only reads literal iterables sees neither.
reported = [v.message.split("`")[1] for v in checker.check_file(_written(tmp_path, _NAMED_MAPPING_CONFTEST))]
assert sorted(reported) == [
"litellm.api_base",
"litellm.drop_params",
"litellm.num_retries",
"litellm.set_verbose",
]
def test_a_named_iterable_that_is_not_a_module_constant_is_skipped_quietly(tmp_path):
source = _NAMED_MAPPING_CONFTEST.replace("for attr in _EXTRA_ATTRS:", "for attr in dir(litellm):")
reported = [v.message.split("`")[1] for v in checker.check_file(_written(tmp_path, source))]
assert sorted(reported) == ["litellm.num_retries", "litellm.set_verbose"]
def _written(tmp_path, source, name="conftest.py"):
path = tmp_path / name
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(source, encoding="utf-8")
return path
_HELPER_DICT_CONFTEST = """import litellm
import pytest
_CALLBACK_ATTRS = ("callbacks", "success_callback")
def _copy_litellm_state():
state = {}
for attr in _CALLBACK_ATTRS:
if hasattr(litellm, attr):
value = getattr(litellm, attr)
state[attr] = value.copy() if isinstance(value, list) else value
return state
@pytest.fixture(autouse=True)
def restore_globals():
saved = _copy_litellm_state()
yield
for attr, value in saved.items():
setattr(litellm, attr, value)
"""
def test_a_snapshot_built_in_a_helper_under_any_dict_name_is_counted(tmp_path):
# Two conftests build their inventory inside a helper and call the dict `state`,
# so a rule keyed on blessed dict names sees neither.
reported = [v.message.split("`")[1] for v in checker.check_file(_written(tmp_path, _HELPER_DICT_CONFTEST))]
assert sorted(reported) == ["litellm.callbacks", "litellm.success_callback"]
def test_the_read_may_sit_a_statement_above_the_store(tmp_path):
# `val = getattr(litellm, attr)` then `state[attr] = val.copy()` is the common
# shape; requiring the store itself to read litellm loses every one of them.
source = _HELPER_DICT_CONFTEST.replace(
" state[attr] = value.copy() if isinstance(value, list) else value",
" state[attr] = list(value)",
)
reported = [v.message.split("`")[1] for v in checker.check_file(_written(tmp_path, source))]
assert sorted(reported) == ["litellm.callbacks", "litellm.success_callback"]
def test_a_loop_storing_under_a_key_that_is_not_the_loop_variable_is_not_an_inventory(tmp_path):
source = _HELPER_DICT_CONFTEST.replace("state[attr] =", 'state["fixed"] =')
assert [v.code for v in checker.check_file(_written(tmp_path, source))] == []
_FANS_OUT = checker._worker_count(checker.PARALLEL_MIN_PATHS) > 1
_SERIAL_ONLY = "one usable core, so scan_paths stays serial and there is no fan-out to compare"
def _corpus(tmp_path: Path, count: int) -> tuple[Path, ...]:
for index in range(count):
(tmp_path / f"test_gen_{index}.py").write_text(
f"def test_flagged_{index}():\n compute()\n\n\ndef test_clean_{index}():\n assert compute() == {index}\n",
encoding="utf-8",
)
return tuple(sorted(tmp_path.rglob("*.py")))
def _run_checker(target: Path) -> list[str]:
completed = subprocess.run(
[sys.executable, str(_MODULE_PATH), str(target)],
capture_output=True, text=True, timeout=300,
)
return completed.stdout.splitlines()
def test_worker_count_stays_serial_below_the_threshold():
assert checker._worker_count(checker.PARALLEL_MIN_PATHS - 1) == 1
def test_worker_count_fans_out_at_the_threshold():
assert checker._worker_count(checker.PARALLEL_MIN_PATHS) == max(
1, min(os.cpu_count() or 1, checker.MAX_WORKERS)
)
def test_worker_count_never_exceeds_the_cap():
assert checker._worker_count(100_000) <= checker.MAX_WORKERS
def test_scan_paths_below_the_threshold_returns_every_violation(tmp_path):
paths = _corpus(tmp_path, 3)
assert checker._worker_count(len(paths)) == 1
assert [v.code for v in checker.scan_paths(paths)] == ["TQ001"] * 3
@pytest.mark.skipif(not _FANS_OUT, reason=_SERIAL_ONLY)
def test_a_fanned_out_run_reports_exactly_what_a_serial_run_reports(tmp_path):
paths = _corpus(tmp_path, checker.PARALLEL_MIN_PATHS + 5)
serial = [v.render() for v in sorted(v for path in paths for v in checker.check_file(path))]
assert serial, "corpus must produce violations or the comparison proves nothing"
assert _run_checker(tmp_path) == serial
@pytest.mark.skipif(not _FANS_OUT, reason=_SERIAL_ONLY)
def test_a_fanned_out_run_reports_each_generated_file_exactly_once(tmp_path):
paths = _corpus(tmp_path, checker.PARALLEL_MIN_PATHS + 5)
reported = _run_checker(tmp_path)
assert len(reported) == len(paths)
assert len({line.split(":")[0] for line in reported}) == len(paths)
assert all(" TQ001 " in line for line in reported)
_VIOLATING_SNIPPETS: Final = MappingProxyType(
{
"TQ000": ("test_snippet.py", "def test_broken(:\n pass\n"),
"TQ001": ("test_snippet.py", "def test_nothing():\n compute()\n"),
"TQ002": (
"test_snippet.py",
"from unittest.mock import patch\n"
"\n"
"\n"
"def test_echo():\n"
" with patch('litellm.completion') as mock_completion:\n"
" run()\n"
" mock_completion.assert_called_once()\n",
),
"TQ003": ("test_snippet.py", "import sys\n\nsys.path.insert(0, '..')\n"),
"TQ004": ("test_snippet.py", "import os\n\nos.environ['KEY'] = 'v'\n"),
"TQ005": ("test_snippet.py", "import litellm\n\nlitellm.drop_params = True\n"),
"TQ006": ("test_snippet.py", _DIRECT_GATE),
"TQ007": ("conftest.py", _SNAPSHOT_CONFTEST),
"TQ009": (
"test_snippet.py",
'import subprocess, sys\nsubprocess.run([sys.executable, "-c", "pass"])\n',
),
"TQ010": ("tests/integration/chaos/test_snippet.py", "import os, signal\n\nos.kill(1, signal.SIGKILL)\n"),
"TQ011": ("tests/integration/chaos/test_snippet.py", "def test_fast():\n elapsed = run()\n assert elapsed < 2\n"),
}
)
def test_rule_codes_match_every_code_the_checker_emits(tmp_path):
emitted: Final = frozenset(
v.code
for name, source in _VIOLATING_SNIPPETS.values()
for v in checker.check_file(_written(tmp_path, source, name))
)
for code, (name, source) in _VIOLATING_SNIPPETS.items():
assert code in [v.code for v in checker.check_file(_written(tmp_path, source, name))], code
assert emitted == checker.RULE_CODES
def test_sys_executable_child_without_isolation_flag_is_flagged(tmp_path):
source = 'import subprocess, sys\nsubprocess.run([sys.executable, "-c", "pass"])\n'
assert _codes(tmp_path, source) == ["TQ009"]
def test_sys_executable_child_with_dash_i_is_clean(tmp_path):
source = 'import subprocess, sys\nsubprocess.run([sys.executable, "-I", "-c", "pass"])\n'
assert _codes(tmp_path, source) == []
def test_sys_executable_child_with_dash_p_is_clean(tmp_path):
source = 'import subprocess, sys\nsubprocess.run([sys.executable, "-P", "-c", "pass"])\n'
assert _codes(tmp_path, source) == []
def test_non_interpreter_subprocess_call_is_untouched(tmp_path):
source = 'import subprocess\nsubprocess.run(["python", "-c", "pass"])\n'
assert _codes(tmp_path, source) == []
def test_popen_sys_executable_tuple_is_flagged(tmp_path):
source = 'import subprocess, sys\nsubprocess.Popen((sys.executable, "script.py"))\n'
assert _codes(tmp_path, source) == ["TQ009"]
_CHAOS_TEST: Final = "tests/integration/observability/test_snippet.py"
def _chaos_codes(tmp_path, source, name=_CHAOS_TEST):
return [v.code for v in checker.check_file(_written(tmp_path, source, name))]
@pytest.mark.parametrize(
"call",
(
"os.kill(pid, signal.SIGKILL)",
"os.killpg(pid, signal.SIGTERM)",
"os.kill(pid, 0)",
"worker.send_signal(signal.SIGTERM)",
"signal_group(pid, signal.SIGKILL)",
"redis.signal(SIGSTOP)",
"redis.signal(signal.SIGCONT)",
"worker.kill()",
"worker.terminate()",
"worker.suspend()",
"worker.resume()",
),
)
def test_an_integration_test_that_signals_a_process_itself_is_flagged_once_per_call(tmp_path, call):
assert _chaos_codes(tmp_path, f"import os, signal\nfrom signal import SIGSTOP\n\n{call}\n") == ["TQ010"]
@pytest.mark.parametrize(
"source",
(
"assert record['exit_before_stop'] == -signal.SIGKILL\n",
"signal.signal(signal.SIGTERM, handler)\n",
"task.cancel()\n",
"slot.kill(reason)\n",
"owned.kill_worker(pid)\n",
"stop_child(process)\n",
),
)
def test_reading_a_signal_number_or_calling_a_harness_helper_is_not_signalling(tmp_path, source):
assert _chaos_codes(tmp_path, f"import signal\n\n{source}") == []
@pytest.mark.parametrize(
"name",
(
"tests/integration/_support/process.py",
"tests/unit/test_snippet.py",
"tests/e2e/integration_like/test_snippet.py",
),
)
def test_the_signal_rule_only_applies_to_integration_tests_outside_the_harness(tmp_path, name):
assert _chaos_codes(tmp_path, "import os, signal\n\nos.kill(1, signal.SIGKILL)\nworker.suspend()\n", name) == []
def test_the_signal_rule_is_suppressible_with_a_reason(tmp_path):
source = "import os, signal\n\nos.kill(1, signal.SIGKILL) # test-quality-ok: reaps a leaked fake helper\n"
assert _chaos_codes(tmp_path, source) == []
@pytest.mark.parametrize(
"assertion",
(
"assert elapsed < 2",
"assert 2 > elapsed",
"assert elapsed <= 2.5",
"assert time.monotonic() - started < 5",
"assert all(duration < 2 for _, duration in results)",
"assert max(latencies) < 1",
"assert response.elapsed.total_seconds() < 5",
"assert outcome.elapsed < BUDGET_SECONDS",
"assert elapsed < BUDGET_SECONDS - 1",
"assert 59 <= elapsed <= 75",
"assert taken < 3",
),
)
def test_an_elapsed_time_capped_by_a_number_is_flagged(tmp_path, assertion):
source = (
"import time\n\nBUDGET_SECONDS = 10\n\n\n"
"def test_fast():\n"
" started = time.monotonic()\n"
" taken = time.perf_counter() - started\n"
f" {assertion}\n"
)
assert _chaos_codes(tmp_path, source) == ["TQ011"]
@pytest.mark.parametrize(
"statement",
(
"assert elapsed >= 2",
"assert 2 <= elapsed",
"assert elapsed < 25 * control_elapsed",
"assert elapsed < control + injected_delay",
"assert_enforced_within(elapsed, configured=CAP_SECONDS, slack=15, not_before=CAP_SECONDS - 1)",
"assert_cut_short(time.monotonic() - started, injected_delay=30)",
"assert after - baseline < BUDGET_SECONDS",
"assert len(durations) == 3",
"assert count < 2",
"while time.monotonic() - started < 30:\n poll()",
),
)
def test_lower_bounds_relative_bounds_counts_and_polling_deadlines_are_left_alone(tmp_path, statement):
source = (
"import time\n\nBUDGET_SECONDS = 10\n\n\n"
"def _relative():\n"
" started = time.monotonic()\n"
" baseline = settled_reads(read(), time.monotonic())\n"
f" {statement}\n"
)
assert _chaos_codes(tmp_path, source) == []
def test_a_clock_bound_name_is_only_an_elapsed_time_in_the_function_that_binds_it(tmp_path):
source = (
"import time\n\n\n"
"def _measure():\n"
" taken = time.monotonic() - 1\n"
" return taken\n\n\n"
"def test_counts():\n"
" taken = len(rows())\n"
" assert taken < 3\n"
)
assert _chaos_codes(tmp_path, source) == []
def test_the_wall_clock_rule_only_applies_to_integration_tests_outside_the_harness(tmp_path):
source = "def test_fast():\n elapsed = run()\n assert elapsed < 2\n"
assert _chaos_codes(tmp_path, source, "tests/unit/test_snippet.py") == []
assert _chaos_codes(tmp_path, source, "tests/integration/_support/timing.py") == []