The 7 baselined Optional accesses in plex/stream.py were one fact the type did not carry: the initial spawn (replace_only=None) always supersedes, so only the fallback respawn can get None. An assert at the call site says so; the pyright baseline drops 195 -> 188. test_abuse_limits: the public-URL and YouTube enqueue tests stopped at the profile lookup (400 no_profile) and passed on that unrelated refusal. They now send an inline spec and assert the job is queued. The same shape — a request whose response is discarded — sat at 53 more places across the suite (all returned what they should, measured with a TestClient probe); each now asserts its status, and test_response_checked keeps it that way (seen red).
59 lines
2.4 KiB
Python
59 lines
2.4 KiB
Python
"""No test sends a request and throws the response away (E32 S2).
|
|
|
|
A discarded `client.post(...)` passes whatever it got back. As a SETUP step, a failure leaves the
|
|
test asserting on a state it never reached; as the step UNDER test, the test proves nothing. E32
|
|
found `test_youtube_sources_never_consult_the_guard` passing on a 400 that stopped the request
|
|
before the code it meant to exercise, and 53 more discarded responses across the suite. Each one
|
|
now states the status it expects; this keeps it that way.
|
|
"""
|
|
|
|
import ast
|
|
from pathlib import Path
|
|
|
|
TESTS = Path(__file__).resolve().parent
|
|
VERBS = {"get", "post", "put", "patch", "delete", "head", "options", "request"}
|
|
|
|
|
|
def discarded_requests(source: str) -> list[int]:
|
|
"""Line numbers of the statements that are a bare request call on an app path."""
|
|
hits = []
|
|
for node in ast.walk(ast.parse(source)):
|
|
if not (isinstance(node, ast.Expr) and isinstance(node.value, ast.Call)):
|
|
continue
|
|
func = node.value.func
|
|
if not (isinstance(func, ast.Attribute) and func.attr in VERBS):
|
|
continue
|
|
path = node.value.args[0] if node.value.args else None
|
|
literal = path.value if isinstance(path, ast.Constant) else None
|
|
if isinstance(path, ast.JoinedStr):
|
|
first = path.values[0] if path.values else None
|
|
literal = first.value if isinstance(first, ast.Constant) else None
|
|
if isinstance(literal, str) and literal.startswith(("/api", "/auth")):
|
|
hits.append(node.lineno)
|
|
return hits
|
|
|
|
|
|
def test_the_detector_sees_a_discarded_request_and_passes_a_checked_one():
|
|
src = (
|
|
"client.post('/api/x')\n"
|
|
"client.get(f'/auth/{u}')\n"
|
|
"assert client.post('/api/x').status_code == 200\n"
|
|
"r = client.get('/api/y')\n"
|
|
"items.get('/api/not-a-request-but-a-key')\n"
|
|
)
|
|
# The last line is a false positive by design: a dict keyed by an app path is not a thing the
|
|
# suite does, and a narrower match would miss a client held under any other name.
|
|
assert discarded_requests(src) == [1, 2, 5]
|
|
|
|
|
|
def test_no_test_discards_a_response():
|
|
offenders = [
|
|
f"{p.name}:{line}"
|
|
for p in sorted(TESTS.rglob("test_*.py"))
|
|
for line in discarded_requests(p.read_text(encoding="utf-8"))
|
|
]
|
|
assert offenders == [], (
|
|
"assert the status these requests expect (`assert client.post(...).status_code == 200`), "
|
|
f"or keep the response and check it: {offenders}"
|
|
)
|