refactor: store runtime identity and mileage in mysql metrics
This commit is contained in:
@@ -25,6 +25,10 @@
|
||||
<groupId>com.lingniu.ingest</groupId>
|
||||
<artifactId>observability</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lingniu.ingest</groupId>
|
||||
<artifactId>vehicle-identity</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.lingniu.ingest</groupId>
|
||||
<artifactId>protocol-gb32960</artifactId>
|
||||
|
||||
@@ -78,9 +78,13 @@ lingniu:
|
||||
store: ${SESSION_STORE:memory}
|
||||
ttl: ${SESSION_TTL:30m}
|
||||
identity:
|
||||
store: ${VEHICLE_IDENTITY_STORE:file}
|
||||
file:
|
||||
path: ${VEHICLE_IDENTITY_FILE:./data/vehicle-identity.jsonl}
|
||||
store: ${VEHICLE_IDENTITY_STORE:mysql}
|
||||
mysql:
|
||||
jdbc-url: ${VEHICLE_IDENTITY_MYSQL_JDBC_URL:jdbc:mysql://127.0.0.1:3306/lingniu_vehicle?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai}
|
||||
username: ${VEHICLE_IDENTITY_MYSQL_USERNAME:root}
|
||||
password: ${VEHICLE_IDENTITY_MYSQL_PASSWORD:}
|
||||
table-name: ${VEHICLE_IDENTITY_MYSQL_TABLE:vehicle_identity_bindings}
|
||||
initialize-schema: ${VEHICLE_IDENTITY_MYSQL_INITIALIZE_SCHEMA:true}
|
||||
sink:
|
||||
mq:
|
||||
enabled: ${KAFKA_ENABLED:true}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.lingniu.ingest.gb32960app;
|
||||
|
||||
import com.lingniu.ingest.core.config.IngestCoreAutoConfiguration;
|
||||
import com.lingniu.ingest.identity.MySqlVehicleIdentityService;
|
||||
import com.lingniu.ingest.identity.config.VehicleIdentityAutoConfiguration;
|
||||
import com.lingniu.ingest.protocol.gb32960.codec.Gb32960MessageDecoder;
|
||||
import com.lingniu.ingest.protocol.gb32960.config.Gb32960AutoConfiguration;
|
||||
import com.lingniu.ingest.protocol.gb32960.inbound.Gb32960NettyServer;
|
||||
@@ -27,6 +29,7 @@ class Gb32960IngestAppCompositionTest {
|
||||
.withConfiguration(AutoConfigurations.of(
|
||||
IngestCoreAutoConfiguration.class,
|
||||
SessionCoreAutoConfiguration.class,
|
||||
VehicleIdentityAutoConfiguration.class,
|
||||
SinkMqAutoConfiguration.class,
|
||||
SinkArchiveAutoConfiguration.class,
|
||||
Gb32960AutoConfiguration.class))
|
||||
@@ -36,6 +39,8 @@ class Gb32960IngestAppCompositionTest {
|
||||
"lingniu.ingest.gb32960.enabled=true",
|
||||
"lingniu.ingest.gb32960.server.enabled=true",
|
||||
"lingniu.ingest.gb32960.port=0",
|
||||
"lingniu.ingest.identity.store=mysql",
|
||||
"lingniu.ingest.identity.mysql.initialize-schema=false",
|
||||
"lingniu.ingest.session.store=memory",
|
||||
"lingniu.ingest.sink.mq.enabled=true",
|
||||
"lingniu.ingest.sink.mq.type=kafka",
|
||||
@@ -53,6 +58,7 @@ class Gb32960IngestAppCompositionTest {
|
||||
contextRunner.run(context -> {
|
||||
assertThat(context).hasSingleBean(Gb32960MessageDecoder.class);
|
||||
assertThat(context).hasSingleBean(Gb32960NettyServer.class);
|
||||
assertThat(context).hasSingleBean(MySqlVehicleIdentityService.class);
|
||||
assertThat(context).hasSingleBean(KafkaEventSink.class);
|
||||
assertThat(context).hasSingleBean(KafkaEnvelopeDeadLetterSink.class);
|
||||
assertThat(context).hasSingleBean(ArchiveStore.class);
|
||||
|
||||
@@ -27,6 +27,9 @@ class Gb32960IngestAppDefaultsTest {
|
||||
.containsEntry("lingniu.ingest.sink.mq.consumer.enabled", false)
|
||||
.containsEntry("lingniu.ingest.sink.archive.enabled", "${SINK_ARCHIVE_ENABLED:true}")
|
||||
.containsEntry("lingniu.ingest.sink.archive.path", "${SINK_ARCHIVE_PATH:./archive/}")
|
||||
.containsEntry("lingniu.ingest.identity.store", "${VEHICLE_IDENTITY_STORE:mysql}")
|
||||
.containsEntry("lingniu.ingest.identity.mysql.table-name",
|
||||
"${VEHICLE_IDENTITY_MYSQL_TABLE:vehicle_identity_bindings}")
|
||||
.containsEntry("lingniu.ingest.event-file-store.enabled", false)
|
||||
.containsEntry("lingniu.ingest.event-history.enabled", false)
|
||||
.containsEntry("lingniu.ingest.vehicle-state.enabled", false)
|
||||
|
||||
@@ -48,9 +48,7 @@ lingniu:
|
||||
store: ${SESSION_STORE:memory}
|
||||
ttl: ${SESSION_TTL:30m}
|
||||
identity:
|
||||
store: ${VEHICLE_IDENTITY_STORE:file}
|
||||
file:
|
||||
path: ${VEHICLE_IDENTITY_FILE:./data/vehicle-identity.jsonl}
|
||||
store: ${VEHICLE_IDENTITY_STORE:mysql}
|
||||
mysql:
|
||||
jdbc-url: ${VEHICLE_IDENTITY_MYSQL_JDBC_URL:jdbc:mysql://127.0.0.1:3306/lingniu_vehicle?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai}
|
||||
username: ${VEHICLE_IDENTITY_MYSQL_USERNAME:root}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.lingniu.ingest.jt808app;
|
||||
|
||||
import com.lingniu.ingest.core.config.IngestCoreAutoConfiguration;
|
||||
import com.lingniu.ingest.identity.MySqlVehicleIdentityService;
|
||||
import com.lingniu.ingest.identity.config.VehicleIdentityAutoConfiguration;
|
||||
import com.lingniu.ingest.protocol.jt808.codec.Jt808MessageDecoder;
|
||||
import com.lingniu.ingest.protocol.jt808.config.Jt808AutoConfiguration;
|
||||
@@ -37,6 +38,8 @@ class Jt808IngestAppCompositionTest {
|
||||
.withPropertyValues(
|
||||
"lingniu.ingest.jt808.enabled=true",
|
||||
"lingniu.ingest.jt808.port=0",
|
||||
"lingniu.ingest.identity.store=mysql",
|
||||
"lingniu.ingest.identity.mysql.initialize-schema=false",
|
||||
"lingniu.ingest.session.store=memory",
|
||||
"lingniu.ingest.sink.mq.enabled=true",
|
||||
"lingniu.ingest.sink.mq.type=kafka",
|
||||
@@ -54,6 +57,7 @@ class Jt808IngestAppCompositionTest {
|
||||
contextRunner.run(context -> {
|
||||
assertThat(context).hasSingleBean(Jt808MessageDecoder.class);
|
||||
assertThat(context).hasSingleBean(Jt808NettyServer.class);
|
||||
assertThat(context).hasSingleBean(MySqlVehicleIdentityService.class);
|
||||
assertThat(context).hasSingleBean(KafkaEventSink.class);
|
||||
assertThat(context).hasSingleBean(KafkaEnvelopeDeadLetterSink.class);
|
||||
assertThat(context).hasSingleBean(ArchiveStore.class);
|
||||
|
||||
@@ -28,7 +28,7 @@ class Jt808IngestAppDefaultsTest {
|
||||
.containsEntry("lingniu.ingest.sink.mq.topics.realtime", "${KAFKA_TOPIC_JT808_EVENT:vehicle.event.jt808.v1}")
|
||||
.containsEntry("lingniu.ingest.sink.mq.topics.raw-archive", "${KAFKA_TOPIC_JT808_RAW:vehicle.raw.jt808.v1}")
|
||||
.containsEntry("lingniu.ingest.sink.mq.topics.dlq", "${KAFKA_TOPIC_JT808_DLQ:vehicle.dlq.jt808.v1}")
|
||||
.containsEntry("lingniu.ingest.identity.store", "${VEHICLE_IDENTITY_STORE:file}")
|
||||
.containsEntry("lingniu.ingest.identity.store", "${VEHICLE_IDENTITY_STORE:mysql}")
|
||||
.containsEntry("lingniu.ingest.identity.mysql.table-name",
|
||||
"${VEHICLE_IDENTITY_MYSQL_TABLE:vehicle_identity_bindings}")
|
||||
.containsEntry("lingniu.ingest.identity.mysql.jdbc-url",
|
||||
|
||||
@@ -78,8 +78,6 @@ lingniu:
|
||||
enabled: ${VEHICLE_STATE_ENABLED:false}
|
||||
vehicle-stat:
|
||||
enabled: ${VEHICLE_STAT_ENABLED:true}
|
||||
repository-type: ${VEHICLE_STAT_REPOSITORY_TYPE:jdbc}
|
||||
file-path: ${VEHICLE_STAT_FILE_PATH:./target/vehicle-stat/}
|
||||
zone-id: ${VEHICLE_STAT_ZONE_ID:Asia/Shanghai}
|
||||
jt808:
|
||||
enabled: ${VEHICLE_STAT_JT808_MILEAGE_ENABLED:false}
|
||||
|
||||
@@ -7,7 +7,7 @@ import com.lingniu.ingest.sink.mq.SinkMqAutoConfiguration;
|
||||
import com.lingniu.ingest.vehiclestate.VehicleStateEnvelopeIngestor;
|
||||
import com.lingniu.ingest.vehiclestate.config.VehicleStateAutoConfiguration;
|
||||
import com.lingniu.ingest.vehiclestat.DailyVehicleStatService;
|
||||
import com.lingniu.ingest.vehiclestat.FileVehicleStatRepository;
|
||||
import com.lingniu.ingest.vehiclestat.JdbcVehicleStatMetricRepository;
|
||||
import com.lingniu.ingest.vehiclestat.VehicleStatController;
|
||||
import com.lingniu.ingest.vehiclestat.VehicleStatEnvelopeIngestor;
|
||||
import com.lingniu.ingest.vehiclestat.VehicleStatEventProcessor;
|
||||
@@ -16,22 +16,17 @@ import com.lingniu.ingest.vehiclestat.VehicleStatRepository;
|
||||
import com.lingniu.ingest.vehiclestat.config.VehicleStatAutoConfiguration;
|
||||
import org.apache.kafka.clients.producer.KafkaProducer;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
class VehicleAnalyticsAppCompositionTest {
|
||||
|
||||
@TempDir
|
||||
Path tempDir;
|
||||
|
||||
@Test
|
||||
void createsStatsBeansWithoutProtocolListenerOrEventFileStore() {
|
||||
new ApplicationContextRunner()
|
||||
@@ -41,6 +36,7 @@ class VehicleAnalyticsAppCompositionTest {
|
||||
VehicleStatAutoConfiguration.class))
|
||||
.withAllowBeanDefinitionOverriding(true)
|
||||
.withBean("kafkaProducer", KafkaProducer.class, VehicleAnalyticsAppCompositionTest::kafkaProducer)
|
||||
.withBean(JdbcTemplate.class, () -> mock(JdbcTemplate.class))
|
||||
.withPropertyValues(
|
||||
"lingniu.ingest.sink.mq.enabled=true",
|
||||
"lingniu.ingest.sink.mq.type=kafka",
|
||||
@@ -48,13 +44,12 @@ class VehicleAnalyticsAppCompositionTest {
|
||||
"lingniu.ingest.sink.mq.consumer.enabled=false",
|
||||
"lingniu.ingest.vehicle-state.enabled=false",
|
||||
"lingniu.ingest.vehicle-stat.enabled=true",
|
||||
"lingniu.ingest.vehicle-stat.file-path=" + tempDir.resolve("vehicle-stat"),
|
||||
"lingniu.ingest.event-file-store.enabled=false",
|
||||
"lingniu.ingest.event-history.enabled=false",
|
||||
"lingniu.ingest.gb32960.enabled=false")
|
||||
.run(context -> {
|
||||
assertThat(context).hasSingleBean(VehicleStatRepository.class);
|
||||
assertThat(context).hasSingleBean(FileVehicleStatRepository.class);
|
||||
assertThat(context).hasSingleBean(JdbcVehicleStatMetricRepository.class);
|
||||
assertThat(context).hasSingleBean(DailyVehicleStatService.class);
|
||||
assertThat(context).hasSingleBean(VehicleStatEventProcessor.class);
|
||||
assertThat(context).hasSingleBean(VehicleStatEnvelopeIngestor.class);
|
||||
|
||||
@@ -25,7 +25,6 @@ class VehicleAnalyticsAppDefaultsTest {
|
||||
.containsEntry("lingniu.ingest.event-file-store.enabled", false)
|
||||
.containsEntry("lingniu.ingest.event-history.enabled", false)
|
||||
.containsEntry("lingniu.ingest.vehicle-stat.enabled", "${VEHICLE_STAT_ENABLED:true}")
|
||||
.containsEntry("lingniu.ingest.vehicle-stat.repository-type", "${VEHICLE_STAT_REPOSITORY_TYPE:jdbc}")
|
||||
.containsEntry("lingniu.ingest.vehicle-state.enabled", "${VEHICLE_STATE_ENABLED:false}")
|
||||
.containsEntry("lingniu.ingest.sink.mq.consumer.enabled", "${KAFKA_CONSUMER_ENABLED:true}")
|
||||
.containsEntry(
|
||||
|
||||
@@ -60,16 +60,13 @@ lingniu:
|
||||
rate-limit:
|
||||
per-vin-qps: 50
|
||||
identity:
|
||||
store: ${VEHICLE_IDENTITY_STORE:file}
|
||||
file:
|
||||
path: ${VEHICLE_IDENTITY_FILE:./data/vehicle-identity.jsonl}
|
||||
store: ${VEHICLE_IDENTITY_STORE:mysql}
|
||||
mysql:
|
||||
table: ${VEHICLE_IDENTITY_MYSQL_TABLE:vehicle_identity_binding}
|
||||
jdbc-url: ${VEHICLE_IDENTITY_MYSQL_JDBC_URL:}
|
||||
username: ${VEHICLE_IDENTITY_MYSQL_USERNAME:}
|
||||
jdbc-url: ${VEHICLE_IDENTITY_MYSQL_JDBC_URL:jdbc:mysql://127.0.0.1:3306/lingniu_vehicle?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai}
|
||||
username: ${VEHICLE_IDENTITY_MYSQL_USERNAME:root}
|
||||
password: ${VEHICLE_IDENTITY_MYSQL_PASSWORD:}
|
||||
driver-class-name: ${VEHICLE_IDENTITY_MYSQL_DRIVER_CLASS_NAME:com.mysql.cj.jdbc.Driver}
|
||||
refresh-interval: ${VEHICLE_IDENTITY_MYSQL_REFRESH_INTERVAL:60s}
|
||||
table-name: ${VEHICLE_IDENTITY_MYSQL_TABLE:vehicle_identity_bindings}
|
||||
initialize-schema: ${VEHICLE_IDENTITY_MYSQL_INITIALIZE_SCHEMA:true}
|
||||
sink:
|
||||
mq:
|
||||
enabled: ${KAFKA_ENABLED:true}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.lingniu.ingest.yutongmqttapp;
|
||||
|
||||
import com.lingniu.ingest.core.config.IngestCoreAutoConfiguration;
|
||||
import com.lingniu.ingest.identity.MySqlVehicleIdentityService;
|
||||
import com.lingniu.ingest.identity.config.VehicleIdentityAutoConfiguration;
|
||||
import com.lingniu.ingest.inbound.mqtt.client.MqttEndpointManager;
|
||||
import com.lingniu.ingest.inbound.mqtt.config.MqttInboundAutoConfiguration;
|
||||
@@ -37,6 +38,8 @@ class YutongMqttAppCompositionTest {
|
||||
"lingniu.ingest.mqtt.endpoints[0].uri=tcp://127.0.0.1:1883",
|
||||
"lingniu.ingest.mqtt.endpoints[0].topic=/yutong/#",
|
||||
"lingniu.ingest.mqtt.endpoints[0].profile=yutong",
|
||||
"lingniu.ingest.identity.store=mysql",
|
||||
"lingniu.ingest.identity.mysql.initialize-schema=false",
|
||||
"lingniu.ingest.sink.mq.enabled=true",
|
||||
"lingniu.ingest.sink.mq.type=kafka",
|
||||
"lingniu.ingest.sink.mq.bootstrap-servers=localhost:9092",
|
||||
@@ -54,6 +57,7 @@ class YutongMqttAppCompositionTest {
|
||||
assertThat(context).hasSingleBean(MqttEndpointManager.class);
|
||||
assertThat(context).hasSingleBean(MqttProfileRegistry.class);
|
||||
assertThat(context).hasSingleBean(MqttRealtimeHandler.class);
|
||||
assertThat(context).hasSingleBean(MySqlVehicleIdentityService.class);
|
||||
assertThat(context).hasSingleBean(KafkaEventSink.class);
|
||||
assertThat(context).hasSingleBean(KafkaEnvelopeDeadLetterSink.class);
|
||||
assertThat(context).hasSingleBean(ArchiveStore.class);
|
||||
|
||||
@@ -30,8 +30,9 @@ class YutongMqttAppDefaultsTest {
|
||||
.containsEntry("lingniu.ingest.sink.mq.topics.realtime", "${KAFKA_TOPIC_YUTONG_MQTT_EVENT:vehicle.event.mqtt-yutong.v1}")
|
||||
.containsEntry("lingniu.ingest.sink.mq.topics.raw-archive", "${KAFKA_TOPIC_YUTONG_MQTT_RAW:vehicle.raw.mqtt-yutong.v1}")
|
||||
.containsEntry("lingniu.ingest.sink.mq.topics.dlq", "${KAFKA_TOPIC_YUTONG_MQTT_DLQ:vehicle.dlq.mqtt-yutong.v1}")
|
||||
.containsEntry("lingniu.ingest.identity.store", "${VEHICLE_IDENTITY_STORE:file}")
|
||||
.containsEntry("lingniu.ingest.identity.mysql.table", "${VEHICLE_IDENTITY_MYSQL_TABLE:vehicle_identity_binding}")
|
||||
.containsEntry("lingniu.ingest.identity.store", "${VEHICLE_IDENTITY_STORE:mysql}")
|
||||
.containsEntry("lingniu.ingest.identity.mysql.table-name",
|
||||
"${VEHICLE_IDENTITY_MYSQL_TABLE:vehicle_identity_bindings}")
|
||||
.containsEntry("lingniu.ingest.sink.archive.enabled", "${SINK_ARCHIVE_ENABLED:true}")
|
||||
.containsEntry("lingniu.ingest.event-file-store.enabled", false)
|
||||
.containsEntry("lingniu.ingest.event-history.enabled", false)
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package com.lingniu.ingest.identity.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.lingniu.ingest.identity.FileVehicleIdentityService;
|
||||
import com.lingniu.ingest.identity.InMemoryVehicleIdentityService;
|
||||
import com.lingniu.ingest.identity.MySqlVehicleIdentityService;
|
||||
import com.lingniu.ingest.identity.VehicleIdentityRegistry;
|
||||
import com.lingniu.ingest.identity.VehicleIdentityResolver;
|
||||
@@ -14,7 +12,6 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.nio.file.Path;
|
||||
|
||||
@AutoConfiguration
|
||||
@EnableConfigurationProperties(VehicleIdentityProperties.class)
|
||||
@@ -28,16 +25,8 @@ public class VehicleIdentityAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean({VehicleIdentityResolver.class, VehicleIdentityRegistry.class})
|
||||
@ConditionalOnProperty(prefix = "lingniu.ingest.identity", name = "store", havingValue = "file")
|
||||
public FileVehicleIdentityService fileVehicleIdentityService(VehicleIdentityProperties properties,
|
||||
ObjectMapper objectMapper) {
|
||||
// 文件实现同时提供 resolver 和 registry,协议层既能查绑定,也能在注册/鉴权时补写绑定。
|
||||
return new FileVehicleIdentityService(Path.of(properties.getFile().getPath()), objectMapper);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean({VehicleIdentityResolver.class, VehicleIdentityRegistry.class})
|
||||
@ConditionalOnProperty(prefix = "lingniu.ingest.identity", name = "store", havingValue = "mysql")
|
||||
@ConditionalOnProperty(prefix = "lingniu.ingest.identity", name = "store", havingValue = "mysql",
|
||||
matchIfMissing = true)
|
||||
public MySqlVehicleIdentityService mysqlVehicleIdentityService(VehicleIdentityProperties properties,
|
||||
ObjectMapper objectMapper) {
|
||||
VehicleIdentityProperties.Mysql mysql = properties.getMysql();
|
||||
@@ -45,12 +34,4 @@ public class VehicleIdentityAutoConfiguration {
|
||||
mysql.getJdbcUrl(), mysql.getUsername(), mysql.getPassword());
|
||||
return new MySqlVehicleIdentityService(dataSource, mysql, objectMapper);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean({VehicleIdentityResolver.class, VehicleIdentityRegistry.class})
|
||||
@ConditionalOnProperty(prefix = "lingniu.ingest.identity", name = "store", havingValue = "memory",
|
||||
matchIfMissing = true)
|
||||
public InMemoryVehicleIdentityService vehicleIdentityService() {
|
||||
return new InMemoryVehicleIdentityService();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,24 +5,14 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
@ConfigurationProperties(prefix = "lingniu.ingest.identity")
|
||||
public class VehicleIdentityProperties {
|
||||
|
||||
private String store = "memory";
|
||||
private File file = new File();
|
||||
private String store = "mysql";
|
||||
private Mysql mysql = new Mysql();
|
||||
|
||||
public String getStore() { return store; }
|
||||
public void setStore(String store) { this.store = store; }
|
||||
public File getFile() { return file; }
|
||||
public void setFile(File file) { this.file = file; }
|
||||
public Mysql getMysql() { return mysql; }
|
||||
public void setMysql(Mysql mysql) { this.mysql = mysql; }
|
||||
|
||||
public static class File {
|
||||
private String path = "./data/vehicle-identity.jsonl";
|
||||
|
||||
public String getPath() { return path; }
|
||||
public void setPath(String path) { this.path = path; }
|
||||
}
|
||||
|
||||
public static class Mysql {
|
||||
private String jdbcUrl = "jdbc:mysql://127.0.0.1:3306/lingniu_vehicle?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai";
|
||||
private String username = "root";
|
||||
|
||||
@@ -3,42 +3,31 @@ package com.lingniu.ingest.identity.config;
|
||||
import com.lingniu.ingest.identity.VehicleIdentityRegistry;
|
||||
import com.lingniu.ingest.identity.VehicleIdentityResolver;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class VehicleIdentityAutoConfigurationTest {
|
||||
|
||||
@TempDir
|
||||
Path tempDir;
|
||||
|
||||
private final ApplicationContextRunner runner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(VehicleIdentityAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void createsDefaultIdentityService() {
|
||||
runner.run(context -> {
|
||||
assertThat(context).hasSingleBean(VehicleIdentityResolver.class);
|
||||
assertThat(context).hasSingleBean(VehicleIdentityRegistry.class);
|
||||
assertThat(context.getBean(VehicleIdentityResolver.class))
|
||||
.isSameAs(context.getBean(VehicleIdentityRegistry.class));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void createsFileIdentityServiceWhenConfigured() {
|
||||
void createsMysqlIdentityServiceByDefault() {
|
||||
runner
|
||||
.withPropertyValues(
|
||||
"lingniu.ingest.identity.store=file",
|
||||
"lingniu.ingest.identity.file.path=" + tempDir.resolve("identity.jsonl"))
|
||||
"lingniu.ingest.identity.mysql.jdbc-url=jdbc:h2:mem:auto-identity-default;MODE=MySQL;DATABASE_TO_UPPER=false;DB_CLOSE_DELAY=-1",
|
||||
"lingniu.ingest.identity.mysql.username=sa",
|
||||
"lingniu.ingest.identity.mysql.password=",
|
||||
"lingniu.ingest.identity.mysql.table-name=vehicle_identity_bindings")
|
||||
.run(context -> {
|
||||
assertThat(context).hasSingleBean(VehicleIdentityResolver.class);
|
||||
assertThat(context).hasSingleBean(VehicleIdentityRegistry.class);
|
||||
assertThat(context.getBean(VehicleIdentityResolver.class))
|
||||
.isSameAs(context.getBean(VehicleIdentityRegistry.class));
|
||||
assertThat(context.getBean(VehicleIdentityResolver.class).getClass().getSimpleName())
|
||||
.isEqualTo("FileVehicleIdentityService");
|
||||
.isEqualTo("MySqlVehicleIdentityService");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -60,4 +49,14 @@ class VehicleIdentityAutoConfigurationTest {
|
||||
.isEqualTo("MySqlVehicleIdentityService");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void unsupportedStoreModeDoesNotCreateRuntimeFallback() {
|
||||
runner
|
||||
.withPropertyValues("lingniu.ingest.identity.store=file")
|
||||
.run(context -> {
|
||||
assertThat(context).doesNotHaveBean(VehicleIdentityResolver.class);
|
||||
assertThat(context).doesNotHaveBean(VehicleIdentityRegistry.class);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.lingniu.ingest.api.consumer.EnvelopeDeadLetterSink;
|
||||
import com.lingniu.ingest.vehiclestat.DailyMileageCalculator;
|
||||
import com.lingniu.ingest.vehiclestat.DailyMileageStrategy;
|
||||
import com.lingniu.ingest.vehiclestat.DailyVehicleStatService;
|
||||
import com.lingniu.ingest.vehiclestat.FileVehicleStatRepository;
|
||||
import com.lingniu.ingest.vehiclestat.JdbcVehicleStatMetricRepository;
|
||||
import com.lingniu.ingest.vehiclestat.VehicleStatController;
|
||||
import com.lingniu.ingest.vehiclestat.VehicleStatEnvelopeIngestor;
|
||||
@@ -33,7 +32,6 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.time.ZoneId;
|
||||
|
||||
@@ -48,20 +46,11 @@ public class VehicleStatAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(JdbcTemplate.class)
|
||||
@ConditionalOnProperty(prefix = "lingniu.ingest.vehicle-stat", name = "repository-type",
|
||||
havingValue = "jdbc", matchIfMissing = true)
|
||||
@ConditionalOnMissingBean
|
||||
public VehicleStatRepository jdbcVehicleStatMetricRepository(JdbcTemplate jdbcTemplate) {
|
||||
return new JdbcVehicleStatMetricRepository(jdbcTemplate);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public VehicleStatRepository vehicleStatRepository(VehicleStatProperties props) {
|
||||
// 无 JDBC 指标库时才回落本地文件,主要用于开发和单元验证。
|
||||
return new FileVehicleStatRepository(Path.of(props.getFilePath()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public VehicleStatRuleRepository vehicleStatRuleRepository() {
|
||||
|
||||
@@ -5,33 +5,11 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
@ConfigurationProperties(prefix = "lingniu.ingest.vehicle-stat")
|
||||
public class VehicleStatProperties {
|
||||
|
||||
/** 派生统计本地文件根目录;不是 32960 RAW archive 或 DuckDB 历史库目录。 */
|
||||
private String filePath = "./target/vehicle-stat/";
|
||||
|
||||
/** 指标仓储类型:有 JDBC 数据源时生产使用 jdbc;本地无数据库时回落 file。 */
|
||||
private String repositoryType = "jdbc";
|
||||
|
||||
/** 统计自然日口径,默认按国内业务使用东八区。 */
|
||||
private String zoneId = "Asia/Shanghai";
|
||||
|
||||
private Jt808 jt808 = new Jt808();
|
||||
|
||||
public String getFilePath() {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
public void setFilePath(String filePath) {
|
||||
this.filePath = filePath;
|
||||
}
|
||||
|
||||
public String getRepositoryType() {
|
||||
return repositoryType;
|
||||
}
|
||||
|
||||
public void setRepositoryType(String repositoryType) {
|
||||
this.repositoryType = repositoryType;
|
||||
}
|
||||
|
||||
public String getZoneId() {
|
||||
return zoneId;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import com.lingniu.ingest.api.consumer.EnvelopeDeadLetterSink;
|
||||
import com.lingniu.ingest.vehiclestat.DailyMileageCalculator;
|
||||
import com.lingniu.ingest.vehiclestat.DailyMileageStrategy;
|
||||
import com.lingniu.ingest.vehiclestat.DailyVehicleStatService;
|
||||
import com.lingniu.ingest.vehiclestat.FileVehicleStatRepository;
|
||||
import com.lingniu.ingest.vehiclestat.JdbcVehicleStatMetricRepository;
|
||||
import com.lingniu.ingest.vehiclestat.MileagePoint;
|
||||
import com.lingniu.ingest.vehiclestat.VehicleStatController;
|
||||
@@ -71,17 +70,14 @@ class VehicleStatAutoConfigurationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void createsFileRepositoryWhenNoRepositoryBeanExists() {
|
||||
void doesNotCreateRepositoryWithoutJdbcMetricStore() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(VehicleStatAutoConfiguration.class))
|
||||
.withPropertyValues("lingniu.ingest.vehicle-stat.enabled=true")
|
||||
.run(context -> {
|
||||
assertThat(context).hasSingleBean(VehicleStatRepository.class);
|
||||
assertThat(context).hasSingleBean(FileVehicleStatRepository.class);
|
||||
assertThat(context).hasSingleBean(VehicleStatRuleRepository.class);
|
||||
assertThat(context).hasSingleBean(DailyMileageCalculator.class);
|
||||
assertThat(context).hasSingleBean(DailyVehicleStatService.class);
|
||||
assertThat(context).hasSingleBean(VehicleStatEventProcessor.class);
|
||||
assertThat(context).doesNotHaveBean(VehicleStatRepository.class);
|
||||
assertThat(context).doesNotHaveBean(DailyVehicleStatService.class);
|
||||
assertThat(context).doesNotHaveBean(VehicleStatEventProcessor.class);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -142,7 +138,7 @@ class VehicleStatAutoConfigurationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void canForceFileRepositoryEvenWhenJdbcTemplateExists() {
|
||||
void ignoresFileRepositoryTypeAndKeepsJdbcMetricRepository() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(
|
||||
JdbcTemplateAutoConfiguration.class,
|
||||
@@ -156,8 +152,7 @@ class VehicleStatAutoConfigurationTest {
|
||||
"lingniu.ingest.vehicle-stat.repository-type=file")
|
||||
.run(context -> {
|
||||
assertThat(context).hasSingleBean(VehicleStatRepository.class);
|
||||
assertThat(context).hasSingleBean(FileVehicleStatRepository.class);
|
||||
assertThat(context).doesNotHaveBean(JdbcVehicleStatMetricRepository.class);
|
||||
assertThat(context).hasSingleBean(JdbcVehicleStatMetricRepository.class);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user