Files
FitTrack_ReportGenerator/tests/performance/test_performance.py
sstent 9e0bd322d3 feat: Initial implementation of FitTrack Report Generator
This commit introduces the initial version of the FitTrack Report Generator, a FastAPI application for analyzing workout files.

Key features include:
- Parsing of FIT, TCX, and GPX workout files.
- Analysis of power, heart rate, speed, and elevation data.
- Generation of summary reports and charts.
- REST API for single and batch workout analysis.

The project structure has been set up with a `src` directory for core logic, an `api` directory for the FastAPI application, and a `tests` directory for unit, integration, and contract tests.

The development workflow is configured to use Docker and modern Python tooling.
2025-10-11 09:54:13 -07:00

87 lines
3.9 KiB
Python

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.")