Skip to content

Commit e592d2a

Browse files
Studio CLI: Fix Windows E2E tests (#2299)
* Abort async operations on SIGTERM/SIGINT * Also send abort message to child server * Only create AbortController when topic is not `abort` * Fix * More fixes * Tweaks * Fix unit tests * Fix types * Remove `this.sessionPath` files individually To help us diagnose which specific files or directories are causing trouble * Stop running servers in a detached process * Revert "Remove `this.sessionPath` files individually" This reverts commit 8786163. * Retry * Increase timeouts * Fix deprecated blueprint syntax * Increase timeout * Try adding a small delay * Kill `site list --watch` on SIGINT * Create main window after creating site watcher * Try using async fs method for cleanup * Try rimraf (which has advanced retry strategies) * New approach: don't remove `sessionPath` dir * Unused import * Force close app * disconnect from pm2 in response to SIGTERM * Revert user data watcher changes from #2313 * Wait for running button * Use Electron's will-quit event in `execute-command.ts` * SIGINT and SIGTERM listeners in `wp` command * More SIGINT and SIGTERM listeners in `wp` command * Temporarily skip blueprints test * Revert "Temporarily skip blueprints test" This reverts commit 0d16ae5. * Try with force kill again * Logging * New approach to waiting for app close * Logging again * Try to make all child processes detached * Experiment * Revert "Experiment" This reverts commit 3596bac. * Revert "Try to make all child processes detached" This reverts commit f99f4b0. * Try a 5s timeout for closing the app * Experiment with removing stopAllServersOnQuit * shutdown message * Revert "shutdown message" This reverts commit 9d56d0c. * Revert E2ESession::closeApp implementation * Temporarily skip app.test.ts * Temporarily skip blueprints.test.ts * Revert "Temporarily skip app.test.ts" This reverts commit 8307750. * Revert "Temporarily skip blueprints.test.ts" This reverts commit 9d78492. * Add logging to Playwright source code * pidtree * More playwright logging * More logging and await pidtree * pidtree after close * Remove stdio listeners * Fix pidtree logging after close * destroy stdio streams on exit * Disconnect IPC * Try teardown workaround * Log pid and result in will-quit handler * Unregister will-quit handlers * Bring back logging * Stop all servers on quit * Undo all Windows hacks in E2ESession * Bring back tree-kill * Log stop-all pid and pidtree * Catch errors from tree-kill * Remove pidtree * No IPC channel in stopAllServersOnQuit * Update playwright-core patch to test theory * Fix patch * `spawn` over `fork` * Temporarily remove `stopAllServersOnQuit` * Never call `electronApp.close` on Windows * Restore `e2e/e2e-helpers.ts` * Reinstate `stopAllServersOnQuit` * Revert `spawn` and IPC channel theory * Fix unit tests * Remove playwright-core patch * Remove tree-kill dependency * Remove `started` event * More lenient child process cleanup * Revert "Remove `started` event" This reverts commit b42fa0b. * Destroy stdio streams again * Explicitly disconnect IPC * Clean up `E2ESession` * Always call `killRemainingProcesses` * Reset test timeouts * No `detached` option * Reset more test timings * Only prevent `will-quit` when applicable * fix e2e test * Children connect to pm2 daemon in sequence * Fix unit tests * Kill pm2 daemon in `site stop --all` command * Fix stop command unit test, async disconnect, `process.exit` * Remove stray `console.info` calls * Undo all hacks in `E2ESession` * Restore `E2ESession`, but don't kill children * Increase timeout * Don't log child pids * Experimental: detach `site stop --all` again * Clean up session files again * Let's give rimraf one more try * Experiment with removing `child.disconnect()` call * Don't destroy stdio streams on exit * Always run `site stop --all` command if pending update * Notify Studio if user runs `site stop --all` * Fix `package-lock.json` diff * Fix and document "stop sites on exit" logic * Speed up `site stop --all` * Fix logic * Revert "Experimental: detach `site stop --all` again" This reverts commit 01ae1c4. * String tweaks --------- Co-authored-by: bcotrim <bernardo.cotrim@a8c.com>
1 parent cc674a4 commit e592d2a

31 files changed

+602
-400
lines changed

cli/commands/site/create.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ export async function runCommand(
336336
logger.reportKeyValuePair( 'id', siteDetails.id );
337337
logger.reportKeyValuePair( 'running', String( siteDetails.running ) );
338338
} finally {
339-
disconnect();
339+
await disconnect();
340340
}
341341
}
342342

