2026-08-13 20:00:30 +08:00
|
|
|
import assert from 'node:assert/strict'
|
|
|
|
|
import { readFile } from 'node:fs/promises'
|
|
|
|
|
import test from 'node:test'
|
|
|
|
|
|
|
|
|
|
const pipeline = (await readFile(new URL('../Jenkinsfile', import.meta.url), 'utf8'))
|
|
|
|
|
.replaceAll('\r\n', '\n')
|
2026-09-18 18:02:27 +08:00
|
|
|
const servicePipeline = (await readFile(new URL('../Jenkinsfile.service', import.meta.url), 'utf8'))
|
|
|
|
|
.replaceAll('\r\n', '\n')
|
2026-08-13 20:00:30 +08:00
|
|
|
|
2026-08-22 17:46:11 +08:00
|
|
|
test('coordinator releases its builder while waiting for downstream jobs', () => {
|
|
|
|
|
assert.match(pipeline, /pipeline \{[\s\S]*?agent none/)
|
|
|
|
|
assert.match(pipeline, /stage\('确定构建范围'\) \{[\s\S]*?agent \{ label 'java-builder' \}/)
|
2026-08-22 11:45:14 +08:00
|
|
|
assert.match(pipeline, /agent \{ label 'java-builder' \}/)
|
|
|
|
|
assert.doesNotMatch(pipeline, /agent any/)
|
2026-08-22 17:53:18 +08:00
|
|
|
assert.doesNotMatch(pipeline, /cleanWs\(/)
|
2026-08-24 17:37:36 +08:00
|
|
|
assert.doesNotMatch(pipeline, /^\s*(?:&&|\|\|)/m)
|
2026-08-22 11:45:14 +08:00
|
|
|
})
|
|
|
|
|
|
2026-08-24 13:43:38 +08:00
|
|
|
test('coordinator runs selected tests once before parallel service packaging', () => {
|
|
|
|
|
const gateIndex = pipeline.indexOf("stage('统一 Maven 测试门禁')")
|
|
|
|
|
const dispatchIndex = pipeline.indexOf("stage('并行调度独立服务 Job')")
|
2026-08-28 10:32:41 +08:00
|
|
|
const staleReportCleanupIndex = pipeline.indexOf(
|
|
|
|
|
"find . -type f -path '*/target/surefire-reports/TEST-*.xml' -delete"
|
|
|
|
|
)
|
|
|
|
|
const selectedTestIndex = pipeline.indexOf('-pl ${selectedModules} -am test')
|
2026-08-24 13:43:38 +08:00
|
|
|
|
|
|
|
|
assert.ok(gateIndex >= 0, 'unified test gate must exist')
|
|
|
|
|
assert.ok(dispatchIndex > gateIndex, 'unified tests must finish before downstream dispatch')
|
2026-08-28 10:32:41 +08:00
|
|
|
assert.ok(staleReportCleanupIndex > gateIndex, 'stale Surefire reports must be removed inside the test gate')
|
|
|
|
|
assert.ok(selectedTestIndex > staleReportCleanupIndex, 'stale reports must be removed before selected tests run')
|
2026-08-24 13:43:38 +08:00
|
|
|
assert.match(pipeline, /-pl \$\{selectedModules\} -am test/)
|
2026-08-28 10:32:41 +08:00
|
|
|
assert.match(pipeline, /junit allowEmptyResults: true, testResults: '\*\*\/target\/surefire-reports\/TEST-\*\.xml'/)
|
2026-08-24 13:43:38 +08:00
|
|
|
assert.match(pipeline, /booleanParam\(name: 'SKIP_TESTS', value: true\)/)
|
|
|
|
|
assert.doesNotMatch(pipeline, /TESTED_COMMIT/)
|
|
|
|
|
})
|
|
|
|
|
|
2026-08-13 20:00:30 +08:00
|
|
|
test('AUTO detects database migrations without expanding them to all services', () => {
|
|
|
|
|
assert.match(pipeline, /def databaseMigrationPaths = \['deploy\/sql\/'\]/)
|
2026-09-04 17:17:08 +08:00
|
|
|
assert.match(pipeline, /List serviceRelevantChanges = changed\.findAll/)
|
|
|
|
|
assert.match(pipeline, /!databaseMigrationPaths\.any \{ prefix -> path\.startsWith\(prefix\) \}/)
|
2026-08-13 20:00:30 +08:00
|
|
|
assert.match(pipeline, /env\.DATABASE_CHANGE_DETECTED = databaseChanged \? 'true' : 'false'/)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
test('database-only changes are reported as a separate migration action', () => {
|
|
|
|
|
assert.match(pipeline, /仅数据库迁移变更 \| 需单独审核执行/)
|
|
|
|
|
assert.match(pipeline, /统一 SQL 须独立审核并执行/)
|
|
|
|
|
})
|
2026-08-24 12:01:37 +08:00
|
|
|
|
|
|
|
|
test('coordinator cannot initialize test databases', () => {
|
|
|
|
|
assert.doesNotMatch(pipeline, /INITIALIZE_TEST_DATABASE/)
|
|
|
|
|
assert.doesNotMatch(pipeline, /initialize-test-databases\.sh/)
|
|
|
|
|
assert.doesNotMatch(pipeline, /测试数据库初始化/)
|
|
|
|
|
})
|
2026-08-24 17:19:36 +08:00
|
|
|
|
2026-10-07 11:02:47 +08:00
|
|
|
test('coordinator dispatches exactly the current TEST service map without retired regional units', async () => {
|
|
|
|
|
const serviceMap = await readFile(new URL('../deploy/service-map.yml', import.meta.url), 'utf8')
|
|
|
|
|
const expected = [...serviceMap.matchAll(/^ ([a-z][a-z0-9-]+):$/gm)].map(match => match[1]).sort()
|
|
|
|
|
const declaration = pipeline.match(/def serviceModules = \[([\s\S]*?)\]/)?.[1] || ''
|
|
|
|
|
const actual = [...declaration.matchAll(/'([^']+)'/g)].map(match => match[1]).sort()
|
|
|
|
|
assert.equal(expected.length, 13)
|
|
|
|
|
assert.deepEqual(actual, expected)
|
|
|
|
|
assert.doesNotMatch(pipeline, /EVENT_BRIDGE_REGION|gateway-overseas|event-bridge-service/)
|
2026-08-24 17:19:36 +08:00
|
|
|
})
|
2026-09-17 16:01:00 +08:00
|
|
|
|
2026-10-07 11:02:47 +08:00
|
|
|
test('TEST and gray jobs use fixed independent environment mappings and explicit DEPLOY', () => {
|
2026-09-17 16:01:00 +08:00
|
|
|
assert.match(pipeline, /booleanParam\(name: 'DEPLOY'/)
|
2026-10-07 11:02:47 +08:00
|
|
|
assert.match(pipeline, /case 'backend-java':[\s\S]*?return 'test'/)
|
|
|
|
|
assert.match(pipeline, /case 'backend-java-prod':[\s\S]*?return 'production'/)
|
|
|
|
|
assert.match(pipeline, /case 'backend-java-prod':[\s\S]*?return 'baiyue-firstleg-prod-'/)
|
|
|
|
|
assert.doesNotMatch(pipeline, /return 'development'|backend-java-dev/)
|
|
|
|
|
assert.match(pipeline, /booleanParam\(name: 'DEPLOY', value: params\.DEPLOY\)/)
|
2026-09-17 16:01:00 +08:00
|
|
|
assert.doesNotMatch(pipeline, /input message:/)
|
|
|
|
|
assert.doesNotMatch(pipeline, /\u786e\u8ba4\u90e8\u7f72/)
|
|
|
|
|
})
|
2026-09-18 18:02:27 +08:00
|
|
|
|
2026-10-07 11:02:47 +08:00
|
|
|
test('TEST coordinator records downstream identity and fails the aggregate on any unsuccessful service', () => {
|
|
|
|
|
assert.match(pipeline, /env\.SOURCE_COMMIT = sh\(script: 'git rev-parse HEAD'/)
|
2026-09-18 18:50:40 +08:00
|
|
|
assert.match(pipeline, /def downstreamBuildUrls = \[:\]/)
|
|
|
|
|
assert.match(pipeline, /downstreamBuildUrls\[service\] = downstreamBuild\.absoluteUrl/)
|
|
|
|
|
assert.match(pipeline, /downstreamBuildNumbers\[service\] = downstreamBuild\.number/)
|
2026-10-07 11:02:47 +08:00
|
|
|
assert.match(pipeline, /downstreamResults\.findAll \{ service, result -> result != 'SUCCESS' \}/)
|
|
|
|
|
assert.match(pipeline, /if \(failed\) \{[\s\S]*?unstable\(/)
|
|
|
|
|
assert.doesNotMatch(pipeline + servicePipeline, /wecom-prod-webhook|sendProductionWeComNotification/)
|
2026-09-18 18:02:27 +08:00
|
|
|
})
|