package telemetry import ( "testing" "lingniu-vehicle-ingest/go/vehicle-gateway/internal/envelope" ) func TestLocationProjectionForProtocolUsesProtocolFields(t *testing.T) { tests := []struct { name string protocol envelope.Protocol fields map[string]any assert func(*testing.T, LocationProjection) }{ { name: "gb32960", protocol: envelope.ProtocolGB32960, fields: map[string]any{ "gb32960.position.latitude": "30.56", "gb32960.position.longitude": "121.0", "gb32960.vehicle.speed_kmh": "54.3", "gb32960.vehicle.soc_percent": "85", "gb32960.vehicle.total_mileage": "123", }, assert: func(t *testing.T, location LocationProjection) { assertFloatPointer(t, location.SpeedKMH, 54.3) assertFloatPointer(t, location.SOCPercent, 85) }, }, { name: "jt808", protocol: envelope.ProtocolJT808, fields: map[string]any{ "jt808.location.latitude": "30.590151", "jt808.location.longitude": "121.069881", "jt808.location.speed_kmh": "23", "jt808.location.altitude_m": "5", "jt808.location.direction_deg": "79", "jt808.location.alarm_flag": "2", "jt808.location.status_flag": "786435", }, assert: func(t *testing.T, location LocationProjection) { assertFloatPointer(t, location.SpeedKMH, 23) assertFloatPointer(t, location.AltitudeM, 5) assertFloatPointer(t, location.DirectionDeg, 79) assertIntPointer(t, location.AlarmFlag, 2) assertIntPointer(t, location.StatusFlag, 786435) }, }, { name: "yutong root fallback", protocol: envelope.ProtocolYutongMQTT, fields: map[string]any{ "yutong_mqtt.root.data.latitude": "30.590921", "yutong_mqtt.root.data.longitude": "121.075044", "yutong_mqtt.root.data.meter_speed": "27", "yutong_mqtt.root.data.battery_capacity_soc": "78.4", "yutong_mqtt.root.data.gpsdirection": "88", }, assert: func(t *testing.T, location LocationProjection) { assertFloatPointer(t, location.SpeedKMH, 27) assertFloatPointer(t, location.SOCPercent, 78.4) assertFloatPointer(t, location.DirectionDeg, 88) }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { location, ok := LocationProjectionForProtocol(tt.protocol, tt.fields) if !ok { t.Fatal("LocationProjectionForProtocol() did not find coordinates") } if location.Latitude == 0 || location.Longitude == 0 { t.Fatalf("coordinates = %v,%v", location.Latitude, location.Longitude) } tt.assert(t, location) }) } } func TestLocationProjectionForProtocolRejectsBareStandardizedFields(t *testing.T) { for _, protocol := range []envelope.Protocol{ envelope.ProtocolGB32960, envelope.ProtocolJT808, envelope.ProtocolYutongMQTT, } { if location, ok := LocationProjectionForProtocol(protocol, map[string]any{ "latitude": 30.5, "longitude": 121.0, "speed_kmh": 20, }); ok { t.Fatalf("protocol %s unexpectedly accepted bare fields: %#v", protocol, location) } } } func TestHasRealtimeFieldsExcludesMetadataOnlyPayloads(t *testing.T) { tests := []struct { protocol envelope.Protocol fields map[string]any want bool }{ {protocol: envelope.ProtocolGB32960, fields: map[string]any{"gb32960.header.command": "0x02"}, want: false}, {protocol: envelope.ProtocolGB32960, fields: map[string]any{"gb32960.gd_fc_stack.stack_count": "1"}, want: true}, {protocol: envelope.ProtocolJT808, fields: map[string]any{"jt808.registration.plate": "粤A00001"}, want: false}, {protocol: envelope.ProtocolJT808, fields: map[string]any{"jt808.location.speed_kmh": "20"}, want: true}, {protocol: envelope.ProtocolYutongMQTT, fields: map[string]any{"yutong_mqtt.metadata.topic": "/ytforward/shln/3"}, want: false}, {protocol: envelope.ProtocolYutongMQTT, fields: map[string]any{"yutong_mqtt.data.meter_speed": "20"}, want: true}, } for _, tt := range tests { if got := HasRealtimeFields(tt.protocol, tt.fields); got != tt.want { t.Fatalf("HasRealtimeFields(%s, %#v) = %v, want %v", tt.protocol, tt.fields, got, tt.want) } } } func assertFloatPointer(t *testing.T, value *float64, want float64) { t.Helper() if value == nil || *value != want { t.Fatalf("float pointer = %v, want %v", value, want) } } func assertIntPointer(t *testing.T, value *int64, want int64) { t.Helper() if value == nil || *value != want { t.Fatalf("int pointer = %v, want %v", value, want) } }