Files
openrun/tests/unit/test_fit_download.py

136 lines
4.5 KiB
Python
Raw Normal View History

2026-06-12 05:48:30 -04:00
"""Path B per-second: pulling original FITs from the API instead of a website export.
`download_fit` / `backfill_fits` are mocked at the `garth.download` boundary
(network-dependent, upstream-deprecated see ROADMAP test conventions). The FIT
extractor is pure and tested directly.
"""
from __future__ import annotations
import io
import zipfile
import pytest
from openrun.ingest import garmin_api as g
# A FIT header carries the literal b".FIT" at bytes 8..12; payload after is opaque here.
FIT_BYTES = b"\x0e\x10\x00\x00\x20\x00\x00\x00.FITdata-goes-here"
def _zip(*members: tuple[str, bytes]) -> bytes:
buf = io.BytesIO()
with zipfile.ZipFile(buf, "w") as zf:
for name, data in members:
zf.writestr(name, data)
return buf.getvalue()
# --- _extract_fit_bytes ----------------------------------------------------
def test_extract_from_zip():
assert g._extract_fit_bytes(_zip(("9.fit", FIT_BYTES))) == FIT_BYTES
def test_extract_from_zip_extensionless_member_picks_largest():
blob = _zip(("small", b"x"), ("big", FIT_BYTES))
assert g._extract_fit_bytes(blob) == FIT_BYTES
def test_extract_from_bare_fit():
assert g._extract_fit_bytes(FIT_BYTES) == FIT_BYTES
@pytest.mark.parametrize("blob", [None, b"", b"not a fit at all"])
def test_extract_rejects_non_fit(blob):
assert g._extract_fit_bytes(blob) is None
# --- download_fit ----------------------------------------------------------
def _seed_activity(conn, aid: int, atype: str = "running") -> None:
conn.execute(
"INSERT INTO activities (activity_id, activity_type, start_time_gmt, raw, fetched_at) "
"VALUES (?, ?, ?, ?, datetime('now'))",
(aid, atype, "2026-05-01T10:00:00", "{}"),
)
def test_download_fit_writes_and_links(tmp_conn, tmp_path, monkeypatch):
_seed_activity(tmp_conn, 42)
monkeypatch.setattr(g.garth, "download", lambda path: _zip(("42.fit", FIT_BYTES)))
ok = g.download_fit(tmp_conn, 42, fit_dir=tmp_path)
assert ok is True
dest = tmp_path / "42.fit"
assert dest.read_bytes() == FIT_BYTES
row = tmp_conn.execute(
"SELECT fit_path FROM activity_fit_files WHERE activity_id = 42"
).fetchone()
assert row is not None and row[0].endswith("42.fit")
def test_download_fit_skips_when_already_linked(tmp_conn, tmp_path, monkeypatch):
_seed_activity(tmp_conn, 7)
(tmp_path / "7.fit").write_bytes(FIT_BYTES)
g.record_link(tmp_conn, 7, tmp_path / "7.fit")
calls = []
monkeypatch.setattr(g.garth, "download", lambda path: calls.append(path) or b"")
assert g.download_fit(tmp_conn, 7, fit_dir=tmp_path) is True
assert calls == [] # no network call when on disk + linked
def test_download_fit_force_redownloads(tmp_conn, tmp_path, monkeypatch):
_seed_activity(tmp_conn, 7)
(tmp_path / "7.fit").write_bytes(b"stale")
g.record_link(tmp_conn, 7, tmp_path / "7.fit")
monkeypatch.setattr(g.garth, "download", lambda path: _zip(("7.fit", FIT_BYTES)))
assert g.download_fit(tmp_conn, 7, fit_dir=tmp_path, force=True) is True
assert (tmp_path / "7.fit").read_bytes() == FIT_BYTES
def test_download_fit_returns_false_on_empty_response(tmp_conn, tmp_path, monkeypatch):
_seed_activity(tmp_conn, 99)
monkeypatch.setattr(g.garth, "download", lambda path: None)
assert g.download_fit(tmp_conn, 99, fit_dir=tmp_path) is False
assert tmp_conn.execute(
"SELECT 1 FROM activity_fit_files WHERE activity_id = 99"
).fetchone() is None
# --- backfill_fits ---------------------------------------------------------
def test_backfill_only_targets_unlinked(tmp_conn, tmp_path, monkeypatch):
_seed_activity(tmp_conn, 1)
_seed_activity(tmp_conn, 2)
(tmp_path / "1.fit").write_bytes(FIT_BYTES)
g.record_link(tmp_conn, 1, tmp_path / "1.fit") # 1 already has a FIT
pulled = []
monkeypatch.setattr(
g.garth, "download",
lambda path: pulled.append(path) or _zip(("x.fit", FIT_BYTES)),
)
got = g.backfill_fits(tmp_conn, fit_dir=tmp_path)
assert got == 1
assert pulled == ["/download-service/files/activity/2"]
def test_backfill_respects_type_filter(tmp_conn, tmp_path, monkeypatch):
_seed_activity(tmp_conn, 10, atype="running")
_seed_activity(tmp_conn, 11, atype="cycling")
monkeypatch.setattr(g.garth, "download", lambda path: _zip(("x.fit", FIT_BYTES)))
got = g.backfill_fits(tmp_conn, fit_dir=tmp_path, activity_type="running")
assert got == 1
assert (tmp_path / "10.fit").exists()
assert not (tmp_path / "11.fit").exists()