import pytest import time from fastapi.testclient import TestClient from api.main import app import os import zipfile import io client = TestClient(app) # Performance Goal SC-002: Analysis of a typical 2-hour workout file MUST complete in under 30 seconds. # Performance Goal SC-004: Processing a batch of 100 workout files concurrently without generating errors or significant performance degradation. # Helper to create a dummy FIT file for testing def create_dummy_fit_file(file_path, duration_minutes=120): # This is a very basic placeholder. A real dummy FIT file would be more complex. # For actual performance testing, use a realistic 2-hour FIT file. with open(file_path, "w") as f: f.write(f"Dummy FIT file for {duration_minutes} minutes\n") for i in range(duration_minutes * 60): f.write(f"Time: {i}, Power: {200 + (i % 50)}, HR: {120 + (i % 20)}\n") # Helper to create a dummy ZIP file with multiple workout files def create_dummy_zip_file(num_files=100): zip_buffer = io.BytesIO() with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zf: for i in range(num_files): file_content = f"Dummy workout file {i}\n".encode('utf-8') zf.writestr(f"workout_{i}.fit", file_content) zip_buffer.seek(0) return zip_buffer def test_performance_single_workout_analysis(tmp_path): # SC-002: Analysis of a typical 2-hour workout file MUST complete in under 30 seconds. dummy_fit_file_path = tmp_path / "2_hour_workout.fit" create_dummy_fit_file(dummy_fit_file_path, duration_minutes=120) start_time = time.time() with open(dummy_fit_file_path, "rb") as f: response = client.post( "/api/analyze/workout", files={"file": ("2_hour_workout.fit", f, "application/octet-stream")}, data={ "ftp_value": 250.0 } ) end_time = time.time() elapsed_time = end_time - start_time assert response.status_code == 200 assert elapsed_time < 30, f"Single workout analysis took {elapsed_time:.2f} seconds, exceeding 30 seconds." print(f"Single workout analysis completed in {elapsed_time:.2f} seconds.") # This test is conceptual. True concurrent batch processing performance testing # would require a more sophisticated setup (e.g., using a load testing tool like Locust). # This test only checks the sequential processing time of a batch. def test_performance_batch_analysis_sequential(tmp_path): # SC-004: Processing a batch of 100 workout files concurrently without generating errors or significant performance degradation. # This test simulates processing 100 files sequentially within the batch endpoint. # For true concurrency testing, external load testing tools are recommended. num_files = 10 dummy_zip_content = create_dummy_zip_file(num_files) start_time = time.time() response = client.post( "/api/analyze/batch", files={"zip_file": ("batch_workouts.zip", dummy_zip_content.getvalue(), "application/zip")}, data={ "ftp_value": 250.0 } ) end_time = time.time() elapsed_time = end_time - start_time assert response.status_code == 200 response_json = response.json() assert response_json["status"] != "failed" assert response_json["total_files"] == num_files # Define a reasonable threshold for sequential processing. This will vary greatly. # For 100 files, if each takes ~1 second, then 100 seconds is a rough estimate. # This threshold needs to be adjusted based on actual system performance and file complexity. expected_max_time = num_files * 5 # e.g., 5 seconds per file as a very rough estimate assert elapsed_time < expected_max_time, f"Batch analysis of {num_files} files took {elapsed_time:.2f} seconds, exceeding {expected_max_time} seconds." print(f"Batch analysis of {num_files} files completed in {elapsed_time:.2f} seconds.")