增加服务端配置文件与测试文件

This commit is contained in:
chenlinlin 2025-02-28 17:00:37 +08:00
parent 1a66192ee8
commit e593b545d4
14 changed files with 1044 additions and 0 deletions

View File

@ -0,0 +1,39 @@
spring:
config:
activate:
on-profile: dev
jpa:
# database-platform: com.aisino.iles.core.hibernate.MysqlDialectPlus
# database-platform: org.hibernate.dialect.Kingbase8Dialect
database-platform: com.aisino.iles.core.hibernate.PostgreSQLDialectPlus
hibernate:
ddl-auto: update
datasource:
hikari:
maximum-pool-size: 10
minimum-idle: 5
# driver-class-name: com.mysql.cj.jdbc.Driver
# username: socialcollect
# password: Socialcollect@pg2025
# jdbc-url: jdbc:mysql://mysql-dev:33060/iles_db?useSSL=false&serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8
driver-class-name: org.postgresql.Driver
username: socialcollect
password: Socialcollect@pg2025
jdbc-url: jdbc:postgresql://mysql-dev:60002/iles_db?timezone=Asia/Shanghai
pool-name: hikari-dev-pool
data:
redis:
host: localhost
port: 6379
database: 5
server:
port: 9091
logging:
level:
com.aisino.iles.core.hibernate.RedissonLocalStorage: DEBUG
com.aisino.iles.lawenforcement.controller.AuthController: debug
org.hibernate.SQL: debug
org.hibernate.orm.jdbc.bind: TRACE
org.springframework.web.client.RestTemplate: DEBUG
org.apache.kafka.clients.NetworkClient: ERROR

View File

@ -0,0 +1,62 @@
spring:
jpa:
database-platform: org.hibernate.dialect.Kingbase8Dialect
hibernate:
ddl-auto: update
datasource:
hikari:
maximum-pool-size: 10
minimum-idle: 5
driver-class-name: com.kingbase8.Driver
username: iles_db
password: Zhyj@2025
jdbc-url: jdbc:kingbase8://db:54321/iles_db?timezone=Asia/Shanghai
pool-name: hikari-prod-pool
data:
redis:
host: redis
port: 6379
database: 5
kafka:
bootstrap-servers: 10.22.245.242:9092
listener:
# 手动提交模式必须配置与enable-auto-commit: false配合
ack-mode: MANUAL_IMMEDIATE # 调用ack.acknowledge()后立即提交
producer:
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
acks: all # 确认策略:所有副本确认后返回成功
consumer:
group-id: zhzf-group
auto-offset-reset: earliest # 偏移量重置策略:从最早消息开始消费
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
enable-auto-commit: false # 启用自动提交偏移量
server:
port: 9091
custom:
aws:
access-key: aisino@2021
secret-key: aisino@2021
bucket: iles
endpoint: http://minio:10010
filePath:
# 整合支撑系统认证
sso:
enabled: true
base_url: http://10.22.245.209:16165/ht
authorize_server: ${sso.base_url}/uaa
client_id: A-610100000000-0005
client_secret: 949783e1735b45948658b44744b0c3c3
redirect_uri: https://10.22.245.213:10011/zhzf/index.html
third-party:
enterprise:
# 内网环境的综合执法用户的手机号码
yddh: 18009235209
logging:
level:
com.aisino.iles.core.hibernate.RedissonLocalStorage: DEBUG
org.hibernate.SQL: debug
org.hibernate.orm.jdbc.bind: TRACE

View File

@ -0,0 +1,61 @@
spring:
jpa:
properties:
hibernate:
cache:
redisson:
hibernate:
default-query-results-region:
eviction:
max_entries: 10000
expiration:
max_idle_time: 18000
time_to_live: 60000
Constant:
eviction:
max_entries: 40000
expiration:
max_idle_time: 0
time_to_live: 0
User:
expiration:
time_to_live: 600000
max_idle_time: 300000
eviction:
max_entries: 20000
Function:
expiration:
time_to_live: 0
max_idle_time: 0
eviction:
max_entries: 10000
Menu:
expiration:
time_to_live: 0
max_idle_time: 0
eviction:
max_entries: 4000
UserType:
expiration:
time_to_live: 0
max_idle_time: 0
eviction:
max_entries: 1000
Permission:
expiration:
time_to_live: 0
max_idle_time: 0
eviction:
max_entries: 5000
Role:
expiration:
time_to_live: 0
max_idle_time: 0
eviction:
max_entries: 4000
Resource:
expiration:
time_to_live: 0
max_idle_time: 0
eviction:
max_entries: 10000