cli/commands/site/delete.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,14 @@ export async function runCommand(
6565
deleteFiles: boolean = false
6666
): Promise< void > {
6767
try {
68-
logger.reportStart( LoggerAction.LOAD_SITES, __( 'Loading site…' ) );
69-
const site = await getSiteByFolder( siteFolder );
70-
logger.reportSuccess( __( 'Site loaded' ) );
71-
7268
logger.reportStart( LoggerAction.START_DAEMON, __( 'Starting process daemon…' ) );
7369
await connect();
7470
logger.reportSuccess( __( 'Process daemon started' ) );
7571

72+
logger.reportStart( LoggerAction.LOAD_SITES, __( 'Loading site…' ) );
73+
const site = await getSiteByFolder( siteFolder );
74+
logger.reportSuccess( __( 'Site loaded' ) );
75+
7676
const runningProcess = await isServerRunning( site.id );
7777
if ( runningProcess ) {
7878
logger.reportStart( LoggerAction.STOP_SITE, __( 'Stopping WordPress server…' ) );
@@ -126,7 +126,7 @@ export async function runCommand(
126126
logger.reportSuccess( __( 'Site files deleted' ) );
127127
}
128128
} finally {
129-
disconnect();
129+
await disconnect();
130130
}
131131
}
132132

cli/commands/site/list.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { __, _n, sprintf } from '@wordpress/i18n';
22
import Table from 'cli-table3';
33
import { SiteCommandLoggerAction as LoggerAction } from 'common/logger-actions';
44
import { getSiteUrl, readAppdata, type SiteData } from 'cli/lib/appdata';
5-
import { connect, disconnect } from 'cli/lib/pm2-manager';
5+
import { connect, disconnect, subscribePm2KillEvent } from 'cli/lib/pm2-manager';
66
import { getColumnWidths, getPrettyPath } from 'cli/lib/utils';
77
import { isServerRunning, subscribeSiteEvents } from 'cli/lib/wordpress-server-manager';
88
import { Logger, LoggerError } from 'cli/logger';
@@ -126,10 +126,24 @@ export async function runCommand( format: 'table' | 'json', watch: boolean ): Pr
126126
},
127127
{ debounceMs: 500 }
128128
);
129+
130+
await subscribePm2KillEvent( () => {
131+
for ( const site of sitesData ) {
132+
const payload = {
133+
siteId: site.id,
134+
status: 'stopped',
135+
url: site.url,
136+
};
137+
logger.reportKeyValuePair( 'site-status', JSON.stringify( payload ) );
138+
}
139+
} );
140+
141+
process.on( 'SIGINT', disconnect );
142+
process.on( 'SIGTERM', disconnect );
129143
}
130144
} finally {
131145
if ( ! watch ) {
132-
disconnect();
146+
await disconnect();
133147
}
134148
}
135149
}

cli/commands/site/set.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ export async function runCommand(
246246

247247
return { usedWpCli: wpChanged };
248248
} finally {
249-
disconnect();
249+
await disconnect();
250250
}
251251
}
252252

