PG数据库切换测试用例验证

This commit is contained in:
2026-01-19 14:06:34 +08:00
parent da5648e753
commit ef70728ba0
6 changed files with 1415 additions and 0 deletions

View File

@@ -0,0 +1,60 @@
-- 1. 创建表结构
CREATE TABLE "file_storage" (
-- [兼容模式] 支持 AUTO_INCREMENT
"id" BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
"fileName" VARCHAR(255) NOT NULL DEFAULT '',
"fileId" BIGINT NOT NULL,
"userGroupId" BIGINT DEFAULT NULL,
"tenantId" BIGINT DEFAULT NULL,
"userId" BIGINT DEFAULT NULL,
"dirId" BIGINT NOT NULL,
"fileBizType" INTEGER DEFAULT NULL,
"fileSuffix" VARCHAR(50) NOT NULL DEFAULT '',
-- [兼容模式] 去掉 UNSIGNED使用 BIGINT (范围足够覆盖)
"fileSize" BIGINT NOT NULL,
-- [兼容模式] 支持 DATETIME 类型
"createTime" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
-- [兼容模式] 支持 ON UPDATE 语法,无需触发器实现自动更新
"updateTime" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
"fullPath" VARCHAR(1024) NOT NULL DEFAULT '',
-- [修复核心报错]
-- 将 date_format 替换为标准的提取拼接逻辑,确保是 IMMUTABLE (不可变) 表达式
"createYearMonth" VARCHAR(7) GENERATED ALWAYS AS (
CAST(EXTRACT(YEAR FROM "createTime") AS VARCHAR) || '-' ||
LPAD(CAST(EXTRACT(MONTH FROM "createTime") AS VARCHAR), 2, '0')
) STORED
);
-- 2. 创建索引
CREATE INDEX "idx_dirid_size" ON "file_storage" ("dirId", "fileSize");
CREATE INDEX "idx_userid_size" ON "file_storage" ("userId", "fileSize");
CREATE INDEX "idx_dirid_createtime_size" ON "file_storage" ("dirId", "createTime", "fileSize");
CREATE INDEX "idx_userid_createtime_size" ON "file_storage" ("userId", "createTime", "fileSize");
CREATE INDEX "idx_dirid_createmonth_size" ON "file_storage" ("dirId", "createYearMonth", "fileSize");
CREATE INDEX "idx_userid_createmonth_size" ON "file_storage" ("userId", "createYearMonth", "fileSize");
CREATE INDEX "idx_dir_file_suffix_biz_createtime_size" ON "file_storage" ("dirId", "fileName", "fileSuffix", "fileBizType", "createTime", "fileSize");
CREATE INDEX "idx_filename" ON "file_storage" ("fileName");
-- 3. 添加字段注释
COMMENT ON TABLE "file_storage" IS '文件存储统计主表(支持项目/学科/用户维度的存储占用统计)';
COMMENT ON COLUMN "file_storage"."id" IS '主键ID自增';
COMMENT ON COLUMN "file_storage"."fileName" IS '文件名(含后缀)';
COMMENT ON COLUMN "file_storage"."fileId" IS '文件唯一标识ID关联文件元数据表';
COMMENT ON COLUMN "file_storage"."userGroupId" IS '用户组ID';
COMMENT ON COLUMN "file_storage"."tenantId" IS '租户ID';
COMMENT ON COLUMN "file_storage"."userId" IS '文件所属用户ID';
COMMENT ON COLUMN "file_storage"."dirId" IS '保存所有父目录ID项目/学科等目录的唯一标识)';
COMMENT ON COLUMN "file_storage"."fileBizType" IS '文件业务类型1模型文件 2仿真报告、3计算文件、4曲线文件、5云图文件6网格文件7计算过程文件';
COMMENT ON COLUMN "file_storage"."fileSuffix" IS '文件后缀如txt、jpg、pdf';
COMMENT ON COLUMN "file_storage"."fileSize" IS '文件大小(字节数,存储占用计算依据)';
COMMENT ON COLUMN "file_storage"."createTime" IS '文件创建时间';
COMMENT ON COLUMN "file_storage"."updateTime" IS '记录更新时间(自动更新)';
COMMENT ON COLUMN "file_storage"."fullPath" IS '文件完整路径(冗余字段,优化查询)';
COMMENT ON COLUMN "file_storage"."createYearMonth" IS '创建年月(自动生成)';

View File

@@ -118,6 +118,18 @@
<version>${org.mapstruct.version}</version>
</dependency>
<!-- Test Dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>

View File