View File

@ -0,0 +1,44 @@
spring:
jpa:
database-platform: org.hibernate.dialect.Kingbase8Dialect
hibernate:
ddl-auto: update
datasource:
hikari:
maximum-pool-size: 10
minimum-idle: 5
driver-class-name: com.kingbase8.Driver
username: iles_user
password: iles_user@2025
jdbc-url: jdbc:kingbase8://db:54321/iles_db?timezone=Asia/Shanghai
pool-name: hikari-test-pool
server:
port: 9091
custom:
aws:
access-key: aisino@2021
secret-key: aisino@2021
bucket: iles
endpoint: http://10.22.245.219:10010
filePath:
# 整合支撑系统认证
sso:
enabled: true
base_url: http://10.22.245.219:16165/ht
authorize_server: ${sso.base_url}/uaa
client_id: A-610100000000-0005
client_secret: 949783e1735b45948658b44744b0c3c3
redirect_uri: http://10.22.245.219:10011/zhzf/index.html
third-party:
enterprise:
# 内网环境的综合执法用户的手机号码
yddh: 13996761895
logging:
level:
com.aisino.iles.core.hibernate.RedissonLocalStorage: DEBUG
com.aisino.iles.lawenforcement.controller.AuthController: debug
org.hibernate.SQL: debug
org.hibernate.orm.jdbc.bind: TRACE
org.springframework.web.client.RestTemplate: DEBUG

View File