cli/commands/site/start.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ export async function runCommand(
1616
skipLogDetails = false
1717
): Promise< void > {
1818
try {
19-
logger.reportStart( LoggerAction.LOAD_SITES, __( 'Loading site…' ) );
20-
const site = await getSiteByFolder( sitePath );
21-
logger.reportSuccess( __( 'Site loaded' ) );
22-
2319
logger.reportStart( LoggerAction.START_DAEMON, __( 'Starting process daemon…' ) );
2420
await connect();
2521
logger.reportSuccess( __( 'Process daemon started' ) );
2622

23+
logger.reportStart( LoggerAction.LOAD_SITES, __( 'Loading site…' ) );
24+
const site = await getSiteByFolder( sitePath );
25+
logger.reportSuccess( __( 'Site loaded' ) );
26+
2727
const runningProcess = await isServerRunning( site.id );
2828
if ( runningProcess ) {
2929
logger.reportSuccess( __( 'WordPress server is already running' ) );
@@ -67,7 +67,7 @@ export async function runCommand(
6767
throw new LoggerError( __( 'Failed to start WordPress server' ), error );
6868
}
6969
} finally {
70-
disconnect();
70+
await disconnect();
7171
}
7272
}
7373

cli/commands/site/status.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ const logger = new Logger< LoggerAction >();
1313

1414
export async function runCommand( siteFolder: string, format: 'table' | 'json' ): Promise< void > {
1515
try {
16+
logger.reportStart( LoggerAction.START_DAEMON, __( 'Starting process daemon…' ) );
17+
await connect();
18+
logger.reportSuccess( __( 'Process daemon started' ) );
19+
1620
logger.reportStart( LoggerAction.LOAD_SITES, __( 'Loading site…' ) );
1721
const site = await getSiteByFolder( siteFolder );
1822
logger.reportSuccess( __( 'Site loaded' ) );
1923

20-
await connect();
21-
2224
const isOnline = Boolean( await isServerRunning( site.id ) );
2325
const status = isOnline ? `🟢 ${ __( 'Online' ) }` : `🔴 ${ __( 'Offline' ) }`;
2426
const siteUrl = getSiteUrl( site );
@@ -74,7 +76,7 @@ export async function runCommand( siteFolder: string, format: 'table' | 'json' )
7476
console.log( JSON.stringify( logData, null, 2 ) );
7577
}
7678
} finally {
77-
disconnect();
79+
await disconnect();
7880
}
7981
}
8082

cli/commands/site/stop.ts

