tiandytmd

This commit is contained in:
Ankle committed 2026-09-15 09:53:00 +08:00
1 parent f7a782dcef
commit ddea6d0578
6 files changed
+389 -34

No files matched your search

+119
View File
@@ -51,6 +51,29 @@ class ApiRecoveryTests(unittest.TestCase):
self.assertEqual(payload["scan"]["state"], "idle")
wait_mock.assert_called_once_with()
def test_move_not_reached_error_is_explained_for_operator(self):
result = completed(
22,
stdout=json.dumps({
"error": {
"code": "sdk_error",
"message": (
"ERR move_not_reached pan_error=-25 tilt_error=56 "
"zoom_error=0 target=25892,2044,4620 "
"actual=25917,1988,4620"
),
}
}),
stderr="curl: (22) The requested URL returned error: 500",
)
detail = core.api_error_detail(result)
self.assertIn("没有完全到位", detail)
self.assertIn("tilt=2044 (20.44°)", detail)
self.assertIn("实际", detail)
self.assertIn("现场处理", detail)
@mock.patch("scan_calibrator.wait_for_scan_http")
@mock.patch("scan_calibrator.subprocess.run")
def test_non_transient_http_error_is_not_retried(self, run_mock, wait_mock):
@@ -111,8 +134,104 @@ class ApiRecoveryTests(unittest.TestCase):
self.assertIn("恢复起点失败", stderr.getvalue())
self.assertEqual(move_mock.call_count, 2)
@mock.patch("scan_calibrator.api")
def test_calibration_ptz_requests_identify_their_control_source(self, api_mock):
api_mock.return_value = {"ptz": {"pan": 1, "tilt": 2, "zoom": 3}}
self.assertEqual(core.get_ptz(), {"pan": 1, "tilt": 2, "zoom": 3})
api_mock.assert_called_with(
"GET", "/api/v1/ptz?source=scan_calibrator", timeout=50
)
core.move({"pan": 4, "tilt": 5, "zoom": 6})
api_mock.assert_called_with(
"POST", "/api/v1/ptz/absolute",
{"pan": 4, "tilt": 5, "zoom": 6,
"source": "scan_calibrator"},
timeout=50,
)
def test_hikvision_control_contract_is_supported(self):
result = core.validate_control_status({
"vendor": "hikvision",
"driver_ready": True,
"capabilities": ["get_position", "move_absolute", "jog"],
"camera": {"sdk_host": "192.168.2.10", "sdk_port": 8000},
})
self.assertEqual(result["vendor"], "hikvision")
self.assertIn("move_absolute", result["capabilities"])
def test_tiandy_control_contract_is_supported(self):
result = core.validate_control_status({
"vendor": "tiandy",
"driver_ready": True,
"capabilities": ["get_position", "move_absolute", "presets"],
"camera": {"sdk_host": "192.168.100.64", "sdk_port": 3000},
})
self.assertEqual(result["vendor"], "tiandy")
self.assertIn("get_position", result["capabilities"])
def test_control_contract_rejects_unready_driver(self):
with self.assertRaisesRegex(SystemExit, "login failed"):
core.validate_control_status({
"vendor": "tiandy",
"driver_ready": False,
"driver_error": "login failed",
"capabilities": [],
})
def test_control_contract_rejects_missing_absolute_move(self):
with self.assertRaisesRegex(SystemExit, "move_absolute"):
core.validate_control_status({
"vendor": "hikvision",
"driver_ready": True,
"capabilities": ["get_position", "jog"],
})
def test_ptz_response_must_use_normalized_contract(self):
with self.assertRaisesRegex(SystemExit, "pan超出"):
core.parse_ptz_payload({
"ptz": {"pan": 40000, "tilt": 100, "zoom": 200}
})
class InteractiveWizardTests(unittest.TestCase):
def test_guided_steps_use_actual_motion_not_requested_motion(self):
self.assertEqual(
wizard.fov_guided_deltas(62, 0.802, "tilt"),
[56, 88, 125, 163, 204],
)
def test_guided_steps_wait_for_measurable_image_shift(self):
self.assertEqual(wizard.fov_guided_deltas(33, 0.952, "tilt"), [])
def test_probe_cap_uses_camera_reported_motion(self):
self.assertEqual(wizard.safe_probe_cap(33, 0.952), 584)
self.assertEqual(wizard.safe_probe_cap(62, 0.802), 266)
@mock.patch("interactive_calibrator.core.get_ptz")
@mock.patch("interactive_calibrator.core.api")
def test_calibration_pauses_active_patrol_before_ptz_barrier(
self, api_mock, get_ptz_mock
):
status = {"control": {"scan_active": False, "patrol_active": True,
"patrol_paused_by_operator": False}}
camera = {"vendor": "tiandy", "camera": {}, "capabilities": set()}
api_mock.return_value = {"success": True}
with mock.patch(
"interactive_calibrator.core.get_control_status",
return_value=(status, camera),
):
self.assertTrue(wizard.acquire_calibration_control())
api_mock.assert_called_once_with(
"POST", "/api/v1/patrol/stop",
{"source": "scan_calibrator"}, timeout=15,
)
get_ptz_mock.assert_called_once_with()
def test_manual_ptz_accepts_annotated_display_format(self):
self.assertEqual(
wizard.parse_ptz_input(