mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-10 21:47:02 +01:00
Endurain API keys are upload-only by design: the scope allow-list is
frozenset({"activities:upload"}), enforced in both validate_api_key_scopes
and the create schema, and the activities read route is mounted with
validate_access_token rather than validate_access_token_or_api_key. A key
therefore fails at authentication before any scope check, so the HTTP
dedupe check added in 325d5a8b could never succeed and every pass fell
back to the ledger alone. Verified against v0.19.0; upstream documents no
plan to widen the allow-list.
Read the start times out of postgres instead. The container publishes no
host port, so this goes through docker exec -- no new dependency and no
port opened just to read four rows. The HTTP path is still tried first so
the supported route resumes working on its own if the allow-list ever
grows.
None and [] are kept strictly apart: a dead container, timeout or non-zero
exit means "could not ask" and returns to the ledger, while an empty result
set is a real answer. Conflating them would re-upload everything on any
docker hiccup, which is the bug the dedupe check exists to prevent.
Proven with an empty ledger: the known-duplicate TCX was skipped and the
activity count held at 4, and the same file WAS imported with
ENDURAIN_NO_DB=1, so the check is what blocks it. The duplicate that
negative control created was removed afterwards.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GbYEnfGnf1988cdFdGebot
78 lines
2.3 KiB
Python
78 lines
2.3 KiB
Python
"""Shared fixtures for the endurain_import orchestration tests."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
from pathlib import Path
|
|
from typing import TYPE_CHECKING
|
|
|
|
import pytest
|
|
|
|
if TYPE_CHECKING:
|
|
from python_pkg.endurain_import.upload import Result
|
|
|
|
|
|
@pytest.fixture
|
|
def inbox(tmp_path: Path) -> Path:
|
|
path = tmp_path / "inbox"
|
|
path.mkdir()
|
|
return path
|
|
|
|
|
|
def _file(inbox: Path, name: str = "RunnerUp_ts_Running.tcx") -> Path:
|
|
path = inbox / name
|
|
path.write_text("<xml/>")
|
|
return path
|
|
|
|
|
|
class _StubMainClient:
|
|
"""Stands in for EndurainClient across a whole main() run."""
|
|
|
|
def __init__(
|
|
self,
|
|
result: Result,
|
|
*,
|
|
reachable: bool = True,
|
|
remote: list[datetime] | None = None,
|
|
) -> None:
|
|
self._result = result
|
|
self._reachable = reachable
|
|
self._remote = remote
|
|
self.uploads = 0
|
|
|
|
def about(self) -> dict[str, object]:
|
|
if not self._reachable:
|
|
message = "connection refused"
|
|
raise OSError(message)
|
|
return {"version": "test"}
|
|
|
|
def recent_start_times(self, _user_id: int) -> list[datetime] | None:
|
|
return self._remote
|
|
|
|
def upload(self, _path: Path) -> Result:
|
|
self.uploads += 1
|
|
return self._result
|
|
|
|
|
|
def _env(
|
|
monkeypatch: pytest.MonkeyPatch, tmp_path: Path, inbox: Path, **extra: str
|
|
) -> None:
|
|
monkeypatch.setenv("ENDURAIN_API_KEY", "k")
|
|
monkeypatch.setenv("ENDURAIN_INBOX", str(inbox))
|
|
monkeypatch.setenv("ENDURAIN_STATE", str(tmp_path / "state"))
|
|
monkeypatch.setenv("ENDURAIN_NO_ADB", "1")
|
|
# Off by default so no test ever shells out to the real postgres container:
|
|
# the DB fallback runs whenever the stubbed HTTP lookup returns None, and a
|
|
# test that reached the live database would pass or fail on this machine's
|
|
# actual activity rows. Tests that want it set ENDURAIN_NO_DB="0" and stub
|
|
# EndurainDatabase explicitly.
|
|
monkeypatch.setenv("ENDURAIN_NO_DB", "1")
|
|
for key, value in extra.items():
|
|
monkeypatch.setenv(key, value)
|
|
|
|
|
|
def _patch_client(monkeypatch: pytest.MonkeyPatch, client: _StubMainClient) -> None:
|
|
import python_pkg.endurain_import.__main__ as mod
|
|
|
|
monkeypatch.setattr(mod, "EndurainClient", lambda *_a, **_k: client)
|