@ -0,0 +1,196 @@
spring:
profiles:
include:
- redisson-cache
jpa:
open-in-view: false
hibernate:
ddl-auto: none
properties:
hibernate:
default_batch_fetch_size: 50
jdbc:
batch_size: 50
cache:
use_second_level_cache: true
use_query_cache: true
# region.factory_class: org.redisson.hibernate.RedissonRegionFactory
region_prefix: hibernate
redisson:
fallback: true
generate.statistics: true
cache:
type: redis
data:
redis:
host: localhost
port: 6379
password: null
database: 0
repositories:
enabled: false
servlet:
multipart:
max-file-size: 1000MB
max-request-size: 1000MB
jackson:
locale: zh_CN
time-zone: Asia/Shanghai
serialization:
write_dates_as_timestamps: false # 关闭序列化的时候,把时间按照毫秒方式输出的特性
redisson:
config: |
singleServerConfig:
address: "redis://${spring.data.redis.host}:${spring.data.redis.port}"
connectionMinimumIdleSize: 10
connectionPoolSize: 64
idleConnectionTimeout: 10000
connectTimeout: 10000
timeout: 3000
retryAttempts: 3
retryInterval: 1500
password: null
subscriptionsPerConnection: 24
clientName: "redisson-client"
sslEnableEndpointIdentification: false
database: ${spring.data.redis.database}
server:
servlet:
session:
timeout: 180
logging:
file:
name: ./logs/iles.log
logback:
rollingpolicy:
max-history: 7
max-file-size: 10MB
total-size-cap: 5GB
charset:
console: UTF-8
file: UTF-8
level:
org.hibernate.cache: DEBUG
com.aisino.iles: INFO
custom:
aws:
access-key: aisino@2021
secret-key: aisino@2021
bucket: bucket-test
endpoint: https://mysql-dev:10010
filePath:
# 整合支撑系统认证
sso:
enabled: true
base_url: http://218.77.106.90:16166/ht
authorize_server: ${sso.base_url}/uaa
client_id: A-610100000000-0005
client_secret: 949783e1735b45948658b44744b0c3c3
redirect_uri: http://localhost:5173/zhzf/index.html
#第三方接口相关配置
third-party:
#消息服务
message:
url: ${sso.base_url}/msg/v1/messages/create
dict: ${sso.base_url}/system/dict/cache/
enterprise:
yddh: 18685429490
#互联网
query: ${sso.base_url}/jcxxgl/company/jbxx/queryPage
save: ${sso.base_url}/jcxxgl/company/jbxx/save
token: ${sso.base_url}/uaa/oauth/backendServiceToken
refresh: ${sso.base_url}/uaa/oauth/token
selfInsAndSelfReport: ${sso.base_url}/jcxxglApi/djbQyfxxj/queryPage
produceLicensePage: ${sso.base_url}/jcxxglApi/djbQyscxk/queryPage
hazardPage: ${sso.base_url}/jcxxglApi/djbQyyhxx/queryPage
sourcesDangerPage: ${sso.base_url}/jcxxglApi/djbQyzdbw/queryPage
report_check:
query: https://xa-pro.12350.work/backend/php/complaintsReport/index
single: https://xa-pro.12350.work/backend/php/complaintsReport/detail
sign: x7Dp9K2zR4bY8qW3
# 执法机构信息
agency:
query: ${sso.base_url}/system/sysDept/queryPage
# 执法人员信息
person:
query: ${sso.base_url}/system/sysUser/queryPage
roles:
# 执法市级
- zhzfsj
# 执法区级
- zhzfxj
# 执法检查
- zhzfjc
# 文书送达
delivery:
username: zhifa
password: zhifa@95113
base-url: http://10.22.245.226:9080/xtjy
publish-sms-call-url: ${third-party.delivery.base-url}/kt-module-task/v1/callAndResponse/publishSMS
publish-voice-call-url: ${third-party.delivery.base-url}/kt-module-task/v1/callAndResponse/publishVoice
# 执法信息
enforcement:
save: ${sso.base_url}/djbZfajxx/save
# 执法文书
document:
save: ${sso.base_url}/djbZfwsxx/save
# 执法检查
enforce-check:
save: ${sso.base_url}/djbZfjcxx/save
# 执法案件
case:
save: ${sso.base_url}/djbZfajxx/save
agency-arr: 01610100000726000-01610100000701000-01610100000016000-01610100000715000-01610100000726000-01610100000037000
iles:
sync:
api:
base-url: ${sso.base_url}
dto-converters:
"com.aisino.iles.lawenforcement.model.Document": com.aisino.iles.lawenforcement.model.dto.DjbZfwsxxRequestDto
"com.aisino.iles.lawenforcement.model.EnforcementInfo": com.aisino.iles.lawenforcement.model.dto.DjbZfjbxxRequestDto
"com.aisino.iles.lawenforcement.model.EnforceCheck": com.aisino.iles.lawenforcement.model.dto.DjbZfjcxxRequestDto
"com.aisino.iles.lawenforcement.model.Case": com.aisino.iles.lawenforcement.model.dto.DjbZfajxxRequestDto
endpoints:
com.aisino.iles.lawenforcement.model.dto.DjbZfajxxRequestDto: /djbZfajxx/save
com.aisino.iles.lawenforcement.model.dto.DjbZfwsxxRequestDto: /djbZfwsxx/save
com.aisino.iles.lawenforcement.model.dto.DjbZfjcxxRequestDto: /djbZfjcxx/save
com.aisino.iles.lawenforcement.model.dto.DjbZfjbxxRequestDto: /djbZfjbxx/save
scheduler:
enabled: false
task:
enterprise:
cron.expression: 20 16 * * * ?
agency:
cron.expression: 0 0 1 * * ?
officer:
cron.expression: 0 0 1 * * ?
waferEnterprise:
cron.expression: 0 2 * * * ?
data-package:
#是否打开JPA事务拦截器 默认true
enable: true
# 打包标记
packaging-flag: false
# 打包接口
packaging-api: http://localhost:8090/dtt/pack
# 写入目标redis失败时重试次数
retry-times: 3
# 写入目标redis失败时重试间隔时间毫秒
retry-interval: 200
# 数据包后续业务处理器
data-pack-processors:
- sendToDttPack
# 需要打包的实体名称(列表)
process-entity-names:
include:
- com.aisino.iles.core.model.*
- com.aisino.iles.lawenforcement.model.*

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,24 @@
# 服务地址 格式 ip:port
address: 10.22.245.159:19190
## 以下两项使用kcsp平台的kms必填,均由kcsp平台提供。非kcsp平台可为空
contextPath:
kid:
#以下两项必填(由kms aksk 管理解密生成)
accessKey: Sgk5hVoeEEpgUhK7
secretKey: eWjPzctSUTODF2Xm
#使用cbc模式加密的keyId可为空
cbcKeyId:
#使用ctr模式加密的keyId可为空
crtKeyId:
#是否使用tls
useTLS: false
#本地信任keyStore路径
trustStorePath:
#本地信任keyStore密码
trustStorePassword:
#本地keyStore路径
keyStorePath:
#本地keyStore密码
keyStorePassword:
#本地keyStore中key的密码
keyPassword:

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- Spring Boot的基本配置 -->
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<!-- Dead-Letter日志Appender -->
<appender name="DEAD_LETTER_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/dead-letter.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 每天滚动 -->
<fileNamePattern>logs/dead-letter.%d{yyyy-MM-dd}.log</fileNamePattern>
<!-- 保留30天的日志 -->
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<!-- 只日志信息,因为已经是JSON格式 -->
<pattern>%msg%n</pattern>
</encoder>
</appender>
<!-- Dead-Letter Queue日志 -->
<!-- 写入DEAD_LETTER_FILE Appender -->
<!-- additivity="false" 使日志不再传递到root logger,避免日志重复 -->
<logger name="dead-letter-log" level="ERROR" additivity="false">
<appender-ref ref="DEAD_LETTER_FILE" />
</logger>
<!-- 可以在这里添加其他日志配置 -->
</configuration>

