import pytest from unittest.mock import MagicMock, patch from datetime import datetime, timedelta import garth from garth.exc import GarthException from src.services.garmin.client import GarminClient from src.models.api_token import APIToken # Needed for AuthMixin @pytest.fixture def garmin_client_instance(): """Fixture for a GarminClient instance with test credentials.""" client = GarminClient(username="testuser", password="testpassword") client.is_connected = True # Assume connected for data tests return client @patch("garth.client.connectapi") def test_get_activities_success(mock_connectapi, garmin_client_instance): """Test successful fetching of activities.""" mock_connectapi.return_value = [{"activityId": 1, "activityName": "Run"}, {"activityId": 2, "activityName": "Bike"}] start_date = "2023-01-01" end_date = "2023-01-07" limit = 2 activities = garmin_client_instance.get_activities(start_date, end_date, limit) mock_connectapi.assert_called_once_with( "/activitylist-service/activities/search/activities", params={"startDate": start_date, "endDate": end_date, "limit": limit} ) assert len(activities) == 2 assert activities[0]["activityName"] == "Run" @patch("garth.client.connectapi") def test_get_activities_failure(mock_connectapi, garmin_client_instance): """Test failure during fetching of activities.""" mock_connectapi.side_effect = GarthException("API error") start_date = "2023-01-01" end_date = "2023-01-07" limit = 2 with pytest.raises(GarthException, match="API error"): garmin_client_instance.get_activities(start_date, end_date, limit) mock_connectapi.assert_called_once() @patch("garth.client.download") def test_download_activity_success(mock_download, garmin_client_instance): """Test successful downloading of an activity file.""" mock_download.return_value = b"file_content_mock" activity_id = "12345" file_type = "tcx" file_content = garmin_client_instance.download_activity(activity_id, file_type) mock_download.assert_called_once_with(f"/download-service/export/{file_type}/activity/{activity_id}") assert file_content == b"file_content_mock" @patch("garth.client.download") def test_download_activity_failure(mock_download, garmin_client_instance): """Test failure during downloading of an activity file.""" mock_download.side_effect = GarthException("Download error") activity_id = "12345" file_type = "gpx" file_content = garmin_client_instance.download_activity(activity_id, file_type) mock_download.assert_called_once() assert file_content is None # Should return None on exception @patch("src.services.garmin.data.DailySteps") @patch("src.services.garmin.data.DailyHRV") @patch("src.services.garmin.data.SleepData") def test_get_daily_metrics_success(mock_sleep_data, mock_daily_hrv, mock_daily_steps, garmin_client_instance): """Test successful fetching of daily metrics.""" mock_daily_steps.list.return_value = [MagicMock(calendar_date="2023-01-01", total_steps=1000)] mock_daily_hrv.list.return_value = [MagicMock(calendar_date="2023-01-01", last_night_avg=50)] mock_sleep_data.list.return_value = [MagicMock(daily_sleep_dto=MagicMock(calendar_date="2023-01-01", sleep_time_seconds=28800))] start_date = "2023-01-01" end_date = "2023-01-01" metrics = garmin_client_instance.get_daily_metrics(start_date, end_date) mock_daily_steps.list.assert_called_once_with(datetime(2023, 1, 1).date(), period=1) mock_daily_hrv.list.assert_called_once_with(datetime(2023, 1, 1).date(), period=1) mock_sleep_data.list.assert_called_once_with(datetime(2023, 1, 1).date(), days=1) assert len(metrics["steps"]) == 1 assert metrics["steps"][0].total_steps == 1000 assert len(metrics["hrv"]) == 1 assert metrics["hrv"][0].last_night_avg == 50 assert len(metrics["sleep"]) == 1 assert metrics["sleep"][0].daily_sleep_dto.sleep_time_seconds == 28800 @patch("src.services.garmin.data.DailySteps") @patch("src.services.garmin.data.DailyHRV") @patch("src.services.garmin.data.SleepData") def test_get_daily_metrics_partial_failure(mock_sleep_data, mock_daily_hrv, mock_daily_steps, garmin_client_instance): """Test fetching daily metrics with some failures.""" mock_daily_steps.list.side_effect = GarthException("Steps error") mock_daily_hrv.list.return_value = [MagicMock(calendar_date="2023-01-01", last_night_avg=50)] mock_sleep_data.list.return_value = [] start_date = "2023-01-01" end_date = "2023-01-01" metrics = garmin_client_instance.get_daily_metrics(start_date, end_date) assert metrics["steps"] == [] # Should return empty list on error assert len(metrics["hrv"]) == 1 assert metrics["sleep"] == []