From 005c3f54e22e85512604eda8da40074c33ff5b73 Mon Sep 17 00:00:00 2001 From: ouyangxq <775153912@qq.com> Date: Mon, 24 Aug 2026 20:14:40 +0800 Subject: [PATCH] test: align full acceptance contracts --- deploy/sql/README.md | 2 +- deploy/sql/头程数据库统一增量-MySQL8.sql | 3 +-- .../customer-system-contract.test.mjs | 2 +- .../domestic-container-contract.test.mjs | 3 ++- .../finance-contract.test.mjs | 3 ++- .../finance-extended-fees-contract.test.mjs | 5 ++-- .../initialization-baseline-contract.test.mjs | 23 ++++++++++--------- .../manual-state-matrix-contract.test.mjs | 2 +- ...nt-qualification-fixture-contract.test.mjs | 3 ++- ...e3-loading-dynamic-final-contract.test.mjs | 2 +- 10 files changed, 26 insertions(+), 22 deletions(-) diff --git a/deploy/sql/README.md b/deploy/sql/README.md index 0946cd9df..b81a56b25 100644 --- a/deploy/sql/README.md +++ b/deploy/sql/README.md @@ -9,7 +9,7 @@ - 正式上线前的数据库变更直接维护该文件中的当前基线、存量兼容处理和最终校验,不再创建按日期拆分的发布 SQL;正式上线后的迁移策略在生产发布规范中另行冻结。 - 当前测试环境尚未上线,船期价格表相关表、字段和索引只维护在现有初始化建表定义及本固定入口中,不向 `phase1-order-extension.sql`、`phase2-fba-pricing-migration.sql` 或新的增量脚本追加同一结构。 - 模块 `src/main/resources/db/` 下的 SQL 用于开发溯源;`deploy/sql/` 下已有日期文件全部冻结为历史记录,不再单独部署,也不得与固定入口重复执行。 -- 固定入口不包含 `auth/phase1-admin-accounts.sql` 和 `warehouse/warehouse-seed.sql`,不会写入固定密码账号、演示仓库、演示快递公司或演示订单;正式平台公共仓库主数据已内联到固定入口。 +- 固定入口不包含 `auth/phase1-admin-accounts.sql` 和 `warehouse/warehouse-seed.sql`;仅在开发/测试基线账号缺失时创建最小登录账号,重复执行不覆盖现有密码。脚本不写入演示订单;正式平台公共仓库主数据已内联到固定入口。 - `warehouse/phase2-pallet-location-schema-migration.sql` 的有效结构已被当前 `phase2-pallet-location-schema.sql` 和后续共享溢出位迁移完整覆盖,因此不重复内联,避免每次部署无条件删除并重建同名唯一索引。 - 脚本会创建 9 个独立数据库:`baiyue_auth`、`baiyue_iam`、`baiyue_order`、`baiyue_warehouse`、`baiyue_firstleg`、`baiyue_file`、`baiyue_audit`、`baiyue_event_bridge`、`baiyue_finance`。Gateway、Print、Integration Service 无数据库。 - IAM 消息中心基线已内联到固定入口,包括 5 张 `iam_notification_*` 表、任务/事件幂等约束、平台消息管理权限、企业成员收件箱权限及默认角色授权;模块溯源脚本为 `iam/src/main/resources/db/notification-center.sql`。 diff --git a/deploy/sql/头程数据库统一增量-MySQL8.sql b/deploy/sql/头程数据库统一增量-MySQL8.sql index ccc7e9bf0..f29c7ed49 100644 --- a/deploy/sql/头程数据库统一增量-MySQL8.sql +++ b/deploy/sql/头程数据库统一增量-MySQL8.sql @@ -244,7 +244,7 @@ EXECUTE auth_password_change_required_stmt; DEALLOCATE PREPARE auth_password_change_required_stmt; -- 开发/测试环境最小登录基线:一个平台系统管理员和一个 IT 测试客户管理员。 --- 初始密码统一为 ChangeMe123!;只保存 BCrypt 哈希,不写入明文。 +-- 缺失账号首次创建时写入开发基线 BCrypt 哈希;重复执行统一增量绝不覆盖现有密码。 INSERT INTO auth_account ( id, username, password_hash, display_name, account_status, failed_login_count, token_version, password_change_required, default_tenant_id, @@ -255,7 +255,6 @@ INSERT INTO auth_account ( (1000002, 'merchant_admin', '$2a$12$AMZJjd88leYPLI9uKvjZiew2CTQXI32BXoHFX.FrCi28/IeZ7mZ96', 'IT 测试客户管理员', 'ACTIVE', 0, 1, 0, 10001, 10001, 3000002, 'MERCHANT', 0) ON DUPLICATE KEY UPDATE - password_hash = VALUES(password_hash), display_name = VALUES(display_name), account_status = 'ACTIVE', failed_login_count = 0, diff --git a/scripts/admin-test-env-modules/customer-system-contract.test.mjs b/scripts/admin-test-env-modules/customer-system-contract.test.mjs index f1d57e6a2..64527c588 100644 --- a/scripts/admin-test-env-modules/customer-system-contract.test.mjs +++ b/scripts/admin-test-env-modules/customer-system-contract.test.mjs @@ -58,7 +58,7 @@ test('客户详情经营统计模块登记三项独立正式接口与精度字 test('后端统计契约测试覆盖客户详情已确认边界口径', () => { for (const marker of ["order_role = 'master'", 'submitted_at is not null', 'monthstart', 'nextmonthstart', 'doesNotContain\\\("status ="\\\)']) assert.match(orderStatisticsTest, new RegExp(marker, 'i')) for (const marker of ['VOIDED', 'totalReceivable', 'receivedAmount', 'outstandingReceivable']) assert.match(financeStatisticsTest, new RegExp(marker, 'i')) - for (const marker of ['actual_sailing_at', 'actual_warehouse_arrival_at', 'CANCELLED', 'FAILED', '20\\*=1', '40\\*=2', '45\\*=2.25', '2.25', 'unknown']) assert.match(transitStatisticsTest, new RegExp(marker, 'i')) + for (const marker of ['actual_sailing_at', 'actual_warehouse_arrival_at', 'CANCELLED', 'NOT EXISTS', '20\\*=1', '40\\*=2', '45\\*=2.25', '2.25', 'unknown']) assert.match(transitStatisticsTest, new RegExp(marker, 'i')) assert.match(orderStatisticsTest, /tenant_id|tenantSubmittedStatistics/) assert.match(financeStatisticsTest, /customerId|customer_id/) assert.match(transitStatisticsTest, /customerId|customer_id/) diff --git a/scripts/admin-test-env-modules/domestic-container-contract.test.mjs b/scripts/admin-test-env-modules/domestic-container-contract.test.mjs index 33561fdcc..510f78a85 100644 --- a/scripts/admin-test-env-modules/domestic-container-contract.test.mjs +++ b/scripts/admin-test-env-modules/domestic-container-contract.test.mjs @@ -16,7 +16,8 @@ test('国内整柜模块仅由总编排注入 context 后执行', () => { }) test('正式全量验收默认注册国内整柜模块', () => { - assert.match(acceptance, /DEFAULT_MODULES\s*=\s*\[[^\]]*['"]domestic-container['"]/s) + assert.match(acceptance, /CONFIGURED_MODULES\s*=\s*\[[^\]]*['"]domestic-container['"]/s) + assert.match(acceptance, /DEFAULT_MODULES\s*=\s*normalizeModuleOrder\(CONFIGURED_MODULES\)/) }) test('覆盖国内仓、待单、完成入库、部分和全部出库及列表详情流水', () => { diff --git a/scripts/admin-test-env-modules/finance-contract.test.mjs b/scripts/admin-test-env-modules/finance-contract.test.mjs index 29d60e523..8580fde43 100644 --- a/scripts/admin-test-env-modules/finance-contract.test.mjs +++ b/scripts/admin-test-env-modules/finance-contract.test.mjs @@ -9,7 +9,8 @@ const acceptance = fs.readFileSync(path.join(here, '..', 'admin-test-env-accepta const finance = fs.readFileSync(path.join(here, 'finance.mjs'), 'utf8') test('正式全量验收默认包含 Finance 模块', () => { - assert.match(acceptance, /DEFAULT_MODULES\s*=\s*\[[\s\S]*['"]finance['"]/) + assert.match(acceptance, /CONFIGURED_MODULES\s*=\s*\[[\s\S]*['"]finance['"]/) + assert.match(acceptance, /DEFAULT_MODULES\s*=\s*normalizeModuleOrder\(CONFIGURED_MODULES\)/) }) test('验收请求器支持并透传额外请求头', () => { diff --git a/scripts/admin-test-env-modules/finance-extended-fees-contract.test.mjs b/scripts/admin-test-env-modules/finance-extended-fees-contract.test.mjs index f07805750..6eb694b53 100644 --- a/scripts/admin-test-env-modules/finance-extended-fees-contract.test.mjs +++ b/scripts/admin-test-env-modules/finance-extended-fees-contract.test.mjs @@ -46,7 +46,8 @@ test('writes carry marker idempotency and include replay and stale-version confl assert.match(source, /错误 sourceVersion 调整产生并发版本冲突/) }) -test('uses existing ACTIVE Warehouse supplier and never creates one', () => { - assert.match(source, /\/api\/platform\/v1\/suppliers\?page=1&size=200&status=ACTIVE&category=BOOKING/) +test('uses the fee item supplier category to select an existing ACTIVE supplier and never creates one', () => { + assert.match(source, /\/api\/platform\/v1\/suppliers\?page=1&size=200&status=ACTIVE\$\{suffix\}/) + assert.match(source, /const supplier = await loadActiveSupplier\(context, payableItem\?\.supplierCategory \|\| null\)/) assert.doesNotMatch(source, /\/api\/platform\/v1\/partners/) }) diff --git a/scripts/admin-test-env-modules/initialization-baseline-contract.test.mjs b/scripts/admin-test-env-modules/initialization-baseline-contract.test.mjs index 2b30d9a18..746730c2a 100644 --- a/scripts/admin-test-env-modules/initialization-baseline-contract.test.mjs +++ b/scripts/admin-test-env-modules/initialization-baseline-contract.test.mjs @@ -12,6 +12,10 @@ test('统一初始化 SQL 保留最小登录与客户主体', () => { assert.equal((sql.match(/'platform_admin'/g) || []).length, 1) assert.equal((sql.match(/'merchant_admin'/g) || []).length, 1) assert.match(sql, /\(10001, 'IT_TEST', 'IT 测试客户'/) + const accountSeed = sql.match(/INSERT INTO auth_account \([\s\S]*?deleted = 0;/)?.[0] + assert.ok(accountSeed, 'missing auth account seed') + assert.doesNotMatch(accountSeed, /ON DUPLICATE KEY UPDATE[\s\S]*?password_hash\s*=/, + 're-running the unified SQL must not reset an existing account password') }) test('IT 测试客户初始化后具备已审核的必填资质和下单资格', () => { @@ -34,25 +38,22 @@ test('统一初始化 SQL 提供人工验收所需公共仓储主数据', () => assert.doesNotMatch(palletSeed, /\bstatus\b|'AVAILABLE'/) }) -test('三期权限迁移允许脚本历史版本写入的旧权限并在随后收敛', () => { +test('三期权限迁移删除退役权限并只保留 canonical 权限', () => { for (const source of [sql, oceanBookingSchema]) { - assert.match(source, /id = 5102141[\s\S]*?ocean-booking:view/) - assert.match(source, /id = 5102147[\s\S]*?ocean-booking:cancel[\s\S]*?ocean-booking:edit/) - assert.match(source, /id = 5102148[\s\S]*?ocean-booking:change[\s\S]*?ocean-booking:delete/) - assert.match(source, /SET permission_code='platform:firstleg:ocean-booking:view',status='INACTIVE',deleted=1/) - assert.match(source, /UPDATE iam_permission SET status='INACTIVE',deleted=1 WHERE id=5102141/) - assert.match(source, /DELETE FROM iam_permission WHERE id IN \(5102143,5102144,5102145\)/) + assert.match(source, /DELETE FROM iam_permission WHERE id IN \(5102141,5102143,5102144,5102145\)/) + assert.match(source, /5102147[\s\S]*?platform:firstleg:ocean-booking:edit/) + assert.match(source, /5102148[\s\S]*?platform:firstleg:ocean-booking:delete/) + assert.doesNotMatch(source, /platform:firstleg:ocean-booking:(view|cancel|change)/) assert.ok( - source.indexOf('DELETE FROM iam_permission WHERE id IN (5102143,5102144,5102145)') < + source.indexOf('DELETE FROM iam_permission WHERE id IN (5102141,5102143,5102144,5102145)') < source.indexOf('(5102147,0,\'PLATFORM\',\'BUTTON\',5102140,\'platform:firstleg:ocean-booking:edit\''), 'legacy ocean-booking edit permission must be removed before assigning the code to 5102147', ) } for (const source of [sql, truckAppointmentSchema]) { - assert.match(source, /id = 5102151[\s\S]*?truck-appointment:view/) - assert.match(source, /SET permission_code='platform:firstleg:truck-appointment:view',status='INACTIVE',deleted=1/) - assert.match(source, /UPDATE iam_permission SET status='INACTIVE',deleted=1 WHERE id=5102151/) + assert.match(source, /DELETE FROM iam_permission WHERE id=5102151/) + assert.doesNotMatch(source, /platform:firstleg:truck-appointment:view[',]/) } assert.match(sql, /status='ACTIVE' AND deleted=0[\s\S]*?id BETWEEN 5102140 AND 5102149/) diff --git a/scripts/admin-test-env-modules/manual-state-matrix-contract.test.mjs b/scripts/admin-test-env-modules/manual-state-matrix-contract.test.mjs index 096592364..5f7455aa8 100644 --- a/scripts/admin-test-env-modules/manual-state-matrix-contract.test.mjs +++ b/scripts/admin-test-env-modules/manual-state-matrix-contract.test.mjs @@ -35,9 +35,9 @@ test('focused splitting and manual groups resolve producers before consumers wit 'merchant-qualification-fixture', 'phase3-container-loading', 'phase3-loading', - 'phase3-order-splitting', 'ocean-bookings', 'phase3-loading-finalize', + 'phase3-order-splitting', 'phase3-customs', 'manual-state-matrix', ] diff --git a/scripts/admin-test-env-modules/merchant-qualification-fixture-contract.test.mjs b/scripts/admin-test-env-modules/merchant-qualification-fixture-contract.test.mjs index 4da2e138d..8d080ea93 100644 --- a/scripts/admin-test-env-modules/merchant-qualification-fixture-contract.test.mjs +++ b/scripts/admin-test-env-modules/merchant-qualification-fixture-contract.test.mjs @@ -6,9 +6,10 @@ const acceptance = readFileSync(new URL('../admin-test-env-acceptance.mjs', impo const fixture = readFileSync(new URL('./merchant-qualification-fixture.mjs', import.meta.url), 'utf8') test('默认全量验收先准备已审核商户再运行订单链路', () => { - const modules = acceptance.match(/const DEFAULT_MODULES = \[([^\n]+)\]/)?.[1] || '' + const modules = acceptance.match(/const CONFIGURED_MODULES = \[([^\n]+)\]/)?.[1] || '' assert.match(modules, /^'merchant-qualification-fixture', 'customers'/) assert.ok(modules.indexOf("'merchant-qualification-fixture'") < modules.indexOf("'orders'")) + assert.match(acceptance, /DEFAULT_MODULES\s*=\s*normalizeModuleOrder\(CONFIGURED_MODULES\)/) }) test('商户夹具通过正式 File 和 IAM 审核流程建立下单资格', () => { diff --git a/scripts/admin-test-env-modules/phase3-loading-dynamic-final-contract.test.mjs b/scripts/admin-test-env-modules/phase3-loading-dynamic-final-contract.test.mjs index c48a31309..8e604f641 100644 --- a/scripts/admin-test-env-modules/phase3-loading-dynamic-final-contract.test.mjs +++ b/scripts/admin-test-env-modules/phase3-loading-dynamic-final-contract.test.mjs @@ -41,7 +41,7 @@ test('OpenAPI freezes LOADING incremental plan capabilities and optimistic versi }) test('default fixture publishes a second marker-owned inbound for the same-plan increment', () => { - assert.match(entry, /const incrementalMarker = `\$\{originalMarker\}-LOAD-INC`/) + assert.match(entry, /const incrementalMarker = `\$\{originalMarker\}-LOAD\$\{suffix\}-INC`/) assert.match(entry, /orders-phase3-loading-incremental-fixture/) assert.match(entry, /inbound-measurement-phase3-loading-incremental-fixture/) assert.match(entry, /phase3LoadingIncrementalPackageCount = 2/)