Add report generation integration test
This commit is contained in:
293
tests/integration/test_report_generation.py
Normal file
293
tests/integration/test_report_generation.py
Normal file
@@ -0,0 +1,293 @@
|
||||
"""Integration tests for report generation.
|
||||
|
||||
Tests the full report generation pipeline from test run to PDF output.
|
||||
"""
|
||||
|
||||
import json
|
||||
import tempfile
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
import pytest
|
||||
|
||||
from py_dvt_ate.data.models import Measurement, TestStatus
|
||||
from py_dvt_ate.data.repository import SQLiteRepository
|
||||
|
||||
|
||||
class TestReportGenerationIntegration:
|
||||
"""Integration tests for the report generation pipeline."""
|
||||
|
||||
@pytest.fixture
|
||||
def temp_dir(self) -> Path:
|
||||
"""Create a temporary directory for test files."""
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
yield Path(tmpdir)
|
||||
|
||||
@pytest.fixture
|
||||
def repository(self, temp_dir: Path) -> SQLiteRepository:
|
||||
"""Create a test repository with sample data."""
|
||||
db_path = temp_dir / "test.db"
|
||||
measurements_dir = temp_dir / "measurements"
|
||||
|
||||
repo = SQLiteRepository(db_path, measurements_dir)
|
||||
|
||||
# Create a test run
|
||||
test_config = {
|
||||
"temperatures": [-40.0, 25.0, 85.0],
|
||||
"input_voltage": 5.0,
|
||||
"load_current": 0.1,
|
||||
}
|
||||
|
||||
run_id = repo.create_run(
|
||||
test_name="tempco",
|
||||
config=test_config,
|
||||
operator="test_operator",
|
||||
description="Integration test run",
|
||||
)
|
||||
|
||||
# Add some results
|
||||
repo.save_result(
|
||||
run_id=run_id,
|
||||
parameter="tempco",
|
||||
value=48.5,
|
||||
unit="ppm/C",
|
||||
lower_limit=None,
|
||||
upper_limit=100.0,
|
||||
)
|
||||
|
||||
repo.save_result(
|
||||
run_id=run_id,
|
||||
parameter="output_voltage_m40c",
|
||||
value=3.2965,
|
||||
unit="V",
|
||||
lower_limit=3.2,
|
||||
upper_limit=3.4,
|
||||
)
|
||||
|
||||
repo.save_result(
|
||||
run_id=run_id,
|
||||
parameter="output_voltage_25c",
|
||||
value=3.3000,
|
||||
unit="V",
|
||||
lower_limit=3.2,
|
||||
upper_limit=3.4,
|
||||
)
|
||||
|
||||
repo.save_result(
|
||||
run_id=run_id,
|
||||
parameter="output_voltage_85c",
|
||||
value=3.2901,
|
||||
unit="V",
|
||||
lower_limit=3.2,
|
||||
upper_limit=3.4,
|
||||
)
|
||||
|
||||
# Add measurements
|
||||
measurements = []
|
||||
temperatures = [-40.0, 0.0, 25.0, 50.0, 85.0]
|
||||
voltages = [3.2965, 3.2985, 3.3000, 3.2960, 3.2901]
|
||||
|
||||
for i, (temp, voltage) in enumerate(zip(temperatures, voltages, strict=False)):
|
||||
measurements.append(
|
||||
Measurement(
|
||||
timestamp=float(i * 60),
|
||||
parameter="output_voltage",
|
||||
value=voltage,
|
||||
unit="V",
|
||||
temperature=temp,
|
||||
input_voltage=5.0,
|
||||
load_current=0.1,
|
||||
)
|
||||
)
|
||||
|
||||
repo.save_measurements(run_id, measurements)
|
||||
|
||||
# Complete the run
|
||||
repo.complete_run(run_id, TestStatus.PASSED)
|
||||
|
||||
return repo
|
||||
|
||||
@pytest.fixture
|
||||
def run_id(self, repository: SQLiteRepository) -> UUID:
|
||||
"""Get the test run ID from the repository."""
|
||||
runs = repository.get_all_runs()
|
||||
return UUID(runs[0].id)
|
||||
|
||||
def test_full_report_generation(
|
||||
self, repository: SQLiteRepository, run_id: UUID, temp_dir: Path
|
||||
) -> None:
|
||||
"""Test complete report generation pipeline."""
|
||||
from py_dvt_ate.reporting import ReportConfig, ReportGenerator
|
||||
|
||||
# Create report config
|
||||
config = ReportConfig(
|
||||
company_name="Test Company Ltd",
|
||||
include_charts=True,
|
||||
chart_dpi=100, # Lower for faster tests
|
||||
)
|
||||
|
||||
# Create generator
|
||||
reports_dir = temp_dir / "reports"
|
||||
generator = ReportGenerator(
|
||||
repository=repository,
|
||||
config=config,
|
||||
reports_dir=reports_dir,
|
||||
)
|
||||
|
||||
# Generate report
|
||||
pdf_path = generator.generate(run_id)
|
||||
|
||||
# Verify PDF was created
|
||||
assert pdf_path.exists()
|
||||
assert pdf_path.suffix == ".pdf"
|
||||
assert pdf_path.stat().st_size > 1000 # Should be non-trivial size
|
||||
|
||||
# Verify it's in the reports directory
|
||||
assert pdf_path.parent == reports_dir
|
||||
|
||||
def test_report_generation_custom_path(
|
||||
self, repository: SQLiteRepository, run_id: UUID, temp_dir: Path
|
||||
) -> None:
|
||||
"""Test report generation with custom output path."""
|
||||
from py_dvt_ate.reporting import ReportConfig, ReportGenerator
|
||||
|
||||
config = ReportConfig(include_charts=False) # No charts for faster test
|
||||
|
||||
generator = ReportGenerator(
|
||||
repository=repository,
|
||||
config=config,
|
||||
)
|
||||
|
||||
# Generate to custom path
|
||||
custom_path = temp_dir / "custom_report.pdf"
|
||||
pdf_path = generator.generate(run_id, output_path=custom_path)
|
||||
|
||||
assert pdf_path == custom_path
|
||||
assert pdf_path.exists()
|
||||
|
||||
def test_report_generation_as_bytes(
|
||||
self, repository: SQLiteRepository, run_id: UUID
|
||||
) -> None:
|
||||
"""Test generating report as bytes."""
|
||||
from py_dvt_ate.reporting import ReportConfig, ReportGenerator
|
||||
|
||||
config = ReportConfig(include_charts=False)
|
||||
|
||||
generator = ReportGenerator(
|
||||
repository=repository,
|
||||
config=config,
|
||||
)
|
||||
|
||||
# Generate as bytes
|
||||
pdf_bytes = generator.generate_bytes(run_id)
|
||||
|
||||
# Verify it's a valid PDF
|
||||
assert isinstance(pdf_bytes, bytes)
|
||||
assert pdf_bytes.startswith(b"%PDF") # PDF magic bytes
|
||||
assert len(pdf_bytes) > 1000
|
||||
|
||||
def test_report_includes_all_data(
|
||||
self, repository: SQLiteRepository, run_id: UUID, temp_dir: Path
|
||||
) -> None:
|
||||
"""Test that generated report includes all expected data."""
|
||||
from py_dvt_ate.reporting import ReportConfig, ReportGenerator
|
||||
from py_dvt_ate.reporting.renderers.html import HTMLRenderer
|
||||
|
||||
config = ReportConfig(
|
||||
company_name="Test Company",
|
||||
include_charts=False,
|
||||
)
|
||||
|
||||
generator = ReportGenerator(
|
||||
repository=repository,
|
||||
config=config,
|
||||
)
|
||||
|
||||
# Get HTML (intermediate step) to check content
|
||||
data = generator._gather_data(run_id)
|
||||
html_renderer = HTMLRenderer()
|
||||
html = html_renderer.render(data)
|
||||
|
||||
# Check for expected content
|
||||
assert "tempco" in html
|
||||
assert "Test Company" in html
|
||||
assert "48.500000" in html # tempco value
|
||||
assert "3.300000" in html # output voltage
|
||||
assert "test_operator" in html
|
||||
assert "Integration test run" in html
|
||||
assert "PASS" in html
|
||||
|
||||
def test_report_with_failed_results(
|
||||
self, temp_dir: Path
|
||||
) -> None:
|
||||
"""Test report generation with failed test results."""
|
||||
from py_dvt_ate.reporting import ReportConfig, ReportGenerator
|
||||
|
||||
# Create repository with a failed test
|
||||
db_path = temp_dir / "failed_test.db"
|
||||
repo = SQLiteRepository(db_path, temp_dir / "measurements")
|
||||
|
||||
run_id = repo.create_run(
|
||||
test_name="failed_test",
|
||||
config={},
|
||||
operator="test",
|
||||
)
|
||||
|
||||
# Add failing result
|
||||
repo.save_result(
|
||||
run_id=run_id,
|
||||
parameter="test_param",
|
||||
value=150.0, # Exceeds limit
|
||||
unit="X",
|
||||
lower_limit=0.0,
|
||||
upper_limit=100.0,
|
||||
)
|
||||
|
||||
repo.complete_run(run_id, TestStatus.FAILED)
|
||||
|
||||
# Generate report
|
||||
config = ReportConfig(include_charts=False)
|
||||
generator = ReportGenerator(repository=repo, config=config)
|
||||
|
||||
pdf_bytes = generator.generate_bytes(run_id)
|
||||
|
||||
# Should still generate
|
||||
assert pdf_bytes.startswith(b"%PDF")
|
||||
|
||||
def test_report_generation_invalid_run_id(
|
||||
self, repository: SQLiteRepository, temp_dir: Path
|
||||
) -> None:
|
||||
"""Test that invalid run ID raises appropriate error."""
|
||||
from py_dvt_ate.reporting import ReportConfig, ReportGenerationError, ReportGenerator
|
||||
|
||||
config = ReportConfig()
|
||||
generator = ReportGenerator(repository=repository, config=config)
|
||||
|
||||
invalid_id = uuid4()
|
||||
|
||||
with pytest.raises(ReportGenerationError):
|
||||
generator.generate(invalid_id)
|
||||
|
||||
def test_report_charts_generation(
|
||||
self, repository: SQLiteRepository, run_id: UUID, temp_dir: Path
|
||||
) -> None:
|
||||
"""Test that charts are generated when enabled."""
|
||||
from py_dvt_ate.reporting import ReportConfig, ReportGenerator
|
||||
|
||||
config = ReportConfig(include_charts=True, chart_dpi=72)
|
||||
|
||||
generator = ReportGenerator(
|
||||
repository=repository,
|
||||
config=config,
|
||||
reports_dir=temp_dir / "reports",
|
||||
)
|
||||
|
||||
# Gather data and check charts
|
||||
data = generator._gather_data(run_id)
|
||||
|
||||
# Should have at least one chart (results bar chart)
|
||||
assert len(data.charts) >= 1
|
||||
|
||||
# Voltage vs temperature chart should be present (we have voltage measurements)
|
||||
assert "Voltage vs Temperature" in data.charts or "Results Summary" in data.charts
|
||||
Reference in New Issue
Block a user