trax/tests/test_visualization_reportin...

445 lines
16 KiB
Python

"""
Unit tests for visualization and reporting system.
Tests the comprehensive visualization and reporting system to analyze
performance data and generate actionable insights.
"""
import json
import pytest
import tempfile
from pathlib import Path
from unittest.mock import MagicMock, patch, mock_open
from typing import Dict, List, Any
from datetime import datetime, timezone
import pandas as pd
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from src.services.performance import PerformanceMetrics
from src.services.performance_profiling import BenchmarkData
class TestVisualizationReportingSystem:
"""Test the visualization and reporting system."""
@pytest.fixture
def sample_benchmark_data(self):
"""Create sample benchmark data for testing."""
return [
BenchmarkData(
operation_name="transcription",
batch_size=1,
duration_seconds=10.5,
peak_memory_mb=1024.0,
throughput_items_per_second=2.5,
timestamp=datetime.now(timezone.utc)
),
BenchmarkData(
operation_name="transcription",
batch_size=2,
duration_seconds=8.2,
peak_memory_mb=1536.0,
throughput_items_per_second=3.1,
timestamp=datetime.now(timezone.utc)
),
BenchmarkData(
operation_name="transcription",
batch_size=4,
duration_seconds=6.8,
peak_memory_mb=2048.0,
throughput_items_per_second=3.7,
timestamp=datetime.now(timezone.utc)
)
]
@pytest.fixture
def sample_performance_metrics(self):
"""Create sample performance metrics for testing."""
return [
PerformanceMetrics(
operation="transcription",
duration_seconds=10.0,
memory_peak_mb=1024.0,
cpu_peak_percent=50.0,
throughput_items_per_second=2.0,
error_count=0,
success_count=10,
total_count=10
),
PerformanceMetrics(
operation="diarization",
duration_seconds=15.0,
memory_peak_mb=1536.0,
cpu_peak_percent=60.0,
throughput_items_per_second=1.5,
error_count=1,
success_count=9,
total_count=10
)
]
def test_interactive_chart_creation(self, sample_benchmark_data):
"""Test creation of interactive charts using Plotly."""
from src.services.visualization_reporting import InteractiveChartGenerator
generator = InteractiveChartGenerator()
# Test throughput chart
fig = generator.create_throughput_chart(sample_benchmark_data)
assert isinstance(fig, go.Figure)
assert len(fig.data) > 0
assert fig.layout.title.text == "Transcription Throughput by Batch Size"
# Test memory usage chart
fig = generator.create_memory_chart(sample_benchmark_data)
assert isinstance(fig, go.Figure)
assert len(fig.data) > 0
assert fig.layout.title.text == "Memory Usage by Batch Size"
# Test combined chart
fig = generator.create_combined_chart(sample_benchmark_data)
assert isinstance(fig, go.Figure)
assert len(fig.data) > 0
def test_bottleneck_identification(self, sample_performance_metrics):
"""Test bottleneck identification algorithms."""
from src.services.visualization_reporting import BottleneckAnalyzer
analyzer = BottleneckAnalyzer()
# Test bottleneck identification
bottlenecks = analyzer.identify_bottlenecks(sample_performance_metrics)
assert isinstance(bottlenecks, list)
assert len(bottlenecks) > 0
# Check that bottlenecks have required fields
for bottleneck in bottlenecks:
assert 'component' in bottleneck
assert 'severity' in bottleneck
assert 'description' in bottleneck
assert 'recommendation' in bottleneck
def test_report_generation_formats(self, sample_benchmark_data, tmp_path):
"""Test report generation in various formats."""
from src.services.visualization_reporting import ReportGenerator
generator = ReportGenerator()
# Test HTML report
html_path = tmp_path / "report.html"
generator.generate_html_report(sample_benchmark_data, html_path)
assert html_path.exists()
# Test PDF report
pdf_path = tmp_path / "report.pdf"
generator.generate_pdf_report(sample_benchmark_data, pdf_path)
assert pdf_path.exists()
# Test CSV export
csv_path = tmp_path / "data.csv"
generator.export_csv(sample_benchmark_data, csv_path)
assert csv_path.exists()
# Test JSON export
json_path = tmp_path / "data.json"
generator.export_json(sample_benchmark_data, json_path)
assert json_path.exists()
def test_comparison_views(self, sample_benchmark_data):
"""Test before/after optimization analysis."""
from src.services.visualization_reporting import ComparisonAnalyzer
analyzer = ComparisonAnalyzer()
# Create "before" and "after" data
before_data = sample_benchmark_data[:2] # First two entries
after_data = sample_benchmark_data[1:] # Last two entries
# Test comparison analysis
comparison = analyzer.compare_performance(before_data, after_data)
assert isinstance(comparison, dict)
assert 'improvements' in comparison
assert 'regressions' in comparison
assert 'summary' in comparison
# Test comparison chart
fig = analyzer.create_comparison_chart(before_data, after_data)
assert isinstance(fig, go.Figure)
assert len(fig.data) > 0
def test_trend_analysis(self, sample_benchmark_data):
"""Test trend analysis for performance metrics over time."""
from src.services.visualization_reporting import TrendAnalyzer
analyzer = TrendAnalyzer()
# Test trend calculation
trends = analyzer.calculate_trends(sample_benchmark_data)
assert isinstance(trends, dict)
assert 'throughput_trend' in trends
assert 'memory_trend' in trends
assert 'duration_trend' in trends
# Test trend visualization
fig = analyzer.create_trend_chart(sample_benchmark_data)
assert isinstance(fig, go.Figure)
assert len(fig.data) > 0
def test_report_templates(self, sample_benchmark_data, tmp_path):
"""Test different report templates."""
from src.services.visualization_reporting import ReportTemplateManager
manager = ReportTemplateManager()
# Test executive summary template
exec_path = tmp_path / "executive_summary.html"
manager.generate_executive_summary(sample_benchmark_data, exec_path)
assert exec_path.exists()
# Test detailed technical report template
tech_path = tmp_path / "technical_report.html"
manager.generate_technical_report(sample_benchmark_data, tech_path)
assert tech_path.exists()
# Test custom template
custom_path = tmp_path / "custom_report.html"
template_vars = {"title": "Custom Report", "author": "Test User"}
manager.generate_custom_report(sample_benchmark_data, custom_path, template_vars)
assert custom_path.exists()
def test_export_functionality(self, sample_benchmark_data, tmp_path):
"""Test export functionality for various formats."""
from src.services.visualization_reporting import DataExporter
exporter = DataExporter()
# Test CSV export
csv_path = tmp_path / "export.csv"
exporter.export_to_csv(sample_benchmark_data, csv_path)
assert csv_path.exists()
# Verify CSV content
df = pd.read_csv(csv_path)
assert len(df) == len(sample_benchmark_data)
assert 'operation_name' in df.columns
assert 'batch_size' in df.columns
# Test JSON export
json_path = tmp_path / "export.json"
exporter.export_to_json(sample_benchmark_data, json_path)
assert json_path.exists()
# Verify JSON content
with open(json_path, 'r') as f:
data = json.load(f)
assert isinstance(data, list)
assert len(data) == len(sample_benchmark_data)
def test_chart_customization(self, sample_benchmark_data):
"""Test chart customization options."""
from src.services.visualization_reporting import InteractiveChartGenerator
generator = InteractiveChartGenerator()
# Test custom colors
custom_colors = ['#FF6B6B', '#4ECDC4', '#45B7D1']
fig = generator.create_throughput_chart(
sample_benchmark_data,
colors=custom_colors
)
assert isinstance(fig, go.Figure)
# Test custom layout
custom_layout = {
'title': 'Custom Title',
'xaxis_title': 'Custom X Axis',
'yaxis_title': 'Custom Y Axis'
}
fig = generator.create_memory_chart(
sample_benchmark_data,
layout=custom_layout
)
assert fig.layout.title.text == 'Custom Title'
assert fig.layout.xaxis.title.text == 'Custom X Axis'
def test_performance_insights(self, sample_performance_metrics):
"""Test performance insights generation."""
from src.services.visualization_reporting import PerformanceInsightsGenerator
generator = PerformanceInsightsGenerator()
# Test insights generation
insights = generator.generate_insights(sample_performance_metrics)
assert isinstance(insights, list)
assert len(insights) > 0
# Check insight structure
for insight in insights:
assert 'type' in insight
assert 'message' in insight
assert 'severity' in insight
assert 'actionable' in insight
def test_report_validation(self, sample_benchmark_data, tmp_path):
"""Test report validation and error handling."""
from src.services.visualization_reporting import ReportValidator
validator = ReportValidator()
# Test valid data
is_valid = validator.validate_data(sample_benchmark_data)
assert is_valid
# Test invalid data
invalid_data = [{"invalid": "data"}]
is_valid = validator.validate_data(invalid_data)
assert not is_valid
# Test report file validation
report_path = tmp_path / "test_report.html"
with open(report_path, 'w') as f:
f.write("<html><body>Test Report</body></html>")
is_valid = validator.validate_report_file(report_path)
assert is_valid
class TestVisualizationReportingIntegration:
"""Integration tests for visualization and reporting system."""
@pytest.mark.asyncio
async def test_complete_reporting_workflow(self, tmp_path):
"""Test the complete reporting workflow."""
from src.services.visualization_reporting import (
ReportGenerator,
InteractiveChartGenerator,
BottleneckAnalyzer,
ComparisonAnalyzer,
TrendAnalyzer
)
# Create sample data
sample_data = [
BenchmarkData(
operation_name="transcription",
batch_size=1,
duration_seconds=10.0,
peak_memory_mb=1024.0,
throughput_items_per_second=2.0,
timestamp=datetime.now(timezone.utc)
),
BenchmarkData(
operation_name="transcription",
batch_size=2,
duration_seconds=8.0,
peak_memory_mb=1536.0,
throughput_items_per_second=2.5,
timestamp=datetime.now(timezone.utc)
)
]
# Initialize components
generator = ReportGenerator()
chart_generator = InteractiveChartGenerator()
bottleneck_analyzer = BottleneckAnalyzer()
comparison_analyzer = ComparisonAnalyzer()
trend_analyzer = TrendAnalyzer()
# Generate charts
throughput_chart = chart_generator.create_throughput_chart(sample_data)
memory_chart = chart_generator.create_memory_chart(sample_data)
combined_chart = chart_generator.create_combined_chart(sample_data)
# Analyze bottlenecks
bottlenecks = bottleneck_analyzer.identify_bottlenecks(sample_data)
# Generate trends
trends = trend_analyzer.calculate_trends(sample_data)
# Generate comprehensive report
report_path = tmp_path / "comprehensive_report.html"
generator.generate_comprehensive_report(
sample_data,
report_path,
charts=[throughput_chart, memory_chart, combined_chart],
bottlenecks=bottlenecks,
trends=trends
)
# Verify report was generated
assert report_path.exists()
# Verify report content
with open(report_path, 'r') as f:
content = f.read()
assert "Performance Report" in content
assert "Bottlenecks" in content
assert "Trends" in content
def test_multi_format_export(self, tmp_path):
"""Test exporting data in multiple formats."""
from src.services.visualization_reporting import MultiFormatExporter
exporter = MultiFormatExporter()
# Create sample data
sample_data = [
BenchmarkData(
operation_name="test",
batch_size=1,
duration_seconds=5.0,
peak_memory_mb=512.0,
throughput_items_per_second=1.0,
timestamp=datetime.now(timezone.utc)
)
]
# Export in multiple formats
export_paths = exporter.export_all_formats(sample_data, tmp_path)
# Verify all formats were created
assert 'html' in export_paths
assert 'pdf' in export_paths
assert 'csv' in export_paths
assert 'json' in export_paths
# Verify files exist
for format_type, path in export_paths.items():
assert Path(path).exists()
def test_report_scheduling(self):
"""Test automated report scheduling."""
from src.services.visualization_reporting import ReportScheduler
scheduler = ReportScheduler()
# Test schedule creation
schedule = scheduler.create_schedule(
frequency="daily",
time="09:00",
report_type="executive_summary"
)
assert schedule['frequency'] == "daily"
assert schedule['time'] == "09:00"
assert schedule['report_type'] == "executive_summary"
# Test schedule validation
is_valid = scheduler.validate_schedule(schedule)
assert is_valid
# Test invalid schedule
invalid_schedule = {
'frequency': "invalid",
'time': "25:00",
'report_type': "unknown"
}
is_valid = scheduler.validate_schedule(invalid_schedule)
assert not is_valid