View File

@ -0,0 +1,72 @@
package com.aisino.iles.core.hibernate;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.Session;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.transaction.annotation.Transactional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* PostgreSQLDialectPlus集成测试类
* 用于验证SQL生成是否符合预期
*
* @author Cascade
* @since 2025-08-08
*/
@Slf4j
@SpringBootTest
@ActiveProfiles("test")
@Transactional
class PostgreSQLDialectPlusIntegrationTest {
@PersistenceContext
private EntityManager entityManager;
@Test
void testJsonValueFunctionSimplePathSqlGeneration() {
// 获取Hibernate Session
Session session = entityManager.unwrap(Session.class);
// 创建一个包含json_value函数的HQL查询
String hql = "SELECT json_value('{\"name\":\"John\", \"info\":{\"age\":30}}', '$.info.age')";
String result = (String) session.createQuery(hql).getSingleResult();
assertEquals("30", result);
}
@Test
void testJsonValueFunctionTranslationVerification() {
// 获取Hibernate Session
Session session = entityManager.unwrap(Session.class);
// 测试不同的JSON路径模式
String[] testCases = {
"SELECT json_value(jsonData, '$.property')",
"SELECT json_value(jsonData, '$.nested.object')",
"SELECT json_value(jsonData, '$.array[0].item')"
};
for (String hql : testCases) {
try {
// 尝试将HQL转换为SQL
String sql = session.createQuery(hql).getQueryString();
System.out.println("HQL: " + hql);
System.out.println("生成的SQL: " + sql);
// 验证是否包含json_extract_path_text函数
assertTrue(sql.contains("json_extract_path_text"),
"所有json_value函数调用都应该被转译为json_extract_path_text");
} catch (Exception e) {
// 打印异常但不失败因为某些复杂路径可能不被支持
System.out.println("处理HQL时出现警告: " + hql + " - " + e.getMessage());
}
}
}
}

View File

