mirror of
https://github.com/sstent/FitTrack_GarminSync.git
synced 2026-01-26 00:51:44 +00:00
feat: Implement Garmin sync, login improvements, and utility scripts
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
import pytest
|
||||
from unittest.mock import AsyncMock, patch
|
||||
from src.services.auth_service import AuthService
|
||||
from src.schemas import UserCreate, User, TokenCreate, TokenUpdate
|
||||
import uuid
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from src.schemas import TokenCreate, User
|
||||
from src.services.auth_service import AuthService
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def auth_service():
|
||||
@@ -34,7 +37,9 @@ def mock_garth_client():
|
||||
yield mock_client
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_authenticate_garmin_connect_new_user_success(auth_service, mock_garth_login, mock_garth_client):
|
||||
async def test_authenticate_garmin_connect_new_user_success(
|
||||
auth_service, mock_garth_login, mock_garth_client
|
||||
):
|
||||
"""Test successful Garmin authentication with a new user."""
|
||||
email = "new_user@example.com"
|
||||
password = "password123"
|
||||
@@ -55,7 +60,9 @@ async def test_authenticate_garmin_connect_new_user_success(auth_service, mock_g
|
||||
assert result == {"message": "Garmin Connect authentication successful", "user_id": str(mock_user.id)}
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_authenticate_garmin_connect_existing_user_success(auth_service, mock_garth_login, mock_garth_client):
|
||||
async def test_authenticate_garmin_connect_existing_user_success(
|
||||
auth_service, mock_garth_login, mock_garth_client
|
||||
):
|
||||
"""Test successful Garmin authentication with an existing user and no existing token."""
|
||||
email = "existing_user@example.com"
|
||||
password = "password123"
|
||||
@@ -75,7 +82,9 @@ async def test_authenticate_garmin_connect_existing_user_success(auth_service, m
|
||||
assert result == {"message": "Garmin Connect authentication successful", "user_id": str(mock_user.id)}
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_authenticate_garmin_connect_existing_user_existing_token_success(auth_service, mock_garth_login, mock_garth_client):
|
||||
async def test_authenticate_garmin_connect_existing_user_existing_token_success(
|
||||
auth_service, mock_garth_login, mock_garth_client
|
||||
):
|
||||
"""Test successful Garmin authentication with an existing user and existing token."""
|
||||
email = "existing_user_token@example.com"
|
||||
password = "password123"
|
||||
@@ -117,7 +126,9 @@ async def test_authenticate_garmin_connect_garmin_failure(auth_service, mock_gar
|
||||
assert result is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_authenticate_garmin_connect_central_db_user_creation_failure(auth_service, mock_garth_login, mock_garth_client):
|
||||
async def test_authenticate_garmin_connect_central_db_user_creation_failure(
|
||||
auth_service, mock_garth_login, mock_garth_client
|
||||
):
|
||||
"""Test CentralDB user creation failure."""
|
||||
email = "fail_user_create@example.com"
|
||||
password = "password123"
|
||||
|
||||
1
backend/tests/unit/test_central_db_service.py
Normal file
1
backend/tests/unit/test_central_db_service.py
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
91
backend/tests/unit/test_garmin_auth_service.py
Normal file
91
backend/tests/unit/test_garmin_auth_service.py
Normal file
@@ -0,0 +1,91 @@
|
||||
from datetime import datetime, timedelta
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
import pytest
|
||||
from backend.src.schemas import GarminCredentials
|
||||
from backend.src.services.garmin_auth_service import GarminAuthService
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def garmin_auth_service():
|
||||
return GarminAuthService()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_initial_login_success(garmin_auth_service):
|
||||
username = "test@example.com"
|
||||
password = "password123"
|
||||
|
||||
with patch('backend.src.services.garmin_auth_service.garth') as mock_garth:
|
||||
mock_garth.Client.return_value = AsyncMock()
|
||||
mock_garth.Client.return_value.login.return_value = None # garth.login doesn't return anything directly
|
||||
# Mock the attributes that would be set on the client after login
|
||||
mock_garth.Client.return_value.access_token = f"mock_access_token_for_{username}"
|
||||
mock_garth.Client.return_value.access_token_secret = f"mock_access_token_secret_for_{username}"
|
||||
mock_garth.Client.return_value.expires_in = 300
|
||||
|
||||
credentials = await garmin_auth_service.initial_login(username, password)
|
||||
|
||||
assert credentials is not None
|
||||
assert credentials.garmin_username == username
|
||||
assert credentials.garmin_password_plaintext == password
|
||||
assert credentials.access_token.startswith("mock_access_token")
|
||||
assert credentials.access_token_secret.startswith("mock_access_token_secret")
|
||||
assert isinstance(credentials.token_expiration_date, datetime)
|
||||
assert credentials.token_expiration_date > datetime.utcnow()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_initial_login_failure(garmin_auth_service):
|
||||
username = "invalid@example.com"
|
||||
password = "wrongpassword"
|
||||
|
||||
with patch('backend.src.services.garmin_auth_service.garth') as mock_garth:
|
||||
mock_garth.Client.return_value = AsyncMock()
|
||||
mock_garth.Client.return_value.login.side_effect = Exception("Garmin login failed")
|
||||
|
||||
credentials = await garmin_auth_service.initial_login(username, password)
|
||||
|
||||
assert credentials is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_refresh_tokens_success(garmin_auth_service):
|
||||
credentials = GarminCredentials(
|
||||
garmin_username="test@example.com",
|
||||
garmin_password_plaintext="password123",
|
||||
access_token="old_access_token",
|
||||
access_token_secret="old_access_token_secret",
|
||||
token_expiration_date=datetime.utcnow() - timedelta(minutes=1) # Expired token
|
||||
)
|
||||
|
||||
with patch('backend.src.services.garmin_auth_service.garth') as mock_garth:
|
||||
mock_garth.Client.return_value = AsyncMock()
|
||||
mock_garth.Client.return_value.reauthorize.return_value = None
|
||||
mock_garth.Client.return_value.access_token = "refreshed_access_token"
|
||||
mock_garth.Client.return_value.access_token_secret = "refreshed_access_token_secret"
|
||||
mock_garth.Client.return_value.expires_in = 300
|
||||
|
||||
refreshed_credentials = await garmin_auth_service.refresh_tokens(credentials)
|
||||
|
||||
assert refreshed_credentials is not None
|
||||
assert refreshed_credentials.garmin_username == credentials.garmin_username
|
||||
assert refreshed_credentials.access_token == "refreshed_access_token"
|
||||
assert refreshed_credentials.access_token_secret == "refreshed_access_token_secret"
|
||||
assert isinstance(refreshed_credentials.token_expiration_date, datetime)
|
||||
assert refreshed_credentials.token_expiration_date > datetime.utcnow()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_refresh_tokens_failure(garmin_auth_service):
|
||||
credentials = GarminCredentials(
|
||||
garmin_username="test@example.com",
|
||||
garmin_password_plaintext="invalid_password",
|
||||
access_token="old_access_token",
|
||||
access_token_secret="old_access_token_secret",
|
||||
token_expiration_date=datetime.utcnow() - timedelta(minutes=1)
|
||||
)
|
||||
|
||||
with patch('backend.src.services.garmin_auth_service.garth') as mock_garth:
|
||||
mock_garth.Client.return_value = AsyncMock()
|
||||
mock_garth.Client.return_value.reauthorize.side_effect = Exception("Garmin reauthorize failed")
|
||||
|
||||
refreshed_credentials = await garmin_auth_service.refresh_tokens(credentials)
|
||||
|
||||
assert refreshed_credentials is None
|
||||
@@ -1,8 +1,10 @@
|
||||
import pytest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from fastapi import HTTPException
|
||||
|
||||
from src.services.rate_limiter import RateLimiter
|
||||
import asyncio
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_rate_limiter_allows_requests_within_limit():
|
||||
|
||||
@@ -3,8 +3,10 @@ from datetime import datetime
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from src.jobs import JobStore, SyncJob
|
||||
from src.services.sync_status_service import SyncStatusService
|
||||
from src.jobs import SyncJob, JobStore
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_job_store():
|
||||
|
||||
Reference in New Issue
Block a user