fix(ci): stabilize windows team runtime tests
This commit is contained in:
parent
2f37be4bd0
commit
465b031873
3 changed files with 41 additions and 25 deletions
|
|
@ -24,13 +24,24 @@ export function getTeamLaunchSummaryPath(teamName: string): string {
|
|||
return path.join(getTeamsBasePath(), teamName, TEAM_LAUNCH_SUMMARY_FILE);
|
||||
}
|
||||
|
||||
async function isMissingTeamDirectoryWriteRace(teamName: string, error: unknown): Promise<boolean> {
|
||||
async function isMissingTeamDirectoryWriteRace(
|
||||
targetPath: string,
|
||||
error: unknown
|
||||
): Promise<boolean> {
|
||||
const code = (error as NodeJS.ErrnoException).code;
|
||||
if (code !== 'ENOENT' && code !== 'EINVAL') {
|
||||
return false;
|
||||
}
|
||||
const targetDir = path.dirname(targetPath);
|
||||
const errorPaths = [
|
||||
(error as NodeJS.ErrnoException).path,
|
||||
(error as NodeJS.ErrnoException & { dest?: string }).dest,
|
||||
].filter((value): value is string => typeof value === 'string' && value.length > 0);
|
||||
if (code === 'ENOENT' && errorPaths.some((errorPath) => path.dirname(errorPath) === targetDir)) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
await fs.promises.access(path.dirname(getTeamLaunchStatePath(teamName)));
|
||||
await fs.promises.access(targetDir);
|
||||
return false;
|
||||
} catch {
|
||||
return true;
|
||||
|
|
@ -53,17 +64,16 @@ export class TeamLaunchStateStore {
|
|||
}
|
||||
|
||||
async write(teamName: string, snapshot: PersistedTeamLaunchSnapshot): Promise<void> {
|
||||
const launchStatePath = getTeamLaunchStatePath(teamName);
|
||||
const launchSummaryPath = getTeamLaunchSummaryPath(teamName);
|
||||
try {
|
||||
await atomicWriteAsync(launchStatePath, `${JSON.stringify(snapshot, null, 2)}\n`);
|
||||
await atomicWriteAsync(
|
||||
getTeamLaunchStatePath(teamName),
|
||||
`${JSON.stringify(snapshot, null, 2)}\n`
|
||||
);
|
||||
await atomicWriteAsync(
|
||||
getTeamLaunchSummaryPath(teamName),
|
||||
launchSummaryPath,
|
||||
`${JSON.stringify(createPersistedLaunchSummaryProjection(snapshot), null, 2)}\n`
|
||||
);
|
||||
} catch (error) {
|
||||
if (await isMissingTeamDirectoryWriteRace(teamName, error)) {
|
||||
if (await isMissingTeamDirectoryWriteRace(launchStatePath, error)) {
|
||||
return;
|
||||
}
|
||||
logger.warn(
|
||||
|
|
|
|||
|
|
@ -11962,8 +11962,8 @@ describe('Team agent launch matrix safe e2e', () => {
|
|||
svc.stopTeam(teamName);
|
||||
|
||||
await waitForCondition(() => adapter.stopInputs.length === 2);
|
||||
expect(staleKillCount).toBe(0);
|
||||
expect(currentKillCount).toBe(1);
|
||||
expectDirectChildKillCount(staleKillCount, 0);
|
||||
expectDirectChildKillCount(currentKillCount, 1);
|
||||
expect(staleRun.cancelRequested).toBe(false);
|
||||
expect(currentRun.cancelRequested).toBe(true);
|
||||
expect(adapter.stopInputs.map((input) => input.laneId).sort()).toEqual([
|
||||
|
|
@ -12019,8 +12019,8 @@ describe('Team agent launch matrix safe e2e', () => {
|
|||
|
||||
await svc.cancelProvisioning(staleRun.runId);
|
||||
|
||||
expect(staleKillCount).toBe(1);
|
||||
expect(currentKillCount).toBe(0);
|
||||
expectDirectChildKillCount(staleKillCount, 1);
|
||||
expectDirectChildKillCount(currentKillCount, 0);
|
||||
expect(staleRun.cancelRequested).toBe(true);
|
||||
expect(currentRun.cancelRequested).toBe(false);
|
||||
expect(adapter.stopInputs).toEqual([]);
|
||||
|
|
@ -12085,8 +12085,8 @@ describe('Team agent launch matrix safe e2e', () => {
|
|||
|
||||
svc.stopTeam(teamName);
|
||||
|
||||
expect(staleKillCount).toBe(0);
|
||||
expect(currentKillCount).toBe(1);
|
||||
expectDirectChildKillCount(staleKillCount, 0);
|
||||
expectDirectChildKillCount(currentKillCount, 1);
|
||||
expect(staleRun.cancelRequested).toBe(false);
|
||||
expect(currentRun.cancelRequested).toBe(true);
|
||||
expect(await svc.getRuntimeState(teamName)).toMatchObject({
|
||||
|
|
@ -12120,8 +12120,8 @@ describe('Team agent launch matrix safe e2e', () => {
|
|||
|
||||
await svc.cancelProvisioning(staleRun.runId);
|
||||
|
||||
expect(staleKillCount).toBe(1);
|
||||
expect(currentKillCount).toBe(0);
|
||||
expectDirectChildKillCount(staleKillCount, 1);
|
||||
expectDirectChildKillCount(currentKillCount, 0);
|
||||
expect(staleRun.cancelRequested).toBe(true);
|
||||
expect(currentRun.cancelRequested).toBe(false);
|
||||
expect(svc.isTeamAlive(teamName)).toBe(true);
|
||||
|
|
@ -12157,8 +12157,8 @@ describe('Team agent launch matrix safe e2e', () => {
|
|||
|
||||
await svc.cancelProvisioning(currentRun.runId);
|
||||
|
||||
expect(staleKillCount).toBe(0);
|
||||
expect(currentKillCount).toBe(1);
|
||||
expectDirectChildKillCount(staleKillCount, 0);
|
||||
expectDirectChildKillCount(currentKillCount, 1);
|
||||
expect(staleRun.cancelRequested).toBe(false);
|
||||
expect(currentRun.cancelRequested).toBe(true);
|
||||
expect(svc.isTeamAlive(teamName)).toBe(false);
|
||||
|
|
@ -16465,6 +16465,11 @@ function trackLiveRun(svc: TeamProvisioningService, run: any): void {
|
|||
(svc as any).aliveRunByTeam.set(run.teamName, run.runId);
|
||||
}
|
||||
|
||||
function expectDirectChildKillCount(actual: number, expected: number): void {
|
||||
// Windows uses taskkill.exe for process-tree termination, so fake child.kill is not called.
|
||||
expect(actual).toBe(process.platform === 'win32' ? 0 : expected);
|
||||
}
|
||||
|
||||
function injectStaleTerminalProvisioningRun(
|
||||
svc: TeamProvisioningService,
|
||||
teamName: string,
|
||||
|
|
|
|||
|
|
@ -69,13 +69,14 @@ describe('electron userData migration', () => {
|
|||
}
|
||||
|
||||
it('derives legacy candidates beside the current Electron userData directory', () => {
|
||||
expect(
|
||||
getLegacyElectronUserDataCandidates('/Users/me/Library/Application Support/Agent Teams UI')
|
||||
).toEqual([
|
||||
'/Users/me/Library/Application Support/Claude Agent Teams UI',
|
||||
'/Users/me/Library/Application Support/claude-agent-teams-ui',
|
||||
'/Users/me/Library/Application Support/claude-devtools',
|
||||
'/Users/me/Library/Application Support/claude-code-context',
|
||||
const currentPath = path.join('/Users/me/Library/Application Support', 'Agent Teams UI');
|
||||
const parentPath = path.dirname(currentPath);
|
||||
|
||||
expect(getLegacyElectronUserDataCandidates(currentPath)).toEqual([
|
||||
path.join(parentPath, 'Claude Agent Teams UI'),
|
||||
path.join(parentPath, 'claude-agent-teams-ui'),
|
||||
path.join(parentPath, 'claude-devtools'),
|
||||
path.join(parentPath, 'claude-code-context'),
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue