mirror of
https://github.com/mwisnowski/mtg_python_deckbuilder.git
synced 2025-12-17 08:00:13 +01:00
feat(preview): sampling, metrics, governance, server mana data
Preview endpoint + fast caches; curated pins + role quotas + rarity/overlap tuning; catalog+preview metrics; governance enforcement flags; server mana/color identity fields; docs/tests/scripts updated.
This commit is contained in:
parent
8f47dfbb81
commit
c4a7fc48ea
40 changed files with 6092 additions and 17312 deletions
72
code/tests/test_theme_preview_p0_new.py
Normal file
72
code/tests/test_theme_preview_p0_new.py
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import os
|
||||
import time
|
||||
import json
|
||||
from code.web.services.theme_preview import get_theme_preview, preview_metrics, bust_preview_cache # type: ignore
|
||||
|
||||
|
||||
def test_colors_filter_constraint_green_subset():
|
||||
"""colors=G should only return cards whose color identities are subset of {G} or colorless ('' list)."""
|
||||
payload = get_theme_preview('Blink', limit=8, colors='G') # pick any theme; data-driven
|
||||
for card in payload['sample']:
|
||||
if not card['colors']:
|
||||
continue
|
||||
assert set(card['colors']).issubset({'G'}), f"Card {card['name']} had colors {card['colors']} outside filter"
|
||||
|
||||
|
||||
def test_synthetic_placeholder_fill_present_when_short():
|
||||
# Force scarcity via impossible color filter letter ensuring empty real pool -> synthetic placeholders
|
||||
payload = get_theme_preview('Blink', limit=50, colors='Z')
|
||||
# All real cards filtered out; placeholders must appear
|
||||
synthetic_roles = [c for c in payload['sample'] if 'synthetic' in (c.get('roles') or [])]
|
||||
assert synthetic_roles, 'Expected at least one synthetic placeholder entry under restrictive color filter'
|
||||
assert any('synthetic_synergy_placeholder' in (c.get('reasons') or []) for c in synthetic_roles), 'Missing synthetic placeholder reason'
|
||||
|
||||
|
||||
def test_cache_hit_timing_and_log(monkeypatch, capsys):
|
||||
os.environ['WEB_THEME_PREVIEW_LOG'] = '1'
|
||||
# Force fresh build
|
||||
bust_preview_cache()
|
||||
payload1 = get_theme_preview('Blink', limit=6)
|
||||
assert payload1['cache_hit'] is False
|
||||
# Second call should hit cache
|
||||
payload2 = get_theme_preview('Blink', limit=6)
|
||||
assert payload2['cache_hit'] is True
|
||||
captured = capsys.readouterr().out.splitlines()
|
||||
assert any('theme_preview_build' in line for line in captured), 'Missing build log'
|
||||
assert any('theme_preview_cache_hit' in line for line in captured), 'Missing cache hit log'
|
||||
|
||||
|
||||
def test_per_theme_percentiles_and_raw_counts():
|
||||
bust_preview_cache()
|
||||
for _ in range(5):
|
||||
get_theme_preview('Blink', limit=6)
|
||||
metrics = preview_metrics()
|
||||
per = metrics['per_theme']
|
||||
assert 'blink' in per, 'Expected theme slug in per_theme metrics'
|
||||
blink_stats = per['blink']
|
||||
assert 'p50_ms' in blink_stats and 'p95_ms' in blink_stats, 'Missing percentile metrics'
|
||||
assert 'curated_total' in blink_stats and 'sampled_total' in blink_stats, 'Missing raw curated/sample per-theme totals'
|
||||
|
||||
|
||||
def test_structured_log_contains_new_fields(capsys):
|
||||
os.environ['WEB_THEME_PREVIEW_LOG'] = '1'
|
||||
bust_preview_cache()
|
||||
get_theme_preview('Blink', limit=5)
|
||||
out_lines = capsys.readouterr().out.splitlines()
|
||||
build_lines = [line for line in out_lines if 'theme_preview_build' in line]
|
||||
assert build_lines, 'No build log lines found'
|
||||
parsed = [json.loads(line) for line in build_lines]
|
||||
obj = parsed[-1]
|
||||
assert 'curated_total' in obj and 'sampled_total' in obj and 'role_counts' in obj, 'Missing expected structured log fields'
|
||||
|
||||
|
||||
def test_warm_index_latency_reduction():
|
||||
bust_preview_cache()
|
||||
t0 = time.time()
|
||||
get_theme_preview('Blink', limit=6)
|
||||
cold = time.time() - t0
|
||||
t1 = time.time()
|
||||
get_theme_preview('Blink', limit=6)
|
||||
warm = time.time() - t1
|
||||
# Warm path should generally be faster; allow flakiness with generous factor
|
||||
assert warm <= cold * 1.2, f"Expected warm path faster or near equal (cold={cold}, warm={warm})"
|
||||
Loading…
Add table
Add a link
Reference in a new issue