perf(ci): Optimize MySQL integration verification (#15200)

Close Spring contexts before fixture database cleanup, run integration classes in isolated reusable forks, and remove redundant fixture validation and duplicate load-test execution. Document bounded local validation and preserve full CI gates.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
jinye 2026-10-22 20:03:13 +08:00 • committed by GitHub
parent e9011d21c3
commit 288e4c481d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 709 additions and 237 deletions

View file

@ -378,6 +378,37 @@ describe('Hosted real-process gates', () => {
expect(profile(id), id).toMatch(skipsUnits);
}
expect(profile('mysql-integration')).not.toContain('maven-surefire-plugin');
const mysqlProfile = profile('mysql-integration');
expect(mysqlProfile).toContain(
'<mysql.integration.forks>1</mysql.integration.forks>',
);
const mysqlFailsafe = mysqlProfile
.split('<artifactId>maven-failsafe-plugin</artifactId>')[1]
.split('</plugin>')[0];
expect(mysqlFailsafe).toContain(
'<forkCount>${mysql.integration.forks}</forkCount>',
);
expect(mysqlFailsafe).toContain('<reuseForks>true</reuseForks>');
expect(mysqlFailsafe).toContain(
'junit.jupiter.execution.parallel.enabled = false',
);
const routingProperties = mysqlFailsafe
.split('<systemPropertyVariables>')[1]
.split('</systemPropertyVariables>')[0];
expect(routingProperties).toContain(
'<qwen.mysql.forkCount>${mysql.integration.forks}</qwen.mysql.forkCount>',
);
expect(routingProperties).toContain(
'<qwen.mysql.forkNumber>0${surefire.forkNumber}</qwen.mysql.forkNumber>',
);
expect(pom.match(/<qwen\.mysql\.forkCount>/g)).toHaveLength(1);
expect(pom.match(/<qwen\.mysql\.forkNumber>/g)).toHaveLength(1);
expect(
read(
'packages/managed-agent-server/src/test/resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener',
).trim(),
).toBe('com.alibaba.qwen.code.managedagent.MySqlForkRoutingListener');
expect(mysqlRun.run).not.toMatch(/-DforkCount\b/);
// The step stages the SDK with -DskipTests before the MySQL run; only
// the integration command itself must keep its tests.
const mysqlVerify = mysqlRun.run.slice(

View file

@ -802,6 +802,7 @@ describe('SDK Java MySQL lane on the ECS pool', () => {
// here would invite dropping that flag and dying on first connect.
expect(start.run).not.toContain('MYSQL_DATABASE');
expect(start.run).toContain("--env MYSQL_ROOT_PASSWORD='runtime-broker'");
expect(start.run).toContain('for fork in 1 2');
expect(start.run).toContain('for attempt in {1..60}');
expect(start.run).toContain('sleep 2');
// MariaDB ships healthcheck.sh; MySQL does not. Each leg must wait on
@ -816,25 +817,34 @@ describe('SDK Java MySQL lane on the ECS pool', () => {
'mysqladmin ping --host=127.0.0.1 --user=root --password=runtime-broker --silent',
);
expect(start.run).toContain(
'echo "MYSQL_PORT=${MYSQL_PORT}" >> "${GITHUB_ENV}"',
'echo "MYSQL_PORT_${fork}=${port}" >> "${GITHUB_ENV}"',
);
expect(configure.env?.MYSQL_CONTAINER).toBeUndefined();
expect(configure.run).toContain('docker exec "${MYSQL_CONTAINER}" sh -c');
expect(configure.run).toContain('for fork in 1 2');
expect(configure.run).toContain(
'docker exec "${MYSQL_CONTAINER}-${fork}" sh -c',
);
expect(configure.run).toContain(
'MYSQL_PWD="${MYSQL_ROOT_PASSWORD}" \'"${DATABASE_CLIENT}"\'',
);
expect(configure.run).toContain('SET GLOBAL max_allowed_packet=134217728');
expect(verify.env.MYSQL_PORT).toBeUndefined();
expect(verify.run).toContain(
'-Dmysql.url="jdbc:mysql://127.0.0.1:${MYSQL_PORT}/managed_agent_test?createDatabaseIfNotExist=true&allowPublicKeyRetrieval=true&useSSL=false"',
'-Dmysql.url="jdbc:mysql://127.0.0.1:${MYSQL_PORT_1}/managed_agent_test?createDatabaseIfNotExist=true&allowPublicKeyRetrieval=true&useSSL=false"',
);
expect(verify.run).toContain('-Dmysql.integration.forks=2');
for (const fork of [1, 2]) {
expect(verify.run).toContain(
`-Dmysql.url.${fork}="jdbc:mysql://127.0.0.1:\${MYSQL_PORT_${fork}}/managed_agent_test?createDatabaseIfNotExist=true&allowPublicKeyRetrieval=true&useSSL=false"`,
);
}
expect(mysql.steps.indexOf(start)).toBeLessThan(
mysql.steps.indexOf(configure),
);
expect(mysql.steps.indexOf(configure)).toBeLessThan(
mysql.steps.indexOf(verify),
);
expect(cleanup.name).toBe('Remove the database container');
expect(cleanup.name).toBe('Remove the database containers');
// The shell probe below cannot establish Actions cancellation scheduling.
expect(cleanup.if).toBe('${{ always() }}');
expect(cleanup.shell).toBe('bash');
@ -861,7 +871,9 @@ describe('SDK Java MySQL lane on the ECS pool', () => {
.skipIf(process.platform === 'win32')
.each(
databaseLegs.flatMap((leg) =>
['ready', 'dead', 'timeout'].map((mode) => ({ ...leg, mode })),
['ready', 'dead', 'timeout', 'dead-second', 'timeout-second'].map(
(mode) => ({ ...leg, mode }),
),
),
)(
'executes $database startup and consumers with a $mode container',
@ -899,11 +911,11 @@ describe('SDK Java MySQL lane on the ECS pool', () => {
printf 'DOCKER<%s>\\n' "$*" >> "$TRACE"
printf 'ARGC<%s>\\n' "$#" >> "$TRACE"
case "$1" in
run) return 0 ;;
run) attempts=0; return 0 ;;
exec)
if [[ "$3" == "$READINESS" ]]; then
attempts=$((attempts + 1))
if [[ "$MODE" == ready && "$attempts" -eq 3 ]]; then
if [[ ( "$MODE" == ready || ( "$MODE" == *-second && "$2" == *-1 ) ) && "$attempts" -eq 3 ]]; then
return 0
fi
echo 'PROBE_SAYS_NO' >&2
@ -912,9 +924,9 @@ describe('SDK Java MySQL lane on the ECS pool', () => {
[[ "$3" == sh && "$5" == *'SET GLOBAL max_allowed_packet=134217728'* ]] ;;
inspect)
if [[ "$3" == *State.Running* ]]; then
[[ "$MODE" == dead ]] && echo false || echo true
[[ "$MODE" == dead || ( "$MODE" == dead-second && "$4" == *-2 ) ]] && echo false || echo true
else
echo 43219
[[ "$4" == *-1 ]] && echo 43219 || echo 43220
fi ;;
logs) echo MYSQL_FAILURE_LOG ;;
*) return 92 ;;
@ -950,7 +962,7 @@ describe('SDK Java MySQL lane on the ECS pool', () => {
expect(result.error).toBeUndefined();
const trace = readFileSync(join(dir, 'trace'), 'utf8');
expect(trace).toContain(
`run --detach --name ${container} --publish 127.0.0.1::3306 --mount type=tmpfs,destination=/var/lib/mysql --env MYSQL_ROOT_PASSWORD=runtime-broker ${image} ${engineArgs}`,
`run --detach --name ${container}-1 --publish 127.0.0.1::3306 --mount type=tmpfs,destination=/var/lib/mysql --env MYSQL_ROOT_PASSWORD=runtime-broker ${image} ${engineArgs}`,
);
// `"$*"` joins argv, so the trace above cannot tell N correctly split
// engine args from one argument containing spaces. The arg count can:
@ -958,16 +970,29 @@ describe('SDK Java MySQL lane on the ECS pool', () => {
// reaches that many. A joined element would report one fewer.
expect(trace).toContain(`ARGC<${11 + engineArgs.split(' ').length}>`);
// Each leg must wait on the readiness signal its own image ships.
expect(trace).toContain(`exec ${container} ${readiness}`);
expect(trace).toContain(`exec ${container}-1 ${readiness}`);
if (mode === 'ready' || mode.endsWith('-second')) {
expect(trace).toContain(
`run --detach --name ${container}-2 --publish 127.0.0.1::3306 --mount type=tmpfs,destination=/var/lib/mysql --env MYSQL_ROOT_PASSWORD=runtime-broker ${image} ${engineArgs}`,
);
expect(trace).toContain(`exec ${container}-2 ${readiness}`);
}
if (mode === 'ready') {
expect(result.status, result.stderr).toBe(0);
expect(readFileSync(join(dir, 'env'), 'utf8')).toBe(
'MYSQL_PORT=43219\n',
'MYSQL_PORT_1=43219\nMYSQL_PORT_2=43220\n',
);
expect(trace.match(/SLEEP<2>/g)).toHaveLength(2);
expect(trace.match(/SLEEP<2>/g)).toHaveLength(4);
expect(result.stdout).toContain(
'MAVEN<-Dmysql.url=jdbc:mysql://127.0.0.1:43219/managed_agent_test?createDatabaseIfNotExist=true&allowPublicKeyRetrieval=true&useSSL=false>',
);
expect(result.stdout).toContain('MAVEN<-Dmysql.integration.forks=2>');
for (const fork of [1, 2]) {
expect(result.stdout).toContain(
`MAVEN<-Dmysql.url.${fork}=jdbc:mysql://127.0.0.1:${43218 + fork}/managed_agent_test?createDatabaseIfNotExist=true&allowPublicKeyRetrieval=true&useSSL=false>`,
);
expect(trace).toContain(`exec ${container}-${fork} sh -c`);
}
expect(result.stdout).not.toContain('MYSQL_FAILURE_LOG');
expect(result.stdout).not.toContain('PROBE_SAYS_NO');
} else {
@ -976,12 +1001,19 @@ describe('SDK Java MySQL lane on the ECS pool', () => {
// The probe's own output must reach the log: a broken probe is
// otherwise indistinguishable from a server still starting.
expect(result.stdout).toContain('PROBE_SAYS_NO');
expect(existsSync(join(dir, 'env'))).toBe(false);
const second = mode.endsWith('-second');
if (second) {
expect(readFileSync(join(dir, 'env'), 'utf8')).toBe(
'MYSQL_PORT_1=43219\n',
);
} else {
expect(existsSync(join(dir, 'env'))).toBe(false);
}
expect(
trace.match(new RegExp(`exec \\S+ ${readiness}`, 'g')),
).toHaveLength(mode === 'dead' ? 1 : 60);
).toHaveLength((second ? 3 : 0) + (mode.startsWith('dead') ? 1 : 60));
expect(trace.match(/SLEEP<2>/g) ?? []).toHaveLength(
mode === 'dead' ? 0 : 59,
(second ? 2 : 0) + (mode.startsWith('dead') ? 0 : 59),
);
expect(result.stdout).not.toContain('MAVEN<');
}
@ -993,49 +1025,57 @@ describe('SDK Java MySQL lane on the ECS pool', () => {
it
.skipIf(process.platform === 'win32')
.each(['exists', 'missing', 'removal-fails'])(
'executes owned MySQL cleanup when the container %s',
(mode) => {
const cleanup = parse(workflow).jobs['mysql-integration'].steps.at(-1);
const result = spawnSync(
'bash',
[
'-e',
'-c',
`
.each([
'exists',
'missing',
'removal-fails',
'first-missing',
'first-removal-fails',
])('executes owned MySQL cleanup when the container %s', (mode) => {
const cleanup = parse(workflow).jobs['mysql-integration'].steps.at(-1);
const result = spawnSync(
'bash',
[
'-e',
'-c',
`
docker() {
printf 'DOCKER<%s>\\n' "$*"
if [[ "$1" == inspect ]]; then [[ "$MODE" != missing ]];
elif [[ "$1" == rm ]]; then [[ "$MODE" != removal-fails ]];
if [[ "$1" == inspect ]]; then [[ "$MODE" != missing && ! ( "$MODE" == first-missing && "$2" == *-1 ) ]];
elif [[ "$1" == rm ]]; then [[ "$MODE" != removal-fails && ! ( "$MODE" == first-removal-fails && "$3" == *-1 ) ]];
else return 92; fi
}
${cleanup.run}
`,
],
{
encoding: 'utf8',
timeout: 5000,
env: {
...process.env,
MODE: mode,
MYSQL_CONTAINER: 'qwen-code-sdk-java-mysql-123-2',
},
],
{
encoding: 'utf8',
timeout: 5000,
env: {
...process.env,
MODE: mode,
MYSQL_CONTAINER: 'qwen-code-sdk-java-mysql-123-2',
},
},
);
expect(result.error).toBeUndefined();
expect(result.status, result.stderr).toBe(0);
for (const fork of [1, 2]) {
expect(
result.stdout.includes(
`DOCKER<rm --force qwen-code-sdk-java-mysql-123-2-${fork}>`,
),
).toBe(mode !== 'missing' && !(mode === 'first-missing' && fork === 1));
expect(
result.stdout.includes(
`::warning::could not remove qwen-code-sdk-java-mysql-123-2-${fork}; the host cleanup service reaps it within ~48h`,
),
).toBe(
mode === 'removal-fails' ||
(mode === 'first-removal-fails' && fork === 1),
);
expect(result.error).toBeUndefined();
expect(result.status, result.stderr).toBe(0);
expect(
result.stdout.includes(
'DOCKER<rm --force qwen-code-sdk-java-mysql-123-2>',
),
).toBe(mode !== 'missing');
expect(
result.stdout.includes(
'::warning::could not remove qwen-code-sdk-java-mysql-123-2; the host cleanup service reaps it within ~48h',
),
).toBe(mode === 'removal-fails');
},
);
}
});
it('holds the per-host sdk-java lock once around both Maven runs', () => {
// Derived from the parsed steps, not a string count: the install and