feat: AM-2 wire swiftly_auth.get_token() into LuckyCaliforniaScraper

fetch_category() now calls swiftly_auth.get_token() to mint a fresh
Firebase JWT on demand when no explicit bearer_token override is
pinned by tests. The cache short-circuit means the per-call mint
overhead is ~zero in the steady state.

- Removed the empty-token short-circuit; auto-mint makes it moot
- Updated _AUTH_ERROR_MESSAGE: 401-after-mint now points at the spec
  (Lucky tightening anon-auth) rather than asking for manual capture
- Replaced test_swiftly_auth_error_when_token_missing with a positive
  test that verifies fetch_category mints when bearer_token is None
- bearer_token constructor arg preserved for the 401-path test

Full suite: 92/92 green. Live verification via
scripts/spike_swiftly_ingest.py --confirm-live deferred to next step
per HANDOFF AM-2 halt boundary.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-06 15:27:37 -07:00
co-authored by Claude Opus 4.7
parent 5e0a49e4ae
commit dfd79a9d08
2 changed files with 33 additions and 18 deletions
+21 -12
View File
@@ -140,22 +140,31 @@ def test_swiftly_auth_error_on_401_from_api() -> None:
with pytest.raises(SwiftlyAuthError) as excinfo:
scraper.fetch_category("Product/meat_seafood")
assert "SWIFTLY_BEARER_TOKEN expired" in str(excinfo.value)
assert "Swiftly returned 401" in str(excinfo.value)
def test_swiftly_auth_error_when_token_missing() -> None:
"""An empty token short-circuits to SwiftlyAuthError without any HTTP call.
Force the token empty AFTER construction so the test is independent of
whatever ``SWIFTLY_BEARER_TOKEN`` happens to be set in the environment
(it WILL be set when pytest runs inside ``docker compose``).
def test_fetch_category_mints_token_when_none_pinned() -> None:
"""With no explicit bearer_token, fetch_category calls swiftly_auth.get_token()
and threads the minted JWT into the Authorization header.
"""
from app.scraper import lucky_ca_scraper as scraper_mod
scraper = LuckyCaliforniaScraper()
scraper.bearer_token = ""
with patch.object(scraper.api_session, "get") as mock_get:
with pytest.raises(SwiftlyAuthError):
scraper.fetch_category("Product/meat_seafood")
mock_get.assert_not_called()
assert scraper.bearer_token is None # auto-mint path
with patch.object(scraper_mod, "_get_swiftly_token", return_value="minted-jwt") as mtoken, \
patch.object(
scraper.api_session,
"get",
return_value=_mock_response(
200, payload={"products": {"items": []}}
),
) as mget:
scraper.fetch_category("Product/meat_seafood")
mtoken.assert_called_once()
sent_headers = mget.call_args.kwargs["headers"]
assert sent_headers["Authorization"] == "Bearer minted-jwt"
@pytest.mark.requires_postgres