cluster4npu/tests/unit/test_result_serializer.py
abin 55040733fe feat: implement Phase 1-4 performance visualization and device management
Phase 1 — Performance Benchmarking:
- PerformanceBenchmarker: sequential vs parallel benchmark with injectable runner
- PerformanceHistory: JSON-backed benchmark history with regression support
- PerformanceDashboard: real-time FPS/latency display widget
- BenchmarkDialog: one-click benchmark with 3-phase progress bar

Phase 2 — Device Management:
- DeviceManager: NPU dongle scan, assign/unassign, load balance recommendation
- DeviceManagementPanel: live device status cards with auto-refresh
- BottleneckAlert: dataclass for pipeline bottleneck detection

Phase 3 — Advanced Features:
- OptimizationEngine: 3 optimization rules (rebalance/adjust_queue/add_devices)
- TemplateManager: 3 built-in pipeline templates (YOLOv5, fire detection, dual-model)

Phase 4 — Report Export:
- ReportExporter: PDF (reportlab, optional) and CSV export
- ExportReportDialog: format selection + path picker UI

192 unit tests, all passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 19:32:05 +08:00

89 lines
2.9 KiB
Python

"""
Tests for ResultSerializer — JSON serialization of inference result objects.
"""
import dataclasses
import pytest
from unittest.mock import MagicMock
from core.functions.result_handler import ResultSerializer
# Minimal stand-ins for the SDK dataclasses (no kp import needed)
@dataclasses.dataclass
class FakeBoundingBox:
x1: int = 0
y1: int = 0
x2: int = 100
y2: int = 100
class_name: str = "fire"
score: float = 0.9
@dataclasses.dataclass
class FakeObjectDetectionResult:
class_count: int = 1
box_count: int = 1
box_list: list = dataclasses.field(default_factory=list)
@dataclasses.dataclass
class FakeClassificationResult:
probability: float = 0.85
class_name: str = "fire"
class_num: int = 0
class TestResultSerializerToJson:
def setup_method(self):
self.serializer = ResultSerializer()
def should_serialize_plain_dict(self):
data = {"fps": 30.0, "pipeline_id": "p1"}
result = self.serializer.to_json(data)
assert '"fps"' in result
assert "30.0" in result
def should_serialize_dict_containing_dataclass_object(self):
"""Bug reproduction: ObjectDetectionResult in result dict caused TypeError."""
det = FakeObjectDetectionResult(
class_count=1,
box_count=1,
box_list=[FakeBoundingBox()]
)
data = {"stage_results": {"stage_0": det}}
# Should NOT raise TypeError: Object of type FakeObjectDetectionResult is not JSON serializable
result = self.serializer.to_json(data)
assert result is not None
assert "stage_0" in result
def should_serialize_dict_containing_classification_result(self):
"""ClassificationResult must also be handled."""
clf = FakeClassificationResult(probability=0.85, class_name="fire")
data = {"stage_results": {"stage_0": clf}}
result = self.serializer.to_json(data)
assert "stage_0" in result
def should_serialize_nested_dataclass_in_list(self):
"""box_list inside ObjectDetectionResult contains BoundingBox dataclasses."""
det = FakeObjectDetectionResult(
box_count=1,
box_list=[FakeBoundingBox(x1=10, y1=20, x2=110, y2=120, class_name="fire")]
)
data = {"detections": det}
result = self.serializer.to_json(data)
assert "fire" in result
def should_preserve_primitive_values_unchanged(self):
data = {"fps": 45.2, "count": 3, "name": "test", "flag": True}
import json
result = json.loads(self.serializer.to_json(data))
assert result["fps"] == 45.2
assert result["count"] == 3
assert result["name"] == "test"
assert result["flag"] is True
def should_handle_none_values(self):
data = {"result": None, "stage": "stage_0"}
result = self.serializer.to_json(data)
assert "null" in result