feat: 推广 V3.5 实时氢耗并完善导出
This commit is contained in:
@@ -301,6 +301,26 @@ func TestLoadHydrogenObservationVINsFiltersMissingCapacity(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadHydrogenBrandVINsUsesExactBrandAndValidVINs(t *testing.T) {
|
||||
db, mock, err := sqlmock.New()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer db.Close()
|
||||
mock.ExpectQuery(regexp.QuoteMeta("SELECT UPPER(TRIM(vin))")).
|
||||
WithArgs("现代").
|
||||
WillReturnRows(sqlmock.NewRows([]string{"vin"}).
|
||||
AddRow("lb9a32a25r0ls1452").
|
||||
AddRow("invalid"))
|
||||
vins, err := LoadHydrogenBrandVINs(context.Background(), db, " 现代 ")
|
||||
if err != nil || len(vins) != 1 || vins[0] != "LB9A32A25R0LS1452" {
|
||||
t.Fatalf("vins=%v err=%v", vins, err)
|
||||
}
|
||||
if err := mock.ExpectationsWereMet(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHydrogenObservationDateRangeForAllUsesBoundedQueries(t *testing.T) {
|
||||
db, mock, err := sqlmock.New()
|
||||
if err != nil {
|
||||
@@ -351,6 +371,37 @@ func TestReplaceHydrogenDailyStatsForVINDeletesOnlyScopedVehicle(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplaceHydrogenDailyStatsForVINsDeletesOnlyScopedBrandVehicles(t *testing.T) {
|
||||
db, mock, err := sqlmock.New()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer db.Close()
|
||||
vins := []string{"LB9A32A24R0LS1376", "LB9A32A25R0LS1452"}
|
||||
stat := HydrogenDailyStat{
|
||||
VIN: vins[0], Date: "2026-08-12", Source: "source-a", ConsumptionKg: 2.5,
|
||||
FirstMassKg: 12, LastMassKg: 9.5, SampleCount: 500, QualityStatus: "OK",
|
||||
}
|
||||
mock.ExpectBegin()
|
||||
mock.ExpectExec(regexp.QuoteMeta("DELETE FROM vehicle_open_daily_energy WHERE stat_date=? AND energy_type='HYDROGEN' AND vin IN (?,?)")).
|
||||
WithArgs(stat.Date, vins[0], vins[1]).
|
||||
WillReturnResult(sqlmock.NewResult(0, 2))
|
||||
mock.ExpectExec(regexp.QuoteMeta("INSERT INTO vehicle_open_daily_energy(")).
|
||||
WithArgs(stat.VIN, stat.Date, stat.Source, stat.ConsumptionKg, stat.FirstMassKg, stat.LastMassKg,
|
||||
stat.SampleCount, 0, stat.QualityStatus, "", stat.ConsumptionKg,
|
||||
sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), 0.0, 0.0,
|
||||
sqlmock.AnyArg(), sqlmock.AnyArg(), 0, 0, 0, "", sqlmock.AnyArg(), sqlmock.AnyArg()).
|
||||
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||
mock.ExpectCommit()
|
||||
|
||||
if err := ReplaceHydrogenDailyStatsForVINs(context.Background(), db, stat.Date, vins, []HydrogenDailyStat{stat}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := mock.ExpectationsWereMet(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplaceHydrogenDailyStatsAndSeedStreamIsAtomic(t *testing.T) {
|
||||
db, mock, err := sqlmock.New()
|
||||
if err != nil {
|
||||
@@ -396,7 +447,37 @@ func TestReplaceHydrogenDailyStatsAndSeedStreamIsAtomic(t *testing.T) {
|
||||
if err := json.Unmarshal(encoded, &state); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if state["lastObservedMassKg"] != 9.4 || state["finalizedConsumptionKg"] != 2.6 || state["lastEventTime"] == "" {
|
||||
if state["lastMassKg"] != 9.4 || state["finalizedHydrogenKg"] != 2.6 || state["lastEventTime"] == "" || state["algorithmVersion"] != trustedHydrogenAlgorithmVersion {
|
||||
t.Fatalf("seed state=%s", encoded)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReplaceHydrogenDailyStatsAndSeedStreamSkipsMissingWatermark(t *testing.T) {
|
||||
db, mock, err := sqlmock.New()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer db.Close()
|
||||
stat := HydrogenDailyStat{
|
||||
VIN: "LB9A32A24R0LS1376", Date: "2026-09-04", Source: "source-a",
|
||||
QualityStatus: "NO_DATA", QualityReason: "有效运行分界点不足2条",
|
||||
}
|
||||
mock.ExpectBegin()
|
||||
mock.ExpectExec(regexp.QuoteMeta("DELETE FROM vehicle_open_daily_energy WHERE stat_date=? AND energy_type='HYDROGEN'")).
|
||||
WithArgs("2026-09-04").WillReturnResult(sqlmock.NewResult(0, 1))
|
||||
mock.ExpectExec(regexp.QuoteMeta("DELETE FROM vehicle_open_hydrogen_segment_stream_state WHERE stat_date=?")).
|
||||
WithArgs("2026-09-04").WillReturnResult(sqlmock.NewResult(0, 0))
|
||||
mock.ExpectExec(regexp.QuoteMeta("INSERT INTO vehicle_open_daily_energy(")).
|
||||
WithArgs(stat.VIN, stat.Date, stat.Source, 0.0, 0.0, 0.0, 0, 0, stat.QualityStatus, stat.QualityReason,
|
||||
0.0, sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), 0.0, 0.0,
|
||||
sqlmock.AnyArg(), sqlmock.AnyArg(), 0, 0, 0, "", sqlmock.AnyArg(), sqlmock.AnyArg()).
|
||||
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||
mock.ExpectCommit()
|
||||
|
||||
if err := ReplaceHydrogenDailyStatsAndSeedStream(context.Background(), db, stat.Date, []HydrogenDailyStat{stat}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := mock.ExpectationsWereMet(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user