@ -0,0 +1,161 @@
package com.aisino.iles.core.service;
import com.aisino.iles.core.hibernate.RedissonLocalStorage;
import com.aisino.iles.core.hibernate.RedissonRegionFactoryPlus;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class CacheAdminServicePerformanceTest {
private static final int THREAD_COUNT = 10;
private static final int OPERATION_COUNT = 1000;
private static final String TEST_REGION = "performanceTest";
private static final String KEY_PREFIX = "key";
private static final String VALUE_PREFIX = "value";
@Mock
private RedissonRegionFactoryPlus regionFactory;
@Mock
private RedissonLocalStorage region;
@InjectMocks
private CacheAdminService cacheAdminService;
private ExecutorService executorService;
@BeforeEach
void setUp() {
when(regionFactory.getAllCacheRegions()).thenReturn(Map.of(TEST_REGION, region));
executorService = Executors.newFixedThreadPool(THREAD_COUNT);
}
@Test
void concurrentPutAndGetOperations_ShouldNotLoseData() {
// Arrange
AtomicInteger successCount = new AtomicInteger();
AtomicInteger failureCount = new AtomicInteger();
// Act - Perform concurrent put operations
var putFutures = IntStream.range(0, OPERATION_COUNT)
.mapToObj(i -> CompletableFuture.runAsync(() -> {
try {
String key = KEY_PREFIX + i;
String value = VALUE_PREFIX + i;
when(region.getFromCache(key, null)).thenReturn(value);
doNothing().when(region).putIntoCache(key, value, null);
boolean result = cacheAdminService.putCacheValue(TEST_REGION, key, value);
if (result) {
successCount.incrementAndGet();
} else {
failureCount.incrementAndGet();
}
} catch (Exception e) {
failureCount.incrementAndGet();
}
}, executorService))
.toArray(CompletableFuture[]::new);
// Wait for all operations to complete
CompletableFuture.allOf(putFutures).join();
// Verify all puts were successful
assertEquals(OPERATION_COUNT, successCount.get());
assertEquals(0, failureCount.get());
verify(region, times(OPERATION_COUNT)).putIntoCache(any(), any(), any());
// Reset counters for get operations
successCount.set(0);
failureCount.set(0);
// Perform concurrent get operations
var getFutures = IntStream.range(0, OPERATION_COUNT)
.mapToObj(i -> CompletableFuture.runAsync(() -> {
try {
String key = KEY_PREFIX + i;
String expectedValue = VALUE_PREFIX + i;
when(region.getFromCache(key, null)).thenReturn(expectedValue);
Object value = cacheAdminService.getCacheValue(TEST_REGION, key);
if (expectedValue.equals(value)) {
successCount.incrementAndGet();
} else {
failureCount.incrementAndGet();
}
} catch (Exception e) {
failureCount.incrementAndGet();
}
}, executorService))
.toArray(CompletableFuture[]::new);
// Wait for all get operations to complete
CompletableFuture.allOf(getFutures).join();
// Verify all gets were successful
assertEquals(OPERATION_COUNT, successCount.get());
assertEquals(0, failureCount.get());
}
@Test
void testCacheEvictionPerformance() {
// Arrange
int cacheSize = 1000;
int iterations = 10000;
// Warm up the cache
for (int i = 0; i < cacheSize; i++) {
String key = KEY_PREFIX + i;
String value = VALUE_PREFIX + i;
cacheAdminService.putCacheValue(TEST_REGION, key, value);
}
// Act - Perform cache operations under load
long startTime = System.currentTimeMillis();
IntStream.range(0, iterations).parallel().forEach(i -> {
String key = KEY_PREFIX + (i % cacheSize);
if (i % 10 == 0) {
// Every 10th operation is a put
String newValue = VALUE_PREFIX + (i % cacheSize) + "_updated";
cacheAdminService.putCacheValue(TEST_REGION, key, newValue);
} else if (i % 5 == 0) {
// Every 5th operation is a remove
cacheAdminService.removeCacheValue(TEST_REGION, key);
} else {
// Other operations are gets
cacheAdminService.getCacheValue(TEST_REGION, key);
}
});
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
// Assert - Verify performance metrics
double operationsPerSecond = (double) iterations / (totalTime / 1000.0);
System.out.printf("Performance Test Results:%n");
System.out.printf("Total operations: %d%n", iterations);
System.out.printf("Total time: %d ms%n", totalTime);
System.out.printf("Operations per second: %.2f%n", operationsPerSecond);
// Verify that the cache operations completed in a reasonable time
assertTrue(totalTime < 5000, "Cache operations took too long: " + totalTime + "ms");
}
}

