This commit is contained in:
2026-08-12 19:14:41 +08:00
parent af6d348ac3
commit e7dfd2790d
3 changed files with 75 additions and 0 deletions
@@ -563,6 +563,10 @@ BEGIN
IF current_plan_status = 'LOADING' AND (
NOT (OLD.id <=> NEW.id) OR NOT (OLD.booking_no <=> NEW.booking_no)
OR NOT (OLD.cabinet_no <=> NEW.cabinet_no)
OR NOT (OLD.channel_code <=> NEW.channel_code)
OR NOT (OLD.channel_name <=> NEW.channel_name)
OR NOT (OLD.ocean_booking_id <=> NEW.ocean_booking_id)
OR NOT (OLD.ocean_booking_requirement_id <=> NEW.ocean_booking_requirement_id)
OR NOT (OLD.warehouse_id <=> NEW.warehouse_id)
OR NOT (OLD.warehouse_name <=> NEW.warehouse_name)
OR NOT (OLD.bill_of_lading_no <=> NEW.bill_of_lading_no)
@@ -0,0 +1,67 @@
package com.baiyue.firstleg.repository;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.ClassPathResource;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import static org.assertj.core.api.Assertions.assertThat;
class Phase3ChannelContainerMigrationContractTest {
@Test
void moduleMigrationRestoresGuardsBeforeSurfacingFailures() throws Exception {
assertSafeWindow(moduleMigration(), false);
}
@Test
void unifiedMigrationRestoresGuardsBeforeSurfacingFailures() throws Exception {
assertSafeWindow(unifiedMigration(), true);
}
private static void assertSafeWindow(String sql, boolean qualified) {
String containerTrigger = qualified
? "CREATE TRIGGER baiyue_firstleg.trg_container_booking_before_update"
: "CREATE TRIGGER trg_container_booking_before_update";
String pickTrigger = qualified
? "CREATE TRIGGER baiyue_firstleg.trg_loading_pick_task_before_update"
: "CREATE TRIGGER trg_loading_pick_task_before_update";
int call = sql.indexOf("CALL migrate_phase3_channel_containers();");
int containerRestore = sql.indexOf(containerTrigger, call);
int pickRestore = sql.indexOf(pickTrigger, call);
int failureAssertion = sql.indexOf("CALL assert_phase3_channel_container_migration();", call);
assertThat(sql)
.contains("DECLARE EXIT HANDLER FOR SQLEXCEPTION")
.contains("GET DIAGNOSTICS CONDITION 1")
.contains("@phase3_channel_sqlstate = RETURNED_SQLSTATE")
.contains("@phase3_channel_errno = MYSQL_ERRNO")
.contains("@phase3_channel_message = MESSAGE_TEXT")
.contains("渠道柜迁移失败:货柜只读触发器未恢复")
.contains("渠道柜迁移失败:PDA任务只读触发器未恢复")
.contains("装柜完成后货柜全部只读,不允许修改")
.contains("已完成PDA拣货任务不可修改")
.contains("NOT (OLD.channel_code <=> NEW.channel_code)")
.contains("NOT (OLD.channel_name <=> NEW.channel_name)")
.contains("NOT (OLD.ocean_booking_id <=> NEW.ocean_booking_id)")
.contains("NOT (OLD.ocean_booking_requirement_id <=> NEW.ocean_booking_requirement_id)")
.doesNotContain("p.plan_status='COMPLETED'");
assertThat(call).isGreaterThan(0);
assertThat(containerRestore).isGreaterThan(call);
assertThat(pickRestore).isGreaterThan(call);
assertThat(failureAssertion).isGreaterThan(containerRestore).isGreaterThan(pickRestore);
}
private static String moduleMigration() throws Exception {
return new ClassPathResource("db/phase3-channel-container-migration.sql")
.getContentAsString(StandardCharsets.UTF_8);
}
private static String unifiedMigration() throws Exception {
Path direct = Path.of("deploy", "sql", "头程数据库统一增量-MySQL8.sql");
Path path = Files.exists(direct) ? direct : Path.of("..", "deploy", "sql", "头程数据库统一增量-MySQL8.sql");
return Files.readString(path.normalize(), StandardCharsets.UTF_8);
}
}