test_lac_stress.py python
59 lines 2.4 KB
Raw
sha256:0e9549ec7b463911bc08b7d586dc320b1ac9b1f5c943ee7e3865dcc6cb0f6f83 chore(governance): sync handover+roadmap to 84db8c8 (drift:… Human 1 day ago
1 """Stress tests — concurrent landing SVG + api/health GETs (§LAC.12)."""
2
3 from __future__ import annotations
4
5 from concurrent.futures import ThreadPoolExecutor, as_completed
6 from pathlib import Path
7
8 import urllib.request
9
10 from tests.fixtures.app import seed_app_repo, start_test_app
11
12 KIT_ROOT = Path(__file__).resolve().parents[2]
13 LANDING_SVGS = (
14 KIT_ROOT / "docs" / "landing" / "assets" / "diagrams" / "lanes.svg",
15 KIT_ROOT / "docs" / "landing" / "assets" / "diagrams" / "regimes.svg",
16 KIT_ROOT / "docs" / "landing" / "assets" / "diagrams" / "layers.svg",
17 KIT_ROOT / "docs" / "landing" / "assets" / "diagrams" / "kit-consumer.svg",
18 )
19
20
21 def test_concurrent_landing_svgs_and_health_do_not_leak_credentials(tmp_path: Path) -> None:
22 seed_app_repo(tmp_path)
23 handle, client = start_test_app(tmp_path)
24 try:
25 def one_round(i: int) -> tuple[int, str]:
26 svg = LANDING_SVGS[i % len(LANDING_SVGS)]
27 text = svg.read_text(encoding="utf-8")
28 status, health = client.get("/api/health")
29 blob = text + "\n" + str(health)
30 return status, blob
31
32 with ThreadPoolExecutor(max_workers=8) as pool:
33 futures = [pool.submit(one_round, i) for i in range(24)]
34 for fut in as_completed(futures):
35 status, blob = fut.result()
36 assert status == 200
37 assert client.session not in blob
38 assert client.csrf not in blob
39 assert "test-session-credential" not in blob
40 assert "test-csrf-token" not in blob
41
42 # Static path also survives concurrent GETs of Path B diagrams.
43 def fetch_svg(name: str) -> int:
44 req = urllib.request.Request(
45 f"{client.base_url}/assets/diagrams/{name}",
46 headers={"Authorization": f"Bearer {client.session}"},
47 )
48 with urllib.request.urlopen(req, timeout=5) as response:
49 body = response.read()
50 assert client.session.encode() not in body
51 return response.status
52
53 names = ["lanes.svg", "regimes.svg", "layers.svg", "kit-consumer.svg"]
54 with ThreadPoolExecutor(max_workers=8) as pool:
55 futs = [pool.submit(fetch_svg, names[i % 4]) for i in range(20)]
56 for fut in as_completed(futs):
57 assert fut.result() == 200
58 finally:
59 handle.shutdown()
File History 1 commit
sha256:6abcf1fa82a7a621ccbc945f19acdba5bc0db54569599404a1452fb4a096a199 fix(ISR): default require_independent_second_reviewer to require Human minor 1 day ago