test(sql): align contracts with clean initialization
This commit is contained in:
@@ -7,23 +7,18 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
class NotificationSqlContractTest {
|
||||
@Test void definesTablesIsolationIdempotencyAndPermissions() throws Exception {String sql;try(var in=getClass().getResourceAsStream("/db/notification-center.sql")){assertThat(in).isNotNull();sql=new String(in.readAllBytes(),StandardCharsets.UTF_8);}assertThat(sql).contains("iam_notification_template","iam_notification_task","iam_notification_recipient","iam_notification_inbox","iam_notification_event_inbox","uk_notification_task_no","uk_notification_task_idempotency","uk_notification_source_event","uk_notification_recipient","idx_notification_inbox_list","platform:notification:template:status","platform:notification:task:retry","platform:notification:read","platform:notification:read-all","merchant:notification:view","merchant:notification:read","merchant:notification:read-all").contains("'MENU',5106000,'platform:notification:template:list'","'MENU',5106000,'platform:notification:task:list'");}
|
||||
|
||||
@Test void unifiedMigrationContainsNotificationBaselineAndSevenIndexAssertion() throws Exception {
|
||||
@Test void cleanInitializationContainsNotificationSchemaAndPermissionSeeds() throws Exception {
|
||||
Path direct=Path.of("deploy","sql","头程数据库统一增量-MySQL8.sql");
|
||||
Path migration=Files.exists(direct)?direct:Path.of("..","deploy","sql","头程数据库统一增量-MySQL8.sql").normalize();
|
||||
String sql=Files.readString(migration,StandardCharsets.UTF_8);
|
||||
assertThat(sql).contains("iam_notification_template","iam_notification_task","iam_notification_recipient",
|
||||
assertThat(sql).contains("CREATE TABLE iam_notification_template","CREATE TABLE iam_notification_task","CREATE TABLE iam_notification_recipient",
|
||||
"iam_notification_inbox","iam_notification_event_inbox","uk_notification_template_code",
|
||||
"uk_notification_task_no","uk_notification_task_idempotency","uk_notification_source_event",
|
||||
"uk_notification_recipient","uk_notification_inbox_recipient","uk_notification_event",
|
||||
"assert_notification_center_schema","permission_code='merchant:notification:view'",
|
||||
"permission_code LIKE 'platform:notification%'");
|
||||
assertThat(sql).contains("COUNT(DISTINCT index_name) FROM information_schema.statistics WHERE table_schema='baiyue_iam'");
|
||||
"'merchant:notification:view'", "'platform:notification:template:list'",
|
||||
"'platform:notification:task:list'");
|
||||
assertThat(sql)
|
||||
.contains(")) <> 7 THEN")
|
||||
.contains("permission_code='merchant:notification:view')) <> 13 THEN")
|
||||
.contains("permission_code LIKE 'platform:notification%') <> 12 THEN")
|
||||
.contains("'merchant:notification:view','merchant:notification:read','merchant:notification:read-all')) <> 3 THEN");
|
||||
assertThat(sql.indexOf("(5106014,0,'MERCHANT','BUTTON'"))
|
||||
.isLessThan(sql.indexOf("CALL baiyue_iam.assert_notification_center_schema();"));
|
||||
.contains("(5106014,0,'MERCHANT','BUTTON'")
|
||||
.doesNotContain("assert_notification_center_schema", "information_schema.statistics");
|
||||
}
|
||||
}
|
||||
|
||||
+7
-11
@@ -60,15 +60,9 @@ class AdminPrototypeMenuPermissionSqlContractTest {
|
||||
}
|
||||
assertThat(unified)
|
||||
.contains("platform:finance:receivable-statistics:export")
|
||||
.contains("permission_code LIKE 'platform:finance:%' AND status='ACTIVE' AND deleted=0) <> 34")
|
||||
.contains("(p.permission_code='platform:finance' OR p.permission_code LIKE 'platform:finance:%')) <> 35")
|
||||
.contains("Finance 导出和下载中心授权不完整")
|
||||
.contains("客户全局 Finance 权限模板不完整")
|
||||
.contains("客户全局管理员 Finance 模板授权不完整")
|
||||
.satisfies(content -> assertThat(content.indexOf("(5105050,0,'PLATFORM','BUTTON'"))
|
||||
.isLessThan(content.indexOf("CREATE PROCEDURE assert_finance_permissions()")))
|
||||
.satisfies(content -> assertThat(content.indexOf("CALL migrate_wallet_permissions();"))
|
||||
.isLessThan(content.indexOf("CALL assert_finance_permissions();")));
|
||||
.contains("(4000001,5105050,0,CURRENT_TIMESTAMP(3))")
|
||||
.contains("(4000100,5305010,0,CURRENT_TIMESTAMP(3))")
|
||||
.doesNotContain("CREATE PROCEDURE assert_finance_permissions", "CALL migrate_wallet_permissions");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -80,8 +74,10 @@ class AdminPrototypeMenuPermissionSqlContractTest {
|
||||
.contains("'platform:overseas-storage-fee:create','platform:overseas-storage-fee:delete'");
|
||||
|
||||
String unified = Files.readString(resolveUnifiedSql(), StandardCharsets.UTF_8);
|
||||
assertThat(unified).contains("<> 4")
|
||||
.contains("platform:overseas-storage-fee:list', 'platform:overseas-storage-fee:create'");
|
||||
assertThat(unified)
|
||||
.contains("'platform:overseas-storage-fee:list','海外仓阶梯费用','/customers/overseas-storage-fees','GET',20,'ACTIVE'")
|
||||
.contains("'platform:overseas-storage-fee:create','新增海外仓阶梯费用',NULL,NULL,10,'INACTIVE'")
|
||||
.contains("'platform:overseas-storage-fee:delete','删除海外仓阶梯费用',NULL,NULL,30,'INACTIVE'");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+5
-16
@@ -90,27 +90,16 @@ class ContainerWorkspacePermissionSqlContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void unifiedIncrementContainsTheCompleteModuleSql() throws Exception {
|
||||
void cleanInitializationContainsTheCompletePermissionCatalog() throws Exception {
|
||||
Path unifiedPath = Path.of("deploy", "sql", "头程数据库统一增量-MySQL8.sql");
|
||||
if (!Files.exists(unifiedPath)) {
|
||||
unifiedPath = Path.of("..", "deploy", "sql", "头程数据库统一增量-MySQL8.sql");
|
||||
}
|
||||
String unified = Files.readString(unifiedPath, StandardCharsets.UTF_8);
|
||||
String startMarker = "-- 货柜双工作台权限开始(与 iam/db/container-workspace-permissions.sql 保持一致)";
|
||||
String endMarker = "-- 货柜双工作台权限结束,恢复头程数据库上下文";
|
||||
int start = unified.indexOf(startMarker);
|
||||
int bodyStart = unified.indexOf('\n', start) + 1;
|
||||
int end = unified.indexOf(endMarker, bodyStart);
|
||||
|
||||
assertThat(start).isGreaterThanOrEqualTo(0);
|
||||
assertThat(bodyStart).isGreaterThan(start);
|
||||
assertThat(end).isGreaterThan(bodyStart);
|
||||
assertThat(normalizeLineEndings(unified.substring(bodyStart, end)).trim())
|
||||
.isEqualTo(normalizeLineEndings(sql()).trim());
|
||||
}
|
||||
|
||||
private static String normalizeLineEndings(String value) {
|
||||
return value.replace("\r\n", "\n");
|
||||
assertThat(codes(unified)).containsAll(REQUIRED);
|
||||
assertThat(unified)
|
||||
.contains("(5102090,0,'PLATFORM','MENU'", "(5102205,0,'PLATFORM','BUTTON'")
|
||||
.doesNotContain("migrate_container_workspace_permissions", "ON DUPLICATE KEY UPDATE");
|
||||
}
|
||||
|
||||
private static String sql() throws Exception {
|
||||
|
||||
@@ -20,15 +20,24 @@ class CustomerCodeSchemaContractTest {
|
||||
}
|
||||
String unified = Files.readString(unifiedPath, StandardCharsets.UTF_8);
|
||||
|
||||
assertSequenceDefinition(baseline);
|
||||
assertSequenceDefinition(unified);
|
||||
assertMigrationSequenceDefinition(baseline);
|
||||
assertInitializationSequenceDefinition(unified);
|
||||
}
|
||||
|
||||
private static void assertSequenceDefinition(String sql) {
|
||||
private static void assertMigrationSequenceDefinition(String sql) {
|
||||
assertThat(sql)
|
||||
.contains("tenant_code VARCHAR(8) NOT NULL")
|
||||
.contains("CREATE TABLE IF NOT EXISTS iam_number_sequence")
|
||||
.contains("PRIMARY KEY (sequence_key)")
|
||||
.contains("INSERT IGNORE INTO iam_number_sequence(sequence_key, next_value) VALUES ('CUSTOMER_CODE', 1)");
|
||||
}
|
||||
|
||||
private static void assertInitializationSequenceDefinition(String sql) {
|
||||
assertThat(sql)
|
||||
.contains("tenant_code varchar(8) NOT NULL")
|
||||
.contains("CREATE TABLE iam_number_sequence")
|
||||
.contains("PRIMARY KEY (sequence_key)")
|
||||
.contains("INSERT INTO iam_number_sequence (sequence_key, next_value, updated_at) VALUES ('CUSTOMER_CODE',1")
|
||||
.doesNotContain("CREATE TABLE IF NOT EXISTS iam_number_sequence", "INSERT IGNORE INTO iam_number_sequence");
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -28,7 +28,9 @@ class CustomerDimensionInitializationSqlContractTest {
|
||||
assertContract(standalone);
|
||||
assertContract(unified);
|
||||
assertThat(standalone).contains("information_schema.columns", "CREATE TABLE IF NOT EXISTS");
|
||||
assertThat(unified).contains("information_schema.columns", "CREATE TABLE IF NOT EXISTS");
|
||||
assertThat(unified)
|
||||
.contains("CREATE TABLE iam_customer_dimension_initialization_task")
|
||||
.doesNotContain("information_schema.columns", "CREATE TABLE IF NOT EXISTS");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+17
-24
@@ -49,7 +49,7 @@ class CustomerProfileMigrationContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldHandleCase03() throws IOException {
|
||||
void cleanInitializationContainsTheFinalCustomerProfileContract() throws IOException {
|
||||
Path repositoryRoot = Path.of(System.getProperty("maven.multiModuleProjectDirectory", ".."));
|
||||
Path migration = repositoryRoot.resolve("deploy/sql/头程数据库统一增量-MySQL8.sql");
|
||||
Path readme = repositoryRoot.resolve("deploy/sql/README.md");
|
||||
@@ -60,43 +60,36 @@ class CustomerProfileMigrationContractTest {
|
||||
String instructions = Files.readString(readme, StandardCharsets.UTF_8);
|
||||
|
||||
assertThat(sql)
|
||||
.contains("customer_nickname VARCHAR(32)")
|
||||
.contains("ALTER TABLE iam_tenant ADD COLUMN customer_nickname VARCHAR(32)")
|
||||
.contains("ALTER TABLE iam_tenant MODIFY COLUMN status")
|
||||
.contains("customer_nickname varchar(32)")
|
||||
.contains("DEFAULT 'PROFILE_REQUIRED'")
|
||||
.contains("CALL phase1_iam_add_column('iam_tenant', 'approved_at'")
|
||||
.contains("CALL phase1_iam_add_column('iam_tenant', 'approved_by'")
|
||||
.contains("CALL phase1_iam_add_column('iam_tenant', 'reject_reason'")
|
||||
.contains("CALL phase1_iam_add_column('iam_tenant_qualification', 'review_comment'")
|
||||
.contains("approved_at datetime(3)")
|
||||
.contains("approved_by bigint")
|
||||
.contains("reject_reason varchar(500)")
|
||||
.contains("review_comment varchar(500)")
|
||||
.contains("platform:customer:view")
|
||||
.contains("platform:customer:export")
|
||||
.contains("platform:download:list")
|
||||
.contains("'MERCHANT_OWNER'")
|
||||
.contains("owner_role.id, permission.id, 0")
|
||||
.contains("统一增量全部执行完成");
|
||||
.contains("SELECT 'PASS' AS initialization_status")
|
||||
.doesNotContain("ALTER TABLE iam_tenant", "phase1_iam_add_column");
|
||||
assertThat(instructions)
|
||||
.contains("phase1-platform-master-data-and-permission-management.sql")
|
||||
.contains("phase1-customer-profile.sql")
|
||||
.contains("phase1-onboarding.sql")
|
||||
.contains("`PROFILE_REQUIRED` 默认状态、审核结果字段、资质审核备注及成员审计字段")
|
||||
.contains("全局 `MERCHANT_OWNER` 角色模板")
|
||||
.contains("测试环境结构发布只执行全量固定入口");
|
||||
.contains("当前开发阶段只维护纯初始化")
|
||||
.contains("模块 `src/main/resources/db/` 用作结构来源和开发追溯")
|
||||
.contains("不再向历史迁移文件追加发布步骤");
|
||||
}
|
||||
|
||||
@Test
|
||||
void unifiedMigrationGrantsCustomerOperationsToPlatformAdmin() throws IOException {
|
||||
void cleanInitializationGrantsCustomerOperationsToPlatformAdmin() throws IOException {
|
||||
Path repositoryRoot = Path.of(System.getProperty("maven.multiModuleProjectDirectory", ".."));
|
||||
String sql = Files.readString(
|
||||
repositoryRoot.resolve("deploy/sql/头程数据库统一增量-MySQL8.sql"),
|
||||
StandardCharsets.UTF_8);
|
||||
int grantStart = sql.indexOf("-- 新增平台操作权限默认只授予系统管理员。");
|
||||
int grantEnd = sql.indexOf("-- 已有客户运营角色继续具备", grantStart);
|
||||
|
||||
assertThat(grantStart).isGreaterThanOrEqualTo(0);
|
||||
assertThat(grantEnd).isGreaterThan(grantStart);
|
||||
assertThat(sql.substring(grantStart, grantEnd))
|
||||
assertThat(sql)
|
||||
.contains("'platform:customer:reset-password'")
|
||||
.contains("'platform:customer:delete'")
|
||||
.contains("'platform:customer:impersonate'");
|
||||
.contains("'platform:customer:impersonate'")
|
||||
.contains("(4000001,5100016,0,CURRENT_TIMESTAMP(3))")
|
||||
.contains("(4000001,5100017,0,CURRENT_TIMESTAMP(3))")
|
||||
.contains("(4000001,5100018,0,CURRENT_TIMESTAMP(3))");
|
||||
}
|
||||
}
|
||||
|
||||
+6
-18
@@ -46,28 +46,16 @@ class FinanceG1G2PermissionSqlContractTest {
|
||||
|
||||
@Test
|
||||
void unifiedSqlMirrorsCatalogAndGrantsTheFinanceCatalogToPlatformAdmin() throws Exception {
|
||||
String sql = Files.readString(resolveUnifiedSql(), StandardCharsets.UTF_8)
|
||||
.replace("\r\n", "\n");
|
||||
String financeSection = sql.substring(sql.indexOf("-- Finance F1 人工财务权限"),
|
||||
sql.indexOf("-- Admin 原型菜单与财务五页权限补充"));
|
||||
String sql = Files.readString(resolveUnifiedSql(), StandardCharsets.UTF_8);
|
||||
|
||||
assertThat(financeSection)
|
||||
.contains("(5105024, 0, 'PLATFORM', 'BUTTON', 5105000, 'platform:finance:fee-source:review'")
|
||||
.contains("(5105025, 0, 'PLATFORM', 'BUTTON', 5105000, 'platform:finance:fee-source:edit'")
|
||||
.contains("NULL, 'POST', 150, 'ACTIVE', 1, 0")
|
||||
.contains("NULL, 'PUT', 160, 'ACTIVE', 1, 0")
|
||||
.contains("permission_code IN (\n 'platform:finance',")
|
||||
.contains("Finance G1-G4");
|
||||
assertThat(financeSection)
|
||||
.contains("SELECT 4000001, id, 0 FROM baiyue_iam.iam_permission")
|
||||
.contains("status='INACTIVE',deleted=1");
|
||||
assertThat(sql)
|
||||
.contains("(5105024,0,'PLATFORM','BUTTON',5105041,'platform:finance:fee-source:review'")
|
||||
.contains("(5105025,0,'PLATFORM','BUTTON',5105041,'platform:finance:fee-source:edit'")
|
||||
.contains("(4000001,5105024,0,CURRENT_TIMESTAMP(3))")
|
||||
.contains("(4000001,5105025,0,CURRENT_TIMESTAMP(3))")
|
||||
.contains("platform:finance:settlement-ar:list")
|
||||
.contains("platform:finance:settlement-ap:list")
|
||||
.contains("permission_code LIKE 'platform:finance:%' AND status='ACTIVE' AND deleted=0) <> 34")
|
||||
.contains("rp.role_id=4000001")
|
||||
.contains("LIKE 'platform:finance:%')) <> 35")
|
||||
.contains("平台管理员 Finance 授权不完整");
|
||||
.doesNotContain("migrate_finance_g1_g4_permissions", "status='INACTIVE',deleted=1");
|
||||
}
|
||||
|
||||
private static Path resolveUnifiedSql() {
|
||||
|
||||
+4
-12
@@ -39,21 +39,13 @@ class FinanceG3G4PermissionSqlContractTest {
|
||||
@Test
|
||||
void unifiedSqlContainsCatalogAndGrantsItToPlatformAdmin() throws Exception {
|
||||
String sql = Files.readString(resolveUnifiedSql(), StandardCharsets.UTF_8);
|
||||
String financeSection = sql.substring(sql.indexOf("-- Finance F1 人工财务权限"),
|
||||
sql.indexOf("-- Admin 原型菜单与财务五页权限补充"));
|
||||
for (String code : CODES) assertThat(financeSection).contains(code);
|
||||
assertThat(financeSection)
|
||||
.contains("migrate_finance_g1_g4_permissions")
|
||||
.contains("finance G1-G4 permission id/code conflict");
|
||||
assertThat(financeSection)
|
||||
.contains("SELECT 4000001, id, 0 FROM baiyue_iam.iam_permission")
|
||||
.contains("platform:finance:reconciliation:create");
|
||||
for (String code : CODES) assertThat(sql).contains(code);
|
||||
assertThat(sql)
|
||||
.contains("(4000001,5105026,0,CURRENT_TIMESTAMP(3))")
|
||||
.contains("(4000001,5105035,0,CURRENT_TIMESTAMP(3))")
|
||||
.contains("platform:finance:settlement-ar:list")
|
||||
.contains("platform:finance:settlement-ap:list")
|
||||
.contains("permission_code LIKE 'platform:finance:%' AND status='ACTIVE' AND deleted=0) <> 34")
|
||||
.contains("rp.role_id=4000001")
|
||||
.contains("LIKE 'platform:finance:%')) <> 35");
|
||||
.doesNotContain("migrate_finance_g1_g4_permissions", "finance G1-G4 permission id/code conflict");
|
||||
}
|
||||
|
||||
private static Path resolveUnifiedSql() {
|
||||
|
||||
+5
-11
@@ -63,10 +63,11 @@ class InboundHoldPermissionSqlContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void unifiedIncrementContainsTheSameMigrationBody() throws Exception {
|
||||
String marker = "DROP PROCEDURE IF EXISTS migrate_inbound_hold_permission;";
|
||||
|
||||
assertThat(migrationBody(unifiedSql(), marker)).isEqualTo(migrationBody(sql(), marker));
|
||||
void cleanInitializationContainsThePermissionAndDefaultGrant() throws Exception {
|
||||
assertThat(unifiedSql())
|
||||
.contains("(5102032,0,'PLATFORM','BUTTON',5102030,'platform:firstleg:inbound:hold'")
|
||||
.contains("(4000001,5102032,0,CURRENT_TIMESTAMP(3))")
|
||||
.doesNotContain("migrate_inbound_hold_permission", "ON DUPLICATE KEY UPDATE");
|
||||
}
|
||||
|
||||
private static String sql() throws Exception {
|
||||
@@ -80,11 +81,4 @@ class InboundHoldPermissionSqlContractTest {
|
||||
return Files.readString(path.normalize(), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
private static String migrationBody(String sql, String marker) {
|
||||
int start = sql.indexOf(marker);
|
||||
int end = sql.indexOf(marker, start + marker.length());
|
||||
assertThat(start).isGreaterThanOrEqualTo(0);
|
||||
assertThat(end).isGreaterThan(start);
|
||||
return sql.substring(start, end + marker.length()).replaceAll("\\s+", " ").trim();
|
||||
}
|
||||
}
|
||||
|
||||
+18
-2
@@ -18,9 +18,17 @@ class InitialIdentitySeedSqlContractTest {
|
||||
.getContentAsString(StandardCharsets.UTF_8);
|
||||
String unified = Files.readString(unifiedSql(), StandardCharsets.UTF_8);
|
||||
assertPlatformIdentitySeed(identitySeed);
|
||||
assertPlatformIdentitySeed(unified);
|
||||
assertCleanPlatformIdentitySeed(unified);
|
||||
assertGlobalMerchantTemplate(templateSeed);
|
||||
assertGlobalMerchantTemplate(unified);
|
||||
assertCleanGlobalMerchantTemplate(unified);
|
||||
}
|
||||
|
||||
private static void assertCleanPlatformIdentitySeed(String sql) {
|
||||
assertThat(sql)
|
||||
.contains("(0,'PLATFORM','虫虫出海平台'")
|
||||
.contains("(2000001,1000001,'INTERNAL','平台系统管理员'")
|
||||
.contains("(3000001,0,2000001,'EMPLOYEE'")
|
||||
.doesNotContain("merchant_admin", "IT_TEST", "一期演示企业", "ON DUPLICATE KEY UPDATE");
|
||||
}
|
||||
|
||||
private static void assertPlatformIdentitySeed(String sql) {
|
||||
@@ -47,6 +55,14 @@ class InitialIdentitySeedSqlContractTest {
|
||||
.doesNotContain("WHERE tenant_id = 10001 AND app_code = 'MERCHANT'");
|
||||
}
|
||||
|
||||
private static void assertCleanGlobalMerchantTemplate(String sql) {
|
||||
assertThat(sql)
|
||||
.contains("(4000100,0,'MERCHANT','MERCHANT_OWNER'")
|
||||
.contains("(5300000,0,'MERCHANT','MENU'")
|
||||
.contains("(5301024,0,'MERCHANT','BUTTON'")
|
||||
.doesNotContain("WHERE tenant_id = 10001 AND app_code = 'MERCHANT'");
|
||||
}
|
||||
|
||||
private static Path unifiedSql() {
|
||||
Path path = Path.of("deploy", "sql", "头程数据库统一增量-MySQL8.sql");
|
||||
return Files.exists(path) ? path : Path.of("..", "deploy", "sql", "头程数据库统一增量-MySQL8.sql");
|
||||
|
||||
@@ -13,7 +13,16 @@ class LocationPermissionSqlContractTest {
|
||||
@Test
|
||||
void acceptsKnownPollutionAndRestoresCanonicalPermissionIds() throws Exception {
|
||||
assertRepairContract(moduleSql());
|
||||
assertRepairContract(unifiedSql());
|
||||
assertFinalInitializationContract(unifiedSql());
|
||||
}
|
||||
|
||||
private static void assertFinalInitializationContract(String sql) {
|
||||
assertThat(sql)
|
||||
.contains("(5103040,0,'PLATFORM','MENU',5103000,'platform:download:list'")
|
||||
.contains("(5103041,0,'PLATFORM','BUTTON',5103040,'platform:download:all'")
|
||||
.contains("(5103060,0,'PLATFORM','MENU',5103000,'platform:location:list'")
|
||||
.contains("(5103061,0,'PLATFORM','BUTTON',5103060,'platform:location:create'")
|
||||
.doesNotContain("tmp_location_role_grant", "库位权限迁移失败");
|
||||
}
|
||||
|
||||
private static void assertRepairContract(String sql) {
|
||||
|
||||
+30
-22
@@ -64,10 +64,10 @@ class OverseasPhase4PermissionSqlContractTest {
|
||||
Set<String> moduleCatalog = codes(new ClassPathResource("db/lastleg-permissions.sql")
|
||||
.getContentAsString(StandardCharsets.UTF_8));
|
||||
assertThat(codes(sql)).containsAll(moduleCatalog);
|
||||
assertThat(sql).contains("baiyue_iam.iam_permission", "baiyue_iam.iam_role_permission", "'lastleg:pda:operate'");
|
||||
assertPdaPickerGrant(sql);
|
||||
assertCustomAdminGrant(sql);
|
||||
assertCustomAdminNavigationGrant(sql);
|
||||
assertThat(sql)
|
||||
.contains("CREATE TABLE iam_permission", "CREATE TABLE iam_role_permission", "'lastleg:pda:operate'")
|
||||
.contains("(4000005,5107015,0,CURRENT_TIMESTAMP(3))")
|
||||
.doesNotContain("assert_overseas_pda_picker_permission", "DELETE role_permission FROM");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -78,25 +78,33 @@ class OverseasPhase4PermissionSqlContractTest {
|
||||
if (!Files.exists(path)) path = Path.of("../deploy/sql/头程数据库统一增量-MySQL8.sql");
|
||||
String unifiedSql = Files.readString(path, StandardCharsets.UTF_8);
|
||||
|
||||
for (String sql : List.of(moduleSql, unifiedSql)) {
|
||||
String matrix = matrixBlock(sql);
|
||||
assertThat(matrix).contains("WAREHOUSE_OPERATOR", "WAREHOUSE_TALLY");
|
||||
assertThat(codes(matrix)).containsExactlyInAnyOrder(
|
||||
"platform:overseas-warehouse:last-mile-order:list",
|
||||
"platform:overseas-warehouse:inbound-order:list",
|
||||
"platform:overseas-warehouse:relabel-order:list",
|
||||
"platform:overseas-warehouse:inventory:list",
|
||||
"platform:overseas-warehouse:warehouse:list",
|
||||
"platform:overseas-warehouse:location:list",
|
||||
"platform:overseas-warehouse:pallet:list",
|
||||
"platform:overseas-business:purchase:list",
|
||||
"platform:overseas-business:truck:list",
|
||||
"platform:overseas-business:looseboard:list");
|
||||
assertThat(matrix).doesNotContain("OVERSEAS_WAREHOUSE_PDA_OPERATOR");
|
||||
assertThat(matrix).doesNotContain(":create'", ":edit'", ":status'", ":export'", ":adjust'");
|
||||
assertThat(sql).contains("assert_phase4_warehouse_role_minimum", "<> 20",
|
||||
"role.role_code IN ('WAREHOUSE_OPERATOR','OVERSEAS_WAREHOUSE_PDA_OPERATOR','WAREHOUSE_TALLY','CN_FIRSTLEG_PDA_OPERATOR')");
|
||||
String matrix = matrixBlock(moduleSql);
|
||||
assertThat(matrix).contains("WAREHOUSE_OPERATOR", "WAREHOUSE_TALLY");
|
||||
assertThat(codes(matrix)).containsExactlyInAnyOrder(
|
||||
"platform:overseas-warehouse:last-mile-order:list",
|
||||
"platform:overseas-warehouse:inbound-order:list",
|
||||
"platform:overseas-warehouse:relabel-order:list",
|
||||
"platform:overseas-warehouse:inventory:list",
|
||||
"platform:overseas-warehouse:warehouse:list",
|
||||
"platform:overseas-warehouse:location:list",
|
||||
"platform:overseas-warehouse:pallet:list",
|
||||
"platform:overseas-business:purchase:list",
|
||||
"platform:overseas-business:truck:list",
|
||||
"platform:overseas-business:looseboard:list");
|
||||
assertThat(matrix).doesNotContain("OVERSEAS_WAREHOUSE_PDA_OPERATOR");
|
||||
assertThat(matrix).doesNotContain(":create'", ":edit'", ":status'", ":export'", ":adjust'");
|
||||
assertThat(moduleSql).contains("assert_phase4_warehouse_role_minimum", "<> 20",
|
||||
"role.role_code IN ('WAREHOUSE_OPERATOR','OVERSEAS_WAREHOUSE_PDA_OPERATOR','WAREHOUSE_TALLY','CN_FIRSTLEG_PDA_OPERATOR')");
|
||||
|
||||
for (int permissionId : new int[] {5107000, 5107010, 5107020, 5107030, 5107040,
|
||||
5107050, 5107060, 5107100, 5107110, 5107120}) {
|
||||
assertThat(unifiedSql)
|
||||
.contains("(4000004," + permissionId + ",0,CURRENT_TIMESTAMP(3))")
|
||||
.contains("(4000006," + permissionId + ",0,CURRENT_TIMESTAMP(3))");
|
||||
}
|
||||
assertThat(unifiedSql)
|
||||
.doesNotContain("(4000005,5107000,0,CURRENT_TIMESTAMP(3))")
|
||||
.doesNotContain("(4000007,5107000,0,CURRENT_TIMESTAMP(3))");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+14
-21
@@ -143,35 +143,28 @@ class Phase5DeliveryPermissionSqlContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void domesticUnifiedEntryInlinesTheCompleteModuleSqlAfterPhase4Permissions() throws Exception {
|
||||
String moduleSql = sql().trim();
|
||||
void domesticCleanInitializationContainsTheCompletePermissionCatalog() throws Exception {
|
||||
String unifiedSql = repositoryFile("deploy/sql/头程数据库统一增量-MySQL8.sql");
|
||||
int overseasCatalog = unifiedSql.indexOf("-- 海外权限统一目录");
|
||||
int outboundDelivery = unifiedSql.indexOf("-- 海外排车、出库与派送权限(来源:iam/db/phase5-delivery-permissions.sql)");
|
||||
int bodyStart = unifiedSql.indexOf("USE baiyue_iam;", outboundDelivery);
|
||||
int nextSection = unifiedSql.indexOf("-- IAM 客户提交即成功", bodyStart);
|
||||
|
||||
assertThat(overseasCatalog).isGreaterThanOrEqualTo(0);
|
||||
assertThat(outboundDelivery).isGreaterThan(overseasCatalog);
|
||||
assertThat(bodyStart).isGreaterThan(outboundDelivery);
|
||||
assertThat(nextSection).isGreaterThan(bodyStart);
|
||||
assertThat(unifiedSql.substring(bodyStart, nextSection).trim()).isEqualTo(moduleSql);
|
||||
assertThat(codes(unifiedSql.substring(outboundDelivery, nextSection)))
|
||||
.containsExactlyInAnyOrderElementsOf(REQUIRED);
|
||||
assertThat(codes(unifiedSql)).containsAll(REQUIRED);
|
||||
assertThat(unifiedSql)
|
||||
.contains("(4000004,5107064,0,CURRENT_TIMESTAMP(3))")
|
||||
.contains("(4000004,5107094,0,CURRENT_TIMESTAMP(3))")
|
||||
.contains("(4000100,5306000,0,CURRENT_TIMESTAMP(3))")
|
||||
.contains("(4000100,5306001,0,CURRENT_TIMESTAMP(3))")
|
||||
.doesNotContain("guard_phase5_delivery_permission_ids", "tmp_phase5_delivery_role_permission");
|
||||
}
|
||||
|
||||
@Test
|
||||
void deploymentGuideUsesOnlyTheDomesticUnifiedEntry() throws Exception {
|
||||
void deploymentGuideDefinesCleanRegionalInitializationOnly() throws Exception {
|
||||
String readme = repositoryFile("deploy/sql/README.md");
|
||||
|
||||
assertThat(readme).contains(
|
||||
"海外排车、出库与派送权限",
|
||||
"测试和部署只执行固定入口,不再单独执行模块脚本",
|
||||
"排车列表/编辑/取消/转派送",
|
||||
"异常订单列表/创建/处理和客户回访列表/编辑十六项权限",
|
||||
"merchant:warehouse:delivery:list",
|
||||
"merchant:warehouse:delivery:create",
|
||||
"PDA 岗位不得获得上述后台权限");
|
||||
"当前开发阶段只维护纯初始化",
|
||||
"两个 SQL 文件沿用原文件名",
|
||||
"国内 IAM 是全部平台与客户权限的唯一权威",
|
||||
"模块 `src/main/resources/db/` 用作结构来源和开发追溯",
|
||||
"不再向历史迁移文件追加发布步骤");
|
||||
}
|
||||
|
||||
private static String sql() throws Exception {
|
||||
|
||||
@@ -22,10 +22,7 @@ class QualificationSchemaContractTest {
|
||||
|
||||
assertThat(baseline).contains("original_file_name VARCHAR(255) NOT NULL COMMENT '上传时原始文件名'");
|
||||
assertThat(unified)
|
||||
.contains("original_file_name VARCHAR(255) NOT NULL COMMENT '上传时原始文件名'")
|
||||
.contains("CALL phase1_iam_add_column('iam_tenant_qualification', 'original_file_name',")
|
||||
.contains("table_name='iam_tenant_qualification'")
|
||||
.contains("column_name='original_file_name'")
|
||||
.contains("统一迁移失败:IAM客户资质缺少原始文件名列");
|
||||
.contains("original_file_name varchar(255) NOT NULL COMMENT '上传时原始文件名'")
|
||||
.doesNotContain("phase1_iam_add_column", "information_schema.columns");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,18 +26,17 @@ class SecurityEventSqlContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void unifiedMigrationIncludesSecurityEventSchemaAndAssertion() throws Exception {
|
||||
void cleanInitializationIncludesSecurityEventSchema() throws Exception {
|
||||
Path direct = Path.of("deploy", "sql", "头程数据库统一增量-MySQL8.sql");
|
||||
Path migration = Files.exists(direct)
|
||||
? direct : Path.of("..", "deploy", "sql", "头程数据库统一增量-MySQL8.sql").normalize();
|
||||
String sql = Files.readString(migration, StandardCharsets.UTF_8);
|
||||
assertThat(sql)
|
||||
.contains("CREATE TABLE IF NOT EXISTS iam_security_subject_version")
|
||||
.contains("CREATE TABLE IF NOT EXISTS iam_security_tenant_version")
|
||||
.contains("CREATE TABLE IF NOT EXISTS iam_security_event_outbox")
|
||||
.contains("CREATE TABLE iam_security_subject_version")
|
||||
.contains("CREATE TABLE iam_security_tenant_version")
|
||||
.contains("CREATE TABLE iam_security_event_outbox")
|
||||
.contains("idx_security_outbox_publish", "idx_security_outbox_aggregate")
|
||||
.contains("CALL assert_iam_security_event_schema();");
|
||||
assertThat(sql.indexOf("CALL assert_iam_security_event_schema();"))
|
||||
.isLessThan(sql.lastIndexOf("SELECT 'PASS' AS migration_status"));
|
||||
.contains("SELECT 'PASS' AS initialization_status")
|
||||
.doesNotContain("assert_iam_security_event_schema", "CREATE TABLE IF NOT EXISTS iam_security_event");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,13 +18,19 @@ class WarehouseRoleSqlContractTest {
|
||||
@Test
|
||||
void unifiedDeploymentContainsTheSameWarehouseRoleContract() throws Exception {
|
||||
String sql = unifiedSql();
|
||||
assertWarehouseRoleContract(sql);
|
||||
assertThat(roleMigrationBlock(sql))
|
||||
.doesNotContain("\n ADD COLUMN IF NOT EXISTS")
|
||||
.doesNotContain("DROP CHECK IF EXISTS");
|
||||
assertThat(sql.lastIndexOf("SELECT 'PASS' AS migration_status"))
|
||||
.isGreaterThan(sql.indexOf("CALL assert_phase3_warehouse_roles_ready()"));
|
||||
assertThat(sql.trim()).endsWith("AS message;");
|
||||
assertThat(sql)
|
||||
.contains("(4000004,0,'PLATFORM','WAREHOUSE_OPERATOR','国内仓后台操作员','SYSTEM'")
|
||||
.contains("(4000005,0,'PLATFORM','OVERSEAS_WAREHOUSE_PDA_OPERATOR','海外仓 PDA 作业员','SYSTEM'")
|
||||
.contains("(4000006,0,'PLATFORM','WAREHOUSE_TALLY','国内仓理货复核员','SYSTEM'")
|
||||
.contains("(4000007,0,'PLATFORM','CN_FIRSTLEG_PDA_OPERATOR','国内头程 PDA 作业员','SYSTEM'")
|
||||
.contains("(6000004,4000004,0,'TENANT',NULL")
|
||||
.contains("(6000005,4000005,0,'TENANT',NULL")
|
||||
.contains("(6000006,4000006,0,'TENANT',NULL")
|
||||
.contains("(6000007,4000007,0,'TENANT',NULL")
|
||||
.contains("(4000005,5107015,0,CURRENT_TIMESTAMP(3))")
|
||||
.contains("(4000007,5102190,0,CURRENT_TIMESTAMP(3))")
|
||||
.contains("SELECT 'PASS' AS initialization_status")
|
||||
.doesNotContain("assert_phase3_warehouse_roles_ready", "ON DUPLICATE KEY UPDATE");
|
||||
}
|
||||
|
||||
private static void assertWarehouseRoleContract(String sql) {
|
||||
@@ -100,15 +106,6 @@ class WarehouseRoleSqlContractTest {
|
||||
return sql.substring(start, end > start ? end : sql.length());
|
||||
}
|
||||
|
||||
private static String roleMigrationBlock(String sql) {
|
||||
String marker = "-- 来源:iam/src/main/resources/db/phase3-warehouse-roles.sql";
|
||||
String endMarker = "-- BEGIN FINANCE FEE SOURCE MODULE MIGRATIONS";
|
||||
int start = sql.indexOf(marker);
|
||||
int end = sql.indexOf(endMarker, start + marker.length());
|
||||
if (start < 0 || end < 0) throw new IllegalStateException("统一入口缺少仓库角色连续区块");
|
||||
return sql.substring(start, end);
|
||||
}
|
||||
|
||||
private static String moduleSql() throws Exception {
|
||||
return new ClassPathResource("db/phase3-warehouse-roles.sql")
|
||||
.getContentAsString(StandardCharsets.UTF_8);
|
||||
|
||||
Reference in New Issue
Block a user