From e269c0ad55d5b796f3409e483d7fd936188db5c4 Mon Sep 17 00:00:00 2001 From: lingniu Date: Wed, 1 Jul 2026 05:15:05 +0800 Subject: [PATCH] refactor: narrow vehicle stat repository contract --- .../JdbcVehicleStatMetricRepository.java | 5 ++--- .../vehiclestat/VehicleStatRepository.java | 2 -- .../JdbcVehicleStatMetricRepositoryTest.java | 21 ++++++------------- .../VehicleStatControllerTest.java | 19 +++++++---------- .../VehicleStatRepositoryContractTest.java | 18 ++++++++++++++++ .../Jt808MileageStreamProcessorTest.java | 5 ----- 6 files changed, 33 insertions(+), 37 deletions(-) create mode 100644 modules/services/vehicle-stat-service/src/test/java/com/lingniu/ingest/vehiclestat/VehicleStatRepositoryContractTest.java diff --git a/modules/services/vehicle-stat-service/src/main/java/com/lingniu/ingest/vehiclestat/JdbcVehicleStatMetricRepository.java b/modules/services/vehicle-stat-service/src/main/java/com/lingniu/ingest/vehiclestat/JdbcVehicleStatMetricRepository.java index 818e6f6c..86f6b194 100644 --- a/modules/services/vehicle-stat-service/src/main/java/com/lingniu/ingest/vehiclestat/JdbcVehicleStatMetricRepository.java +++ b/modules/services/vehicle-stat-service/src/main/java/com/lingniu/ingest/vehiclestat/JdbcVehicleStatMetricRepository.java @@ -26,8 +26,7 @@ public final class JdbcVehicleStatMetricRepository implements VehicleStatReposit ensureSchema(); } - @Override - public void saveDailyStat(VehicleDailyStatResult result) { + private void saveDailyMileageMetric(VehicleDailyStatResult result) { if (result == null || result.dailyMileageKm().isEmpty()) { return; } @@ -88,7 +87,7 @@ public final class JdbcVehicleStatMetricRepository implements VehicleStatReposit statDate, OptionalDouble.of(dailyMileageKm), DailyMileageStrategy.JT808_TOTAL_MILEAGE_DIFF); - saveDailyStat(result); + saveDailyMileageMetric(result); return Optional.of(result); } diff --git a/modules/services/vehicle-stat-service/src/main/java/com/lingniu/ingest/vehiclestat/VehicleStatRepository.java b/modules/services/vehicle-stat-service/src/main/java/com/lingniu/ingest/vehiclestat/VehicleStatRepository.java index 3248deff..27f8eb46 100644 --- a/modules/services/vehicle-stat-service/src/main/java/com/lingniu/ingest/vehiclestat/VehicleStatRepository.java +++ b/modules/services/vehicle-stat-service/src/main/java/com/lingniu/ingest/vehiclestat/VehicleStatRepository.java @@ -5,8 +5,6 @@ import java.util.Optional; public interface VehicleStatRepository { - void saveDailyStat(VehicleDailyStatResult result); - Optional recordDailyMileageSample(String vin, LocalDate statDate, double totalMileageKm); Optional findDailyStat(String vin, LocalDate statDate); diff --git a/modules/services/vehicle-stat-service/src/test/java/com/lingniu/ingest/vehiclestat/JdbcVehicleStatMetricRepositoryTest.java b/modules/services/vehicle-stat-service/src/test/java/com/lingniu/ingest/vehiclestat/JdbcVehicleStatMetricRepositoryTest.java index e395b197..fb10ca0d 100644 --- a/modules/services/vehicle-stat-service/src/test/java/com/lingniu/ingest/vehiclestat/JdbcVehicleStatMetricRepositoryTest.java +++ b/modules/services/vehicle-stat-service/src/test/java/com/lingniu/ingest/vehiclestat/JdbcVehicleStatMetricRepositoryTest.java @@ -5,30 +5,21 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.datasource.DriverManagerDataSource; import java.time.LocalDate; -import java.util.OptionalDouble; import static org.assertj.core.api.Assertions.assertThat; class JdbcVehicleStatMetricRepositoryTest { @Test - void upsertsDailyMileageIntoCommonMetricTable() { + void recordsDailyMileageIntoCommonMetricTable() { JdbcTemplate jdbcTemplate = new JdbcTemplate(new DriverManagerDataSource( "jdbc:h2:mem:vehicle_stat_metric;MODE=MySQL;DATABASE_TO_LOWER=TRUE;DB_CLOSE_DELAY=-1", "sa", "")); JdbcVehicleStatMetricRepository repository = new JdbcVehicleStatMetricRepository(jdbcTemplate); - repository.saveDailyStat(new VehicleDailyStatResult( - "VIN001", - LocalDate.of(2026, 6, 30), - OptionalDouble.of(12.345), - DailyMileageStrategy.JT808_TOTAL_MILEAGE_DIFF)); - repository.saveDailyStat(new VehicleDailyStatResult( - "VIN001", - LocalDate.of(2026, 6, 30), - OptionalDouble.of(15.5), - DailyMileageStrategy.JT808_TOTAL_MILEAGE_DIFF)); + repository.recordDailyMileageSample("VIN001", LocalDate.of(2026, 6, 30), 100.0); + repository.recordDailyMileageSample("VIN001", LocalDate.of(2026, 6, 30), 115.5); assertThat(repository.findDailyStat("VIN001", LocalDate.of(2026, 6, 30))) .isPresent() @@ -36,12 +27,12 @@ class JdbcVehicleStatMetricRepositoryTest { .extracting(result -> result.dailyMileageKm().orElseThrow()) .isEqualTo(15.5); assertThat(jdbcTemplate.queryForObject("SELECT COUNT(*) FROM vehicle_stat_metric", Integer.class)) - .isEqualTo(1); + .isEqualTo(3); assertThat(jdbcTemplate.queryForObject( - "SELECT metric_key FROM vehicle_stat_metric WHERE vin = 'VIN001'", + "SELECT metric_key FROM vehicle_stat_metric WHERE vin = 'VIN001' AND metric_key = 'daily_mileage_km'", String.class)).isEqualTo("daily_mileage_km"); assertThat(jdbcTemplate.queryForObject( - "SELECT calculation_method FROM vehicle_stat_metric WHERE vin = 'VIN001'", + "SELECT calculation_method FROM vehicle_stat_metric WHERE vin = 'VIN001' AND metric_key = 'daily_mileage_km'", String.class)).isEqualTo("JT808_TOTAL_MILEAGE_DIFF"); assertThat(jdbcTemplate.queryForObject(""" SELECT COUNT(*) diff --git a/modules/services/vehicle-stat-service/src/test/java/com/lingniu/ingest/vehiclestat/VehicleStatControllerTest.java b/modules/services/vehicle-stat-service/src/test/java/com/lingniu/ingest/vehiclestat/VehicleStatControllerTest.java index 51ca0b82..0cb9db8b 100644 --- a/modules/services/vehicle-stat-service/src/test/java/com/lingniu/ingest/vehiclestat/VehicleStatControllerTest.java +++ b/modules/services/vehicle-stat-service/src/test/java/com/lingniu/ingest/vehiclestat/VehicleStatControllerTest.java @@ -17,11 +17,8 @@ class VehicleStatControllerTest { @Test void returnsDailyStatJson() throws Exception { InMemoryVehicleStatRepository repository = new InMemoryVehicleStatRepository(); - repository.saveDailyStat(new VehicleDailyStatResult( - "VIN001", - LocalDate.parse("2026-06-22"), - OptionalDouble.of(35.5), - DailyMileageStrategy.JT808_TOTAL_MILEAGE_DIFF)); + repository.recordDailyMileageSample("VIN001", LocalDate.parse("2026-06-22"), 100.0); + repository.recordDailyMileageSample("VIN001", LocalDate.parse("2026-06-22"), 135.5); MockMvc mvc = standaloneSetup(new VehicleStatController(repository)).build(); mvc.perform(get("/api/vehicle-stat/VIN001/daily").param("date", "2026-06-22")) @@ -34,21 +31,19 @@ class VehicleStatControllerTest { private static final class InMemoryVehicleStatRepository implements VehicleStatRepository { private final java.util.Map results = new java.util.HashMap<>(); - - @Override - public void saveDailyStat(VehicleDailyStatResult result) { - results.put(result.vin() + ":" + result.statDate(), result); - } + private final java.util.Map firstTotals = new java.util.HashMap<>(); @Override public Optional recordDailyMileageSample(String vin, LocalDate statDate, double totalMileageKm) { + String key = vin + ":" + statDate; + double firstTotal = firstTotals.computeIfAbsent(key, ignored -> totalMileageKm); VehicleDailyStatResult result = new VehicleDailyStatResult( vin, statDate, - OptionalDouble.of(0.0), + OptionalDouble.of(totalMileageKm - firstTotal), DailyMileageStrategy.JT808_TOTAL_MILEAGE_DIFF); - saveDailyStat(result); + results.put(key, result); return Optional.of(result); } diff --git a/modules/services/vehicle-stat-service/src/test/java/com/lingniu/ingest/vehiclestat/VehicleStatRepositoryContractTest.java b/modules/services/vehicle-stat-service/src/test/java/com/lingniu/ingest/vehiclestat/VehicleStatRepositoryContractTest.java new file mode 100644 index 00000000..dbffa523 --- /dev/null +++ b/modules/services/vehicle-stat-service/src/test/java/com/lingniu/ingest/vehiclestat/VehicleStatRepositoryContractTest.java @@ -0,0 +1,18 @@ +package com.lingniu.ingest.vehiclestat; + +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Method; +import java.util.Arrays; + +import static org.assertj.core.api.Assertions.assertThat; + +class VehicleStatRepositoryContractTest { + + @Test + void exposesOnlyMileageSampleAndQueryOperations() { + assertThat(Arrays.stream(VehicleStatRepository.class.getDeclaredMethods()) + .map(Method::getName)) + .containsExactlyInAnyOrder("recordDailyMileageSample", "findDailyStat"); + } +} diff --git a/modules/services/vehicle-stat-service/src/test/java/com/lingniu/ingest/vehiclestat/jt808/Jt808MileageStreamProcessorTest.java b/modules/services/vehicle-stat-service/src/test/java/com/lingniu/ingest/vehiclestat/jt808/Jt808MileageStreamProcessorTest.java index 37c07c7e..f9c3a5ea 100644 --- a/modules/services/vehicle-stat-service/src/test/java/com/lingniu/ingest/vehiclestat/jt808/Jt808MileageStreamProcessorTest.java +++ b/modules/services/vehicle-stat-service/src/test/java/com/lingniu/ingest/vehiclestat/jt808/Jt808MileageStreamProcessorTest.java @@ -101,11 +101,6 @@ class Jt808MileageStreamProcessorTest { private final List samples = new ArrayList<>(); private double firstSample = Double.NaN; - @Override - public void saveDailyStat(VehicleDailyStatResult result) { - results.add(result); - } - @Override public Optional recordDailyMileageSample(String vin, LocalDate statDate, double totalMileageKm) {