import unittest from tools import vehicle_ingest_live_verify as live_verify class VehicleIngestLiveVerifyTest(unittest.TestCase): def test_warns_when_formal_gb32960_platform_login_exists_without_vehicle_frames(self): checks = live_verify.evaluate_counts( { "jt808RawFrames": 36090, "jt808Locations": 8783, "gb32960PlatformLogins": 3, "gb32960VehicleRealtimeFrames": 0, }, live_verify.Thresholds( min_jt808_raw_frames=1, min_jt808_locations=1, min_gb32960_platform_logins=1, min_gb32960_vehicle_realtime_frames=1, require_gb32960_vehicle_realtime=False, ), ) by_name = {check.name: check for check in checks} self.assertEqual(live_verify.overall_status(checks), "warn") self.assertEqual(by_name["gb32960.vehicle_realtime"].status, "warn") self.assertIn("尚未收到正式车辆 0x02", by_name["gb32960.vehicle_realtime"].message) def test_fails_when_vehicle_frames_are_required_but_missing(self): checks = live_verify.evaluate_counts( { "jt808RawFrames": 10, "jt808Locations": 2, "gb32960PlatformLogins": 1, "gb32960VehicleRealtimeFrames": 0, }, live_verify.Thresholds(require_gb32960_vehicle_realtime=True), ) by_name = {check.name: check for check in checks} self.assertEqual(live_verify.overall_status(checks), "fail") self.assertEqual(by_name["gb32960.vehicle_realtime"].status, "fail") def test_gb32960_vehicle_realtime_sql_excludes_test_vins(self): sql = live_verify.gb32960_vehicle_realtime_count_sql( date_from="2026-06-29 00:00:00", date_to="2026-06-29 23:59:59", ) self.assertIn("message_id = 2", sql) self.assertIn("vin <> ''", sql) self.assertIn("vin NOT LIKE 'LTEST%'", sql) self.assertIn("ts >= '2026-06-29 00:00:00'", sql) self.assertIn("ts <= '2026-06-29 23:59:59'", sql) def test_gb32960_peer_filter_treats_plain_ip_as_contains_pattern(self): sql = live_verify.gb32960_platform_login_count_sql( date_from="2026-06-29 00:00:00", date_to="2026-06-29 23:59:59", peer_like="115.29.187.205", ) self.assertIn("peer LIKE '%115.29.187.205%'", sql) def test_gb32960_peer_filter_preserves_explicit_like_pattern(self): sql = live_verify.gb32960_platform_login_count_sql( date_from="2026-06-29 00:00:00", date_to="2026-06-29 23:59:59", peer_like="115.29.187.%", ) self.assertIn("peer LIKE '115.29.187.%'", sql) def test_gb32960_command_counts_sql_uses_same_peer_filter(self): sql = live_verify.gb32960_command_count_sql( date_from="2026-06-29 00:00:00", date_to="2026-06-29 23:59:59", peer_like="115.29.187.205", ) self.assertIn("protocol = 'GB32960'", sql) self.assertIn("peer LIKE '%115.29.187.205%'", sql) self.assertIn("GROUP BY message_id", sql) def test_gb32960_command_count_rows_include_command_names(self): response = { "code": 0, "data": [ [2, 9], [5, 3], ], } rows = live_verify.command_count_rows(response) self.assertEqual(rows, [ {"messageId": 2, "command": "REALTIME_REPORT", "count": 9}, {"messageId": 5, "command": "PLATFORM_LOGIN", "count": 3}, ]) def test_gb32960_recent_frame_rows_surface_peer_and_raw_uri(self): response = { "code": 0, "data": [[ "2026-06-29T12:26:21.385Z", 5, "", "unknown:GB32960:f729d788b943630e", "115.29.187.205:59630", "archive://frame.bin", ]], } rows = live_verify.recent_frame_rows(response) self.assertEqual(rows, [{ "ts": "2026-06-29T12:26:21.385Z", "messageId": 5, "command": "PLATFORM_LOGIN", "vin": "", "vehicleKey": "unknown:GB32960:f729d788b943630e", "peer": "115.29.187.205:59630", "rawUri": "archive://frame.bin", }]) def test_jt808_location_sql_uses_current_vehicle_locations_stable_with_protocol_filter(self): sql = live_verify.jt808_location_count_sql( date_from="2026-06-29 00:00:00", date_to="2026-06-29 23:59:59", ) self.assertEqual( sql, "SELECT COUNT(*) FROM vehicle_locations WHERE protocol = 'JT808' " "AND ts >= '2026-06-29 00:00:00' AND ts <= '2026-06-29 23:59:59'", ) if __name__ == "__main__": unittest.main()