优化
This commit is contained in:
@@ -15,8 +15,8 @@ COMPOSE_FILE="$6"
|
|||||||
BASE_PROJECT="$7"
|
BASE_PROJECT="$7"
|
||||||
|
|
||||||
case "$DEPLOY_ENV" in
|
case "$DEPLOY_ENV" in
|
||||||
production) ;;
|
test|production) ;;
|
||||||
*) echo "蓝绿执行器仅用于 production,当前: $DEPLOY_ENV" >&2; exit 2 ;;
|
*) echo "蓝绿执行器仅用于 test/production,当前: $DEPLOY_ENV" >&2; exit 2 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
for file in "$ENV_FILE" "$COMPOSE_FILE"; do
|
for file in "$ENV_FILE" "$COMPOSE_FILE"; do
|
||||||
@@ -224,6 +224,10 @@ bootstrap_legacy_routes() {
|
|||||||
|
|
||||||
switch_gateway_proxy() {
|
switch_gateway_proxy() {
|
||||||
[ "$SERVICE" = "gateway" ] || [ "$SERVICE" = "gateway-overseas" ] || return 0
|
[ "$SERVICE" = "gateway" ] || [ "$SERVICE" = "gateway-overseas" ] || return 0
|
||||||
|
if [ "$DEPLOY_ENV" = test ]; then
|
||||||
|
echo "测试 Gateway 仍由固定入口承载,不在后端蓝绿执行器中切换" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
if [ "$SERVICE" = "gateway" ]; then required_alias=gateway-active; else required_alias=gateway-overseas-active; fi
|
if [ "$SERVICE" = "gateway" ]; then required_alias=gateway-active; else required_alias=gateway-overseas-active; fi
|
||||||
for frontend_service in admin-web client-web; do
|
for frontend_service in admin-web client-web; do
|
||||||
frontend_state="$STATE_ROOT/frontend-$frontend_service.active"
|
frontend_state="$STATE_ROOT/frontend-$frontend_service.active"
|
||||||
@@ -267,6 +271,7 @@ switch_gateway_proxy() {
|
|||||||
|
|
||||||
reload_frontend_proxies() {
|
reload_frontend_proxies() {
|
||||||
[ "$SERVICE" = "gateway" ] || [ "$SERVICE" = "gateway-overseas" ] || return 0
|
[ "$SERVICE" = "gateway" ] || [ "$SERVICE" = "gateway-overseas" ] || return 0
|
||||||
|
[ "$DEPLOY_ENV" = production ] || return 0
|
||||||
for frontend_service in admin-web client-web; do
|
for frontend_service in admin-web client-web; do
|
||||||
frontend_state="$STATE_ROOT/frontend-$frontend_service.active"
|
frontend_state="$STATE_ROOT/frontend-$frontend_service.active"
|
||||||
[ -s "$frontend_state" ] || return 1
|
[ -s "$frontend_state" ] || return 1
|
||||||
@@ -279,6 +284,7 @@ reload_frontend_proxies() {
|
|||||||
|
|
||||||
rollback_gateway_proxy() {
|
rollback_gateway_proxy() {
|
||||||
[ "$SERVICE" = "gateway" ] || [ "$SERVICE" = "gateway-overseas" ] || return 0
|
[ "$SERVICE" = "gateway" ] || [ "$SERVICE" = "gateway-overseas" ] || return 0
|
||||||
|
[ "$DEPLOY_ENV" = production ] || return 0
|
||||||
if [ "$SERVICE" = "gateway" ]; then
|
if [ "$SERVICE" = "gateway" ]; then
|
||||||
config="$(env_value GATEWAY_BLUE_GREEN_NGINX_CONFIG)"
|
config="$(env_value GATEWAY_BLUE_GREEN_NGINX_CONFIG)"
|
||||||
config="${config:-/www/server/panel/vhost/nginx/api-cn.buggoglobal.com.conf}"
|
config="${config:-/www/server/panel/vhost/nginx/api-cn.buggoglobal.com.conf}"
|
||||||
|
|||||||
@@ -348,7 +348,8 @@ deploy_local() {
|
|||||||
|
|
||||||
if [ "${TARGET_IS_LOCAL:-false}" = "true" ]; then
|
if [ "${TARGET_IS_LOCAL:-false}" = "true" ]; then
|
||||||
echo "镜像已在目标服务器本机,直接部署: $IMAGE"
|
echo "镜像已在目标服务器本机,直接部署: $IMAGE"
|
||||||
if [ "$DEPLOY_ENV" = "production" ]; then
|
if [ "$DEPLOY_ENV" = "production" ] \
|
||||||
|
|| { [ "$DEPLOY_ENV" = "test" ] && [ "$SERVICE" != "gateway" ] && [ "$SERVICE" != "gateway-overseas" ]; }; then
|
||||||
printf '%s' "$REGISTRY_PASSWORD" | docker login -u "$REGISTRY_USER" --password-stdin "$REGISTRY_HOST"
|
printf '%s' "$REGISTRY_PASSWORD" | docker login -u "$REGISTRY_USER" --password-stdin "$REGISTRY_HOST"
|
||||||
trap local_registry_logout EXIT HUP INT TERM
|
trap local_registry_logout EXIT HUP INT TERM
|
||||||
docker pull "$IMAGE"
|
docker pull "$IMAGE"
|
||||||
@@ -432,8 +433,9 @@ printf '%s' "$REGISTRY_PASSWORD" | run_ssh docker login -u "$REGISTRY_USER" --pa
|
|||||||
trap remote_registry_logout EXIT HUP INT TERM
|
trap remote_registry_logout EXIT HUP INT TERM
|
||||||
run_ssh docker pull "$IMAGE"
|
run_ssh docker pull "$IMAGE"
|
||||||
|
|
||||||
if [ "$DEPLOY_ENV" = "production" ]; then
|
if [ "$DEPLOY_ENV" = "production" ] \
|
||||||
echo "生产服务使用蓝绿执行器,旧实例在候选槽健康前保持运行"
|
|| { [ "$DEPLOY_ENV" = "test" ] && [ "$SERVICE" != "gateway" ] && [ "$SERVICE" != "gateway-overseas" ]; }; then
|
||||||
|
echo "$DEPLOY_ENV 服务使用蓝绿执行器,旧实例在候选槽健康前保持运行"
|
||||||
run_ssh sh "$REMOTE_DIR/$REMOTE_BLUE_GREEN_NAME" \
|
run_ssh sh "$REMOTE_DIR/$REMOTE_BLUE_GREEN_NAME" \
|
||||||
"$DEPLOY_ENV" "$IMAGE_REPOSITORY" "$IMAGE_TAG" "$SERVICE" \
|
"$DEPLOY_ENV" "$IMAGE_REPOSITORY" "$IMAGE_TAG" "$SERVICE" \
|
||||||
"$REMOTE_DIR/$REMOTE_ENV_NAME" "$REMOTE_DIR/$REMOTE_COMPOSE_NAME" "$PROJECT_NAME"
|
"$REMOTE_DIR/$REMOTE_ENV_NAME" "$REMOTE_DIR/$REMOTE_COMPOSE_NAME" "$PROJECT_NAME"
|
||||||
|
|||||||
@@ -188,13 +188,18 @@ if [ "$DEPLOY_ENV" = "development" ]; then
|
|||||||
"$IMAGE_REPOSITORY" "$IMAGE_TAG" "$SERVICE_CSV" "$ENV_FILE"
|
"$IMAGE_REPOSITORY" "$IMAGE_TAG" "$SERVICE_CSV" "$ENV_FILE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$DEPLOY_ENV" = "production" ]; then
|
if [ "$DEPLOY_ENV" = "test" ] || [ "$DEPLOY_ENV" = "production" ]; then
|
||||||
docker compose \
|
docker compose \
|
||||||
--project-name "$PROJECT_NAME" \
|
--project-name "$PROJECT_NAME" \
|
||||||
--env-file "$ENV_FILE" \
|
--env-file "$ENV_FILE" \
|
||||||
-f "$COMPOSE_FILE" \
|
-f "$COMPOSE_FILE" \
|
||||||
pull $SERVICES
|
pull $SERVICES
|
||||||
for service in $SERVICES; do
|
for service in $SERVICES; do
|
||||||
|
if [ "$DEPLOY_ENV" = test ] && { [ "$service" = gateway ] || [ "$service" = gateway-overseas ]; }; then
|
||||||
|
docker compose --project-name "$PROJECT_NAME" --env-file "$ENV_FILE" -f "$COMPOSE_FILE" \
|
||||||
|
up -d --no-deps --pull never "$service"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
sh deploy/scripts/deploy-blue-green-service.sh \
|
sh deploy/scripts/deploy-blue-green-service.sh \
|
||||||
"$DEPLOY_ENV" "$IMAGE_REPOSITORY" "$IMAGE_TAG" "$service" "$ENV_FILE" "$COMPOSE_FILE" "$PROJECT_NAME"
|
"$DEPLOY_ENV" "$IMAGE_REPOSITORY" "$IMAGE_TAG" "$service" "$ENV_FILE" "$COMPOSE_FILE" "$PROJECT_NAME"
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -40,7 +40,8 @@ test('booking supplier fixtures keep ACTIVE and BOOKING but never invent a geogr
|
|||||||
financeFixture.indexOf('async function createOrder'))
|
financeFixture.indexOf('async function createOrder'))
|
||||||
assert.match(supplierBody, /category,/)
|
assert.match(supplierBody, /category,/)
|
||||||
assert.match(supplierBody, /status: 'ACTIVE'/)
|
assert.match(supplierBody, /status: 'ACTIVE'/)
|
||||||
assert.doesNotMatch(supplierBody, /scope|DOMESTIC|INTERNATIONAL/)
|
assert.match(supplierBody, /truckingScope: category === 'TRUCKING' \? 'DOMESTIC' : null/)
|
||||||
|
assert.doesNotMatch(supplierBody, /bookingScope|category === 'BOOKING' \? 'DOMESTIC'/)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('Warehouse supplier contract filters by active category without scope in query, save or snapshot', () => {
|
test('Warehouse supplier contract filters by active category without scope in query, save or snapshot', () => {
|
||||||
@@ -54,7 +55,9 @@ test('Firstleg booking supplier snapshot requires ACTIVE BOOKING and has no dome
|
|||||||
assert.match(firstlegSnapshot, /return resolve\(supplierId, suppliedName, "BOOKING"\)/)
|
assert.match(firstlegSnapshot, /return resolve\(supplierId, suppliedName, "BOOKING"\)/)
|
||||||
assert.match(firstlegSnapshot, /!"ACTIVE"\.equals\(response\.data\(\)\.status\(\)\)/)
|
assert.match(firstlegSnapshot, /!"ACTIVE"\.equals\(response\.data\(\)\.status\(\)\)/)
|
||||||
assert.match(firstlegSnapshot, /!category\.equals\(response\.data\(\)\.category\(\)\)/)
|
assert.match(firstlegSnapshot, /!category\.equals\(response\.data\(\)\.category\(\)\)/)
|
||||||
assert.doesNotMatch(firstlegSnapshot, /"INTERNATIONAL"|"DOMESTIC"|String scope/)
|
const bookingBlock = firstlegSnapshot.slice(firstlegSnapshot.indexOf('public WarehouseSupplierClient.Snapshot booking('),
|
||||||
|
firstlegSnapshot.indexOf('public WarehouseSupplierClient.Snapshot domesticTrucking('))
|
||||||
|
assert.doesNotMatch(bookingBlock, /"INTERNATIONAL"|"DOMESTIC"|String scope/)
|
||||||
assert.doesNotMatch(firstlegClient, /String scope|String category,\s*String scope/s)
|
assert.doesNotMatch(firstlegClient, /String scope|String category,\s*String scope/s)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -88,10 +91,10 @@ test('supplier DTO, service and HTTP acceptance freeze normalized multi-carrier
|
|||||||
|
|
||||||
test('normalized relation table and lookup index exist in module baseline and unified SQL', () => {
|
test('normalized relation table and lookup index exist in module baseline and unified SQL', () => {
|
||||||
for (const sql of [supplierSchema, unifiedSql]) {
|
for (const sql of [supplierSchema, unifiedSql]) {
|
||||||
assert.match(sql, /CREATE TABLE IF NOT EXISTS wh_supplier_carrier/)
|
assert.match(sql, /CREATE TABLE(?: IF NOT EXISTS)? wh_supplier_carrier/)
|
||||||
assert.match(sql, /PRIMARY KEY\s*\(?\s*supplier_id\s*,\s*carrier_code\s*\)?/i)
|
assert.match(sql, /PRIMARY KEY\s*\(?\s*supplier_id\s*,\s*carrier_code\s*\)?/i)
|
||||||
assert.match(sql, /idx_wh_supplier_carrier_code\s*\(?\s*tenant_id\s*,\s*carrier_code\s*,\s*supplier_id\s*\)?/i)
|
assert.match(sql, /idx_wh_supplier_carrier_code\s*\(?\s*tenant_id\s*,\s*carrier_code\s*,\s*supplier_id\s*\)?/i)
|
||||||
assert.match(sql, /carrier_code IN\s*\(?\s*'MATSON'\s*,\s*'SML'\s*,\s*'ZIM'\s*,\s*'COSCO'\s*,\s*'EMC'\s*,\s*'HEDE'\s*,\s*'OTHER'\s*\)?/i)
|
assert.match(sql, /carrier_code IN\s*\(?\s*(?:_utf8mb4)?'MATSON'\s*,\s*(?:_utf8mb4)?'SML'\s*,\s*(?:_utf8mb4)?'ZIM'\s*,\s*(?:_utf8mb4)?'COSCO'\s*,\s*(?:_utf8mb4)?'EMC'\s*,\s*(?:_utf8mb4)?'HEDE'\s*,\s*(?:_utf8mb4)?'OTHER'\s*\)?/i)
|
||||||
}
|
}
|
||||||
assert.match(supplierMapper, /FROM wh_supplier_carrier[\s\S]*tenant_id=#\{tenantId\} AND carrier_code=#\{carrierCode\}/)
|
assert.match(supplierMapper, /FROM wh_supplier_carrier[\s\S]*tenant_id=#\{tenantId\} AND carrier_code=#\{carrierCode\}/)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const domesticSchemas = ['baiyue_auth', 'baiyue_iam', 'baiyue_order', 'baiyue_wa
|
|||||||
const overseasSchemas = ['baiyue_event_bridge_overseas', 'baiyue_lastleg', 'baiyue_lastlag_warehouse']
|
const overseasSchemas = ['baiyue_event_bridge_overseas', 'baiyue_lastleg', 'baiyue_lastlag_warehouse']
|
||||||
|
|
||||||
test('两个入口分别只操作国内九库与海外三库,包括限定名引用', () => {
|
test('两个入口分别只操作国内九库与海外三库,包括限定名引用', () => {
|
||||||
for (const [sql, allowed, other, count] of [[cn, domesticSchemas, overseasSchemas, 208], [overseas, overseasSchemas, domesticSchemas, 138]]) {
|
for (const [sql, allowed, other, count] of [[cn, domesticSchemas, overseasSchemas, 210], [overseas, overseasSchemas, domesticSchemas, 138]]) {
|
||||||
assert.deepEqual([...sql.matchAll(/^CREATE DATABASE IF NOT EXISTS (\w+)/gm)].map(m => m[1]), allowed)
|
assert.deepEqual([...sql.matchAll(/^CREATE DATABASE IF NOT EXISTS (\w+)/gm)].map(m => m[1]), allowed)
|
||||||
assert.deepEqual([...new Set([...sql.matchAll(/^USE (\w+);/gm)].map(m => m[1]))], allowed)
|
assert.deepEqual([...new Set([...sql.matchAll(/^USE (\w+);/gm)].map(m => m[1]))], allowed)
|
||||||
const body = sql.replace(/^--.*$/gm, '')
|
const body = sql.replace(/^--.*$/gm, '')
|
||||||
@@ -28,7 +28,7 @@ test('纯初始化禁止迁移、数据回填、清理、重复建表和提前
|
|||||||
assert.doesNotMatch(body.replace(/^CREATE TRIGGER [\s\S]*?\$\$/gm, ''), /^\s*(?:UPDATE|DELETE FROM|REPLACE INTO)\b/gmi)
|
assert.doesNotMatch(body.replace(/^CREATE TRIGGER [\s\S]*?\$\$/gm, ''), /^\s*(?:UPDATE|DELETE FROM|REPLACE INTO)\b/gmi)
|
||||||
assert.doesNotMatch(body, /CREATE TABLE IF NOT EXISTS/i)
|
assert.doesNotMatch(body, /CREATE TABLE IF NOT EXISTS/i)
|
||||||
assert.equal((body.match(/AS initialization_status/g) ?? []).length, 1)
|
assert.equal((body.match(/AS initialization_status/g) ?? []).length, 1)
|
||||||
assert.match(body.trim(), /SELECT 'PASS' AS initialization_status, '(CN|OVERSEAS)' AS region, (208|138) AS initialized_tables;$/)
|
assert.match(body.trim(), /SELECT 'PASS' AS initialization_status, '(CN|OVERSEAS)' AS region, (210|138) AS initialized_tables;$/)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ test('平台管理员由外部bcrypt引导,强制首登改密且不创建客
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('必要系统种子完整保留,但不写入示例资源与业务事实', () => {
|
test('必要系统种子完整保留,但不写入示例资源与业务事实', () => {
|
||||||
for (const [name, count] of Object.entries({ iam_role: 8, iam_permission: 364, iam_role_permission: 539,
|
for (const [name, count] of Object.entries({ iam_role: 8, iam_permission: 367, iam_role_permission: 543,
|
||||||
iam_data_scope: 7, wh_warehouse: 318, wh_warehouse_address: 318, wh_service_capability: 4,
|
iam_data_scope: 7, wh_warehouse: 318, wh_warehouse_address: 318, wh_service_capability: 4,
|
||||||
fl_fee_item: 112, fl_price_channel_catalog: 15, fl_price_origin_alias: 7, fl_price_warehouse_mapping: 4,
|
fl_fee_item: 112, fl_price_channel_catalog: 15, fl_price_origin_alias: 7, fl_price_warehouse_mapping: 4,
|
||||||
file_export_task_guard: 1, fin_subject: 1 })) assert.equal(seedRows(cn, name).length, count, name)
|
file_export_task_guard: 1, fin_subject: 1 })) assert.equal(seedRows(cn, name).length, count, name)
|
||||||
|
|||||||
+3
-3
@@ -58,12 +58,12 @@ test('completion operation has durable PROCESSING and terminal response state',
|
|||||||
assert.match(completionCommand, /nextRetryAt/)
|
assert.match(completionCommand, /nextRetryAt/)
|
||||||
assert.match(completionCommand, /completedAt/)
|
assert.match(completionCommand, /completedAt/)
|
||||||
assert.match(completionCommand, /failureStage/)
|
assert.match(completionCommand, /failureStage/)
|
||||||
const commandTable = unifiedSql.slice(unifiedSql.indexOf('CREATE TABLE IF NOT EXISTS fl_loading_completion_command'),
|
const commandStart = unifiedSql.search(/CREATE TABLE(?: IF NOT EXISTS)? fl_loading_completion_command/)
|
||||||
unifiedSql.indexOf(';', unifiedSql.indexOf('CREATE TABLE IF NOT EXISTS fl_loading_completion_command')) + 1)
|
const commandTable = unifiedSql.slice(commandStart, unifiedSql.indexOf(';', commandStart) + 1)
|
||||||
assert.match(commandTable, /command_status/i)
|
assert.match(commandTable, /command_status/i)
|
||||||
assert.match(commandTable, /next_retry_at/i)
|
assert.match(commandTable, /next_retry_at/i)
|
||||||
assert.match(commandTable, /completed_at/i)
|
assert.match(commandTable, /completed_at/i)
|
||||||
assert.match(unifiedSql, /CREATE TABLE IF NOT EXISTS fl_loading_completion_checkpoint/)
|
assert.match(unifiedSql, /CREATE TABLE(?: IF NOT EXISTS)? fl_loading_completion_checkpoint/)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('durable worker processes inbound settlements incrementally with retry backoff', () => {
|
test('durable worker processes inbound settlements incrementally with retry backoff', () => {
|
||||||
|
|||||||
@@ -10,19 +10,23 @@ const unifiedSql = readFileSync(fileURLToPath(new URL('../../deploy/sql/头程
|
|||||||
test('unified migration selects firstleg before creating the loading model bridge', () => {
|
test('unified migration selects firstleg before creating the loading model bridge', () => {
|
||||||
assert.match(
|
assert.match(
|
||||||
unifiedSql,
|
unifiedSql,
|
||||||
/USE baiyue_firstleg;\s*\/\* Phase 3: link inbound preload plans to one or more container loading plans\. \*\/\s*CREATE TABLE IF NOT EXISTS fl_preload_loading_plan_link/,
|
/USE baiyue_firstleg;[\s\S]*?CREATE TABLE(?: IF NOT EXISTS)? fl_preload_loading_plan_link/,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('unified migration converges declaration ledger table comments before final schema validation', () => {
|
test('unified baseline defines declaration ledger comments before final schema validation', () => {
|
||||||
assert.match(unifiedSql, /queue_table_comment\('baiyue_firstleg', 'fl_order_declaration_event', '[^']*[一-龥][^']*'\)/)
|
const eventStart = unifiedSql.indexOf('CREATE TABLE fl_order_declaration_event')
|
||||||
assert.match(unifiedSql, /queue_table_comment\('baiyue_firstleg', 'fl_order_declaration_snapshot', '[^']*[一-龥][^']*'\)/)
|
const snapshotStart = unifiedSql.indexOf('CREATE TABLE fl_order_declaration_snapshot')
|
||||||
|
const eventTable = unifiedSql.slice(eventStart, snapshotStart)
|
||||||
|
const snapshotTable = unifiedSql.slice(snapshotStart, unifiedSql.indexOf('CREATE TABLE', snapshotStart + 20))
|
||||||
|
assert.match(eventTable, /COMMENT='Order客户申报事件永久幂等账本'/)
|
||||||
|
assert.match(snapshotTable, /COMMENT='Order客户申报版本快照/)
|
||||||
for (const column of ['tenant_id', 'event_id', 'order_id', 'order_version', 'request_hash', 'consumed_at']) {
|
for (const column of ['tenant_id', 'event_id', 'order_id', 'order_version', 'request_hash', 'consumed_at']) {
|
||||||
assert.match(unifiedSql, new RegExp(`queue_column_comment\\('baiyue_firstleg','fl_order_declaration_event','${column}','[^']*[一-龥][^']*'\\)`))
|
assert.match(eventTable, new RegExp(`\\b${column}\\b[^\\n]*COMMENT '[^']*[一-龥][^']*'`))
|
||||||
}
|
}
|
||||||
for (const column of ['tenant_id', 'order_id', 'event_id', 'order_version', 'request_hash', 'customer_remark',
|
for (const column of ['tenant_id', 'order_id', 'event_id', 'order_version', 'request_hash', 'customer_remark',
|
||||||
'expected_arrival_at', 'channel_code', 'channel_name', 'cargoes_json', 'changes_json', 'occurred_at', 'created_at', 'updated_at']) {
|
'expected_arrival_at', 'channel_code', 'channel_name', 'cargoes_json', 'changes_json', 'occurred_at', 'created_at', 'updated_at']) {
|
||||||
assert.match(unifiedSql, new RegExp(`queue_column_comment\\('baiyue_firstleg','fl_order_declaration_snapshot','${column}','[^']*[一-龥][^']*'\\)`))
|
assert.match(snapshotTable, new RegExp(`\\b${column}\\b[^\\n]*COMMENT '[^']*[一-龥][^']*'`))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ test('pending backend contract derives workflow from task items instead of assig
|
|||||||
assert.match(openApi,
|
assert.match(openApi,
|
||||||
/PendingTask:[\s\S]*workflowStatus: \{type: string, enum: \[UNASSIGNED, IN_PROGRESS, AWAITING_REVIEW, PROCESSING, COMPLETION_FAILED\][^\r\n]*}/)
|
/PendingTask:[\s\S]*workflowStatus: \{type: string, enum: \[UNASSIGNED, IN_PROGRESS, AWAITING_REVIEW, PROCESSING, COMPLETION_FAILED\][^\r\n]*}/)
|
||||||
assert.match(mapper,
|
assert.match(mapper,
|
||||||
/WHEN SUM\(CASE WHEN pick_item\.item_status IN \('PENDING', 'PICKING'\)[\s\S]*= 0[\s\S]*THEN 'AWAITING_REVIEW'/)
|
/WHEN COUNT\(DISTINCT CASE WHEN pick_item\.item_status IN \('PENDING', 'PICKING'\)[\s\S]*= 0[\s\S]*THEN 'AWAITING_REVIEW'/)
|
||||||
assert.doesNotMatch(mapper,
|
assert.doesNotMatch(mapper,
|
||||||
/CASE WHEN assignment\.pick_task_id IS NULL THEN 'UNASSIGNED' ELSE 'IN_PROGRESS' END AS workflowStatus/)
|
/CASE WHEN assignment\.pick_task_id IS NULL THEN 'UNASSIGNED' ELSE 'IN_PROGRESS' END AS workflowStatus/)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -29,9 +29,9 @@ test('loading pick operation schemas accept whole-pallet dropship audits', () =>
|
|||||||
const moduleSql = read('../../firstleg/src/main/resources/db/phase3-pda-convergence-schema.sql')
|
const moduleSql = read('../../firstleg/src/main/resources/db/phase3-pda-convergence-schema.sql')
|
||||||
const unifiedSql = read('../../deploy/sql/头程数据库统一增量-MySQL8.sql')
|
const unifiedSql = read('../../deploy/sql/头程数据库统一增量-MySQL8.sql')
|
||||||
for (const sql of [moduleSql, unifiedSql]) {
|
for (const sql of [moduleSql, unifiedSql]) {
|
||||||
assert.match(sql, /chk_loading_pick_operation_action[\s\S]*?'PICK_PALLET'/)
|
assert.match(sql, /chk_loading_pick_operation_action[\s\S]*?(?:_utf8mb4)?'PICK_PALLET'/)
|
||||||
}
|
}
|
||||||
assert.equal((unifiedSql.match(/CHECK \(action_type IN \([^)]*'PICK_PALLET'[^)]*\)\)/g) || []).length, 2)
|
assert.equal((unifiedSql.match(/CHECK \(\(?action_type in \([^)]*(?:_utf8mb4)?'PICK_PALLET'[^)]*\)\)?\)/gi) || []).length, 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('producer collector requires dropship FBA, standard FBA, OVERSEAS and a fourth distinct container', () => {
|
test('producer collector requires dropship FBA, standard FBA, OVERSEAS and a fourth distinct container', () => {
|
||||||
|
|||||||
@@ -66,10 +66,10 @@ test('domestic and overseas PDA operators use isolated authorities', () => {
|
|||||||
assert.match(iamSql, /permission\.permission_code='lastleg:pda:operate'/)
|
assert.match(iamSql, /permission\.permission_code='lastleg:pda:operate'/)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('unified migration creates the phase-four role matrix in the IAM schema used by its assertion routine', () => {
|
test('unified baseline creates the phase-four role matrix in the IAM schema', () => {
|
||||||
assert.match(
|
assert.match(
|
||||||
unifiedSql,
|
unifiedSql,
|
||||||
/USE baiyue_iam;[\s\S]*?DROP TEMPORARY TABLE IF EXISTS tmp_phase4_warehouse_role_permission;\s*CREATE TEMPORARY TABLE tmp_phase4_warehouse_role_permission/,
|
/USE baiyue_iam;[\s\S]*?'OVERSEAS_WAREHOUSE_PDA_OPERATOR'[\s\S]*?'lastleg:pda:operate'/,
|
||||||
)
|
)
|
||||||
assert.match(unifiedSql, /CREATE PROCEDURE assert_phase4_warehouse_role_minimum\(\)/)
|
assert.doesNotMatch(unifiedSql, /tmp_phase4_warehouse_role_permission|assert_phase4_warehouse_role_minimum/)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -90,3 +90,11 @@ test('production single-service pipeline dispatches the blue-green executor', as
|
|||||||
assert.match(deploy, /TARGET_IS_LOCAL[\s\S]*?deploy-blue-green-service\.sh/)
|
assert.match(deploy, /TARGET_IS_LOCAL[\s\S]*?deploy-blue-green-service\.sh/)
|
||||||
assert.match(batch, /if \[ "\$DEPLOY_ENV" = "production" \][\s\S]*?deploy-blue-green-service\.sh/)
|
assert.match(batch, /if \[ "\$DEPLOY_ENV" = "production" \][\s\S]*?deploy-blue-green-service\.sh/)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('test business services use blue-green while test gateways retain their fixed entry ports', async () => {
|
||||||
|
const deploy = await read('deploy/scripts/deploy-built-service.sh')
|
||||||
|
const batch = await read('deploy/scripts/deploy-services.sh')
|
||||||
|
assert.match(deploy, /\[ "\$DEPLOY_ENV" = "test" \][\s\S]*?\[ "\$SERVICE" != "gateway" \]/)
|
||||||
|
assert.match(batch, /\[ "\$DEPLOY_ENV" = "test" \] \|\| \[ "\$DEPLOY_ENV" = "production" \]/)
|
||||||
|
assert.match(batch, /\[ "\$service" = gateway \] \|\| \[ "\$service" = gateway-overseas \]/)
|
||||||
|
})
|
||||||
|
|||||||
@@ -128,8 +128,8 @@ test('development and test deployment locks are acquired before target executors
|
|||||||
})
|
})
|
||||||
|
|
||||||
test('development publishes every service on loopback without changing test defaults', () => {
|
test('development publishes every service on loopback without changing test defaults', () => {
|
||||||
assert.match(serviceCompose, /\$\{PUBLISHED_BIND_ADDRESS:-0\.0\.0\.0\}:\$\{GATEWAY_PORT:-9000\}:9000/)
|
assert.match(serviceCompose, /\$\{PUBLISHED_BIND_ADDRESS:-0\.0\.0\.0\}:\$\{GATEWAY_PUBLISHED_PORT:-\$\{GATEWAY_PORT:-9000\}\}:9000/)
|
||||||
assert.match(overseasCompose, /\$\{PUBLISHED_BIND_ADDRESS:-0\.0\.0\.0\}:\$\{GATEWAY_OVERSEAS_PORT:-9300\}:9300/)
|
assert.match(overseasCompose, /\$\{PUBLISHED_BIND_ADDRESS:-0\.0\.0\.0\}:\$\{GATEWAY_OVERSEAS_PUBLISHED_PORT:-\$\{GATEWAY_OVERSEAS_PORT:-9300\}\}:9300/)
|
||||||
assert.match(directDeployScript, /if \[ "\$DEPLOY_ENV" = "development" \]; then\s+PUBLISHED_BIND_ADDRESS=127\.0\.0\.1/)
|
assert.match(directDeployScript, /if \[ "\$DEPLOY_ENV" = "development" \]; then\s+PUBLISHED_BIND_ADDRESS=127\.0\.0\.1/)
|
||||||
assert.match(directDeployScript, /if \[ "\$deploy_env" = "development" \]; then\s+export PUBLISHED_BIND_ADDRESS=127\.0\.0\.1/)
|
assert.match(directDeployScript, /if \[ "\$deploy_env" = "development" \]; then\s+export PUBLISHED_BIND_ADDRESS=127\.0\.0\.1/)
|
||||||
assert.doesNotMatch(directDeployScript, /gateway\|gateway-overseas\) (?:export )?PUBLISHED_BIND_ADDRESS=0\.0\.0\.0/)
|
assert.doesNotMatch(directDeployScript, /gateway\|gateway-overseas\) (?:export )?PUBLISHED_BIND_ADDRESS=0\.0\.0\.0/)
|
||||||
|
|||||||
Reference in New Issue
Block a user