功能:完善里程边界与氢耗流式统计
This commit is contained in:
@@ -211,12 +211,10 @@ func TestUpsertSourceMileageUsesEventTimeBoundaries(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpsertSourceMileageAccumulatesOnlyContinuousPureHydrogenIntervals(t *testing.T) {
|
||||
func TestUpsertSourceMileageAttributesDeltaToCurrentPureHydrogenMode(t *testing.T) {
|
||||
for _, want := range []string{
|
||||
"pure_hydrogen_mileage_km = pure_hydrogen_mileage_km + CASE",
|
||||
"VALUES(latest_event_time) > latest_event_time",
|
||||
"latest_pure_hydrogen_mode_known = 1",
|
||||
"latest_pure_hydrogen_active = 1",
|
||||
"VALUES(latest_pure_hydrogen_mode_known) = 1",
|
||||
"VALUES(latest_pure_hydrogen_active) = 1",
|
||||
"VALUES(latest_total_mileage_km) - latest_total_mileage_km",
|
||||
@@ -281,6 +279,26 @@ func TestDailyMileageFromDayBoundaryUsesCurrentMinusPrevious(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsUsableDailyMileageBoundaryRejectsOlderOfflineGap(t *testing.T) {
|
||||
loc := time.FixedZone("Asia/Shanghai", 8*3600)
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
baseline time.Time
|
||||
want bool
|
||||
}{
|
||||
{name: "current day cache", baseline: time.Date(2026, 8, 4, 19, 1, 26, 0, loc), want: true},
|
||||
{name: "previous natural day", baseline: time.Date(2026, 8, 3, 23, 59, 59, 0, loc), want: true},
|
||||
{name: "older offline gap", baseline: time.Date(2026, 5, 21, 23, 13, 2, 0, loc), want: false},
|
||||
{name: "future boundary", baseline: time.Date(2026, 8, 5, 0, 0, 0, 0, loc), want: false},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
if got := IsUsableDailyMileageBoundary("2026-08-04", test.baseline, loc); got != test.want {
|
||||
t.Fatalf("IsUsableDailyMileageBoundary() = %v, want %v", got, test.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpsertSourceMileageSkipsBlankSourceIP(t *testing.T) {
|
||||
exec := &recordingExec{}
|
||||
sample := SourceMileageSample{
|
||||
@@ -612,6 +630,15 @@ func TestProjectDailyMileageSelectsCandidateAndMarksSource(t *testing.T) {
|
||||
"project": projectFinal,
|
||||
"mark": markSelected,
|
||||
} {
|
||||
// The project statement also contains an independent day-end odometer
|
||||
// subquery. Check the daily-mileage election order after its main source
|
||||
// FROM clause, rather than mistaking the odometer fallback's freshness
|
||||
// order for the elected daily-distance source order.
|
||||
if queryName == "project" {
|
||||
if index := strings.Index(query, "FROM vehicle_daily_mileage_source s\nLEFT JOIN"); index >= 0 {
|
||||
query = query[index:]
|
||||
}
|
||||
}
|
||||
identityScore := strings.Index(query, "SUM(identity_source.sample_count)")
|
||||
freshness := strings.Index(query, "latest_event_time DESC")
|
||||
rowSamples := strings.LastIndex(query, "sample_count DESC")
|
||||
@@ -699,3 +726,16 @@ func expectProjectDailyMileageSQL(mock sqlmock.Sqlmock, vin string, statDate str
|
||||
WithArgs(vin, statDate, string(protocol), vin, statDate, string(protocol)).
|
||||
WillReturnResult(sqlmock.NewResult(0, 1))
|
||||
}
|
||||
|
||||
func TestProjectDailyMileagePersistsIndependentDayEndTotal(t *testing.T) {
|
||||
for _, want := range []string{
|
||||
"day_end_total_mileage_km",
|
||||
"total_candidate.quality_status = 'OK'",
|
||||
"total_candidate.quality_reason, '') = 'gps_coordinate_accumulation'",
|
||||
"day_end_total_mileage_km = VALUES(day_end_total_mileage_km)",
|
||||
} {
|
||||
if !strings.Contains(projectDailyMileageSQL, want) {
|
||||
t.Fatalf("project SQL missing %q:\n%s", want, projectDailyMileageSQL)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user