2109e3544a
bggpipe resolve works end to end: search -> exact/fuzzy candidate scoring -> auto/ambiguous/unmatched classification with owned-count tie-breaks (mixed base/expansion candidates never auto-match), version scoring from edition cues (never guessed; no cues -> version_unknown), idempotent matches.csv appends. Discovered mid-build: BGG now requires registered-application Bearer tokens on the XML API (2025 policy change) and returns 401 otherwise. Client sends Authorization from BGG_API_TOKEN and raises an actionable BGGAuthError; CLAUDE.md and the bgg-api skill are updated to match. Live fixture recording is blocked until registration is approved, so tests replay hand-crafted stub fixtures via a network-refusing transport; scripts/record_fixtures.py re-records real XML under the same cache keys once a token exists. One live read-only smoke test is skipped unless --run-live. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
32 lines
1015 B
Python
32 lines
1015 B
Python
"""The one test allowed to touch the real BGG API. Read-only, skipped by
|
|
default; run with: uv run pytest --run-live -m live
|
|
|
|
Needs bgg_username in config.toml and BGG_API_TOKEN in the environment
|
|
(register at https://boardgamegeek.com/applications).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from bggpipe.bgg_client import BGGClient
|
|
from bggpipe.config import load_config
|
|
|
|
|
|
@pytest.mark.live
|
|
def test_fetch_own_collection_read_only(tmp_path: Path) -> None:
|
|
cfg = load_config()
|
|
if not cfg.bgg_username:
|
|
pytest.skip("set bgg_username in config.toml to run the live smoke test")
|
|
if not os.environ.get("BGG_API_TOKEN"):
|
|
pytest.skip("set BGG_API_TOKEN to run the live smoke test")
|
|
|
|
# fresh cache dir so this genuinely exercises the live API + 202 queue
|
|
client = BGGClient(cache_dir=tmp_path / "cache")
|
|
items = client.collection_full(cfg.bgg_username)
|
|
assert isinstance(items, list)
|
|
assert all(item.own for item in items)
|