From 2ff25522ccc1e326c9c4f851e81e9faf7fc1e054 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Mon, 19 Jul 2021 07:53:12 +0200 Subject: [PATCH] test: rework port forwarding server tests to launch server out of process (#7693) --- src/cli/cli.ts | 2 +- src/cli/driver.ts | 11 +++++-- tests/portForwardingServer.spec.ts | 50 +++++++++++++++++++++++++----- 3 files changed, 51 insertions(+), 12 deletions(-) diff --git a/src/cli/cli.ts b/src/cli/cli.ts index 39659e66cd..f758bf3d4d 100755 --- a/src/cli/cli.ts +++ b/src/cli/cli.ts @@ -243,7 +243,7 @@ if (!process.env.PW_CLI_TARGET_LANG) { if (process.argv[2] === 'run-driver') runDriver(); else if (process.argv[2] === 'run-server') - runServer(process.argv[3] ? +process.argv[3] : undefined); + runServer(process.argv[3] ? +process.argv[3] : undefined, process.argv[4]).catch(logErrorAndExit); else if (process.argv[2] === 'print-api-json') printApiJson(); else if (process.argv[2] === 'launch-server') diff --git a/src/cli/driver.ts b/src/cli/driver.ts index 936eb153c0..b55de4ba31 100644 --- a/src/cli/driver.ts +++ b/src/cli/driver.ts @@ -23,7 +23,7 @@ import { LaunchServerOptions } from '../client/types'; import { DispatcherConnection } from '../dispatchers/dispatcher'; import { PlaywrightDispatcher } from '../dispatchers/playwrightDispatcher'; import { Transport } from '../protocol/transport'; -import { PlaywrightServer } from '../remote/playwrightServer'; +import { PlaywrightServer, PlaywrightServerOptions } from '../remote/playwrightServer'; import { createPlaywright } from '../server/playwright'; import { gracefullyCloseAll } from '../utils/processLauncher'; @@ -51,8 +51,13 @@ export function runDriver() { new PlaywrightDispatcher(dispatcherConnection.rootDispatcher(), playwright); } -export async function runServer(port: number | undefined) { - const wsEndpoint = await (await PlaywrightServer.startDefault()).listen(port); +export async function runServer(port: number | undefined, configFile?: string) { + let options: PlaywrightServerOptions = {}; + if (configFile) + options = JSON.parse(fs.readFileSync(configFile).toString()); + const server = await PlaywrightServer.startDefault(options); + const wsEndpoint = await server.listen(port); + process.on('exit', () => server.close().catch(console.error)); console.log('Listening on ' + wsEndpoint); // eslint-disable-line no-console } diff --git a/tests/portForwardingServer.spec.ts b/tests/portForwardingServer.spec.ts index cf6948be3e..77f9db8105 100644 --- a/tests/portForwardingServer.spec.ts +++ b/tests/portForwardingServer.spec.ts @@ -14,16 +14,51 @@ * limitations under the License. */ +import childProcess from 'child_process'; import http from 'http'; +import path from 'path'; +import os from 'os'; +import fs from 'fs'; import net from 'net'; -import { PlaywrightClient } from '../lib/remote/playwrightClient'; -import { PlaywrightServer } from '../lib/remote/playwrightServer'; - import { contextTest, expect } from './config/browserTest'; +import { PlaywrightClient } from '../lib/remote/playwrightClient'; +import { createGuid } from '../src/utils/utils'; +import type { PlaywrightServerOptions } from '../src/remote/playwrightServer'; import type { LaunchOptions, ConnectOptions } from '../index'; import type { Page, BrowserServer } from '..'; +class OutOfProcessPlaywrightServer { + private _driverProcess: childProcess.ChildProcess; + private _receivedPortPromise: Promise; + constructor(port: number, config: PlaywrightServerOptions) { + const configFile = path.join(os.tmpdir(), `playwright-server-config-${createGuid()}.json`); + fs.writeFileSync(configFile, JSON.stringify(config)); + this._driverProcess = childProcess.fork(path.join(__dirname, '..', 'lib', 'cli', 'cli.js'), ['run-server', port.toString(), configFile], { + stdio: 'pipe', + detached: true, + }); + this._driverProcess.unref(); + this._receivedPortPromise = new Promise((resolve, reject) => { + this._driverProcess.stdout.on('data', (data: Buffer) => { + const prefix = 'Listening on '; + const line = data.toString(); + if (line.startsWith(prefix)) + resolve(line.substr(prefix.length)); + }); + this._driverProcess.on('exit', () => reject()); + }); + } + async kill() { + const waitForExit = new Promise(resolve => this._driverProcess.on('exit', () => resolve())); + this._driverProcess.kill('SIGKILL'); + await waitForExit; + } + public async wsEndpoint(): Promise { + return await this._receivedPortPromise; + } +} + type PageFactoryOptions = { acceptForwardedPorts: boolean forwardPorts: number[] @@ -35,17 +70,16 @@ const it = contextTest.extend<{ pageFactory: (options?: PageFactoryOptions) => P launchMode: [ 'launchServer', { scope: 'test' }], pageFactory: async ({ launchMode, browserType, browserName, browserOptions }, run) => { const browserServers: BrowserServer[] = []; - const playwrightServers: PlaywrightServer[] = []; + const playwrightServers: OutOfProcessPlaywrightServer[] = []; await run(async (options?: PageFactoryOptions): Promise => { const { acceptForwardedPorts, forwardPorts } = options; if (launchMode === 'playwrightclient') { - const server = await PlaywrightServer.startDefault({ + const server = new OutOfProcessPlaywrightServer(0, { acceptForwardedPorts, }); playwrightServers.push(server); - const wsEndpoint = await server.listen(0); const service = await PlaywrightClient.connect({ - wsEndpoint, + wsEndpoint: await server.wsEndpoint(), forwardPorts, }); const playwright = service.playwright(); @@ -66,7 +100,7 @@ const it = contextTest.extend<{ pageFactory: (options?: PageFactoryOptions) => P for (const browserServer of browserServers) await browserServer.close(); for (const playwrightServer of playwrightServers) - await playwrightServer.close(); + await playwrightServer.kill(); }, });