mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-11-01 04:02:35 +00:00
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:
parent
e9011d21c3
commit
288e4c481d
15 changed files with 709 additions and 237 deletions
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue