refactor: simplify jt808 mileage state
This commit is contained in:
@@ -18,7 +18,6 @@ public final class Jt808DailyMileageState {
|
|||||||
private Instant lastEventTime;
|
private Instant lastEventTime;
|
||||||
private double firstTotalMileageKm = Double.NaN;
|
private double firstTotalMileageKm = Double.NaN;
|
||||||
private double lastTotalMileageKm = Double.NaN;
|
private double lastTotalMileageKm = Double.NaN;
|
||||||
private double odometerMileageKm;
|
|
||||||
private int acceptedPoints;
|
private int acceptedPoints;
|
||||||
private int totalMileageSamples;
|
private int totalMileageSamples;
|
||||||
private int outOfOrderPoints;
|
private int outOfOrderPoints;
|
||||||
@@ -50,7 +49,6 @@ public final class Jt808DailyMileageState {
|
|||||||
Instant lastEventTime,
|
Instant lastEventTime,
|
||||||
double firstTotalMileageKm,
|
double firstTotalMileageKm,
|
||||||
double lastTotalMileageKm,
|
double lastTotalMileageKm,
|
||||||
double odometerMileageKm,
|
|
||||||
int acceptedPoints,
|
int acceptedPoints,
|
||||||
int totalMileageSamples,
|
int totalMileageSamples,
|
||||||
int outOfOrderPoints,
|
int outOfOrderPoints,
|
||||||
@@ -60,7 +58,6 @@ public final class Jt808DailyMileageState {
|
|||||||
state.lastEventTime = lastEventTime;
|
state.lastEventTime = lastEventTime;
|
||||||
state.firstTotalMileageKm = firstTotalMileageKm;
|
state.firstTotalMileageKm = firstTotalMileageKm;
|
||||||
state.lastTotalMileageKm = lastTotalMileageKm;
|
state.lastTotalMileageKm = lastTotalMileageKm;
|
||||||
state.odometerMileageKm = odometerMileageKm;
|
|
||||||
state.acceptedPoints = acceptedPoints;
|
state.acceptedPoints = acceptedPoints;
|
||||||
state.totalMileageSamples = totalMileageSamples;
|
state.totalMileageSamples = totalMileageSamples;
|
||||||
state.outOfOrderPoints = outOfOrderPoints;
|
state.outOfOrderPoints = outOfOrderPoints;
|
||||||
@@ -112,11 +109,9 @@ public final class Jt808DailyMileageState {
|
|||||||
if (current < lastTotalMileageKm) {
|
if (current < lastTotalMileageKm) {
|
||||||
odometerAnomalies++;
|
odometerAnomalies++;
|
||||||
lastTotalMileageKm = current;
|
lastTotalMileageKm = current;
|
||||||
odometerMileageKm = 0.0;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lastTotalMileageKm = current;
|
lastTotalMileageKm = current;
|
||||||
odometerMileageKm = current - firstTotalMileageKm;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private OptionalDouble totalMileageDifference() {
|
private OptionalDouble totalMileageDifference() {
|
||||||
@@ -160,10 +155,6 @@ public final class Jt808DailyMileageState {
|
|||||||
return lastEventTime;
|
return lastEventTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double odometerMileageKm() {
|
|
||||||
return odometerMileageKm;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double lastTotalMileageKm() {
|
public double lastTotalMileageKm() {
|
||||||
return lastTotalMileageKm;
|
return lastTotalMileageKm;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,6 @@ public final class RedisJt808MileageStateStore implements Jt808MileageStateStore
|
|||||||
PointSnapshot lastPoint,
|
PointSnapshot lastPoint,
|
||||||
Double firstTotalMileageKm,
|
Double firstTotalMileageKm,
|
||||||
Double lastTotalMileageKm,
|
Double lastTotalMileageKm,
|
||||||
double odometerMileageKm,
|
|
||||||
int acceptedPoints,
|
int acceptedPoints,
|
||||||
Integer totalMileageSamples,
|
Integer totalMileageSamples,
|
||||||
int outOfOrderPoints,
|
int outOfOrderPoints,
|
||||||
@@ -83,7 +82,6 @@ public final class RedisJt808MileageStateStore implements Jt808MileageStateStore
|
|||||||
null,
|
null,
|
||||||
finiteOrNull(state.firstTotalMileageKm()),
|
finiteOrNull(state.firstTotalMileageKm()),
|
||||||
finiteOrNull(state.lastTotalMileageKm()),
|
finiteOrNull(state.lastTotalMileageKm()),
|
||||||
state.odometerMileageKm(),
|
|
||||||
state.acceptedPoints(),
|
state.acceptedPoints(),
|
||||||
state.totalMileageSamples(),
|
state.totalMileageSamples(),
|
||||||
state.outOfOrderPoints(),
|
state.outOfOrderPoints(),
|
||||||
@@ -100,7 +98,6 @@ public final class RedisJt808MileageStateStore implements Jt808MileageStateStore
|
|||||||
restoredLastEventTime(),
|
restoredLastEventTime(),
|
||||||
nanIfNull(firstTotalMileageKm),
|
nanIfNull(firstTotalMileageKm),
|
||||||
nanIfNull(lastTotalMileageKm),
|
nanIfNull(lastTotalMileageKm),
|
||||||
odometerMileageKm,
|
|
||||||
acceptedPoints,
|
acceptedPoints,
|
||||||
restoredTotalMileageSamples(),
|
restoredTotalMileageSamples(),
|
||||||
outOfOrderPoints,
|
outOfOrderPoints,
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ class Jt808DailyMileageStateTest {
|
|||||||
|
|
||||||
assertThat(state.acceptedPoints()).isEqualTo(1);
|
assertThat(state.acceptedPoints()).isEqualTo(1);
|
||||||
assertThat(state.totalMileageSamples()).isEqualTo(1);
|
assertThat(state.totalMileageSamples()).isEqualTo(1);
|
||||||
assertThat(state.odometerMileageKm()).isZero();
|
|
||||||
assertThat(state.firstTotalMileageKm()).isEqualTo(100.0);
|
assertThat(state.firstTotalMileageKm()).isEqualTo(100.0);
|
||||||
assertThat(state.lastTotalMileageKm()).isEqualTo(100.0);
|
assertThat(state.lastTotalMileageKm()).isEqualTo(100.0);
|
||||||
assertThat(state.toVehicleDailyStatResult()).isEmpty();
|
assertThat(state.toVehicleDailyStatResult()).isEmpty();
|
||||||
@@ -28,7 +27,7 @@ class Jt808DailyMileageStateTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void orderedPointUpdatesGpsSpeedAndOdometerMileage() {
|
void orderedPointsCalculateDailyMileageFromTotalMileageDifference() {
|
||||||
Jt808DailyMileageState state = Jt808DailyMileageState.empty("VIN001", "VIN001", "13900000001",
|
Jt808DailyMileageState state = Jt808DailyMileageState.empty("VIN001", "VIN001", "13900000001",
|
||||||
LocalDate.of(2026, 6, 30));
|
LocalDate.of(2026, 6, 30));
|
||||||
state.apply(point("2026-06-30T00:00:00Z", 120.000000, 30.000000, 36.0, 100.0));
|
state.apply(point("2026-06-30T00:00:00Z", 120.000000, 30.000000, 36.0, 100.0));
|
||||||
@@ -37,7 +36,6 @@ class Jt808DailyMileageStateTest {
|
|||||||
|
|
||||||
assertThat(state.acceptedPoints()).isEqualTo(2);
|
assertThat(state.acceptedPoints()).isEqualTo(2);
|
||||||
assertThat(state.totalMileageSamples()).isEqualTo(2);
|
assertThat(state.totalMileageSamples()).isEqualTo(2);
|
||||||
assertThat(state.odometerMileageKm()).isCloseTo(1.2, offset(0.000001));
|
|
||||||
assertThat(state.firstTotalMileageKm()).isEqualTo(100.0);
|
assertThat(state.firstTotalMileageKm()).isEqualTo(100.0);
|
||||||
assertThat(state.lastTotalMileageKm()).isEqualTo(101.2);
|
assertThat(state.lastTotalMileageKm()).isEqualTo(101.2);
|
||||||
assertThat(state.toVehicleDailyStatResult()).isPresent();
|
assertThat(state.toVehicleDailyStatResult()).isPresent();
|
||||||
@@ -66,7 +64,6 @@ class Jt808DailyMileageStateTest {
|
|||||||
|
|
||||||
state.apply(point("2026-06-30T00:01:40Z", 120.010370, 30.000000, 36.0, 99.5));
|
state.apply(point("2026-06-30T00:01:40Z", 120.010370, 30.000000, 36.0, 99.5));
|
||||||
|
|
||||||
assertThat(state.odometerMileageKm()).isZero();
|
|
||||||
assertThat(state.odometerAnomalies()).isEqualTo(1);
|
assertThat(state.odometerAnomalies()).isEqualTo(1);
|
||||||
assertThat(state.toVehicleDailyStatResult()).isEmpty();
|
assertThat(state.toVehicleDailyStatResult()).isEmpty();
|
||||||
}
|
}
|
||||||
@@ -79,13 +76,12 @@ class Jt808DailyMileageStateTest {
|
|||||||
|
|
||||||
state.apply(point("2026-06-30T00:01:00Z", 120.000100, 30.000000, 36.0, 200.0));
|
state.apply(point("2026-06-30T00:01:00Z", 120.000100, 30.000000, 36.0, 200.0));
|
||||||
|
|
||||||
assertThat(state.odometerMileageKm()).isEqualTo(100.0);
|
|
||||||
assertThat(state.odometerAnomalies()).isZero();
|
assertThat(state.odometerAnomalies()).isZero();
|
||||||
assertThat(state.toVehicleDailyStatResult().orElseThrow().dailyMileageKm()).hasValue(100.0);
|
assertThat(state.toVehicleDailyStatResult().orElseThrow().dailyMileageKm()).hasValue(100.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void gpsDistanceIsFallbackWhenTotalMileageIsMissing() {
|
void totalMileageIsRequiredForDailyMileageMetric() {
|
||||||
Jt808DailyMileageState state = Jt808DailyMileageState.empty("VIN001", "VIN001", "13900000001",
|
Jt808DailyMileageState state = Jt808DailyMileageState.empty("VIN001", "VIN001", "13900000001",
|
||||||
LocalDate.of(2026, 6, 30));
|
LocalDate.of(2026, 6, 30));
|
||||||
state.apply(point("2026-06-30T00:00:00Z", 120.000000, 30.000000, 36.0, null));
|
state.apply(point("2026-06-30T00:00:00Z", 120.000000, 30.000000, 36.0, null));
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.lingniu.ingest.vehiclestat.jt808;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
import org.springframework.data.redis.core.ValueOperations;
|
import org.springframework.data.redis.core.ValueOperations;
|
||||||
|
|
||||||
@@ -31,14 +32,17 @@ class RedisJt808MileageStateStoreTest {
|
|||||||
|
|
||||||
store.save(state);
|
store.save(state);
|
||||||
|
|
||||||
|
ArgumentCaptor<String> json = ArgumentCaptor.forClass(String.class);
|
||||||
verify(values).set(
|
verify(values).set(
|
||||||
org.mockito.ArgumentMatchers.eq("vehicle:mileage:jt808:daily:2026-06-30:VIN001"),
|
org.mockito.ArgumentMatchers.eq("vehicle:mileage:jt808:daily:2026-06-30:VIN001"),
|
||||||
org.mockito.ArgumentMatchers.contains("\"vehicleKey\":\"VIN001\""),
|
json.capture(),
|
||||||
org.mockito.ArgumentMatchers.eq(Duration.ofDays(3)));
|
org.mockito.ArgumentMatchers.eq(Duration.ofDays(3)));
|
||||||
|
assertThat(json.getValue()).contains("\"vehicleKey\":\"VIN001\"");
|
||||||
|
assertThat(json.getValue()).doesNotContain("odometerMileageKm");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void loadsStateFromJson() {
|
void loadsStateFromLegacyJson() {
|
||||||
StringRedisTemplate redis = mock(StringRedisTemplate.class);
|
StringRedisTemplate redis = mock(StringRedisTemplate.class);
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
ValueOperations<String, String> values = mock(ValueOperations.class);
|
ValueOperations<String, String> values = mock(ValueOperations.class);
|
||||||
|
|||||||
Reference in New Issue
Block a user