新增集成:实现外部资源映射与操作记录持久化
This commit is contained in:
1 parent
5de1d2a142
commit
1332b45fae
22 files changed
+2843
No files matched your search
+118
@@ -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"));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user