@@ -0,0 +1,447 @@
package com.sdm.data.dao;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sdm.data.model.dto.NodeSizeDTO;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* Mapper层兼容性测试 - MySQL转PostgreSQL验证
* 覆盖所有Mapper接口的基础CRUD和自定义SQL方法
*/
@SpringBootTest
@ActiveProfiles("test")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@Transactional
@Rollback(true) // 确保测试后回滚,不污染数据库
public class MapperCompatibilityTest {
@Autowired
private FileStorageMapper fileStorageMapper;
@Autowired
private FileMetadataInfoMapper fileMetadataInfoMapper;
@Autowired
private DimensionTemplateMapper dimensionTemplateMapper;
@Autowired
private DimensionTemplateHierarchyMapper dimensionTemplateHierarchyMapper;
@Autowired
private FileStorageQuotaMapper fileStorageQuotaMapper;
@Autowired
private SimulationParameterLibraryMapper simulationParameterLibraryMapper;
@Autowired
private SimulationParameterLibraryCategoryMapper simulationParameterLibraryCategoryMapper;
@Autowired
private SimulationParameterLibraryCategoryObjectMapper simulationParameterLibraryCategoryObjectMapper;
@Autowired
private TrainingModelMapper trainingModelMapper;
@Autowired
private TrainingModelAlgorithmParamMapper trainingModelAlgorithmParamMapper;
@Autowired
private FileMetadataExtensionMapper fileMetadataExtensionMapper;
@Autowired
private FilePermissionDictMapper filePermissionDictMapper;
@Autowired
private FileUserPermissionMapper fileUserPermissionMapper;
@Autowired
private FileSimulationMappingMapper fileSimulationMappingMapper;
// ==================== FileStorageMapper Tests ====================
@Test
@Order(1)
@DisplayName("FileStorageMapper - 基础CRUD测试")
void testFileStorageMapperCRUD() {
// INSERT
FileStorage entity = new FileStorage();
entity.setFileName("mapper_test.txt");
entity.setFileId(100L);
entity.setTenantId(1L);
entity.setUserId(1L);
entity.setDirId(1L);
entity.setFileSuffix("txt");
entity.setFileBizType(1);
entity.setFileSize(2048L);
entity.setCreateTime(LocalDateTime.now());
entity.setUpdateTime(LocalDateTime.now());
entity.setCreateYearMonth("2026-01");
int insertResult = fileStorageMapper.insert(entity);
assertEquals(1, insertResult);
assertNotNull(entity.getId());
// SELECT BY ID
FileStorage selected = fileStorageMapper.selectById(entity.getId());
assertNotNull(selected);
assertEquals("mapper_test.txt", selected.getFileName());
// UPDATE
selected.setFileName("mapper_test_updated.txt");
selected.setFileSize(4096L);
int updateResult = fileStorageMapper.updateById(selected);
assertEquals(1, updateResult);
// VERIFY UPDATE
FileStorage updated = fileStorageMapper.selectById(entity.getId());
assertEquals("mapper_test_updated.txt", updated.getFileName());
assertEquals(4096L, updated.getFileSize());
// DELETE
int deleteResult = fileStorageMapper.deleteById(entity.getId());
assertEquals(1, deleteResult);
// VERIFY DELETE
FileStorage deleted = fileStorageMapper.selectById(entity.getId());
assertNull(deleted);
}
@Test
@Order(2)
@DisplayName("FileStorageMapper - selectNodeSizeByNodeType自定义SQL测试")
void testFileStorageMapperSelectNodeSizeByNodeType() {
List<NodeSizeDTO> result = fileStorageMapper.selectNodeSizeByNodeType(
Arrays.asList(1L, 2L, 3L),
3,
1L
);
assertNotNull(result);
// 验证SQL执行不报错结果可能为空但不应该抛异常
}
@Test
@Order(3)
@DisplayName("FileStorageMapper - statDirStorageByTargetYm自定义SQL测试")
void testFileStorageMapperStatDirStorageByTargetYm() {
List<NodeSizeDTO> result = fileStorageMapper.statDirStorageByTargetYm(
Arrays.asList(1L, 2L),
"2026-01",
1L
);
assertNotNull(result);
}
@Test
@Order(4)
@DisplayName("FileStorageMapper - getTotalFileSizeByCreator自定义SQL测试")
void testFileStorageMapperGetTotalFileSizeByCreator() {
List<UserTotalFileSizeDTO> result = fileStorageMapper.getTotalFileSizeByCreator(
Arrays.asList(1L),
6,
1L
);
assertNotNull(result);
}
@Test
@Order(5)
@DisplayName("FileStorageMapper - getTotalFileSizeByCreatorAndTargetYm自定义SQL测试")
void testFileStorageMapperGetTotalFileSizeByCreatorAndTargetYm() {
List<UserTotalFileSizeDTO> result = fileStorageMapper.getTotalFileSizeByCreatorAndTargetYm(
Arrays.asList(1L),
"2026-01",
1L
);
assertNotNull(result);
}
@Test
@Order(6)
@DisplayName("FileStorageMapper - selectBigFiles自定义SQL测试")
void testFileStorageMapperSelectBigFiles() {
QueryBigFileReq req = new QueryBigFileReq();
req.setIsLatest(true);
req.setDirIds(Arrays.asList(1L));
List<FileStorage> result = fileStorageMapper.selectBigFiles(req, 1000L, 1L);
assertNotNull(result);
}
// ==================== FileMetadataInfoMapper Tests ====================
@Test
@Order(10)
@DisplayName("FileMetadataInfoMapper - 基础CRUD测试")
void testFileMetadataInfoMapperCRUD() {
// INSERT
FileMetadataInfo entity = new FileMetadataInfo();
entity.setRelatedResourceUuid("test-uuid-mapper");
entity.setRelatedResourceUuidOwnType("node");
entity.setOriginalName("mapper_metadata.txt");
entity.setDataType(2);
entity.setIsLatest(true);
entity.setTenantId(1L);
entity.setCreatorId(1L);
entity.setCreateTime(LocalDateTime.now());
entity.setUpdateTime(LocalDateTime.now());
int insertResult = fileMetadataInfoMapper.insert(entity);
assertEquals(1, insertResult);
assertNotNull(entity.getId());
// SELECT
FileMetadataInfo selected = fileMetadataInfoMapper.selectById(entity.getId());
assertNotNull(selected);
assertEquals("mapper_metadata.txt", selected.getOriginalName());
// UPDATE
selected.setOriginalName("mapper_metadata_updated.txt");
fileMetadataInfoMapper.updateById(selected);
// DELETE
fileMetadataInfoMapper.deleteById(entity.getId());
}
@Test
@Order(11)
@DisplayName("FileMetadataInfoMapper - listSimulationNodeDir自定义SQL测试")
void testFileMetadataInfoMapperListSimulationNodeDir() {
List<FileMetadataInfo> result = fileMetadataInfoMapper.listSimulationNodeDir(
Arrays.asList(1L, 2L),
false,
1L
);
assertNotNull(result);
}
@Test
@Order(12)
@DisplayName("FileMetadataInfoMapper - listSimulationNodeFiles自定义SQL测试")
void testFileMetadataInfoMapperListSimulationNodeFiles() {
List<FileMetadataInfo> result = fileMetadataInfoMapper.listSimulationNodeFiles(
Arrays.asList(1L),
Arrays.asList(1L),
false,
1L
);
assertNotNull(result);
}
// ==================== DimensionTemplateMapper Tests ====================
@Test
@Order(20)
@DisplayName("DimensionTemplateMapper - 基础CRUD测试")
void testDimensionTemplateMapperCRUD() {
// INSERT
DimensionTemplate entity = new DimensionTemplate();
entity.setTemplateName("Mapper测试模板");
entity.setTemplateType(1);
entity.setDescription("用于Mapper测试");
entity.setTenantId(1L);
entity.setCreatedBy(1L);
entity.setCreatedAt(LocalDateTime.now());
int insertResult = dimensionTemplateMapper.insert(entity);
assertEquals(1, insertResult);
// SELECT
DimensionTemplate selected = dimensionTemplateMapper.selectById(entity.getId());
assertNotNull(selected);
assertEquals("Mapper测试模板", selected.getTemplateName());
// UPDATE & DELETE
selected.setTemplateName("Mapper测试模板_更新");
dimensionTemplateMapper.updateById(selected);
dimensionTemplateMapper.deleteById(entity.getId());
}
// ==================== FileStorageQuotaMapper Tests ====================
@Test
@Order(30)
@DisplayName("FileStorageQuotaMapper - 基础CRUD测试")
void testFileStorageQuotaMapperCRUD() {
// INSERT
FileStorageQuota entity = new FileStorageQuota();
entity.setUserId(100L);
entity.setTenantId(1L);
entity.setQuotaValue(5368709120L); // 5GB
entity.setQuotaUnit("GB");
entity.setUsedValue(0L);
entity.setStatus("NORMAL");
int insertResult = fileStorageQuotaMapper.insert(entity);
assertEquals(1, insertResult);
// SELECT
FileStorageQuota selected = fileStorageQuotaMapper.selectById(entity.getId());
assertNotNull(selected);
assertEquals("GB", selected.getQuotaUnit());
// UPDATE & DELETE
selected.setStatus("WARNING");
fileStorageQuotaMapper.updateById(selected);
fileStorageQuotaMapper.deleteById(entity.getId());
}
// ==================== SimulationParameterLibraryMapper Tests ====================
@Test
@Order(40)
@DisplayName("SimulationParameterLibraryMapper - 基础CRUD测试")
void testSimulationParameterLibraryMapperCRUD() {
// INSERT
SimulationParameterLibrary entity = new SimulationParameterLibrary();
entity.setParameterLibraryName("Mapper测试参数库");
entity.setTenantId(1L);
entity.setCreatorId(1L);
entity.setCreateTime(LocalDateTime.now());
int insertResult = simulationParameterLibraryMapper.insert(entity);
assertEquals(1, insertResult);
// SELECT
SimulationParameterLibrary selected = simulationParameterLibraryMapper.selectById(entity.getId());
assertNotNull(selected);
// DELETE
simulationParameterLibraryMapper.deleteById(entity.getId());
}
// ==================== TrainingModelMapper Tests ====================
@Test
@Order(50)
@DisplayName("TrainingModelMapper - 基础CRUD测试")
void testTrainingModelMapperCRUD() {
// INSERT
TrainingModel entity = new TrainingModel();
entity.setModelName("Mapper测试模型");
entity.setAlgorithmType("SVM");
entity.setTrainer("tester");
entity.setHandleStatus("待开始");
entity.setTrainingStatus("待开始");
entity.setPredStatus("待开始");
entity.setTenantId(1L);
entity.setCreator(1L);
entity.setCreateTime(LocalDateTime.now());
int insertResult = trainingModelMapper.insert(entity);
assertEquals(1, insertResult);
// SELECT
TrainingModel selected = trainingModelMapper.selectById(entity.getId());
assertNotNull(selected);
assertEquals("Mapper测试模型", selected.getModelName());
// UPDATE & DELETE
selected.setModelName("Mapper测试模型_更新");
trainingModelMapper.updateById(selected);
trainingModelMapper.deleteById(entity.getId());
}
// ==================== 条件查询测试 ====================
@Test
@Order(60)
@DisplayName("LambdaQueryWrapper条件查询测试")
void testLambdaQueryWrapper() {
// 测试MyBatis-Plus的LambdaQueryWrapper在PostgreSQL下的兼容性
LambdaQueryWrapper<FileStorage> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(FileStorage::getTenantId, 1L)
.like(FileStorage::getFileName, "test")
.orderByDesc(FileStorage::getCreateTime);
List<FileStorage> result = fileStorageMapper.selectList(wrapper);
assertNotNull(result);
}
@Test
@Order(61)
@DisplayName("批量查询测试")
void testBatchSelect() {
List<FileStorage> result = fileStorageMapper.selectBatchIds(Arrays.asList(1L, 2L, 3L));
assertNotNull(result);
}
// ==================== 其他Mapper基础测试 ====================
@Test
@Order(70)
@DisplayName("FileMetadataExtensionMapper - 基础测试")
void testFileMetadataExtensionMapper() {
List<FileMetadataExtension> result = fileMetadataExtensionMapper.selectList(null);
assertNotNull(result);
}
@Test
@Order(71)
@DisplayName("FilePermissionDictMapper - 基础测试")
void testFilePermissionDictMapper() {
List<FilePermissionDict> result = filePermissionDictMapper.selectList(null);
assertNotNull(result);
}
@Test
@Order(72)
@DisplayName("FileUserPermissionMapper - 基础测试")
void testFileUserPermissionMapper() {
List<FileUserPermission> result = fileUserPermissionMapper.selectList(null);
assertNotNull(result);
}
@Test
@Order(73)
@DisplayName("FileSimulationMappingMapper - 基础测试")
void testFileSimulationMappingMapper() {
List<FileSimulationMapping> result = fileSimulationMappingMapper.selectList(null);
assertNotNull(result);
}
@Test
@Order(74)
@DisplayName("DimensionTemplateHierarchyMapper - 基础测试")
void testDimensionTemplateHierarchyMapper() {
List<DimensionTemplateHierarchy> result = dimensionTemplateHierarchyMapper.selectList(null);
assertNotNull(result);
}
@Test
@Order(75)
@DisplayName("SimulationParameterLibraryCategoryMapper - 基础测试")
void testSimulationParameterLibraryCategoryMapper() {
List<SimulationParameterLibraryCategory> result = simulationParameterLibraryCategoryMapper.selectList(null);
assertNotNull(result);
}
@Test
@Order(76)
@DisplayName("SimulationParameterLibraryCategoryObjectMapper - 基础测试")
void testSimulationParameterLibraryCategoryObjectMapper() {
List<SimulationParameterLibraryCategoryObject> result = simulationParameterLibraryCategoryObjectMapper.selectList(null);
assertNotNull(result);
}
@Test
@Order(77)
@DisplayName("TrainingModelAlgorithmParamMapper - 基础测试")
void testTrainingModelAlgorithmParamMapper() {
List<TrainingModelAlgorithmParam> result = trainingModelAlgorithmParamMapper.selectList(null);
assertNotNull(result);
}
}

