新增集成:实现外部资源映射与操作记录持久化

This commit is contained in:
wangzhibiao committed 2026-09-16 10:22:50 +08:00
1 parent 5de1d2a142
commit 1332b45fae
22 files changed
+2843

No files matched your search

@@ -0,0 +1,118 @@
package com.ruoyi.web.controller.train;
import static org.junit.Assert.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Locale;
import org.junit.Before;
import org.junit.Test;
/**
* 008 Migration 静态规范契约测试
* 校验 008_external_resource_operation.sql 的设计规范、幂等性设计、约束健全性及敏感数据规避
*
* @author ruoyi
*/
public class ExternalResourceOperationMigrationContractTest
{
private File migrationFile;
private String sqlContent;
@Before
public void setUp() throws IOException
{
// 定位 008 迁移文件
File direct = new File("../sql/system/kingbase/008_external_resource_operation.sql");
if (direct.exists()) {
migrationFile = direct;
} else {
migrationFile = new File("sql/system/kingbase/008_external_resource_operation.sql");
}
assertTrue("008 migration script must exist: " + migrationFile.getAbsolutePath(), migrationFile.exists());
sqlContent = new String(Files.readAllBytes(migrationFile.toPath()));
}
@Test
public void testTablesCreatedWithIdempotentClause()
{
String lower = sqlContent.toLowerCase(Locale.ROOT);
assertTrue("Must create train_external_resource_mapping", lower.contains("train_external_resource_mapping"));
assertTrue("Must create train_external_operation", lower.contains("train_external_operation"));
assertTrue("Must have CREATE TABLE IF NOT EXISTS for mapping", lower.contains("create table if not exists train_external_resource_mapping"));
assertTrue("Must have CREATE TABLE IF NOT EXISTS for operation", lower.contains("create table if not exists train_external_operation"));
}
@Test
public void testForeignKeysAndReferentialIntegrity()
{
String lower = sqlContent.toLowerCase(Locale.ROOT);
assertTrue("Mapping table must reference train_dormitory_info(dorm_id)",
lower.contains("references train_dormitory_info(dorm_id)"));
assertTrue("Operation table must reference train_dorm_auth(auth_id)",
lower.contains("references train_dorm_auth(auth_id)"));
}
@Test
public void testPartialUniqueIndexes()
{
String lower = sqlContent.toLowerCase(Locale.ROOT);
// 1. 房间 Active 唯一约束: vendor_code + dorm_id
assertTrue("Must define uq_ext_res_map_active_room partial unique index",
lower.contains("uq_ext_res_map_active_room"));
assertTrue("Must guard active room mapping with external_resource_type and status",
lower.contains("where external_resource_type = 'room' and mapping_status = 'active'"));
// 2. 外部资源跨房间 Active 唯一约束: vendor_code + external_resource_type + external_resource_id
assertTrue("Must define uq_ext_res_map_active_ext_res partial unique index",
lower.contains("uq_ext_res_map_active_ext_res"));
assertTrue("uq_ext_res_map_active_ext_res must include vendor_code, external_resource_type, external_resource_id",
lower.contains("(vendor_code, external_resource_type, external_resource_id)"));
assertTrue("Must guard active external resource binding with mapping_status = 'active'",
lower.contains("where mapping_status = 'active'"));
}
@Test
public void testOperationTypeAndStatusSemantics()
{
String lower = sqlContent.toLowerCase(Locale.ROOT);
// operation_type 包含 GRANT, REVOKE
assertTrue("Must mention GRANT in operation_type", lower.contains("grant"));
assertTrue("Must mention REVOKE in operation_type", lower.contains("revoke"));
// operation_status 绝不能把 REVOKED 作为其合法枚举值
assertFalse("operation_status comment must NOT contain REVOKED",
lower.contains("operation_status is '操作状态(created, requested, accepted, pending, success, failed, timeout, retry_wait, revoked)'"));
assertFalse("operation_status must NOT contain REVOKED in its definition",
lower.contains("operation_status is '操作状态") && lower.contains("revoked"));
}
@Test
public void testOperationIdempotencyAndPollIndexes()
{
String lower = sqlContent.toLowerCase(Locale.ROOT);
assertTrue("Must define uq_ext_op_idempotency unique index", lower.contains("uq_ext_op_idempotency"));
assertTrue("Must define idx_ext_op_poll index for async polling", lower.contains("idx_ext_op_poll"));
}
@Test
public void testNoDestructiveStatements()
{
// 过滤单行注释
String noComments = sqlContent.replaceAll("--.*", "").toLowerCase(Locale.ROOT);
assertFalse("Must NOT contain DROP TABLE", noComments.contains("drop table"));
assertFalse("Must NOT contain TRUNCATE", noComments.contains("truncate"));
assertFalse("Must NOT contain DELETE FROM", noComments.contains("delete from"));
}
@Test
public void testNoSensitivePlaintextColumns()
{
String lower = sqlContent.toLowerCase(Locale.ROOT);
assertFalse("Must NOT contain plaintext password column", lower.contains("password varchar") || lower.contains("door_password"));
assertFalse("Must NOT contain plaintext card number column", lower.contains("card_number") || lower.contains("cardnumber"));
assertFalse("Must NOT contain token column", lower.contains("token varchar") || lower.contains("app_token"));
assertFalse("Must NOT contain secret column", lower.contains("secret varchar") || lower.contains("app_secret"));
}
}