View File

@ -0,0 +1,184 @@
package com.aisino.iles.core.service;
import com.aisino.iles.core.hibernate.RedissonLocalStorage;
import com.aisino.iles.core.hibernate.RedissonRegionFactoryPlus;
import jakarta.persistence.Cache;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.HashMap;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class CacheAdminServiceTest {
@Mock
private RedissonRegionFactoryPlus regionFactory;
@Mock
private EntityManager entityManager;
@Mock
private EntityManagerFactory entityManagerFactory;
@Mock
private Cache cache;
@InjectMocks
private CacheAdminService cacheAdminService;
private final String testRegion = "testRegion";
private final String testKey = "testKey";
private final String testValue = "testValue";
private final String entityName = "com.example.Entity";
private final Object entityId = 1L;
@BeforeEach
void setUp() {
when(entityManager.getEntityManagerFactory()).thenReturn(entityManagerFactory);
when(entityManagerFactory.getCache()).thenReturn(cache);
}
@Test
void getAllRegions_ShouldReturnAllRegions() {
// Arrange
Map<String, RedissonLocalStorage> expectedRegions = new HashMap<>();
expectedRegions.put("region1", mock(RedissonLocalStorage.class));
expectedRegions.put("region2", mock(RedissonLocalStorage.class));
when(regionFactory.getAllCacheRegions()).thenReturn(expectedRegions);
// Act
Map<String, RedissonLocalStorage> result = cacheAdminService.getAllRegions();
// Assert
assertNotNull(result);
assertEquals(2, result.size());
assertTrue(result.containsKey("region1"));
assertTrue(result.containsKey("region2"));
}
@Test
void getCacheValue_WhenRegionExists_ShouldReturnValue() {
// Arrange
RedissonLocalStorage region = mock(RedissonLocalStorage.class);
when(regionFactory.getAllCacheRegions()).thenReturn(Map.of(testRegion, region));
when(region.getFromCache(testKey, null)).thenReturn(testValue);
// Act
Object result = cacheAdminService.getCacheValue(testRegion, testKey);
// Assert
assertEquals(testValue, result);
}
@Test
void getCacheValue_WhenRegionNotExists_ShouldReturnNull() {
// Arrange
when(regionFactory.getAllCacheRegions()).thenReturn(new HashMap<>());
// Act
Object result = cacheAdminService.getCacheValue("nonExistentRegion", testKey);
// Assert
assertNull(result);
}
@Test
void putCacheValue_ShouldReturnTrueWhenSuccessful() {
// Arrange
RedissonLocalStorage region = mock(RedissonLocalStorage.class);
when(regionFactory.getAllCacheRegions()).thenReturn(Map.of(testRegion, region));
doNothing().when(region).putIntoCache(testKey, testValue, null);
// Act
boolean result = cacheAdminService.putCacheValue(testRegion, testKey, testValue);
// Assert
assertTrue(result);
verify(region).putIntoCache(testKey, testValue, null);
}
@Test
void removeCacheValue_ShouldReturnTrueWhenSuccessful() {
// Arrange
RedissonLocalStorage region = mock(RedissonLocalStorage.class);
when(regionFactory.getAllCacheRegions()).thenReturn(Map.of(testRegion, region));
doNothing().when(region).removeFromCache(testKey, null);
// Act
boolean result = cacheAdminService.removeCacheValue(testRegion, testKey);
// Assert
assertTrue(result);
verify(region).removeFromCache(testKey, null);
}
@Test
void removeCacheValueByEntityManager_ShouldEvictEntityCache() throws Exception {
// Arrange
Class<?> entityClass = Object.class;
when(entityManager.getEntityManagerFactory()).thenReturn(entityManagerFactory);
when(entityManagerFactory.getCache()).thenReturn(cache);
try (MockedStatic<Class> mocked = mockStatic(Class.class)) {
mocked.when(() -> Class.forName(entityName)).thenReturn(entityClass);
// Act
boolean result = cacheAdminService.removeCacheValueByEntityManager(entityName, entityId);
// Assert
assertTrue(result);
verify(cache).evict(entityClass, entityId);
}
}
@Test
void refreshLocalCache_ShouldCallGetFromCache() {
// Arrange
RedissonLocalStorage region = mock(RedissonLocalStorage.class);
when(regionFactory.getAllCacheRegions()).thenReturn(Map.of(testRegion, region));
// Act
cacheAdminService.refreshLocalCache(testRegion, testKey);
// Assert
verify(region).getFromCache(testKey, null);
}
@Test
void removeRegion_ShouldReturnTrueWhenSuccessful() {
// Arrange
RedissonLocalStorage region = mock(RedissonLocalStorage.class);
when(regionFactory.getAllCacheRegions()).thenReturn(Map.of(testRegion, region));
doNothing().when(region).clearCache(null);
// Act
boolean result = cacheAdminService.removeRegion(testRegion);
// Assert
assertTrue(result);
verify(region).clearCache(null);
}
@Test
void removeRegion_WhenExceptionOccurs_ShouldReturnFalse() {
// Arrange
RedissonLocalStorage region = mock(RedissonLocalStorage.class);
when(regionFactory.getAllCacheRegions()).thenReturn(Map.of(testRegion, region));
doThrow(new RuntimeException("Clear cache failed")).when(region).clearCache(null);
// Act
boolean result = cacheAdminService.removeRegion(testRegion);
// Assert
assertFalse(result);
}
}

