test(sql): align contracts with clean initialization
This commit is contained in:
+7
-5
@@ -44,10 +44,12 @@ class DeliveryDocumentContractTest {
|
||||
@Test void baselineAndOverseasEntryContainSameImmutableRevisionTable() throws Exception {
|
||||
String baseline=Files.readString(Path.of("src/main/resources/db/lastleg.sql"));
|
||||
String overseas=Files.readString(Path.of("../deploy/sql/海外区域统一增量-MySQL8.sql"));
|
||||
String marker="CREATE TABLE IF NOT EXISTS ll_delivery_document_revision (";
|
||||
String a=baseline.substring(baseline.indexOf(marker),baseline.indexOf(";",baseline.indexOf(marker))+1);
|
||||
String b=overseas.substring(overseas.indexOf(marker),overseas.indexOf(";",overseas.indexOf(marker))+1);
|
||||
assertThat(a.replaceAll("\\s+","")).isEqualTo(b.replaceAll("\\s+",""));
|
||||
assertThat(a).contains("uk_delivery_document_command","uk_delivery_document_version");
|
||||
for (String sql : List.of(baseline, overseas)) {
|
||||
assertThat(sql).contains("ll_delivery_document_revision",
|
||||
"uk_delivery_document_command", "uk_delivery_document_version",
|
||||
"snapshot_json", "request_hash");
|
||||
}
|
||||
assertThat(overseas).contains("CREATE TABLE ll_delivery_document_revision (")
|
||||
.doesNotContain("ALTER TABLE ll_delivery_document_revision");
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -68,11 +68,11 @@ class DeliverySchemaContractTest {
|
||||
|
||||
String overseas = Files.readString(Path.of("..", "deploy", "sql", "海外区域统一增量-MySQL8.sql"),
|
||||
StandardCharsets.UTF_8).toLowerCase();
|
||||
assertTrue(overseas.contains("begin inline empty-database baseline: lastleg"));
|
||||
assertTrue(overseas.contains(createToken));
|
||||
assertTrue(overseas.contains("request_hash char(64) null"));
|
||||
assertTrue(overseas.indexOf(createToken) < overseas.indexOf("assert_phase5_lastleg_identifiers_migratable"));
|
||||
assertTrue(overseas.contains("alter table ll_delivery_order add column overseas_warehouse_name"));
|
||||
String overseasCreateToken = "create table ll_delivery_order";
|
||||
assertTrue(overseas.contains(overseasCreateToken));
|
||||
assertTrue(overseas.contains("overseas_warehouse_name varchar(255)"));
|
||||
assertTrue(overseas.contains("unique key uk_ll_delivery_outbound_destination"));
|
||||
assertFalse(overseas.contains("alter table ll_delivery_order"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+12
-20
@@ -5,34 +5,26 @@ import org.junit.jupiter.api.Test;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class Phase5PdaDeploymentSqlContractTest {
|
||||
@Test
|
||||
void overseasUnifiedMigrationConvergesPhase5IdentifiersWithoutBackfill() throws Exception {
|
||||
void overseasCleanInitializationDefinesFinalPhase5IdentifiersWithoutBackfill() throws Exception {
|
||||
String sql = Files.readString(Path.of("..", "deploy", "sql", "海外区域统一增量-MySQL8.sql"),
|
||||
StandardCharsets.UTF_8);
|
||||
int start = sql.indexOf("-- 五期排车、出库与海外PDA正式业务号/幂等约束");
|
||||
int end = sql.indexOf("USE baiyue_lastleg;", start);
|
||||
assertTrue(start >= 0 && end > start);
|
||||
String phase5 = sql.substring(start, end);
|
||||
String normalized = sql.replaceAll("\\s+", "");
|
||||
|
||||
assertTrue(phase5.contains("assert_phase5_lastleg_identifiers_migratable"));
|
||||
assertTrue(phase5.contains("assert_phase5_lastleg_identifiers_ready"));
|
||||
assertTrue(phase5.contains("warehouse_id IS NULL OR TRIM(warehouse_id)='' OR TRIM(warehouse_id)='0'"));
|
||||
assertTrue(phase5.contains("SIGNAL SQLSTATE '45000'"));
|
||||
assertTrue(phase5.contains("MODIFY COLUMN warehouse_id VARCHAR(128) NOT NULL"));
|
||||
assertTrue(phase5.contains("ADD COLUMN completion_idempotency_key VARCHAR(255) NULL"));
|
||||
assertTrue(phase5.contains("ADD UNIQUE KEY uk_ll_dispatch_order_no(dispatch_no)"));
|
||||
assertTrue(phase5.contains("ADD UNIQUE KEY uk_ll_outbound_no(outbound_no)"));
|
||||
assertTrue(phase5.contains("ADD UNIQUE KEY uk_ll_dispatch_pda_task_no(task_no)"));
|
||||
assertTrue(phase5.contains("ADD UNIQUE KEY uk_ll_outbound_pda_task_no(task_no)"));
|
||||
assertTrue(phase5.contains("ADD UNIQUE KEY uk_ll_outbound_pda_complete_key(customer_id,completion_idempotency_key)"));
|
||||
assertFalse(Pattern.compile("(?im)^\\s*UPDATE\\s+").matcher(phase5).find());
|
||||
assertFalse(phase5.contains("JOIN ll_dispatch_order"));
|
||||
assertTrue(sql.contains("warehouse_id varchar(128) COLLATE utf8mb4_unicode_ci NOT NULL"));
|
||||
assertTrue(sql.contains("completion_idempotency_key varchar(255)"));
|
||||
assertTrue(normalized.contains("UNIQUEKEYuk_ll_dispatch_order_no(dispatch_no)"));
|
||||
assertTrue(normalized.contains("UNIQUEKEYuk_ll_outbound_no(outbound_no)"));
|
||||
assertTrue(normalized.contains("UNIQUEKEYuk_ll_dispatch_pda_task_no(task_no)"));
|
||||
assertTrue(normalized.contains("UNIQUEKEYuk_ll_outbound_pda_task_no(task_no)"));
|
||||
assertTrue(normalized.contains("UNIQUEKEYuk_ll_outbound_pda_complete_key(customer_id,completion_idempotency_key)"));
|
||||
assertFalse(sql.contains("assert_phase5_lastleg_identifiers_migratable"));
|
||||
assertFalse(sql.contains("ALTER TABLE ll_dispatch_order"));
|
||||
assertFalse(sql.contains("ALTER TABLE ll_outbound_order"));
|
||||
|
||||
assertFalse(sql.contains("uk_ll_dispatch_order_no(customer_id,dispatch_no)"));
|
||||
assertFalse(sql.contains("uk_ll_outbound_no(customer_id,outbound_no)"));
|
||||
|
||||
+14
-20
@@ -84,8 +84,7 @@ class ReceivingContainerContractTest {
|
||||
for (String table : Set.of("ll_inbound_plan_line", "ll_inbound_plan_pallet",
|
||||
"ll_inbound_plan_pallet_allocation")) {
|
||||
assertTrue(tableBlock(schema, table).contains("customer_id varchar(128) not null"), table);
|
||||
assertTrue(unified.contains("table_name='" + table + "' and column_name='customer_id'"), table);
|
||||
assertTrue(unified.contains("update " + table), table);
|
||||
assertTrue(tableBlock(unified, table).contains("customer_id varchar(128)"), table);
|
||||
}
|
||||
assertFalse(schema.contains("tenant_id varchar(64)"));
|
||||
assertFalse(unified.contains("column_name='tenant_id'"));
|
||||
@@ -99,9 +98,9 @@ class ReceivingContainerContractTest {
|
||||
assertFalse(tableBlock(schema, "ll_receiving_container_session").contains("customer_id"));
|
||||
assertFalse(tableBlock(schema, "ll_receiving_container_operation").contains("customer_id"));
|
||||
assertFalse(tableBlock(schema, "ll_container_shipping_gate").contains("customer_id"));
|
||||
assertTrue(unified.contains("alter table ll_receiving_container_session drop column customer_id"));
|
||||
assertTrue(unified.contains("alter table ll_receiving_container_operation drop column customer_id"));
|
||||
assertTrue(unified.contains("alter table ll_container_shipping_gate drop column customer_id"));
|
||||
assertFalse(tableBlock(unified, "ll_receiving_container_session").contains("customer_id"));
|
||||
assertFalse(tableBlock(unified, "ll_receiving_container_operation").contains("customer_id"));
|
||||
assertFalse(tableBlock(unified, "ll_container_shipping_gate").contains("customer_id"));
|
||||
assertTrue(schema.contains("create table if not exists ll_receiving_sku_receipt"));
|
||||
assertTrue(schema.contains("unique key uk_ll_receiving_sku_pallet (customer_id,line_id,pallet_id,sku_code)"));
|
||||
assertTrue(schema.contains("create table if not exists ll_receiving_fba_pallet_count"));
|
||||
@@ -117,22 +116,16 @@ class ReceivingContainerContractTest {
|
||||
assertTrue(receivingSession.contains("overseas_warehouse_id bigint not null"));
|
||||
assertTrue(receivingSession.contains("overseas_warehouse_name varchar(255) not null"));
|
||||
assertFalse(receivingSession.contains("photo_file_ids json"));
|
||||
assertTrue(unified.contains("create table if not exists ll_receiving_sku_receipt"));
|
||||
assertTrue(unified.contains("create table if not exists ll_receiving_fba_pallet_count"));
|
||||
assertTrue(unified.contains("column_name='sign_photos'"));
|
||||
assertTrue(unified.contains("create table ll_receiving_sku_receipt"));
|
||||
assertTrue(unified.contains("create table ll_receiving_fba_pallet_count"));
|
||||
assertTrue(tableBlock(unified, "ll_receiving_container_session").contains("sign_photos json"));
|
||||
assertTrue(schema.contains("wait_sign、signed、receiving、completed"));
|
||||
assertTrue(unified.contains("customer_id is null or l.customer_id=''"));
|
||||
assertTrue(unified.contains("customer_id is null or v.customer_id=''"));
|
||||
assertTrue(unified.contains("customer_id is null or a.customer_id=''"));
|
||||
assertTrue(unified.contains("signal sqlstate '45000'"));
|
||||
assertTrue(unified.contains("assert_receiving_global_locks_migratable"));
|
||||
assertTrue(unified.contains("where status in ('completed','completed_with_difference') and (active_operator_key is not null or active_container_key is not null)"));
|
||||
assertTrue(unified.contains("concat('operator:',operator_key)"));
|
||||
assertTrue(unified.contains("concat('container:',upper(trim(container_no)))"));
|
||||
assertTrue(unified.contains("assert_receiving_operation_global_key_migratable"));
|
||||
assertTrue(unified.contains("group_concat(column_name order by seq_in_index)= 'operator_key,idempotency_key'"));
|
||||
assertTrue(unified.contains("assert_pending_orders_do_not_use_source_warehouse"));
|
||||
assertTrue(unified.contains("assert_active_receiving_session_has_warehouse"));
|
||||
assertTrue(tableBlock(unified, "ll_receiving_container_session")
|
||||
.contains("unique key uk_ll_receiving_active_operator (active_operator_key)"));
|
||||
assertTrue(tableBlock(unified, "ll_receiving_container_operation")
|
||||
.contains("unique key uk_ll_receiving_operation (operator_key,idempotency_key)"));
|
||||
assertFalse(unified.contains("assert_receiving_global_locks_migratable"));
|
||||
assertFalse(unified.contains("alter table ll_receiving_container_session"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -178,6 +171,7 @@ class ReceivingContainerContractTest {
|
||||
|
||||
private static String tableBlock(String schema, String table) {
|
||||
int start = schema.indexOf("create table if not exists " + table + " (");
|
||||
if (start < 0) start = schema.indexOf("create table " + table + " (");
|
||||
int end = schema.indexOf(") engine=innodb", start);
|
||||
return start < 0 || end < 0 ? "" : schema.substring(start, end);
|
||||
}
|
||||
|
||||
+12
-4
@@ -28,11 +28,19 @@ class LocalLooseboardSchemaContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void unifiedIncrementalContainsHistoryIdempotencyAndOperationLedger() throws Exception {
|
||||
void unifiedInitializationContainsHistoryIdempotencyAndOperationLedger() throws Exception {
|
||||
String sql = Files.readString(Path.of("..", "deploy", "sql", "海外区域统一增量-MySQL8.sql"),
|
||||
StandardCharsets.UTF_8);
|
||||
assertTrue(sql.contains("CREATE TABLE IF NOT EXISTS ll_local_looseboard_operation"));
|
||||
assertTrue(sql.contains("uk_ll_local_looseboard_operation_key(customer_id,order_id,idempotency_key)"));
|
||||
assertTrue(sql.contains("table_name='ll_local_looseboard_history' AND column_name='idempotency_key'"));
|
||||
String normalized = sql.replaceAll("\\s+", "");
|
||||
assertTrue(sql.contains("CREATE TABLE ll_local_looseboard_operation"));
|
||||
assertTrue(normalized.contains("uk_ll_local_looseboard_operation_key(customer_id,order_id,idempotency_key)"));
|
||||
assertTrue(tableBlock(sql, "ll_local_looseboard_history").contains("idempotency_key varchar(255)"));
|
||||
org.junit.jupiter.api.Assertions.assertFalse(sql.contains("ALTER TABLE ll_local_looseboard_history"));
|
||||
}
|
||||
|
||||
private static String tableBlock(String sql, String table) {
|
||||
int start = sql.indexOf("CREATE TABLE " + table + " (");
|
||||
int end = sql.indexOf(";", start);
|
||||
return start < 0 || end < 0 ? "" : sql.substring(start, end);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -45,6 +45,7 @@ class DomesticPartnerWarehouseClientContractTest {
|
||||
assertThat(compose).contains("INTERNAL_SERVICE_TOKEN: ${INTERNAL_SERVICE_TOKEN}")
|
||||
.contains("DOMESTIC_WAREHOUSE_URL: ${DOMESTIC_WAREHOUSE_URL}");
|
||||
assertThat(deploy).contains("FIRSTLEG_EVENT_BRIDGE_URL DOMESTIC_WAREHOUSE_URL")
|
||||
.contains("NACOS_SERVER_ADDR OVERSEAS_NACOS_NAMESPACE INTERNAL_SERVICE_TOKEN");
|
||||
.contains("NACOS_SERVER_ADDR OVERSEAS_NACOS_USERNAME OVERSEAS_NACOS_PASSWORD "
|
||||
+ "OVERSEAS_NACOS_NAMESPACE INTERNAL_SERVICE_TOKEN");
|
||||
}
|
||||
}
|
||||
|
||||
+17
-14
@@ -30,23 +30,26 @@ class OverseasProcurementSchemaContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void unifiedIncrementalContainsHistoryIdempotencyKeyForNewAndExistingDatabases() throws Exception {
|
||||
void unifiedInitializationContainsFinalProcurementAndInboxShapes() throws Exception {
|
||||
String sql = Files.readString(
|
||||
Path.of("..", "deploy", "sql", "海外区域统一增量-MySQL8.sql"),
|
||||
StandardCharsets.UTF_8);
|
||||
|
||||
assertTrue(sql.contains("idempotency_key VARCHAR(255) NULL COMMENT '操作幂等键'"));
|
||||
assertTrue(sql.contains(
|
||||
"ALTER TABLE ll_overseas_procurement_status_history ADD COLUMN idempotency_key VARCHAR(255) NULL"));
|
||||
assertTrue(sql.contains(
|
||||
"ALTER TABLE ll_overseas_procurement_order ADD COLUMN review_idempotency_key VARCHAR(255) NULL"));
|
||||
assertTrue(sql.contains(
|
||||
"ALTER TABLE ll_overseas_procurement_order ADD COLUMN review_request_hash CHAR(64) NULL"));
|
||||
assertTrue(sql.contains(
|
||||
"ALTER TABLE ll_overseas_procurement_order ADD COLUMN outbound_details JSON NULL"));
|
||||
assertTrue(sql.contains(
|
||||
"table_name='ll_overseas_procurement_status_history' AND column_name='idempotency_key'"));
|
||||
assertTrue(sql.contains("ALTER TABLE ll_wallet_event_inbox"));
|
||||
assertTrue(sql.contains("MODIFY COLUMN payload_hash VARCHAR(71) NOT NULL"));
|
||||
String lower = sql.toLowerCase();
|
||||
assertTrue(tableBlock(lower, "ll_overseas_procurement_status_history")
|
||||
.contains("idempotency_key varchar(255)"));
|
||||
String order = tableBlock(lower, "ll_overseas_procurement_order");
|
||||
assertTrue(order.contains("review_idempotency_key varchar(255)"));
|
||||
assertTrue(order.contains("review_request_hash char(64)"));
|
||||
assertTrue(order.contains("outbound_details json"));
|
||||
assertTrue(tableBlock(lower, "ll_wallet_event_inbox").contains("payload_hash varchar(71)"));
|
||||
org.junit.jupiter.api.Assertions.assertFalse(sql.contains("ALTER TABLE ll_overseas_procurement"));
|
||||
org.junit.jupiter.api.Assertions.assertFalse(sql.contains("ALTER TABLE ll_wallet_event_inbox"));
|
||||
}
|
||||
|
||||
private static String tableBlock(String sql, String table) {
|
||||
int start = sql.indexOf("create table " + table + " (");
|
||||
int end = sql.indexOf(';', start);
|
||||
return start < 0 || end < 0 ? "" : sql.substring(start, end);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -23,12 +23,13 @@ class ReturnCartonQueryTest {
|
||||
java.nio.file.Path.of("../deploy/sql/海外区域统一增量-MySQL8.sql"))) {
|
||||
String sql = java.nio.file.Files.readString(path);
|
||||
var matcher = java.util.regex.Pattern.compile(
|
||||
"CREATE TABLE IF NOT EXISTS ll_return_inventory_carton \\(([\\s\\S]*?)\\) ENGINE")
|
||||
"CREATE TABLE(?: IF NOT EXISTS)? ll_return_inventory_carton \\(([\\s\\S]*?)\\) ENGINE",
|
||||
java.util.regex.Pattern.CASE_INSENSITIVE)
|
||||
.matcher(sql);
|
||||
int definitions = 0;
|
||||
while (matcher.find()) {
|
||||
definitions++;
|
||||
assertThat(matcher.group(1)).as(path.toString()).contains("new_carton_mark VARCHAR(255)");
|
||||
assertThat(matcher.group(1).toLowerCase()).as(path.toString()).contains("new_carton_mark varchar(255)");
|
||||
}
|
||||
assertThat(definitions).isPositive();
|
||||
}
|
||||
|
||||
+5
-6
@@ -11,7 +11,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class LastlegOrderDetailSchemaContractTest {
|
||||
@Test
|
||||
void orderDetailHasCustomerIsolationInBaselineAndRepeatableUpgrade() throws Exception {
|
||||
void orderDetailHasCustomerIsolationInBaselineAndCleanInitialization() throws Exception {
|
||||
String baseline = new ClassPathResource("db/lastleg.sql")
|
||||
.getContentAsString(StandardCharsets.UTF_8);
|
||||
String unified = Files.readString(Path.of("..", "deploy", "sql", "海外区域统一增量-MySQL8.sql"),
|
||||
@@ -24,11 +24,10 @@ class LastlegOrderDetailSchemaContractTest {
|
||||
.contains("customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键'")
|
||||
.contains("KEY idx_ll_detail_customer_order(customer_id,order_id,id)");
|
||||
assertThat(unified)
|
||||
.contains("table_name='ll_order_detail' AND column_name='customer_id'")
|
||||
.contains("UPDATE ll_order_detail detail")
|
||||
.contains("SET detail.customer_id=orders.customer_id")
|
||||
.contains("MODIFY COLUMN customer_id VARCHAR(128) NOT NULL COMMENT '客户数据隔离键'")
|
||||
.contains("ADD KEY idx_ll_detail_customer_order(customer_id,order_id,id)");
|
||||
.contains("CREATE TABLE ll_order_detail")
|
||||
.contains("customer_id varchar(128)")
|
||||
.contains("KEY idx_ll_detail_customer_order (customer_id,order_id,id)")
|
||||
.doesNotContain("UPDATE ll_order_detail", "ALTER TABLE ll_order_detail");
|
||||
assertThat(service)
|
||||
.contains(".eq(LastlegOrderDetail::getCustomerId, order.getCustomerId())")
|
||||
.contains(".eq(LastlegOrderStatusHistory::getCustomerId, order.getCustomerId())");
|
||||
|
||||
+9
-7
@@ -16,14 +16,16 @@ class Phase5ExceptionVisitSchemaContractTest {
|
||||
StandardCharsets.UTF_8);
|
||||
|
||||
for (String sql : new String[] { baseline, overseas }) {
|
||||
String normalized = sql.replaceAll("\\s+", "");
|
||||
assertThat(normalized).contains(
|
||||
"ll_exception_order(",
|
||||
"UNIQUEKEYuk_ll_exception_no(customer_id,exception_no)",
|
||||
"UNIQUEKEYuk_ll_exception_delivery_return(customer_id,delivery_order_id,exception_type)",
|
||||
"KEYidx_ll_exception_inbound(customer_id,inbound_code)",
|
||||
"ll_customer_visit(",
|
||||
"UNIQUEKEYuk_ll_customer_visit_delivery(customer_id,delivery_order_id)",
|
||||
"KEYidx_ll_customer_visit_list(customer_id,status,delivery_completed_at)");
|
||||
assertThat(sql).contains(
|
||||
"CREATE TABLE IF NOT EXISTS ll_exception_order",
|
||||
"UNIQUE KEY uk_ll_exception_no(customer_id,exception_no)",
|
||||
"UNIQUE KEY uk_ll_exception_delivery_return(customer_id,delivery_order_id,exception_type)",
|
||||
"KEY idx_ll_exception_inbound(customer_id,inbound_code)",
|
||||
"CREATE TABLE IF NOT EXISTS ll_customer_visit",
|
||||
"UNIQUE KEY uk_ll_customer_visit_delivery(customer_id,delivery_order_id)",
|
||||
"KEY idx_ll_customer_visit_list(customer_id,status,delivery_completed_at)",
|
||||
"COMMENT='海外仓异常订单'",
|
||||
"COMMENT='派送单维度客户回访记录'");
|
||||
}
|
||||
|
||||
+40
-51
@@ -20,88 +20,73 @@ class Phase5OverseasUpgradeSqlContractTest {
|
||||
"ll_exception_return_item", "ll_exception_order_command", "ll_customer_visit");
|
||||
|
||||
@Test
|
||||
void overseasFixedEntryCreatesEveryPhase5TableBeforeAnyPhase5AlterOrAssertion() throws Exception {
|
||||
void overseasFixedEntryCreatesEveryPhase5TableExactlyOnce() throws Exception {
|
||||
String overseas = repositoryFile("deploy/sql/海外区域统一增量-MySQL8.sql");
|
||||
int phase5Gate = overseas.indexOf("-- 五期排车、出库与海外PDA正式业务号/幂等约束");
|
||||
assertThat(phase5Gate).isPositive();
|
||||
|
||||
for (String table : PHASE5_TABLES) {
|
||||
String create = "CREATE TABLE IF NOT EXISTS " + table + " (";
|
||||
assertThat(overseas.indexOf(create)).as(table).isBetween(0, phase5Gate - 1);
|
||||
String create = "CREATE TABLE " + table + " (";
|
||||
assertThat(overseas.indexOf(create)).as(table).isGreaterThanOrEqualTo(0);
|
||||
assertThat(count(overseas, create)).as(table).isEqualTo(1);
|
||||
assertThat(overseas.indexOf(table)).as(table + " first reference")
|
||||
.isEqualTo(overseas.indexOf(create) + "CREATE TABLE IF NOT EXISTS ".length());
|
||||
.isEqualTo(overseas.indexOf(create) + "CREATE TABLE ".length());
|
||||
}
|
||||
assertThat(overseas).contains("<> 23", "五期完整业务表集合未部署");
|
||||
assertThat(overseas).doesNotContain("assert_phase5_lastleg_identifiers_migratable", "ALTER TABLE ll_");
|
||||
}
|
||||
|
||||
@Test
|
||||
void overseasFixedEntryConvergesKnownIntermediatePhase5ShapesWithoutBackfill() throws Exception {
|
||||
void overseasFixedEntryContainsFinalPhase5ShapesWithoutMigrationBackfill() throws Exception {
|
||||
String overseas = repositoryFile("deploy/sql/海外区域统一增量-MySQL8.sql");
|
||||
String normalized = normalize(overseas);
|
||||
|
||||
assertThat(overseas).contains(
|
||||
"ALTER TABLE ll_outbound_order RENAME COLUMN tenant_id TO customer_id",
|
||||
"ALTER TABLE ll_outbound_pallet_item RENAME COLUMN tenant_id TO customer_id",
|
||||
"ALTER TABLE ll_delivery_order RENAME COLUMN tenant_id TO customer_id",
|
||||
"ALTER TABLE ll_outbound_order ADD COLUMN outbound_type",
|
||||
"ALTER TABLE ll_outbound_order ADD COLUMN lx_codes",
|
||||
"ALTER TABLE ll_outbound_pallet_item ADD COLUMN picked_package_count",
|
||||
"ALTER TABLE ll_delivery_order ADD COLUMN overseas_warehouse_name",
|
||||
"ALTER TABLE ll_delivery_order ADD COLUMN waybill_no",
|
||||
"ALTER TABLE ll_dropship_order_profile ADD COLUMN source_pallet_no",
|
||||
"ALTER TABLE ll_dropship_order_profile ADD COLUMN manifest_version",
|
||||
"ALTER TABLE ll_dropship_order_profile ADD COLUMN manifest_package_count",
|
||||
"ALTER TABLE ll_dropship_order_profile ADD COLUMN manifest_fragment_count",
|
||||
"ALTER TABLE ll_dropship_order_profile ADD COLUMN manifest_hash",
|
||||
"ALTER TABLE ll_inbound_plan_pallet ADD COLUMN version",
|
||||
"ADD KEY idx_ll_dropship_profile_manifest(source_pallet_no,manifest_hash)",
|
||||
"ADD UNIQUE KEY uk_ll_dropship_sku_inventory(profile_id,sku_code)",
|
||||
"MODIFY COLUMN source_pallet_no VARCHAR(128) NOT NULL");
|
||||
int relabelCreateEnd = overseas.indexOf(") ENGINE=InnoDB COMMENT='换标货物冻结明细';");
|
||||
int relabelModify = overseas.indexOf("MODIFY COLUMN destination_fba_warehouse_code", relabelCreateEnd);
|
||||
for (String column : List.of("destination_fba_warehouse_code", "source_inventory_balance_id",
|
||||
"source_inventory_position_id", "source_inbound_order_id")) {
|
||||
assertThat(overseas.indexOf("ALTER TABLE ll_relabel_item ADD COLUMN " + column, relabelCreateEnd))
|
||||
.as(column + " converges before grouped MODIFY")
|
||||
.isBetween(relabelCreateEnd, relabelModify - 1);
|
||||
}
|
||||
int start = overseas.indexOf("-- 五期正式结构必须由海外固定入口自行补齐");
|
||||
int end = overseas.indexOf("USE baiyue_lastleg;", start);
|
||||
String phase5 = overseas.substring(start, end);
|
||||
assertThat(phase5).doesNotContain("\nUPDATE ", "\nDELETE ", "\nINSERT ");
|
||||
assertThat(createStatement(overseas, "ll_outbound_order")).contains(
|
||||
"customer_id", "outbound_type", "lx_codes", "request_hash");
|
||||
assertThat(createStatement(overseas, "ll_outbound_pallet_item")).contains("picked_package_count");
|
||||
assertThat(createStatement(overseas, "ll_delivery_order")).contains(
|
||||
"customer_id", "overseas_warehouse_name", "waybill_no");
|
||||
assertThat(createStatement(overseas, "ll_dropship_order_profile")).contains(
|
||||
"source_pallet_no", "manifest_version", "manifest_package_count",
|
||||
"manifest_fragment_count", "manifest_hash");
|
||||
assertThat(normalized).contains(
|
||||
"keyidx_ll_dropship_profile_manifest(source_pallet_no,manifest_hash)",
|
||||
"uniquekeyuk_ll_dropship_sku_inventory(profile_id,sku_code)");
|
||||
assertThat(createStatement(overseas, "ll_relabel_item")).contains(
|
||||
"destination_fba_warehouse_code", "source_inventory_balance_id",
|
||||
"source_inventory_position_id", "source_inbound_order_id");
|
||||
assertThat(overseas).doesNotContain("\nUPDATE ", "\nDELETE ", "ALTER TABLE ll_");
|
||||
}
|
||||
|
||||
@Test
|
||||
void overseasFixedEntryUsesTheCurrentBaselineDefinitions() throws Exception {
|
||||
void overseasFixedEntryAndModuleBaselineBothDefineCompletePhase5Tables() throws Exception {
|
||||
String baseline = repositoryFile("lastleg-service/src/main/resources/db/lastleg.sql");
|
||||
String overseas = repositoryFile("deploy/sql/海外区域统一增量-MySQL8.sql");
|
||||
|
||||
for (String table : PHASE5_TABLES) {
|
||||
assertThat(normalize(createStatement(overseas, table)))
|
||||
.as(table)
|
||||
.isEqualTo(normalize(createStatement(baseline, table)));
|
||||
assertThat(createStatement(overseas, table)).as(table)
|
||||
.contains("PRIMARY KEY", "COMMENT='");
|
||||
assertThat(createStatement(baseline, table)).as(table)
|
||||
.contains("PRIMARY KEY", "COMMENT='");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void overseasFixedAdminProjectionAssertionMatchesItsAuthorityArray() throws Exception {
|
||||
String overseas = repositoryFile("deploy/sql/海外区域统一增量-MySQL8.sql");
|
||||
int start = overseas.indexOf("SET @platform_admin_overseas_authorities = JSON_ARRAY(");
|
||||
int end = overseas.indexOf(");", start);
|
||||
String authorityArray = overseas.substring(start, end);
|
||||
int authorityCount = count(authorityArray, "'platform:");
|
||||
int start = overseas.indexOf("VALUES ('AUTHORIZATION','1000001'");
|
||||
int end = overseas.indexOf(";", start);
|
||||
String authorityRow = overseas.substring(start, end);
|
||||
int authorityCount = count(authorityRow, "platform:");
|
||||
|
||||
assertThat(authorityCount).isPositive();
|
||||
assertThat(overseas).contains("JSON_LENGTH(authorities_json) <> " + authorityCount);
|
||||
assertThat(authorityRow).contains("baseline-platform-admin-authorization-v0");
|
||||
assertThat(overseas).doesNotContain("@platform_admin_overseas_authorities");
|
||||
}
|
||||
|
||||
@Test
|
||||
void overseasReturnOrderBackfillNormalizesLegacyColumnCollations() throws Exception {
|
||||
void overseasReturnOrdersUseTheFinalCleanSchemaWithoutLegacyBackfill() throws Exception {
|
||||
String overseas = repositoryFile("deploy/sql/海外区域统一增量-MySQL8.sql");
|
||||
|
||||
assertThat(overseas).contains(
|
||||
"o.source_order_id COLLATE utf8mb4_unicode_ci = CAST(r.id AS CHAR) COLLATE utf8mb4_unicode_ci",
|
||||
"o.source_order_no COLLATE utf8mb4_unicode_ci = r.return_no COLLATE utf8mb4_unicode_ci");
|
||||
assertThat(overseas).contains("CREATE TABLE ll_return_order (", "CREATE TABLE ll_return_order_item (")
|
||||
.doesNotContain("o.source_order_id COLLATE", "o.source_order_no COLLATE");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -122,6 +107,10 @@ class Phase5OverseasUpgradeSqlContractTest {
|
||||
private static String createStatement(String sql, String table) {
|
||||
String token = "CREATE TABLE IF NOT EXISTS " + table + " (";
|
||||
int start = sql.indexOf(token);
|
||||
if (start < 0) {
|
||||
token = "CREATE TABLE " + table + " (";
|
||||
start = sql.indexOf(token);
|
||||
}
|
||||
int end = sql.indexOf(';', start);
|
||||
assertThat(start).as(table).isGreaterThanOrEqualTo(0);
|
||||
assertThat(end).as(table).isGreaterThan(start);
|
||||
|
||||
+21
-6
@@ -25,8 +25,8 @@ class SchemaChineseCommentContractTest {
|
||||
|
||||
private static final Pattern CHINESE = Pattern.compile("[\\u4e00-\\u9fff]");
|
||||
private static final Pattern TABLE = Pattern.compile(
|
||||
"(?is)CREATE\\s+TABLE\\s+IF\\s+NOT\\s+EXISTS\\s+(ll_[a-z0-9_]+)"
|
||||
+ "\\s*\\((.*?)\\)\\s*ENGINE\\s*=\\s*InnoDB\\s+COMMENT\\s*=\\s*'([^']*)'\\s*;");
|
||||
"(?is)CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?(ll_[a-z0-9_]+)"
|
||||
+ "\\s*\\((.*?)\\)\\s*ENGINE\\s*=\\s*InnoDB[^;]*?COMMENT\\s*=\\s*'([^']*)'\\s*;");
|
||||
|
||||
@Test
|
||||
void allLastlegTablesAndColumnsHaveChineseComments() throws Exception {
|
||||
@@ -39,7 +39,7 @@ class SchemaChineseCommentContractTest {
|
||||
|
||||
List<TableDefinition> baselineTables = assertAllChineseComments(baseline, "基线 SQL", 56);
|
||||
assertAllChineseComments(incremental, "增量 SQL", 50);
|
||||
assertAllChineseComments(overseasUnified, "海外统一增量 SQL", 10);
|
||||
assertAllChineseComments(overseasUnified, "海外统一初始化 SQL", 127);
|
||||
assertCommentMigrationCovers(incremental, overseasUnified, baselineTables);
|
||||
}
|
||||
|
||||
@@ -92,7 +92,9 @@ class SchemaChineseCommentContractTest {
|
||||
for (MigrationColumn column : required) {
|
||||
assertSpecificAlterationHasChineseComment(baseline, column);
|
||||
}
|
||||
assertAllAlteredColumnsHaveChineseComments(overseasUnified, "海外统一增量 SQL");
|
||||
for (MigrationColumn column : required) {
|
||||
assertTableColumnHasChineseComment(overseasUnified, column, "海外统一初始化 SQL");
|
||||
}
|
||||
}
|
||||
|
||||
private static List<TableDefinition> assertAllChineseComments(String sql, String source, int expectedCount) {
|
||||
@@ -157,8 +159,8 @@ class SchemaChineseCommentContractTest {
|
||||
|
||||
private static boolean hasCommentedCreate(String sql, String table) {
|
||||
return Pattern.compile(
|
||||
"(?is)CREATE\\s+TABLE\\s+IF\\s+NOT\\s+EXISTS\\s+" + Pattern.quote(table)
|
||||
+ "\\s*\\(.*?\\)\\s*ENGINE\\s*=\\s*InnoDB\\s+COMMENT\\s*=\\s*'[^']*[\\u4e00-\\u9fff][^']*'\\s*;")
|
||||
"(?is)CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?" + Pattern.quote(table)
|
||||
+ "\\s*\\(.*?\\)\\s*ENGINE\\s*=\\s*InnoDB[^;]*?COMMENT\\s*=\\s*'[^']*[\\u4e00-\\u9fff][^']*'\\s*;")
|
||||
.matcher(sql).find();
|
||||
}
|
||||
|
||||
@@ -199,6 +201,19 @@ class SchemaChineseCommentContractTest {
|
||||
"字段增量缺少中文备注: " + target.table() + "." + target.column());
|
||||
}
|
||||
|
||||
private static void assertTableColumnHasChineseComment(String sql, MigrationColumn target, String source) {
|
||||
Matcher table = Pattern.compile(
|
||||
"(?is)CREATE\\s+TABLE\\s+(?:IF\\s+NOT\\s+EXISTS\\s+)?" + Pattern.quote(target.table())
|
||||
+ "\\s*\\((.*?)\\)\\s*ENGINE\\s*=\\s*InnoDB").matcher(sql);
|
||||
assertTrue(table.find(), source + " 缺少表: " + target.table());
|
||||
String definition = splitTopLevel(table.group(1)).stream()
|
||||
.filter(value -> value.stripLeading().replace("`", "").startsWith(target.column() + " "))
|
||||
.findFirst().orElse("");
|
||||
assertTrue(Pattern.compile("(?is)\\bCOMMENT\\s+'[^']*[\\u4e00-\\u9fff][^']*'")
|
||||
.matcher(definition).find(),
|
||||
source + " 字段缺少中文备注: " + target.table() + "." + target.column());
|
||||
}
|
||||
|
||||
private static void assertAllAlteredColumnsHaveChineseComments(String sql, String source) {
|
||||
Pattern pattern = Pattern.compile("(?i)\\b(?:ADD|MODIFY)\\s+COLUMN\\s+([a-z0-9_]+)\\b");
|
||||
Matcher matcher = pattern.matcher(sql);
|
||||
|
||||
+18
-4
@@ -26,8 +26,7 @@ class LastlegSecurityContractTest {
|
||||
"table_name='ll_security_projection' AND column_name='authorities_json'",
|
||||
"UPDATE ll_security_projection SET roles_json=JSON_ARRAY() WHERE roles_json IS NULL",
|
||||
"UPDATE ll_security_projection SET authorities_json=JSON_ARRAY() WHERE authorities_json IS NULL");
|
||||
for (String sql : new String[]{baseline, migration}) {
|
||||
assertThat(sql).contains("SET @platform_admin_overseas_roles = JSON_ARRAY('PLATFORM_ADMIN')",
|
||||
assertThat(baseline).contains("SET @platform_admin_overseas_roles = JSON_ARRAY('PLATFORM_ADMIN')",
|
||||
"SET @platform_admin_overseas_authorities = JSON_ARRAY(",
|
||||
"('USER','1000001',0,'ACTIVE',0,JSON_ARRAY(),JSON_ARRAY(),0",
|
||||
"('AUTHORIZATION','1000001',0,NULL,0,@platform_admin_overseas_roles,@platform_admin_overseas_authorities,0",
|
||||
@@ -42,10 +41,25 @@ class LastlegSecurityContractTest {
|
||||
"AND aggregate_version=0 AND last_event_id='baseline-platform-admin-authorization-v0'")
|
||||
.doesNotContain("('AUTHORIZATION','1000001',0,NULL,0,JSON_ARRAY(),JSON_ARRAY(),0",
|
||||
"baseline-merchant-admin");
|
||||
}
|
||||
assertThat(migration).contains(
|
||||
"CREATE TABLE ll_security_event_inbox (",
|
||||
"CREATE TABLE ll_security_projection (",
|
||||
"VALUES ('AUTHORIZATION','1000001',0,NULL,0,",
|
||||
"VALUES ('USER','1000001',0,'ACTIVE',0,'[]','[]',0",
|
||||
"PLATFORM_ADMIN",
|
||||
"baseline-platform-admin-user-v0",
|
||||
"baseline-platform-admin-authorization-v0",
|
||||
"platform:overseas-warehouse:last-mile-order:list",
|
||||
"platform:overseas-warehouse:inbound-order:list",
|
||||
"platform:overseas-warehouse:dispatch:list",
|
||||
"platform:overseas-business:purchase:list",
|
||||
"platform:overseas-master-data:quote:list",
|
||||
"platform:finance:fee-source:review")
|
||||
.doesNotContain("SET @platform_admin_overseas_roles", "UPDATE ll_security_projection",
|
||||
"baseline-merchant-admin");
|
||||
assertThat(authSeed).contains("(1000001, 'platform_admin'", "default_tenant_id",
|
||||
"default_app_code");
|
||||
assertThat(migration).contains("USE baiyue_lastleg;", "table_schema='baiyue_lastleg'")
|
||||
assertThat(migration).contains("USE baiyue_lastleg;")
|
||||
.doesNotContain("CREATE DATABASE IF NOT EXISTS baiyue_overseas_security",
|
||||
"USE baiyue_overseas_security;", "CREATE TABLE IF NOT EXISTS overseas_security_event_inbox",
|
||||
"CREATE TABLE IF NOT EXISTS overseas_security_projection");
|
||||
|
||||
+5
-3
@@ -67,9 +67,11 @@ class ContainerPlanProgressContractTest {
|
||||
assertFalse(openApi.contains("platform:overseas-warehouse:order:list"));
|
||||
assertFalse(openApi.contains("platform:overseas-warehouse:order:edit"));
|
||||
assertTrue(openApi.contains("ll_order.estimated_warehouse_at"));
|
||||
assertTrue(schema.contains("idx_ll_order_container_progress(source_container_booking_id,estimated_warehouse_at,created_at,id)"));
|
||||
assertTrue(deployment.contains("idx_ll_order_container_progress(source_container_booking_id,estimated_warehouse_at,created_at,id)"));
|
||||
assertTrue(deployment.contains("assert_container_progress_index_ready"));
|
||||
assertTrue(schema.replaceAll("\\s+", "").contains(
|
||||
"idx_ll_order_container_progress(source_container_booking_id,estimated_warehouse_at,created_at,id)"));
|
||||
assertTrue(deployment.replaceAll("\\s+", "").contains(
|
||||
"idx_ll_order_container_progress(source_container_booking_id,estimated_warehouse_at,created_at,id)"));
|
||||
assertFalse(deployment.contains("assert_container_progress_index_ready"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+15
-5
@@ -30,12 +30,22 @@ class UsTruckOrderSchemaContractTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void unifiedIncrementalContainsOperationLedgerAndHistoryColumns() throws Exception {
|
||||
void unifiedInitializationContainsOperationLedgerAndHistoryColumns() throws Exception {
|
||||
String sql = Files.readString(Path.of("..", "deploy", "sql", "海外区域统一增量-MySQL8.sql"),
|
||||
StandardCharsets.UTF_8);
|
||||
assertTrue(sql.contains("CREATE TABLE IF NOT EXISTS ll_us_truck_order_operation"));
|
||||
assertTrue(sql.contains("uk_ll_us_truck_operation_key(customer_id,order_id,idempotency_key)"));
|
||||
assertTrue(sql.contains("table_name='ll_us_truck_order_status_history' AND column_name='operation_type'"));
|
||||
assertTrue(sql.contains("table_name='ll_us_truck_order_status_history' AND column_name='idempotency_key'"));
|
||||
String lower = sql.toLowerCase();
|
||||
String normalized = lower.replaceAll("\\s+", "");
|
||||
assertTrue(lower.contains("create table ll_us_truck_order_operation"));
|
||||
assertTrue(normalized.contains("uk_ll_us_truck_operation_key(customer_id,order_id,idempotency_key)"));
|
||||
String history = tableBlock(lower, "ll_us_truck_order_status_history");
|
||||
assertTrue(history.contains("operation_type varchar(64)"));
|
||||
assertTrue(history.contains("idempotency_key varchar(255)"));
|
||||
org.junit.jupiter.api.Assertions.assertFalse(lower.contains("alter table ll_us_truck_order_status_history"));
|
||||
}
|
||||
|
||||
private static String tableBlock(String sql, String table) {
|
||||
int start = sql.indexOf("create table " + table + " (");
|
||||
int end = sql.indexOf(';', start);
|
||||
return start < 0 || end < 0 ? "" : sql.substring(start, end);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user