292 lines
8.8 KiB
Python
292 lines
8.8 KiB
Python
"""Integration tests for report generation.
|
|
|
|
Tests the full report generation pipeline from test run to PDF output.
|
|
"""
|
|
|
|
import tempfile
|
|
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
|