View File

@@ -0,0 +1,351 @@
package com.sdm.data.dao;
import com.sdm.data.model.dto.NodeSizeDTO;
import com.sdm.data.model.dto.UserTotalFileSizeDTO;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* PostgreSQL SQL语法兼容性专项测试
*
* 重点验证以下MySQL到PostgreSQL的语法差异
* 1. DATE_SUB函数 -> PostgreSQL的INTERVAL语法
* 2. LIMIT在UNION中的使用
* 3. CONCAT函数
* 4. Boolean字段处理
* 5. 字段名大小写敏感性
*/
@SpringBootTest
@ActiveProfiles("test")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@Transactional
@Rollback(true) // 确保测试后回滚,不污染数据库
public class PostgreSQLCompatibilityTest {
@Autowired
private FileStorageMapper fileStorageMapper;
@Autowired
private FileMetadataInfoMapper fileMetadataInfoMapper;
// ==================== DATE_SUB/INTERVAL 语法测试 ====================
@Test
@Order(1)
@DisplayName("测试时间间隔查询 - selectNodeSizeByNodeType (MySQL: DATE_SUB)")
void testDateIntervalQuery() {
// 准备测试数据
FileStorage entity = createTestFileStorage("interval_test.txt");
entity.setCreateTime(LocalDateTime.now().minusMonths(1)); // 1个月前
fileStorageMapper.insert(entity);
// 测试3个月内的数据查询
List<NodeSizeDTO> result = fileStorageMapper.selectNodeSizeByNodeType(
Arrays.asList(entity.getDirId()),
3, // 3个月
1L
);
assertNotNull(result);
// 验证能够查询到1个月前的数据
}
@Test
@Order(2)
@DisplayName("测试时间间隔查询 - getTotalFileSizeByCreator (MySQL: DATE_SUB)")
void testDateIntervalQueryForUser() {
// 测试用户文件大小统计的时间间隔查询
List<UserTotalFileSizeDTO> result = fileStorageMapper.getTotalFileSizeByCreator(
Arrays.asList(1L),
6, // 6个月
1L
);
assertNotNull(result);
}
// ==================== UNION ALL + LIMIT 语法测试 ====================
@Test
@Order(10)
@DisplayName("测试UNION ALL查询 - statDirStorageByTargetYm")
void testUnionAllQuery() {
// 准备不同月份的测试数据
FileStorage entity1 = createTestFileStorage("union_test_1.txt");
entity1.setCreateYearMonth("2026-01");
fileStorageMapper.insert(entity1);
FileStorage entity2 = createTestFileStorage("union_test_2.txt");
entity2.setCreateYearMonth("2025-12");
fileStorageMapper.insert(entity2);
// 测试UNION ALL查询历史累计 + 当月增量)
List<NodeSizeDTO> result = fileStorageMapper.statDirStorageByTargetYm(
Arrays.asList(entity1.getDirId()),
"2026-01",
1L
);
assertNotNull(result);
// 应该返回BEFORE和INCREMENT两种类型的统计
}
@Test
@Order(11)
@DisplayName("测试带LIMIT的UNION查询 - getTotalFileSizeByCreatorAndTargetYm (CTE)")
void testUnionWithLimitAndCTE() {
// 测试使用CTE(WITH)的复杂查询
List<UserTotalFileSizeDTO> result = fileStorageMapper.getTotalFileSizeByCreatorAndTargetYm(
null, // 不传userIds测试LIMIT 10的分支
"2026-01",
1L
);
assertNotNull(result);
}
@Test
@Order(12)
@DisplayName("测试带LIMIT的查询 - getdefaultNodeNameByNodeSize")
void testLimitQuery() {
List<String> result = fileStorageMapper.getdefaultNodeNameByNodeSize(
"node",
5 // LIMIT 5
);
assertNotNull(result);
assertTrue(result.size() <= 5);
}
// ==================== CONCAT 函数测试 ====================
@Test
@Order(20)
@DisplayName("测试CONCAT函数 - selectBigFiles的LIKE查询")
void testConcatInLikeQuery() {
// 准备测试数据
FileStorage fileStorage = createTestFileStorage("concat_test_file.txt");
fileStorageMapper.insert(fileStorage);
FileMetadataInfo metadata = new FileMetadataInfo();
metadata.setId(fileStorage.getFileId());
metadata.setOriginalName("concat_test_file.txt");
metadata.setIsLatest(true);
metadata.setTenantId(1L);
metadata.setDataType(2);
metadata.setApproveType(0);
metadata.setCreateTime(LocalDateTime.now());
metadata.setUpdateTime(LocalDateTime.now());
fileMetadataInfoMapper.insert(metadata);
// 测试CONCAT在LIKE中的使用
QueryBigFileReq req = new QueryBigFileReq();
req.setIsLatest(true);
req.setFileName("concat"); // 模糊匹配
List<FileStorage> result = fileStorageMapper.selectBigFiles(req, 0L, 1L);
assertNotNull(result);
}
// ==================== Boolean 字段测试 ====================
@Test
@Order(30)
@DisplayName("测试Boolean字段 - isLatest = true")
void testBooleanField() {
// 测试PostgreSQL的Boolean类型处理
FileMetadataInfo entityTrue = new FileMetadataInfo();
entityTrue.setOriginalName("boolean_true.txt");
entityTrue.setIsLatest(true);
entityTrue.setIsRoot(false);
entityTrue.setTenantId(1L);
entityTrue.setDataType(2);
entityTrue.setCreateTime(LocalDateTime.now());
entityTrue.setUpdateTime(LocalDateTime.now());
fileMetadataInfoMapper.insert(entityTrue);
FileMetadataInfo entityFalse = new FileMetadataInfo();
entityFalse.setOriginalName("boolean_false.txt");
entityFalse.setIsLatest(false);
entityFalse.setIsRoot(true);
entityFalse.setTenantId(1L);
entityFalse.setDataType(2);
entityFalse.setCreateTime(LocalDateTime.now());
entityFalse.setUpdateTime(LocalDateTime.now());
fileMetadataInfoMapper.insert(entityFalse);
// 测试listSimulationNodeFiles中的 isLatest = true
List<FileMetadataInfo> result = fileMetadataInfoMapper.listSimulationNodeFiles(
Arrays.asList(entityTrue.getParentId() != null ? entityTrue.getParentId() : 0L),
Collections.emptyList(),
false,
1L
);
assertNotNull(result);
}
// ==================== 字段名大小写敏感性测试 ====================
@Test
@Order(40)
@DisplayName("测试驼峰字段名映射 - fileName/fileSize等")
void testCamelCaseFieldMapping() {
FileStorage entity = new FileStorage();
entity.setFileName("camelCase_test.txt");
entity.setFileId(System.currentTimeMillis());
entity.setFileSize(2048L);
entity.setFileBizType(1);
entity.setFileSuffix("txt");
entity.setTenantId(1L);
entity.setUserId(1L);
entity.setDirId(1L);
entity.setCreateYearMonth("2026-01");
entity.setCreateTime(LocalDateTime.now());
entity.setUpdateTime(LocalDateTime.now());
entity.setFullPath("/test/camelCase_test.txt");
// 插入
int insertResult = fileStorageMapper.insert(entity);
assertEquals(1, insertResult);
// 查询并验证所有驼峰命名字段
FileStorage selected = fileStorageMapper.selectById(entity.getId());
assertNotNull(selected);
assertEquals("camelCase_test.txt", selected.getFileName());
assertEquals(2048L, selected.getFileSize());
assertEquals(1, selected.getFileBizType());
assertEquals("txt", selected.getFileSuffix());
assertEquals("2026-01", selected.getCreateYearMonth());
assertEquals("/test/camelCase_test.txt", selected.getFullPath());
}
// ==================== NULL值处理测试 ====================
@Test
@Order(50)
@DisplayName("测试NULL值条件查询")
void testNullConditionQuery() {
// 测试IS NULL查询
List<FileMetadataInfo> result = fileMetadataInfoMapper.listSimulationNodeDir(
Arrays.asList(1L),
false, // 不过滤空数据
1L
);
assertNotNull(result);
}
// ==================== 空集合参数测试 ====================
@Test
@Order(60)
@DisplayName("测试空集合参数处理")
void testEmptyCollectionParameter() {
// 测试传入空列表时的处理
List<UserTotalFileSizeDTO> result = fileStorageMapper.getTotalFileSizeByCreator(
Collections.emptyList(), // 空列表
6,
1L
);
assertNotNull(result);
// 应该返回前10个用户根据SQL逻辑
}
// ==================== ORDER BY 测试 ====================
@Test
@Order(70)
@DisplayName("测试ORDER BY子句")
void testOrderByClause() {
// 准备多条测试数据
for (int i = 1; i <= 3; i++) {
FileStorage entity = createTestFileStorage("order_test_" + i + ".txt");
entity.setFileSize(i * 1000L);
entity.setUpdateTime(LocalDateTime.now().minusHours(i));
fileStorageMapper.insert(entity);
}
// 测试selectBigFiles中的ORDER BY updateTime DESC
QueryBigFileReq req = new QueryBigFileReq();
req.setIsLatest(true);
req.setFileName("order_test");
List<FileStorage> result = fileStorageMapper.selectBigFiles(req, 0L, 1L);
assertNotNull(result);
// 验证是否按updateTime降序排列
if (result.size() >= 2) {
assertTrue(
result.get(0).getUpdateTime().isAfter(result.get(1).getUpdateTime()) ||
result.get(0).getUpdateTime().isEqual(result.get(1).getUpdateTime())
);
}
}
// ==================== 聚合函数测试 ====================
@Test
@Order(80)
@DisplayName("测试SUM聚合函数")
void testSumAggregation() {
// 准备测试数据
Long testDirId = 99999L;
FileStorage entity1 = createTestFileStorage("sum_test_1.txt");
entity1.setDirId(testDirId);
entity1.setFileSize(1000L);
fileStorageMapper.insert(entity1);
FileStorage entity2 = createTestFileStorage("sum_test_2.txt");
entity2.setDirId(testDirId);
entity2.setFileSize(2000L);
fileStorageMapper.insert(entity2);
// 测试SUM聚合
List<NodeSizeDTO> result = fileStorageMapper.selectNodeSizeByNodeType(
Arrays.asList(testDirId),
12,
1L
);
assertNotNull(result);
if (!result.isEmpty()) {
// 验证总大小 = 1000 + 2000 = 3000
assertEquals(3000L, result.get(0).getTotalSize());
}
}
// ==================== Helper Methods ====================
private FileStorage createTestFileStorage(String fileName) {
FileStorage entity = new FileStorage();
entity.setFileName(fileName);
entity.setFileId(System.currentTimeMillis());
entity.setTenantId(1L);
entity.setUserId(1L);
entity.setDirId(1L);
entity.setFileSuffix("txt");
entity.setFileBizType(1);
entity.setFileSize(1024L);
entity.setCreateTime(LocalDateTime.now());
entity.setUpdateTime(LocalDateTime.now());
entity.setCreateYearMonth("2026-01");
return entity;
}
}

