feat: Implement single sync job management and progress tracking

This commit is contained in:
2025-10-11 18:36:19 -07:00
parent 3819e4f5e2
commit 723ca04aa8
51 changed files with 1625 additions and 596 deletions

View File

@@ -1,40 +1,44 @@
from unittest.mock import AsyncMock, patch
import pytest
from backend.src.schemas import GarminCredentials
from backend.src.services.garmin_activity_service import GarminActivityService
from backend.src.services.garmin_health_service import GarminHealthService
from src.schemas import GarminCredentials
from src.services.garmin_activity_service import GarminActivityService
from src.services.garmin_health_service import GarminHealthService
@pytest.fixture
def mock_garmin_auth_service_instance():
with patch(
'backend.src.services.garmin_activity_service.GarminAuthService'
"src.services.garmin_activity_service.GarminAuthService"
) as MockGarminAuthService:
instance = MockGarminAuthService.return_value
yield instance
@pytest.fixture
def mock_central_db_service_instance():
with patch(
'backend.src.services.garmin_activity_service.CentralDBService'
"src.services.garmin_activity_service.CentralDBService"
) as MockCentralDBService:
service_instance = MockCentralDBService.return_value
yield service_instance
@pytest.fixture
def mock_garmin_client_service_instance():
with patch(
'backend.src.services.garmin_activity_service.GarminClientService'
"src.services.garmin_activity_service.GarminClientService"
) as MockGarminClientService:
instance = MockGarminClientService.return_value
yield instance
@pytest.mark.asyncio
async def test_garmin_activity_sync_authentication_flow(
mock_garmin_auth_service_instance,
mock_central_db_service_instance,
mock_garmin_client_service_instance
mock_garmin_client_service_instance,
):
user_id = 1
username = "test@example.com"
@@ -42,10 +46,11 @@ async def test_garmin_activity_sync_authentication_flow(
# Mock GarminCredentials from CentralDB
mock_credentials = GarminCredentials(
garmin_username=username,
garmin_password_plaintext=password
garmin_username=username, garmin_password_plaintext=password
)
mock_central_db_service_instance.get_garmin_credentials.return_value = (
mock_credentials
)
mock_central_db_service_instance.get_garmin_credentials.return_value = mock_credentials
# Mock GarminClientService authentication
mock_garmin_client_service_instance.is_authenticated.return_value = False
@@ -53,31 +58,40 @@ async def test_garmin_activity_sync_authentication_flow(
# Mock GarminClientService.get_client().get_activities
mock_garmin_client_instance = AsyncMock()
mock_garmin_client_service_instance.get_client.return_value = mock_garmin_client_instance
mock_garmin_client_instance.get_activities.return_value = [] # Simulate no activities
mock_garmin_client_service_instance.get_client.return_value = (
mock_garmin_client_instance
)
mock_garmin_client_instance.get_activities.return_value = (
[]
) # Simulate no activities
activity_service = GarminActivityService(
garmin_client_service=mock_garmin_client_service_instance,
activity_download_service=AsyncMock(), # Mock this dependency
garmin_auth_service=mock_garmin_auth_service_instance, # Still needed for init, but methods not called
central_db_service=mock_central_db_service_instance
activity_download_service=AsyncMock(), # Mock this dependency
garmin_auth_service=mock_garmin_auth_service_instance, # Still needed for init, but methods not called
central_db_service=mock_central_db_service_instance,
)
# Call sync_activities_in_background, which will trigger authentication
await activity_service.sync_activities_in_background(job_id="test_job")
await activity_service.sync_activities_in_background(user_id=user_id)
# Assertions
mock_central_db_service_instance.get_garmin_credentials.assert_called_once_with(user_id)
mock_garmin_client_service_instance.update_credentials.assert_called_once_with(username, password)
mock_central_db_service_instance.get_garmin_credentials.assert_called_once_with(
user_id
)
mock_garmin_client_service_instance.update_credentials.assert_called_once_with(
username, password
)
mock_garmin_client_service_instance.is_authenticated.assert_called_once()
mock_garmin_client_service_instance.authenticate.assert_called_once()
mock_garmin_client_instance.get_activities.assert_called_once()
@pytest.mark.asyncio
async def test_garmin_health_sync_authentication_flow(
mock_garmin_auth_service_instance,
mock_central_db_service_instance,
mock_garmin_client_service_instance
mock_garmin_client_service_instance,
):
user_id = 1
username = "test@example.com"
@@ -85,10 +99,11 @@ async def test_garmin_health_sync_authentication_flow(
# Mock GarminCredentials from CentralDB
mock_credentials = GarminCredentials(
garmin_username=username,
garmin_password_plaintext=password
garmin_username=username, garmin_password_plaintext=password
)
mock_central_db_service_instance.get_garmin_credentials.return_value = (
mock_credentials
)
mock_central_db_service_instance.get_garmin_credentials.return_value = mock_credentials
# Mock GarminClientService authentication
mock_garmin_client_service_instance.is_authenticated.return_value = False
@@ -96,21 +111,29 @@ async def test_garmin_health_sync_authentication_flow(
# Mock GarminClientService.get_client().get_daily_summary
mock_garmin_client_instance = AsyncMock()
mock_garmin_client_service_instance.get_client.return_value = mock_garmin_client_instance
mock_garmin_client_instance.get_daily_summary.return_value = [] # Simulate no summaries
mock_garmin_client_service_instance.get_client.return_value = (
mock_garmin_client_instance
)
mock_garmin_client_instance.get_daily_summary.return_value = (
[]
) # Simulate no summaries
health_service = GarminHealthService(
garmin_client_service=mock_garmin_client_service_instance,
central_db_service=mock_central_db_service_instance,
garmin_auth_service=mock_garmin_auth_service_instance # Still needed for init, but methods not called
garmin_auth_service=mock_garmin_auth_service_instance, # Still needed for init, but methods not called
)
# Call sync_health_metrics_in_background, which will trigger authentication
await health_service.sync_health_metrics_in_background(job_id="test_job")
await health_service.sync_health_metrics_in_background(user_id=user_id)
# Assertions
mock_central_db_service_instance.get_garmin_credentials.assert_called_once_with(user_id)
mock_garmin_client_service_instance.update_credentials.assert_called_once_with(username, password)
mock_central_db_service_instance.get_garmin_credentials.assert_called_once_with(
user_id
)
mock_garmin_client_service_instance.update_credentials.assert_called_once_with(
username, password
)
mock_garmin_client_service_instance.is_authenticated.assert_called_once()
mock_garmin_client_service_instance.authenticate.assert_called_once()
mock_garmin_client_instance.get_daily_summary.assert_called_once()