fix(gateway): prefer known JT808 identity snapshot

This commit is contained in:
lingniu
2026-09-01 10:58:46 +08:00
parent 861e0bf207
commit 6fceb0f5b4
2 changed files with 68 additions and 0 deletions
@@ -74,6 +74,62 @@ func TestSnapshotOnlyResolverMissDoesNotQueryMySQL(t *testing.T) {
}
}
func TestKnownSnapshotRecoversAfterUnknownJT808SessionCache(t *testing.T) {
db, mock := newMockDB(t)
defer db.Close()
resolver := NewMySQLResolverWithOptions(db, "vehicle_identity_binding", MySQLResolverOptions{
SnapshotOnlyLookups: true,
DisableRegistrationWrites: true,
LookupCacheTTL: 10 * time.Minute,
})
resolver.snapshot.Store(&identitySnapshot{
bindings: map[string]string{},
identifiers: map[string]vehicleIdentifierMatch{},
registrations: map[string]registrationCacheEntry{
"64100005824": {vin: "LB9A32A2XR0LS1401", plate: "粤AGP9713"},
},
sources: map[string]sourceMetadata{},
})
// A reconnect normally authenticates before the first location report. The
// authentication frame has no VIN and therefore creates an unknown session.
if _, err := resolver.Resolve(context.Background(), envelope.FrameEnvelope{
Protocol: envelope.ProtocolJT808,
MessageID: JT808AuthMessageID,
Phone: "64100005824",
Parsed: map[string]any{},
}); err != nil {
t.Fatalf("resolve authentication frame: %v", err)
}
if entry := resolver.registrationCache["64100005824"]; entry.vin != "unknown" {
t.Fatalf("authentication session vin = %q, want unknown setup", entry.vin)
}
resolved, err := resolver.Resolve(context.Background(), envelope.FrameEnvelope{
Protocol: envelope.ProtocolJT808,
MessageID: "0x0200",
Phone: "64100005824",
Parsed: map[string]any{},
})
if err != nil {
t.Fatalf("resolve location frame: %v", err)
}
if resolved.VIN != "LB9A32A2XR0LS1401" || resolved.Plate != "粤AGP9713" {
t.Fatalf("resolved identity = vin:%q plate:%q", resolved.VIN, resolved.Plate)
}
identityMetadata, _ := resolved.Parsed["identity"].(map[string]any)
if identityMetadata["cache_status"] != "snapshot" {
t.Fatalf("identity metadata = %#v, want authoritative snapshot", identityMetadata)
}
if entry := resolver.registrationCache["64100005824"]; entry.vin != "LB9A32A2XR0LS1401" {
t.Fatalf("location frame did not heal session cache: %+v", entry)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("snapshot-only recovery should not query mysql: %v", err)
}
}
func TestRefreshSnapshotFailureKeepsLastKnownGoodSnapshot(t *testing.T) {
db, mock := newMockDB(t)
defer db.Close()