View File

@@ -0,0 +1,517 @@
package com.sdm.data.service;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
/**
* Service层CRUD测试 - MySQL转PostgreSQL验证
* 覆盖所有Service的基础CRUD操作
*/
@SpringBootTest
@ActiveProfiles("test")
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@Transactional
@Rollback(true) // 确保测试后回滚,不污染数据库
public class ServiceCrudTest {
@Autowired
private IFileStorageService fileStorageService;
@Autowired
private IFileMetadataInfoService fileMetadataInfoService;
@Autowired
private IDimensionTemplateService dimensionTemplateService;
@Autowired
private IFileStorageQuotaService fileStorageQuotaService;
@Autowired
private ISimulationParameterLibraryService simulationParameterLibraryService;
@Autowired
private ITrainingModelService trainingModelService;
@Autowired
private IFileMetadataExtensionService fileMetadataExtensionService;
@Autowired
private IFileSimulationMappingService fileSimulationMappingService;
@Autowired
private IFileUserPermissionService fileUserPermissionService;
@Autowired
private IDimensionTemplateHierarchyService dimensionTemplateHierarchyService;
@Autowired
private ISimulationParameterLibraryCategoryService simulationParameterLibraryCategoryService;
@Autowired
private ISimulationParameterLibraryCategoryObjectService simulationParameterLibraryCategoryObjectService;
@Autowired
private ITrainingModelAlgorithmParamService trainingModelAlgorithmParamService;
// ==================== IFileStorageService Tests ====================
@Test
@Order(1)
@DisplayName("IFileStorageService - save保存测试")
void testFileStorageServiceSave() {
FileStorage entity = createFileStorageEntity("service_test.txt");
boolean result = fileStorageService.save(entity);
assertTrue(result);
assertNotNull(entity.getId());
}
@Test
@Order(2)
@DisplayName("IFileStorageService - getById查询测试")
void testFileStorageServiceGetById() {
// 先插入
FileStorage entity = createFileStorageEntity("service_get_test.txt");
fileStorageService.save(entity);
// 再查询
FileStorage result = fileStorageService.getById(entity.getId());
assertNotNull(result);
assertEquals("service_get_test.txt", result.getFileName());
}
@Test
@Order(3)
@DisplayName("IFileStorageService - updateById更新测试")
void testFileStorageServiceUpdate() {
FileStorage entity = createFileStorageEntity("service_update_test.txt");
fileStorageService.save(entity);
entity.setFileName("service_update_test_modified.txt");
entity.setFileSize(8192L);
boolean result = fileStorageService.updateById(entity);
assertTrue(result);
FileStorage updated = fileStorageService.getById(entity.getId());
assertEquals("service_update_test_modified.txt", updated.getFileName());
assertEquals(8192L, updated.getFileSize());
}
@Test
@Order(4)
@DisplayName("IFileStorageService - removeById删除测试")
void testFileStorageServiceRemove() {
FileStorage entity = createFileStorageEntity("service_remove_test.txt");
fileStorageService.save(entity);
boolean result = fileStorageService.removeById(entity.getId());
assertTrue(result);
assertNull(fileStorageService.getById(entity.getId()));
}
@Test
@Order(5)
@DisplayName("IFileStorageService - list列表查询测试")
void testFileStorageServiceList() {
List<FileStorage> result = fileStorageService.list();
assertNotNull(result);
}
@Test
@Order(6)
@DisplayName("IFileStorageService - 条件查询测试")
void testFileStorageServiceListWithWrapper() {
FileStorage entity = createFileStorageEntity("service_wrapper_test.txt");
entity.setFileBizType(99);
fileStorageService.save(entity);
LambdaQueryWrapper<FileStorage> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(FileStorage::getFileBizType, 99);
List<FileStorage> result = fileStorageService.list(wrapper);
assertNotNull(result);
assertFalse(result.isEmpty());
}
@Test
@Order(7)
@DisplayName("IFileStorageService - 分页查询测试")
void testFileStorageServicePage() {
Page<FileStorage> page = new Page<>(1, 10);
Page<FileStorage> result = fileStorageService.page(page);
assertNotNull(result);
assertNotNull(result.getRecords());
}
@Test
@Order(8)
@DisplayName("IFileStorageService - 批量保存测试")
void testFileStorageServiceSaveBatch() {
List<FileStorage> entities = Arrays.asList(
createFileStorageEntity("batch_1.txt"),
createFileStorageEntity("batch_2.txt"),
createFileStorageEntity("batch_3.txt")
);
boolean result = fileStorageService.saveBatch(entities);
assertTrue(result);
entities.forEach(e -> assertNotNull(e.getId()));
}
@Test
@Order(9)
@DisplayName("IFileStorageService - 自定义方法selectNodeSizeByNodeType测试")
void testFileStorageServiceSelectNodeSizeByNodeType() {
var result = fileStorageService.selectNodeSizeByNodeType(
Arrays.asList(1L, 2L),
3,
1L
);
assertNotNull(result);
}
// ==================== IFileMetadataInfoService Tests ====================
@Test
@Order(20)
@DisplayName("IFileMetadataInfoService - CRUD完整测试")
void testFileMetadataInfoServiceCRUD() {
// CREATE
FileMetadataInfo entity = createFileMetadataInfoEntity("service_metadata.txt");
boolean saveResult = fileMetadataInfoService.save(entity);
assertTrue(saveResult);
// READ
FileMetadataInfo read = fileMetadataInfoService.getById(entity.getId());
assertNotNull(read);
// UPDATE
read.setOriginalName("service_metadata_updated.txt");
boolean updateResult = fileMetadataInfoService.updateById(read);
assertTrue(updateResult);
// DELETE
boolean deleteResult = fileMetadataInfoService.removeById(entity.getId());
assertTrue(deleteResult);
}
@Test
@Order(21)
@DisplayName("IFileMetadataInfoService - listSimulationNodeDir测试")
void testFileMetadataInfoServiceListSimulationNodeDir() {
var result = fileMetadataInfoService.listSimulationNodeDir(
Arrays.asList(1L, 2L),
false,
1L
);
assertNotNull(result);
}
// ==================== IDimensionTemplateService Tests ====================
@Test
@Order(30)
@DisplayName("IDimensionTemplateService - CRUD完整测试")
void testDimensionTemplateServiceCRUD() {
// CREATE
DimensionTemplate entity = createDimensionTemplateEntity("Service测试模板");
boolean saveResult = dimensionTemplateService.save(entity);
assertTrue(saveResult);
// READ
DimensionTemplate read = dimensionTemplateService.getById(entity.getId());
assertNotNull(read);
assertEquals("Service测试模板", read.getTemplateName());
// UPDATE
read.setTemplateName("Service测试模板_更新");
boolean updateResult = dimensionTemplateService.updateById(read);
assertTrue(updateResult);
// DELETE
boolean deleteResult = dimensionTemplateService.removeById(entity.getId());
assertTrue(deleteResult);
}
// ==================== IFileStorageQuotaService Tests ====================
@Test
@Order(40)
@DisplayName("IFileStorageQuotaService - CRUD完整测试")
void testFileStorageQuotaServiceCRUD() {
// CREATE
FileStorageQuota entity = createFileStorageQuotaEntity(200L);
boolean saveResult = fileStorageQuotaService.save(entity);
assertTrue(saveResult);
// READ
FileStorageQuota read = fileStorageQuotaService.getById(entity.getId());
assertNotNull(read);
// UPDATE
read.setStatus("WARNING");
boolean updateResult = fileStorageQuotaService.updateById(read);
assertTrue(updateResult);
// DELETE
boolean deleteResult = fileStorageQuotaService.removeById(entity.getId());
assertTrue(deleteResult);
}
// ==================== ISimulationParameterLibraryService Tests ====================
@Test
@Order(50)
@DisplayName("ISimulationParameterLibraryService - CRUD完整测试")
void testSimulationParameterLibraryServiceCRUD() {
// CREATE
SimulationParameterLibrary entity = createSimulationParameterLibraryEntity("Service测试参数库");
boolean saveResult = simulationParameterLibraryService.save(entity);
assertTrue(saveResult);
// READ
SimulationParameterLibrary read = simulationParameterLibraryService.getById(entity.getId());
assertNotNull(read);
// UPDATE
read.setParameterLibraryName("Service测试参数库_更新");
boolean updateResult = simulationParameterLibraryService.updateById(read);
assertTrue(updateResult);
// DELETE
boolean deleteResult = simulationParameterLibraryService.removeById(entity.getId());
assertTrue(deleteResult);
}
// ==================== ITrainingModelService Tests ====================
@Test
@Order(60)
@DisplayName("ITrainingModelService - CRUD完整测试")
void testTrainingModelServiceCRUD() {
// CREATE
TrainingModel entity = createTrainingModelEntity("Service测试模型");
boolean saveResult = trainingModelService.save(entity);
assertTrue(saveResult);
// READ
TrainingModel read = trainingModelService.getById(entity.getId());
assertNotNull(read);
assertEquals("Service测试模型", read.getModelName());
// UPDATE
read.setModelName("Service测试模型_更新");
boolean updateResult = trainingModelService.updateById(read);
assertTrue(updateResult);
// DELETE
boolean deleteResult = trainingModelService.removeById(entity.getId());
assertTrue(deleteResult);
}
// ==================== 其他Service基础CRUD测试 ====================
@Test
@Order(70)
@DisplayName("IFileMetadataExtensionService - 基础测试")
void testFileMetadataExtensionService() {
List<FileMetadataExtension> result = fileMetadataExtensionService.list();
assertNotNull(result);
}
@Test
@Order(71)
@DisplayName("IFileSimulationMappingService - 基础测试")
void testFileSimulationMappingService() {
List<FileSimulationMapping> result = fileSimulationMappingService.list();
assertNotNull(result);
}
@Test
@Order(72)
@DisplayName("IFileUserPermissionService - 基础测试")
void testFileUserPermissionService() {
List<FileUserPermission> result = fileUserPermissionService.list();
assertNotNull(result);
}
@Test
@Order(73)
@DisplayName("IDimensionTemplateHierarchyService - 基础测试")
void testDimensionTemplateHierarchyService() {
List<DimensionTemplateHierarchy> result = dimensionTemplateHierarchyService.list();
assertNotNull(result);
}
@Test
@Order(74)
@DisplayName("ISimulationParameterLibraryCategoryService - 基础测试")
void testSimulationParameterLibraryCategoryService() {
List<SimulationParameterLibraryCategory> result = simulationParameterLibraryCategoryService.list();
assertNotNull(result);
}
@Test
@Order(75)
@DisplayName("ISimulationParameterLibraryCategoryObjectService - 基础测试")
void testSimulationParameterLibraryCategoryObjectService() {
List<SimulationParameterLibraryCategoryObject> result = simulationParameterLibraryCategoryObjectService.list();
assertNotNull(result);
}
@Test
@Order(76)
@DisplayName("ITrainingModelAlgorithmParamService - 基础测试")
void testTrainingModelAlgorithmParamService() {
List<TrainingModelAlgorithmParam> result = trainingModelAlgorithmParamService.list();
assertNotNull(result);
}
// ==================== 复杂查询测试 ====================
@Test
@Order(80)
@DisplayName("复杂条件组合查询测试")
void testComplexQuery() {
// 准备测试数据
FileStorage entity1 = createFileStorageEntity("complex_1.txt");
entity1.setFileBizType(100);
entity1.setFileSize(1000L);
fileStorageService.save(entity1);
FileStorage entity2 = createFileStorageEntity("complex_2.txt");
entity2.setFileBizType(100);
entity2.setFileSize(2000L);
fileStorageService.save(entity2);
// 复杂查询
LambdaQueryWrapper<FileStorage> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(FileStorage::getFileBizType, 100)
.ge(FileStorage::getFileSize, 1000L)
.orderByDesc(FileStorage::getFileSize);
List<FileStorage> result = fileStorageService.list(wrapper);
assertNotNull(result);
assertEquals(2, result.size());
// 验证排序
assertTrue(result.get(0).getFileSize() >= result.get(1).getFileSize());
}
@Test
@Order(81)
@DisplayName("统计count测试")
void testCount() {
long count = fileStorageService.count();
assertTrue(count >= 0);
}
@Test
@Order(82)
@DisplayName("条件统计count测试")
void testCountWithWrapper() {
LambdaQueryWrapper<FileStorage> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(FileStorage::getTenantId, 1L);
long count = fileStorageService.count(wrapper);
assertTrue(count >= 0);
}
// ==================== Helper Methods ====================
private FileStorage createFileStorageEntity(String fileName) {
FileStorage entity = new FileStorage();
entity.setFileName(fileName);
entity.setFileId(System.currentTimeMillis());
entity.setTenantId(1L);
entity.setUserId(1L);
entity.setDirId(1L);
entity.setFileSuffix("txt");
entity.setFileBizType(1);
entity.setFileSize(1024L);
entity.setCreateTime(LocalDateTime.now());
entity.setUpdateTime(LocalDateTime.now());
entity.setCreateYearMonth("2026-01");
return entity;
}
private FileMetadataInfo createFileMetadataInfoEntity(String originalName) {
FileMetadataInfo entity = new FileMetadataInfo();
entity.setRelatedResourceUuid("uuid-" + System.currentTimeMillis());
entity.setRelatedResourceUuidOwnType("node");
entity.setOriginalName(originalName);
entity.setDataType(2);
entity.setIsLatest(true);
entity.setTenantId(1L);
entity.setCreatorId(1L);
entity.setCreateTime(LocalDateTime.now());
entity.setUpdateTime(LocalDateTime.now());
return entity;
}
private DimensionTemplate createDimensionTemplateEntity(String templateName) {
DimensionTemplate entity = new DimensionTemplate();
entity.setTemplateName(templateName);
entity.setTemplateType(1);
entity.setDescription("测试描述");
entity.setTenantId(1L);
entity.setCreatedBy(1L);
entity.setCreatedAt(LocalDateTime.now());
return entity;
}
private FileStorageQuota createFileStorageQuotaEntity(Long userId) {
FileStorageQuota entity = new FileStorageQuota();
entity.setUserId(userId);
entity.setTenantId(1L);
entity.setQuotaValue(5368709120L);
entity.setQuotaUnit("GB");
entity.setUsedValue(0L);
entity.setStatus("NORMAL");
return entity;
}
private SimulationParameterLibrary createSimulationParameterLibraryEntity(String name) {
SimulationParameterLibrary entity = new SimulationParameterLibrary();
entity.setParameterLibraryName(name);
entity.setTenantId(1L);
entity.setCreatorId(1L);
entity.setCreateTime(LocalDateTime.now());
return entity;
}
private TrainingModel createTrainingModelEntity(String modelName) {
TrainingModel entity = new TrainingModel();
entity.setModelName(modelName);
entity.setAlgorithmType("SVM");
entity.setTrainer("tester");
entity.setHandleStatus("待开始");
entity.setTrainingStatus("待开始");
entity.setPredStatus("待开始");
entity.setTenantId(1L);
entity.setCreator(1L);
entity.setCreateTime(LocalDateTime.now());
return entity;
}
}

View File

@@ -0,0 +1,28 @@
spring:
datasource:
# 直接连接PostgreSQL数据库进行单元测试
url: jdbc:postgresql://192.168.65.161:25432/spdm?currentSchema=public&stringtype=unspecified
driver-class-name: org.postgresql.Driver
username: spdm
password: Spdm@2026
hikari:
maximum-pool-size: 5
minimum-idle: 2
connection-timeout: 30000
mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml
configuration:
map-underscore-to-camel-case: false
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
id-type: auto
logic-delete-value: 1
logic-not-delete-value: 0
logging:
level:
com.sdm.data: DEBUG
org.springframework.jdbc: DEBUG
org.apache.ibatis: DEBUG