Merge branch 'main' of http://192.168.65.198:3000/toolchaintechnologycenter/spdm-backend
This commit is contained in:
11
data/pom.xml
11
data/pom.xml
@@ -122,6 +122,17 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<exclusions>
|
||||
<!-- 排除mockito避免JDK17兼容性问题 -->
|
||||
<exclusion>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-junit-jupiter</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
|
||||
181
data/src/test/java/com/sdm/data/InteractiveTestRunner.java
Normal file
181
data/src/test/java/com/sdm/data/InteractiveTestRunner.java
Normal file
@@ -0,0 +1,181 @@
|
||||
package com.sdm.data;
|
||||
|
||||
import com.sdm.data.dao.MapperCompatibilityTest;
|
||||
import com.sdm.data.dao.PostgreSQLCompatibilityTest;
|
||||
import com.sdm.data.service.ServiceCrudTest;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 交互式测试运行器
|
||||
* 启动一次Spring容器后,可以反复执行不同的测试方法
|
||||
*
|
||||
* 使用方法:直接运行此类的main方法,然后在控制台输入测试方法编号
|
||||
*/
|
||||
public class InteractiveTestRunner {
|
||||
|
||||
private static ConfigurableApplicationContext context;
|
||||
private static final Map<String, TestMethodInfo> testMethods = new LinkedHashMap<>();
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println("========================================");
|
||||
System.out.println(" 交互式测试运行器 - 启动Spring容器");
|
||||
System.out.println("========================================");
|
||||
|
||||
// 启动Spring容器
|
||||
System.setProperty("spring.profiles.active", "test");
|
||||
context = SpringApplication.run(DataApplication.class, args);
|
||||
|
||||
System.out.println("\n✓ Spring容器启动成功!\n");
|
||||
|
||||
// 注册测试类和方法
|
||||
registerTestClass(MapperCompatibilityTest.class);
|
||||
registerTestClass(ServiceCrudTest.class);
|
||||
registerTestClass(PostgreSQLCompatibilityTest.class);
|
||||
|
||||
// 交互式运行
|
||||
runInteractively();
|
||||
}
|
||||
|
||||
private static void registerTestClass(Class<?> testClass) {
|
||||
for (Method method : testClass.getDeclaredMethods()) {
|
||||
if (method.isAnnotationPresent(org.junit.jupiter.api.Test.class)) {
|
||||
String key = testClass.getSimpleName() + "." + method.getName();
|
||||
testMethods.put(key, new TestMethodInfo(testClass, method));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void runInteractively() {
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
|
||||
while (true) {
|
||||
printMenu();
|
||||
System.out.print("\n请输入编号 (q退出, a运行全部): ");
|
||||
String input = scanner.nextLine().trim();
|
||||
|
||||
if ("q".equalsIgnoreCase(input)) {
|
||||
System.out.println("退出测试...");
|
||||
context.close();
|
||||
break;
|
||||
}
|
||||
|
||||
if ("a".equalsIgnoreCase(input)) {
|
||||
runAllTests();
|
||||
continue;
|
||||
}
|
||||
|
||||
if ("l".equalsIgnoreCase(input)) {
|
||||
continue; // 重新显示菜单
|
||||
}
|
||||
|
||||
try {
|
||||
int index = Integer.parseInt(input);
|
||||
runTestByIndex(index);
|
||||
} catch (NumberFormatException e) {
|
||||
// 尝试按方法名匹配
|
||||
runTestByName(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void printMenu() {
|
||||
System.out.println("\n========== 可用测试方法 ==========");
|
||||
int index = 1;
|
||||
String currentClass = "";
|
||||
for (Map.Entry<String, TestMethodInfo> entry : testMethods.entrySet()) {
|
||||
String className = entry.getValue().testClass.getSimpleName();
|
||||
if (!className.equals(currentClass)) {
|
||||
currentClass = className;
|
||||
System.out.println("\n【" + className + "】");
|
||||
}
|
||||
System.out.printf(" %3d. %s%n", index++, entry.getValue().method.getName());
|
||||
}
|
||||
System.out.println("\n==================================");
|
||||
System.out.println("命令: [编号]执行单个 | [a]执行全部 | [l]列表 | [q]退出");
|
||||
}
|
||||
|
||||
private static void runTestByIndex(int index) {
|
||||
if (index < 1 || index > testMethods.size()) {
|
||||
System.out.println("❌ 无效编号: " + index);
|
||||
return;
|
||||
}
|
||||
|
||||
int i = 1;
|
||||
for (TestMethodInfo info : testMethods.values()) {
|
||||
if (i++ == index) {
|
||||
runTest(info);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void runTestByName(String name) {
|
||||
for (Map.Entry<String, TestMethodInfo> entry : testMethods.entrySet()) {
|
||||
if (entry.getKey().contains(name) || entry.getValue().method.getName().contains(name)) {
|
||||
runTest(entry.getValue());
|
||||
return;
|
||||
}
|
||||
}
|
||||
System.out.println("❌ 未找到匹配的测试方法: " + name);
|
||||
}
|
||||
|
||||
private static void runTest(TestMethodInfo info) {
|
||||
System.out.println("\n▶ 运行: " + info.testClass.getSimpleName() + "." + info.method.getName());
|
||||
System.out.println("----------------------------------------");
|
||||
|
||||
try {
|
||||
// 从Spring容器获取测试实例
|
||||
Object testInstance = context.getBean(info.testClass);
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
info.method.invoke(testInstance);
|
||||
long duration = System.currentTimeMillis() - start;
|
||||
|
||||
System.out.println("----------------------------------------");
|
||||
System.out.printf("✓ 测试通过! (耗时: %dms)%n", duration);
|
||||
} catch (Exception e) {
|
||||
System.out.println("----------------------------------------");
|
||||
System.out.println("✗ 测试失败!");
|
||||
Throwable cause = e.getCause() != null ? e.getCause() : e;
|
||||
System.out.println("错误: " + cause.getMessage());
|
||||
cause.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void runAllTests() {
|
||||
System.out.println("\n▶ 运行全部测试...");
|
||||
int passed = 0, failed = 0;
|
||||
long totalStart = System.currentTimeMillis();
|
||||
|
||||
for (TestMethodInfo info : testMethods.values()) {
|
||||
System.out.print(" " + info.method.getName() + " ... ");
|
||||
try {
|
||||
Object testInstance = context.getBean(info.testClass);
|
||||
info.method.invoke(testInstance);
|
||||
System.out.println("✓");
|
||||
passed++;
|
||||
} catch (Exception e) {
|
||||
System.out.println("✗");
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
|
||||
long totalDuration = System.currentTimeMillis() - totalStart;
|
||||
System.out.println("\n========================================");
|
||||
System.out.printf("总计: %d 通过, %d 失败 (耗时: %dms)%n", passed, failed, totalDuration);
|
||||
}
|
||||
|
||||
private static class TestMethodInfo {
|
||||
Class<?> testClass;
|
||||
Method method;
|
||||
|
||||
TestMethodInfo(Class<?> testClass, Method method) {
|
||||
this.testClass = testClass;
|
||||
this.method = method;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,10 @@ import com.sdm.data.model.dto.UserTotalFileSizeDTO;
|
||||
import com.sdm.data.model.entity.*;
|
||||
import com.sdm.data.model.req.QueryBigFileReq;
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.junit.jupiter.api.TestInstance;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.test.annotation.Rollback;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -22,11 +24,13 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
* Mapper层兼容性测试 - MySQL转PostgreSQL验证
|
||||
* 覆盖所有Mapper接口的基础CRUD和自定义SQL方法
|
||||
*/
|
||||
@Component // 让测试类成为Spring Bean,支持交互式运行
|
||||
@SpringBootTest
|
||||
@ActiveProfiles("test")
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS) // 同一类所有测试方法共享实例,只启动一次容器
|
||||
@Transactional
|
||||
@Rollback(true) // 确保测试后回滚,不污染数据库
|
||||
@Rollback(true)
|
||||
public class MapperCompatibilityTest {
|
||||
|
||||
@Autowired
|
||||
@@ -89,7 +93,6 @@ public class MapperCompatibilityTest {
|
||||
entity.setFileSize(2048L);
|
||||
entity.setCreateTime(LocalDateTime.now());
|
||||
entity.setUpdateTime(LocalDateTime.now());
|
||||
entity.setCreateYearMonth("2026-01");
|
||||
|
||||
int insertResult = fileStorageMapper.insert(entity);
|
||||
assertEquals(1, insertResult);
|
||||
|
||||
@@ -6,8 +6,10 @@ import com.sdm.data.model.entity.FileMetadataInfo;
|
||||
import com.sdm.data.model.entity.FileStorage;
|
||||
import com.sdm.data.model.req.QueryBigFileReq;
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.junit.jupiter.api.TestInstance;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.test.annotation.Rollback;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -29,11 +31,13 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
* 4. Boolean字段处理
|
||||
* 5. 字段名大小写敏感性
|
||||
*/
|
||||
@Component // 让测试类成为Spring Bean,支持交互式运行
|
||||
@SpringBootTest
|
||||
@ActiveProfiles("test")
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS) // 同一类所有测试方法共享实例,只启动一次容器
|
||||
@Transactional
|
||||
@Rollback(true) // 确保测试后回滚,不污染数据库
|
||||
@Rollback(true)
|
||||
public class PostgreSQLCompatibilityTest {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -4,8 +4,10 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.sdm.data.model.entity.*;
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.junit.jupiter.api.TestInstance;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.test.annotation.Rollback;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -20,11 +22,13 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
* Service层CRUD测试 - MySQL转PostgreSQL验证
|
||||
* 覆盖所有Service的基础CRUD操作
|
||||
*/
|
||||
@Component // 让测试类成为Spring Bean,支持交互式运行
|
||||
@SpringBootTest
|
||||
@ActiveProfiles("test")
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS) // 同一类所有测试方法共享实例,只启动一次容器
|
||||
@Transactional
|
||||
@Rollback(true) // 确保测试后回滚,不污染数据库
|
||||
@Rollback(true)
|
||||
public class ServiceCrudTest {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -4,8 +4,8 @@ spring:
|
||||
datasource:
|
||||
username: spdm
|
||||
password: Spdm@2026
|
||||
jdbc-url: jdbc:postgresql://192.168.65.161:25432/spdm?currentSchema=public&stringtype=unspecified
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
jdbc-url: jdbc:postgresql://192.168.65.161:25432/spdm_baseline?currentSchema=public&stringtype=unspecified
|
||||
driver-class-name: org.postgresql.Driver
|
||||
hikari:
|
||||
# 设置连接池能够容纳的最大连接数。建议值:CPU核心数 * 2 + 有效磁盘I/O数。一个常见的经验值是 10-20。
|
||||
maximum-pool-size: 20
|
||||
@@ -20,8 +20,8 @@ spring:
|
||||
master:
|
||||
username: spdm
|
||||
password: Spdm@2026
|
||||
jdbc-url: jdbc:postgresql://192.168.65.161:25432/spdm?currentSchema=public&stringtype=unspecified
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
jdbc-url: jdbc:postgresql://192.168.65.161:25432/spdm_baseline?currentSchema=public&stringtype=unspecified
|
||||
driver-class-name: org.postgresql.Driver
|
||||
slave:
|
||||
username: root
|
||||
password: mysql
|
||||
|
||||
@@ -1767,6 +1767,9 @@ public class SimulationRunServiceImpl extends ServiceImpl<SimulationRunMapper, S
|
||||
// 传了新的图片文件
|
||||
if (ObjectUtils.isNotEmpty(req.getAddImageInfo())) {
|
||||
req.getAddFileInfoList().add(req.getAddImageInfo());
|
||||
if (ObjectUtils.isNotEmpty(experimentResult.getImageId())) {
|
||||
deleteFileIds.add(experimentResult.getImageId());
|
||||
}
|
||||
}
|
||||
if (CollectionUtils.size(req.getAddFileInfoList()) > 0 || CollectionUtils.size(req.getDeleteFileIds()) > 0 || ObjectUtils.isNotEmpty(req.getDeleteImageId())) {
|
||||
SdmResponse<List<BatchAddFileInfoResp>> batchAddResponse = SdmResponse.success();
|
||||
@@ -1783,6 +1786,23 @@ public class SimulationRunServiceImpl extends ServiceImpl<SimulationRunMapper, S
|
||||
oldFileIds.removeIf(deleteSet::contains);
|
||||
deleteFileIds.addAll(req.getDeleteFileIds());
|
||||
}
|
||||
// 如果只删除试验截图 没有上传新的截图
|
||||
if (ObjectUtils.isNotEmpty(req.getDeleteImageId())) {
|
||||
experimentResult.setImageId(null);
|
||||
deleteFileIds.add(req.getDeleteImageId());
|
||||
}
|
||||
// 删除文件
|
||||
if (CollectionUtils.isNotEmpty(deleteFileIds)) {
|
||||
for (Long deleteFileId : deleteFileIds) {
|
||||
DelFileReq delFileReq = new DelFileReq();
|
||||
delFileReq.setDelFileId(deleteFileId);
|
||||
SdmResponse response = dataFeignClient.delFile(delFileReq);
|
||||
if (!response.isSuccess()) {
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 再处理新增的文件
|
||||
if (CollectionUtils.size(req.getAddFileInfoList()) > 0) {
|
||||
UploadFilesReq filesReq = new UploadFilesReq();
|
||||
@@ -1798,7 +1818,6 @@ public class SimulationRunServiceImpl extends ServiceImpl<SimulationRunMapper, S
|
||||
// 传了新的图片文件 默认删除以前的
|
||||
if (ObjectUtils.isNotEmpty(req.getAddImageInfo())) {
|
||||
batchAddFileInfoResps.stream().filter(i -> StringUtils.equals(i.getSourceFileName(), req.getAddImageInfo().getFileName())).findFirst().ifPresent(i -> {
|
||||
deleteFileIds.add(experimentResult.getImageId());
|
||||
experimentResult.setImageId(i.getBusinessId());
|
||||
});
|
||||
}
|
||||
@@ -1807,26 +1826,11 @@ public class SimulationRunServiceImpl extends ServiceImpl<SimulationRunMapper, S
|
||||
// 加上新增的附件文件
|
||||
oldFileIds.addAll(addFileIds);
|
||||
}
|
||||
// 如果只删除试验截图 没有上传新的截图
|
||||
if (ObjectUtils.isNotEmpty(req.getDeleteImageId())) {
|
||||
experimentResult.setImageId(null);
|
||||
deleteFileIds.add(req.getDeleteImageId());
|
||||
}
|
||||
|
||||
String fileIds = oldFileIds.stream().map(String::valueOf).collect(Collectors.joining(","));
|
||||
experimentResult.setFileId(fileIds);
|
||||
simulationExpResultService.updateById(experimentResult);
|
||||
// 删除文件
|
||||
if (CollectionUtils.isNotEmpty(deleteFileIds)) {
|
||||
for (Long deleteFileId : deleteFileIds) {
|
||||
DelFileReq delFileReq = new DelFileReq();
|
||||
delFileReq.setDelFileId(deleteFileId);
|
||||
SdmResponse response = dataFeignClient.delFile(delFileReq);
|
||||
if (!response.isSuccess()) {
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return batchAddResponse;
|
||||
}
|
||||
simulationExpResultService.updateById(experimentResult);
|
||||
|
||||
Reference in New Issue
Block a user