fix(access): report only real vehicle sources

This commit is contained in:
lingniu
2026-07-16 18:07:45 +08:00
parent 85de053962
commit ff6df370cb
10 changed files with 106 additions and 54 deletions

View File

@@ -23,7 +23,7 @@ func TestAccessSummaryUsesDynamicFreshnessAndDelay(t *testing.T) {
if summary.DelayAbnormal != 1 || summary.ThresholdVersion != 1 {
t.Fatalf("summary must expose dynamic delay and threshold version: %+v", summary)
}
if summary.HealthyVehicles != 0 || summary.IncompleteVehicles != 3 || summary.DegradedVehicles != 0 {
if summary.HealthyVehicles != 1 || summary.IncompleteVehicles != 0 || summary.DegradedVehicles != 2 {
t.Fatalf("connection-state counters must be mutually exclusive: %+v", summary)
}
}
@@ -47,8 +47,8 @@ func TestAccessVehiclesFiltersAndKeepsEvidenceGapsExplicit(t *testing.T) {
}
attention, err := service.AccessVehicles(context.Background(), AccessQuery{ConnectionState: "attention", Limit: 20})
if err != nil || attention.Total != 6 {
t.Fatalf("attention filter should return every vehicle with an access difference: page=%+v err=%v", attention, err)
if err != nil || attention.Total != 5 {
t.Fatalf("attention filter should return every vehicle requiring attention: page=%+v err=%v", attention, err)
}
}
@@ -116,7 +116,7 @@ func TestAccessVehiclesKeywordMatchesFleetAndModel(t *testing.T) {
}
}
func TestAccessVehicleGroupsCanonicalProtocolsByMasterVehicle(t *testing.T) {
func TestAccessVehicleShowsCanonicalSlotsWithoutInventingExpectedSources(t *testing.T) {
store := NewMockStore()
service := NewService(store)
page, err := service.AccessVehicles(t.Context(), AccessQuery{Keyword: "LB9A32A24R0LS1426", Limit: 10})
@@ -124,19 +124,37 @@ func TestAccessVehicleGroupsCanonicalProtocolsByMasterVehicle(t *testing.T) {
t.Fatalf("access vehicle query failed: page=%+v err=%v", page, err)
}
row := page.Items[0]
if len(row.ExpectedProtocols) != 3 || len(row.ProtocolStatuses) != 3 {
t.Fatalf("vehicle must expose three canonical protocol slots: %+v", row)
if len(row.ExpectedProtocols) != 0 || len(row.ProtocolStatuses) != 3 {
t.Fatalf("vehicle must expose comparison slots without inventing an expected-source baseline: %+v", row)
}
if len(row.ActualProtocols) != 1 || row.ActualProtocols[0] != "JT808" || len(row.MissingProtocols) != 2 {
t.Fatalf("actual and missing protocols are incorrect: %+v", row)
if len(row.ActualProtocols) != 1 || row.ActualProtocols[0] != "JT808" || len(row.MissingProtocols) != 0 {
t.Fatalf("actual source must remain truthful and absent protocols must not be reported as missing: %+v", row)
}
if row.ConnectionState != "incomplete" || row.OnlineState != "online" {
t.Fatalf("single online source should be an online but incomplete vehicle: %+v", row)
if row.ConnectionState != "healthy" || row.OnlineState != "online" {
t.Fatalf("a maintained single online source should be healthy: %+v", row)
}
for _, status := range row.ProtocolStatuses {
if status.Protocol == "JT808" && (!status.Connected || status.LatestReceivedAt == "") {
t.Fatalf("connected protocol lost evidence: %+v", status)
}
if status.Expected {
t.Fatalf("business expectation must remain unknown until OneOS provides it: %+v", status)
}
}
}
func TestAccessVehicleSeparatesMasterDataMaintenanceFromSourceAbsence(t *testing.T) {
now := time.Now()
row := buildAccessVehicleGroup([]AccessEvidenceRow{{
VIN: "VIN-MASTER-DATA", Protocol: "JT808", OEM: "", Provider: "",
LatestEventAt: now.Add(-2 * time.Second).Format(time.RFC3339),
LatestReceivedAt: now.Add(-time.Second).Format(time.RFC3339),
}}, defaultAccessThresholds(now), now)
if row.ConnectionState != "incomplete" || len(row.MasterDataIssues) != 2 {
t.Fatalf("online source with missing brand/provider should enter the maintenance queue: %+v", row)
}
if len(row.MissingProtocols) != 0 || len(row.ExpectedProtocols) != 0 {
t.Fatalf("master-data maintenance must not invent absent protocol alarms: %+v", row)
}
}