import pytest from fastapi.testclient import TestClient from api.main import app from uuid import UUID, uuid4 from unittest.mock import patch, AsyncMock import httpx from src.core.workout_data import WorkoutData, WorkoutMetadata, PowerData, HeartRateData, SpeedData, ElevationData import pandas as pd from datetime import datetime, timedelta client = TestClient(app) @pytest.fixture def mock_workout_data(): # Create a mock WorkoutData object timestamps = pd.to_datetime( [datetime(2025, 1, 1, 10, 0, 0) + timedelta(seconds=i) for i in range(600)] ) power = pd.Series([150 + 50 * (i % 10) for i in range(600)], index=timestamps) time_series_data = pd.DataFrame({"power": power}) metadata = WorkoutMetadata( start_time=datetime(2025, 1, 1, 10, 0, 0), duration=timedelta(minutes=10), device="Garmin", file_type="FIT", ) power_data = PowerData( raw_power_stream=power.tolist(), average_power=power.mean(), normalized_power=power.mean() * 1.05, # Dummy value intensity_factor=0.8, training_stress_score=50, zone_distribution={"Z1": 100, "Z2": 200, "Z3": 300}, ) return WorkoutData( metadata=metadata, time_series_data=time_series_data, power_data=power_data, heart_rate_data=HeartRateData(), speed_data=SpeedData(), elevation_data=ElevationData(), ) @patch("api.routers.analysis.CentralDBClient") @patch("api.routers.analysis.FitParser") async def test_get_analysis_charts_success( mock_fit_parser, mock_centraldb_client, mock_workout_data, client, ): mock_centraldb_instance = AsyncMock() mock_centraldb_instance.retrieve_chart = AsyncMock( side_effect=httpx.HTTPStatusError( "", request=None, response=httpx.Response(status_code=404) ) ) mock_centraldb_instance.download_fit_file = AsyncMock( return_value=b"dummy_fit_content" ) mock_centraldb_instance.upload_chart = AsyncMock() mock_centraldb_instance.get_analysis_artifact = AsyncMock( side_effect=httpx.HTTPStatusError( "", request=None, response=httpx.Response(status_code=404) ) ) mock_centraldb_instance.create_analysis_artifact = AsyncMock() mock_centraldb_client.return_value = mock_centraldb_instance mock_fit_parser.return_value.parse.return_value = mock_workout_data analysis_id = uuid4() chart_type = "power_curve" response = client.get(f"/api/analysis/{analysis_id}/charts?chart_type={chart_type}") assert response.status_code == 200 assert response.headers["content-type"] == "image/png" assert len(response.content) > 0 @patch("api.routers.analysis.CentralDBClient") @patch("api.routers.analysis.FitParser") async def test_get_analysis_charts_not_found( mock_fit_parser, mock_centraldb_client, client ): mock_centraldb_instance = AsyncMock() mock_centraldb_instance.retrieve_chart = AsyncMock( side_effect=httpx.HTTPStatusError( "", request=None, response=httpx.Response(status_code=404) ) ) mock_centraldb_instance.download_fit_file = AsyncMock( side_effect=httpx.HTTPStatusError( "", request=None, response=httpx.Response(status_code=404) ) ) mock_centraldb_client.return_value = mock_centraldb_instance analysis_id = uuid4() chart_type = "power_curve" response = client.get(f"/api/analysis/{analysis_id}/charts?chart_type={chart_type}") assert response.status_code == 404 assert response.json()["code"] == "CHART_RETRIEVAL_ERROR" @patch("api.routers.analysis.CentralDBClient") @patch("api.routers.analysis.FitParser") async def test_get_analysis_charts_chart_type_not_found( mock_fit_parser, mock_centraldb_client, client ): mock_centraldb_instance = AsyncMock() mock_centraldb_instance.retrieve_chart = AsyncMock( side_effect=httpx.HTTPStatusError( "", request=None, response=httpx.Response(status_code=404) ) ) mock_centraldb_instance.download_fit_file = AsyncMock( return_value=b"dummy_fit_content" ) mock_centraldb_client.return_value = mock_centraldb_instance analysis_id = uuid4() chart_type = "invalid_chart_type" response = client.get(f"/api/analysis/{analysis_id}/charts?chart_type={chart_type}") assert response.status_code == 400 assert response.json()["code"] == "INVALID_CHART_TYPE" @patch("api.routers.analysis.CentralDBClient") async def test_get_analysis_charts_retrieval_error(mock_centraldb_client, client): mock_centraldb_instance = AsyncMock() mock_centraldb_instance.retrieve_chart = AsyncMock( side_effect=httpx.HTTPStatusError( "", request=None, response=httpx.Response(status_code=500) ) ) mock_centraldb_client.return_value = mock_centraldb_instance analysis_id = uuid4() chart_type = "power_curve" response = client.get(f"/api/analysis/{analysis_id}/charts?chart_type={chart_type}") assert response.status_code == 500 assert response.json()["code"] == "CHART_RETRIEVAL_ERROR"