import json import pytest import shutil import tempfile from pathlib import Path from datastore import DatastoreEngine from garmin_sync import GarminSyncClient, GarminMirrorWriter, sync_date_range, generate_date_list @pytest.fixture def temp_data_dir(): temp_dir = tempfile.mkdtemp(prefix="garmin_test_") data_dir = Path(temp_dir) # create standard dirs (data_dir / "garmin").mkdir(parents=True) yield data_dir shutil.rmtree(temp_dir) def test_garmin_sync_mock_and_idempotency(temp_data_dir): client = GarminSyncClient(token_dir=temp_data_dir, mock=True) writer = GarminMirrorWriter(temp_data_dir) dates = ["2026-10-01", "2026-10-02"] sync_date_range(client, writer, dates) daily_file = temp_data_dir / "garmin" / "daily" / "2026-10.jsonl" sleep_file = temp_data_dir / "garmin" / "sleep" / "2026-10.jsonl" activities_file = temp_data_dir / "garmin" / "activities" / "2026-10.jsonl" assert daily_file.is_file() assert sleep_file.is_file() assert activities_file.is_file() # Read daily lines with open(daily_file) as f: daily_lines = [json.loads(line) for line in f if line.strip()] assert len(daily_lines) == 2 assert daily_lines[0]["calendarDate"] == "2026-10-01" assert daily_lines[1]["calendarDate"] == "2026-10-02" # Re-syncing 2026-10-01 must not create duplicates (idempotent upsert) sync_date_range(client, writer, ["2026-10-01"]) with open(daily_file) as f: daily_lines_after = [json.loads(line) for line in f if line.strip()] assert len(daily_lines_after) == 2 # Check activities with open(activities_file) as f: act_lines = [json.loads(line) for line in f if line.strip()] # Mock returns activityId 987654321 for each day, so deduplication keeps 1 record with latest info assert len(act_lines) == 1 assert act_lines[0]["activityId"] == 987654321 def test_generate_date_list(): dates = generate_date_list("2026-09-28", "2026-10-01") assert dates == ["2026-09-28", "2026-09-29", "2026-09-30", "2026-10-01"] # Reversed dates should automatically normalize dates_rev = generate_date_list("2026-10-01", "2026-09-28") assert dates_rev == ["2026-09-28", "2026-09-29", "2026-09-30", "2026-10-01"] def test_garmin_auth_error_handling(temp_data_dir): # Non-mock client with empty dir should raise FileNotFoundError with pytest.raises(FileNotFoundError): GarminSyncClient(token_dir=temp_data_dir, mock=False)