fix(go): merge gb32960 realtime snapshot payloads

This commit is contained in:
lingniu
2026-07-03 11:14:57 +08:00
parent 0fa5343ab3
commit 8789a92428
2 changed files with 128 additions and 4 deletions

View File

@@ -3,6 +3,8 @@ package realtime
import (
"context"
"database/sql"
"database/sql/driver"
"encoding/json"
"errors"
"strings"
"testing"
@@ -199,6 +201,52 @@ func TestSnapshotWriterUpsertsRealtimeLocationWhenCoordinatesExist(t *testing.T)
}
}
func TestSnapshotWriterMergesGB32960ParsedJSONAcrossSplitRealtimeFrames(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatal(err)
}
defer db.Close()
writer := NewSnapshotWriter(db)
existing := `{"data_units":[{"type":"0x01","name":"vehicle","value":{"soc_percent":88}}]}`
mock.ExpectQuery("SELECT parsed_json FROM vehicle_realtime_snapshot WHERE protocol = \\? AND vin = \\?").
WithArgs("GB32960", "VIN001").
WillReturnRows(sqlmock.NewRows([]string{"parsed_json"}).AddRow(existing))
mock.ExpectExec("INSERT INTO vehicle_realtime_snapshot").
WithArgs(
"GB32960",
"VIN001",
"",
"",
"",
jsonDataUnitsArg{types: []string{"0x01", "0x30"}},
sqlmock.AnyArg(),
sqlmock.AnyArg(),
sqlmock.AnyArg(),
).
WillReturnResult(sqlmock.NewResult(0, 1))
err = writer.Update(context.Background(), envelope.FrameEnvelope{
Protocol: envelope.ProtocolGB32960,
MessageID: "0x02",
VIN: "VIN001",
EventTimeMS: 1782918600000,
ReceivedAtMS: 1782918601000,
Parsed: map[string]any{
"data_units": []any{
map[string]any{"type": "0x30", "name": "gd_fc_stack", "value": map[string]any{"stack_count": 1}},
},
},
})
if err != nil {
t.Fatalf("Update() error = %v", err)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("sql expectations: %v", err)
}
}
func TestRealtimeUpsertsDoNotOverwriteWithOlderEventTime(t *testing.T) {
for _, tc := range []struct {
name string
@@ -588,3 +636,38 @@ func (r *recordingPlateResolver) PlateByVIN(_ context.Context, vin string) (stri
r.vin = vin
return r.plate, r.err
}
type jsonDataUnitsArg struct {
types []string
}
func (a jsonDataUnitsArg) Match(value driver.Value) bool {
text, ok := value.(string)
if !ok {
return false
}
var parsed map[string]any
if err := json.Unmarshal([]byte(text), &parsed); err != nil {
return false
}
units, ok := parsed["data_units"].([]any)
if !ok {
return false
}
seen := map[string]bool{}
for _, unit := range units {
unitMap, ok := unit.(map[string]any)
if !ok {
continue
}
if unitType, ok := unitMap["type"].(string); ok {
seen[unitType] = true
}
}
for _, unitType := range a.types {
if !seen[unitType] {
return false
}
}
return true
}