Lines changed: 38 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ import { SiteCommandLoggerAction as LoggerAction } from 'common/logger-actions';
33
import {
44
clearSiteLatestCliPid,
55
getSiteByFolder,
6+
lockAppdata,
67
readAppdata,
8+
saveAppdata,
9+
unlockAppdata,
710
updateSiteAutoStart,
811
type SiteData,
912
} from 'cli/lib/appdata';
10-
import { connect, disconnect } from 'cli/lib/pm2-manager';
13+
import { connect, disconnect, killDaemonAndAllChildren } from 'cli/lib/pm2-manager';
1114
import { stopProxyIfNoSitesNeedIt } from 'cli/lib/site-utils';
1215
import { isServerRunning, stopWordPressServer } from 'cli/lib/wordpress-server-manager';
1316
import { Logger, LoggerError } from 'cli/logger';
@@ -38,92 +41,76 @@ export async function runCommand(
3841
try {
3942
await connect();
4043

41-
const sitesToTarget: SiteData[] = [];
42-
4344
if ( target === Mode.STOP_SINGLE_SITE && siteFolder ) {
4445
const site = await getSiteByFolder( siteFolder );
45-
sitesToTarget.push( site );
46-
4746
const runningProcess = await isServerRunning( site.id );
4847
if ( ! runningProcess ) {
4948
logger.reportSuccess( __( 'WordPress server is not running' ) );
5049
return;
5150
}
5251

53-
logger.reportStart( LoggerAction.STOP_SITE, __( 'Stopping WordPress server…' ) );
52+
logger.reportStart( LoggerAction.STOP_SITE, __( 'Stopping WordPress servers…' ) );
53+
54+
try {
55+
await stopWordPressServer( site.id );
56+
await clearSiteLatestCliPid( site.id );
57+
await updateSiteAutoStart( site.id, autoStart );
58+
logger.reportSuccess( __( 'WordPress server stopped' ) );
59+
await stopProxyIfNoSitesNeedIt( site.id, logger );
60+
} catch ( error ) {
61+
throw new LoggerError( __( 'Failed to stop WordPress server' ), error );
62+
}
5463
} else {
5564
const appdata = await readAppdata();
65+
const runningSites: SiteData[] = [];
5666

5767
for ( const site of appdata.sites ) {
5868
const runningProcess = await isServerRunning( site.id );
5969

6070
if ( runningProcess ) {
61-
sitesToTarget.push( site );
71+
runningSites.push( site );
6272
}
6373
}
6474

65-
if ( ! sitesToTarget.length ) {
75+
if ( ! runningSites.length ) {
6676
logger.reportSuccess( __( 'No sites are currently running' ) );
6777
return;
6878
}
6979

70-
logger.reportStart( LoggerAction.STOP_ALL_SITES, __( 'Stopping all WordPress sites...' ) );
71-
}
72-
73-
const stoppedSiteIds: string[] = [];
80+
logger.reportStart( LoggerAction.STOP_ALL_SITES, __( 'Stopping all WordPress servers…' ) );
81+
await killDaemonAndAllChildren();
7482

75-
for ( const site of sitesToTarget ) {
7683
try {
77-
logger.reportProgress(
78-
sprintf(
79-
__( 'Stopping site "%s" (%d/%d)…' ),
80-
site.name,
81-
stoppedSiteIds.length + 1,
82-
sitesToTarget.length
83-
)
84-
);
85-
await stopWordPressServer( site.id );
86-
await clearSiteLatestCliPid( site.id );
87-
await updateSiteAutoStart( site.id, autoStart );
88-
89-
stoppedSiteIds.push( site.id );
90-
} catch ( error ) {
91-
logger.reportError(
92-
new LoggerError( sprintf( __( 'Failed to stop site %s' ), site.name ) )
93-
);
84+
await lockAppdata();
85+
const appdata = await readAppdata();
86+
for ( const site of appdata.sites ) {
87+
if ( runningSites.find( ( r ) => r.id === site.id ) ) {
88+
delete site.latestCliPid;
89+
site.autoStart = autoStart;
90+
}
91+
}
92+
await saveAppdata( appdata );
93+
} finally {
94+
await unlockAppdata();
9495
}
95-
}
96-
97-
try {
98-
await stopProxyIfNoSitesNeedIt( stoppedSiteIds, logger );
99-
} catch ( error ) {
100-
throw new LoggerError( __( 'Failed to stop proxy server' ), error );
101-
}
10296

103-
if ( stoppedSiteIds.length === sitesToTarget.length ) {
10497
logger.reportSuccess(
10598
sprintf(
10699
_n(
107100
'Successfully stopped %d site',
108101
'Successfully stopped %d sites',
109-
sitesToTarget.length
102+
runningSites.length
110103
),
111-
sitesToTarget.length
112-
)
113-
);
114-
} else if ( stoppedSiteIds.length === 0 && sitesToTarget.length === 0 ) {
115-
throw new LoggerError( __( 'Failed to stop site' ) );
116-
} else {
117-
throw new LoggerError(
118-
sprintf(
119-
_n( 'Stopped %d site out of %d', 'Stopped %d sites out of %d', stoppedSiteIds.length ),
120-
stoppedSiteIds.length,
121-
sitesToTarget.length
104+
runningSites.length
122105
)
123106
);
107+
108+
// Calling `pm2.killDaemon` requires us to forcefully exit the process. pm2 does the same
109+
// thing internally in its CLI.
110+
process.exit( 0 );
124111
}
125112
} finally {
126-
disconnect();
113+
await disconnect();
127114
}
128115
}
129116

0 commit comments

Comments
 (0)