View File

@ -0,0 +1,57 @@
package com.aisino.iles.lawenforcement.schedule.service;
import com.aisino.iles.lawenforcement.repository.OfficerRepository;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* OfficerScheduleService 的集成测试.
* <p>
* 注意: 这是一个集成测试它会真实地调用外部API并与数据库进行交互
* 在运行此测试之前请确保 application.yml 或相关 profile 中的配置
* ( third-party.person.*, sso.*, 数据库连接等) 是正确且可用的
* </p>
*/
@SpringBootTest(properties = {
"third-party.enterprise.idno=310000199308124725"
})
@ActiveProfiles("dev")
@DisplayName("执法人员信息同步服务集成测试")
class OfficerScheduleServiceTest {
@Autowired
private OfficerScheduleService officerScheduleService;
@Autowired
private OfficerRepository officerRepository;
@Test
@DisplayName("测试 scheduleTask 方法 - 完整同步流程")
void testScheduleTask() {
// GIVEN: 记录测试前的执法人员数量
long countBefore = officerRepository.count();
System.out.println("同步任务执行前,数据库中有 " + countBefore + " 名执法人员。");
// WHEN: 执行同步任务
// THEN: 断言它不会抛出异常
assertDoesNotThrow(() -> {
officerScheduleService.scheduleTask();
}, "执行执法人员同步任务时,不应抛出异常");
// AND: 记录测试后的执法人员数量
long countAfter = officerRepository.count();
System.out.println("同步任务执行后,数据库中有 " + countAfter + " 名执法人员。");
// AND: 断言任务执行后数据量可能增加或保持不变如果API没有新数据或数据已存在
assertTrue(countAfter >= countBefore, "同步后执法人员数量应大于或等于同步前");
System.out.println("执法人员同步任务测试成功。");
}
}

View File

@ -0,0 +1,113 @@
package com.aisino.iles.lawenforcement.service;
import com.aisino.iles.lawenforcement.model.dto.DjbZfajxxRequestDto;
import com.aisino.iles.lawenforcement.model.Agency;
import com.aisino.iles.lawenforcement.model.Case;
import com.aisino.iles.lawenforcement.model.EnforcementInfo;
import com.aisino.iles.lawenforcement.model.Enterprise;
import com.aisino.iles.lawenforcement.model.dto.EnforcementInfoDto;
import com.aisino.iles.lawenforcement.model.enums.FlowNode;
import com.aisino.iles.lawenforcement.repository.CaseRepository;
import com.aisino.iles.lawenforcement.repository.EnforcementInfoRepository;
import com.smartlx.sso.client.model.RemoteUserInfo;
import lombok.SneakyThrows;
import org.apache.commons.beanutils.BeanUtils;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* 执法信息单元测试
*/
@SpringBootTest
@ActiveProfiles("dev")
public class CaseServiceTest {
@Autowired
private CaseService caseService;
@Autowired
private CaseRepository caseRepository;
@Autowired
private EnforcementInfoRepository enforcementInfoRepository;
@Autowired
private EnforcementInfoService enforcementInfoService;
/**
* 测试保存执法案件信息
*/
@SneakyThrows
@Test
@DisplayName("测试保存执法案件信息")
@Transactional // 使用事务确保测试后数据回滚不影响数据库
public void testSaveLawEnforcementCase() {
// 创建测试所需的执法机构
Agency agency = new Agency();
agency.setAgencyId("1");
agency.setAgencyName("测试执法机构");
agency.setAgencyCode("TEST_AGENCY_CODE");
// 创建测试所需的企业
Enterprise enterprise = new Enterprise();
// enterprise.setEnterpriseId(UUID.randomUUID().toString());
enterprise.setUnitName("测试企业");
enterprise.setUnifiedSocialCode("TEST_UNIT_CODE");
// 创建执法信息
EnforcementInfo enforcementInfo = new EnforcementInfo();
// enforcementInfo.setEnforcementId(UUID.randomUUID().toString());
enforcementInfo.setAgency(agency);
enforcementInfo.setAgencyId(agency.getAgencyId());
enforcementInfo.setEnterprise(enterprise);
enforcementInfo.setCurrentNodeCode(FlowNode.filed);
enforcementInfo.setCreateTime(LocalDateTime.now());
EnforcementInfoDto enforcementInfoDto = new EnforcementInfoDto();
BeanUtils.copyProperties(enforcementInfoDto,enforcementInfo);
enforcementInfoDto.setEnterpriseIds(List.of("01jpebdtden62z6qw01e338zwm"));
// 保存执法信息
List<Object> objects = enforcementInfoService.saveEnforcementInfo(enforcementInfoDto, new RemoteUserInfo());
EnforcementInfo savedEnforcementInfo = (EnforcementInfo) objects.get(0);
// 创建案件信息
Case lawCase = new Case();
// lawCase.setCaseId(UUID.randomUUID().toString());
lawCase.setCaseName("测试执法案件");
lawCase.setCaseNum("TEST-CASE-" + System.currentTimeMillis());
lawCase.setFillingDate(LocalDate.now());
lawCase.setEnforcementInfo(enforcementInfo);
lawCase.setStatus(Case.CaseStatus.filed);
// 保存案件信息
Case savedCase = caseService.saveCase(lawCase);
// 断言保存成功
assertNotNull(savedCase);
assertNotNull(savedCase.getCaseId());
assertEquals("测试执法案件", savedCase.getCaseName());
assertNotNull(savedCase.getEnforcementInfo());
// assertEquals("测试执法机构", savedCase.getEnforcementInfo().getAgency().getAgencyName());
// assertEquals("测试企业", savedCase.getEnforcementInfo().getEnterprise().getUnitName());
// assertEquals(FlowNode.filed, savedCase.getEnforcementInfo().getCurrentNodeCode());
// 测试转换为DTO
DjbZfajxxRequestDto dto = new DjbZfajxxRequestDto();
DjbZfajxxRequestDto convertedDto = dto.convert(savedCase);
// 断言DTO转换成功
assertNotNull(convertedDto);
assertEquals(savedCase.getCaseId(), convertedDto.getCaseId());
assertEquals(savedCase.getCaseName(), convertedDto.getCaseName());
assertEquals(savedCase.getCaseNum(), convertedDto.getCaseNum());
}
}