fix(go): backfill realtime plate from binding

This commit is contained in:
lingniu
2026-07-02 16:36:52 +08:00
parent bc399d2819
commit 75b36f4011
3 changed files with 206 additions and 8 deletions

View File

@@ -3,6 +3,7 @@ package realtime
import (
"context"
"database/sql"
"errors"
"strings"
"testing"
@@ -126,6 +127,109 @@ func TestSnapshotWriterUpsertsRealtimeLocationWhenCoordinatesExist(t *testing.T)
}
}
func TestSnapshotWriterBackfillsPlateFromBindingByVIN(t *testing.T) {
exec := &recordingSnapshotExec{}
resolver := &recordingPlateResolver{plate: "沪A12345"}
writer := NewSnapshotWriterWithPlateResolver(exec, resolver)
if 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{}},
Fields: map[string]any{
envelope.FieldLatitude: 30.590151,
envelope.FieldLongitude: 121.069881,
},
}); err != nil {
t.Fatalf("Update() error = %v", err)
}
if resolver.vin != "VIN001" {
t.Fatalf("resolver vin = %q", resolver.vin)
}
if len(exec.calls) != 2 {
t.Fatalf("exec calls = %d, want 2", len(exec.calls))
}
if got, want := exec.calls[0].args[5], "沪A12345"; got != want {
t.Fatalf("snapshot plate arg = %#v, want %q", got, want)
}
if got, want := exec.calls[1].args[5], "沪A12345"; got != want {
t.Fatalf("location plate arg = %#v, want %q", got, want)
}
}
func TestSnapshotWriterKeepsEventPlateWhenPresent(t *testing.T) {
exec := &recordingSnapshotExec{}
resolver := &recordingPlateResolver{plate: "沪B99999"}
writer := NewSnapshotWriterWithPlateResolver(exec, resolver)
if err := writer.Update(context.Background(), envelope.FrameEnvelope{
Protocol: envelope.ProtocolJT808,
MessageID: "0x0200",
VIN: "VIN001",
Plate: "沪A12345",
EventTimeMS: 1782918600000,
ReceivedAtMS: 1782918601000,
Fields: map[string]any{
envelope.FieldLatitude: 30.590151,
envelope.FieldLongitude: 121.069881,
},
}); err != nil {
t.Fatalf("Update() error = %v", err)
}
if resolver.vin != "" {
t.Fatalf("resolver should not be called, got vin=%q", resolver.vin)
}
if got, want := exec.calls[0].args[5], "沪A12345"; got != want {
t.Fatalf("snapshot plate arg = %#v, want %q", got, want)
}
}
func TestSnapshotWriterIgnoresMissingBindingPlate(t *testing.T) {
exec := &recordingSnapshotExec{}
writer := NewSnapshotWriterWithPlateResolver(exec, &recordingPlateResolver{err: sql.ErrNoRows})
if 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{}},
Fields: map[string]any{envelope.FieldSOCPercent: 90},
}); err != nil {
t.Fatalf("Update() error = %v", err)
}
if got := exec.calls[0].args[5]; got != "" {
t.Fatalf("snapshot plate arg = %#v, want empty", got)
}
}
func TestSnapshotWriterReturnsUnexpectedPlateLookupError(t *testing.T) {
exec := &recordingSnapshotExec{}
writer := NewSnapshotWriterWithPlateResolver(exec, &recordingPlateResolver{err: errors.New("db down")})
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{}},
Fields: map[string]any{envelope.FieldSOCPercent: 90},
})
if err == nil || !strings.Contains(err.Error(), "db down") {
t.Fatalf("Update() error = %v, want db down", err)
}
if len(exec.calls) != 0 {
t.Fatalf("exec calls = %d, want 0", len(exec.calls))
}
}
func TestSnapshotWriterSkipsUnknownVehicleKey(t *testing.T) {
exec := &recordingSnapshotExec{}
writer := NewSnapshotWriter(exec)
@@ -176,3 +280,14 @@ func (e *recordingSnapshotExec) ExecContext(_ context.Context, query string, arg
e.calls = append(e.calls, snapshotExecCall{query: query, args: args})
return nil, nil
}
type recordingPlateResolver struct {
vin string
plate string
err error
}
func (r *recordingPlateResolver) PlateByVIN(_ context.Context, vin string) (string, error) {
r.vin = vin
return r.plate, r.err
}