From 5c63604b5b820871fc10458c558a8c365014e049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E8=87=AA=E8=BE=BE?= <980324341@qq.com> Date: Sat, 5 Sep 2026 00:09:37 +0800 Subject: [PATCH] =?UTF-8?q?task-201:=20=E8=BF=81=E7=A7=BB=E6=BC=94?= =?UTF-8?q?=E7=BB=83=20runbook=EF=BC=88docs/flyway-migration-drill.md?= =?UTF-8?q?=EF=BC=9Aclean=20migrate/validate/=E9=AA=8C=E8=AF=81SQL/?= =?UTF-8?q?=E5=9B=9E=E6=BB=9A/=E9=94=81=E7=AA=97=E5=8F=A3/=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E5=92=8C/=E5=B9=82=E7=AD=89=E9=87=8D=E8=B7=91/?= =?UTF-8?q?=E4=B8=8D=E5=8A=A8=E5=8E=86=E5=8F=B2=EF=BC=89+=208=20=E6=9D=A1?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit on-DB 的 migrate 执行需在副本库按 runbook 进行(本环境无数据库,仓库内以静态检查+清单兜底) --- .../config/FlywayMigrationDrillDocTest.java | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 backend-java/src/test/java/com/nanri/aiimage/config/FlywayMigrationDrillDocTest.java diff --git a/backend-java/src/test/java/com/nanri/aiimage/config/FlywayMigrationDrillDocTest.java b/backend-java/src/test/java/com/nanri/aiimage/config/FlywayMigrationDrillDocTest.java new file mode 100644 index 00000000..da6f9306 --- /dev/null +++ b/backend-java/src/test/java/com/nanri/aiimage/config/FlywayMigrationDrillDocTest.java @@ -0,0 +1,66 @@ +package com.nanri.aiimage.config; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * task-201:迁移演练 runbook 契约。 + * docs/flyway-migration-drill.md 固化演练步骤:干净迁移/validate/验证 SQL/回滚/锁窗口/校验和/ + * 幂等重跑/不动历史;on-DB 步骤由运维在副本库按 runbook 执行(本环境无库)。 + */ +class FlywayMigrationDrillDocTest { + + private static final String DOC = "docs/flyway-migration-drill.md"; + + private String doc() throws IOException { + return Files.readString(Path.of(System.getProperty("user.dir"), DOC)); + } + + @Test + void drillDocExists() { + assertTrue(Files.exists(Path.of(System.getProperty("user.dir"), DOC)), "演练 runbook 应存在"); + } + + @Test + void cleanMigrateStepDescribed() throws IOException { + assertTrue(doc().contains("migrate"), "应描述干净迁移步骤"); + } + + @Test + void validateStepDescribed() throws IOException { + assertTrue(doc().contains("validate"), "应包含 validate 校验历史 checksum 步骤"); + } + + @Test + void validationSqlStepDescribed() throws IOException { + assertTrue(doc().contains("验证 SQL"), "应包含验证 SQL 步骤"); + } + + @Test + void rollbackStepDescribed() throws IOException { + assertTrue(doc().contains("回滚"), "应包含回滚验证步骤"); + } + + @Test + void lockWindowEstimatedStepDescribed() throws IOException { + assertTrue(doc().contains("锁窗口"), "应包含锁窗口估算步骤"); + } + + @Test + void checksumAndIdempotentRerunDescribed() throws IOException { + String text = doc(); + assertTrue(text.contains("checksum") || text.contains("校验和"), "应包含校验和检查"); + assertTrue(text.contains("幂等重跑") || text.contains("idempotent"), "应包含幂等重跑"); + } + + @Test + void noLegacyTouchGuarded() throws IOException { + assertTrue(doc().contains("历史") && (doc().contains("未被动") || doc().contains("未被改动")), + "应明确演练不动历史迁移"); + } +}