fix(stats): reconcile stale gps mileage candidates

This commit is contained in:
lingniu
2026-07-20 03:51:18 +08:00
parent 5ba636419b
commit 758da369d8
6 changed files with 172 additions and 5 deletions

View File

@@ -50,6 +50,73 @@ func TestChooseTrustedSourceKeepsContinuingSourceAndRejectsNewJump(t *testing.T)
}
}
func TestCleanupSubthresholdGPSMileageCandidatesDryRunReportsWithoutDeleting(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("sqlmock.New() error = %v", err)
}
defer db.Close()
mock.ExpectQuery("SELECT vin, DATE_FORMAT").
WithArgs("2026-07-20", "2026-07-20", stats.QualityReasonGPSCoordinate, stats.GPSMinimumDailyDistanceKM, "JT808").
WillReturnRows(sqlmock.NewRows([]string{"vin", "stat_date", "protocol", "row_count"}).
AddRow("LKLG7C4E9NA774739", "2026-07-20", "JT808", 1))
found, deleted, err := cleanupSubthresholdGPSMileageCandidates(context.Background(), db, config{
DateFrom: "2026-07-20",
DateTo: "2026-07-20",
Protocols: []envelope.Protocol{envelope.ProtocolJT808},
}, false)
if err != nil {
t.Fatalf("cleanupSubthresholdGPSMileageCandidates() error = %v", err)
}
if found != 1 || deleted != 0 {
t.Fatalf("cleanup result found=%d deleted=%d", found, deleted)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("unmet SQL expectations: %v", err)
}
}
func TestCleanupSubthresholdGPSMileageCandidatesDeletesAndReprojectsAtomically(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("sqlmock.New() error = %v", err)
}
defer db.Close()
mock.ExpectQuery("SELECT vin, DATE_FORMAT").
WithArgs("2026-07-20", "2026-07-20", stats.QualityReasonGPSCoordinate, stats.GPSMinimumDailyDistanceKM, "JT808").
WillReturnRows(sqlmock.NewRows([]string{"vin", "stat_date", "protocol", "row_count"}).
AddRow("LKLG7C4E9NA774739", "2026-07-20", "JT808", 1))
mock.ExpectBegin()
mock.ExpectExec("DELETE FROM vehicle_daily_mileage_source").
WithArgs("LKLG7C4E9NA774739", "2026-07-20", "JT808", stats.QualityReasonGPSCoordinate, stats.GPSMinimumDailyDistanceKM).
WillReturnResult(sqlmock.NewResult(0, 1))
mock.ExpectExec("INSERT INTO vehicle_daily_mileage").
WillReturnResult(sqlmock.NewResult(0, 0))
mock.ExpectExec("UPDATE vehicle_daily_mileage_source").
WillReturnResult(sqlmock.NewResult(0, 0))
mock.ExpectExec("DELETE FROM vehicle_daily_mileage").
WillReturnResult(sqlmock.NewResult(0, 1))
mock.ExpectCommit()
found, deleted, err := cleanupSubthresholdGPSMileageCandidates(context.Background(), db, config{
DateFrom: "2026-07-20",
DateTo: "2026-07-20",
Protocols: []envelope.Protocol{envelope.ProtocolJT808},
}, true)
if err != nil {
t.Fatalf("cleanupSubthresholdGPSMileageCandidates() error = %v", err)
}
if found != 1 || deleted != 1 {
t.Fatalf("cleanup result found=%d deleted=%d", found, deleted)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatalf("unmet SQL expectations: %v", err)
}
}
func TestChooseTrustedSourceAcceptsSmallNegativeMileageJitter(t *testing.T) {
previous := []dailySourceLast{{
VIN: "LB9A32A28R0LS1574",