diff --git a/packages/playwright-core/package.json b/packages/playwright-core/package.json index bbc57c71fb..3e4fae5d9c 100644 --- a/packages/playwright-core/package.json +++ b/packages/playwright-core/package.json @@ -20,7 +20,6 @@ }, "./cli": "./cli.js", "./package.json": "./package.json", - "./lib/grid/gridServer": "./lib/grid/gridServer.js", "./lib/outofprocess": "./lib/outofprocess.js", "./lib/image_tools/stats": "./lib/image_tools/stats.js", "./lib/image_tools/compare": "./lib/image_tools/compare.js", diff --git a/packages/playwright-core/src/cli/DEPS.list b/packages/playwright-core/src/cli/DEPS.list index 5ab1f1c5e7..fdca1c1698 100644 --- a/packages/playwright-core/src/cli/DEPS.list +++ b/packages/playwright-core/src/cli/DEPS.list @@ -4,7 +4,6 @@ ../common ../debug/injected ../generated/ -../grid ../server/injected/ ../server/trace ../utils diff --git a/packages/playwright-core/src/cli/cli.ts b/packages/playwright-core/src/cli/cli.ts index 31143ef8bd..1675abd7f0 100755 --- a/packages/playwright-core/src/cli/cli.ts +++ b/packages/playwright-core/src/cli/cli.ts @@ -33,9 +33,6 @@ import type { BrowserType } from '../client/browserType'; import type { BrowserContextOptions, LaunchOptions } from '../client/types'; import { spawn } from 'child_process'; import { wrapInASCIIBox, isLikelyNpxGlobal, assert } from '../utils'; -import { launchGridAgent } from '../grid/gridAgent'; -import type { GridFactory } from '../grid/gridServer'; -import { GridServer } from '../grid/gridServer'; import type { Executable } from '../server'; import { registry, writeDockerVersion } from '../server'; import { addContainerCLI } from '../containers/'; @@ -240,25 +237,6 @@ Examples: $ pdf https://example.com example.pdf`); -program - .command('experimental-grid-server', { hidden: true }) - .option('--port ', 'grid port; defaults to 3333') - .option('--address
', 'address of the server') - .option('--agent-factory ', 'path to grid agent factory or npm package') - .option('--auth-token ', 'optional authentication token') - .action(function(options) { - launchGridServer(options.agentFactory, options.port || 3333, options.address, options.authToken); - }); - -program - .command('experimental-grid-agent', { hidden: true }) - .requiredOption('--agent-id ', 'agent ID') - .requiredOption('--grid-url ', 'grid URL') - .option('--run-id ', 'Workflow run_id') - .action(function(options) { - launchGridAgent(options.agentId, options.gridUrl, options.runId); - }); - program .command('run-driver', { hidden: true }) .action(function(options) { @@ -718,25 +696,6 @@ function commandWithOpenOptions(command: string, description: string, options: a .option('--viewport-size ', 'specify browser viewport size in pixels, for example "1280, 720"'); } -async function launchGridServer(factoryPathOrPackageName: string, port: number, address: string | undefined, authToken: string | undefined): Promise { - if (!factoryPathOrPackageName) - factoryPathOrPackageName = path.join('..', 'grid', 'simpleGridFactory'); - let factory; - try { - factory = require(path.resolve(factoryPathOrPackageName)); - } catch (e) { - factory = require(factoryPathOrPackageName); - } - if (factory && typeof factory === 'object' && ('default' in factory)) - factory = factory['default']; - if (!factory || !factory.launch || typeof factory.launch !== 'function') - throw new Error('factory does not export `launch` method'); - factory.name = factory.name || factoryPathOrPackageName; - const gridServer = new GridServer(factory as GridFactory, authToken, address); - await gridServer.start(port); - console.log('Grid server is running at ' + gridServer.gridURL()); -} - function buildBasePlaywrightCLICommand(cliTargetLang: string | undefined): string { switch (cliTargetLang) { case 'python': diff --git a/packages/playwright-core/src/grid/DEPS.list b/packages/playwright-core/src/grid/DEPS.list deleted file mode 100644 index 15a24dc316..0000000000 --- a/packages/playwright-core/src/grid/DEPS.list +++ /dev/null @@ -1,8 +0,0 @@ -[*] -../client/ -../common/ -../dispatchers/ -../remote/ -../server/ -../utils/ -../utilsBundle.ts diff --git a/packages/playwright-core/src/grid/githubGridFactory.ts b/packages/playwright-core/src/grid/githubGridFactory.ts deleted file mode 100644 index cf0e45c3d9..0000000000 --- a/packages/playwright-core/src/grid/githubGridFactory.ts +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the 'License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import type { GridAgentLaunchOptions, GridFactory } from './gridServer'; -import https from 'https'; -import { debug } from '../utilsBundle'; - -const repoName = process.env.GITHUB_AGENT_REPO; -if (!repoName) - throw new Error('GITHUB_AGENT_REPO is not specified.'); - -const repoAccessToken = process.env.GITHUB_AGENT_REPO_ACCESS_TOKEN; -if (!repoAccessToken) - throw new Error('GITHUB_AGENT_REPO_ACCESS_TOKEN is not specified.'); - -const log = debug(`pw:grid:server`); - -const githubFactory: GridFactory = { - name: 'Agents hosted on Github', - // Standard VM is 3-core on mac and 2-core on win and lin - capacity: 4, - launchTimeout: 10 * 60_000, - retireTimeout: 1 * 60 * 60_000, - statusUrl: (runId: string) => { - return `https://github.com/${repoName}/actions/runs/${runId}`; - }, - launch: async (options: GridAgentLaunchOptions) => { - await createWorkflow(options); - }, -}; - -async function createWorkflow(inputs: GridAgentLaunchOptions): Promise { - if (!['windows', 'linux', 'macos'].includes(inputs.os)) { - log(`unsupported OS: ${inputs.os}`); - return false; - } - return new Promise(fulfill => { - log(`triggering workflow ${JSON.stringify(inputs)}`); - const req = https.request(`https://api.github.com/repos/${repoName}/actions/workflows/agent.yml/dispatches`, { - method: 'POST', - headers: { - 'User-Agent': 'request', - 'Accept': 'application/vnd.github.v3+json', - 'Authorization': `token ${repoAccessToken}`, - } - }, response => { - log(`workflow ${inputs.agentId} response: ${response.statusCode} ${response.statusMessage}`); - const success = !!response.statusCode && 200 <= response.statusCode && response.statusCode < 300; - fulfill(success); - }); - req.on('error', e => { - log(`failed to create workflow ${inputs.agentId}`); - fulfill(false); - }); - req.end(JSON.stringify({ - 'ref': 'refs/heads/main', - inputs - })); - }); -} - -export default githubFactory; diff --git a/packages/playwright-core/src/grid/gridAgent.ts b/packages/playwright-core/src/grid/gridAgent.ts deleted file mode 100644 index 39b79165b9..0000000000 --- a/packages/playwright-core/src/grid/gridAgent.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { debug } from '../utilsBundle'; -import { ws as WebSocket } from '../utilsBundle'; -import { fork } from 'child_process'; -import { getPlaywrightVersion } from '../utils/userAgent'; - -export function launchGridAgent(agentId: string, gridURL: string, runId: string | undefined) { - const log = debug(`pw:grid:agent:${agentId}`); - log('created'); - const params = new URLSearchParams(); - params.set('pwVersion', getPlaywrightVersion(true /* majorMinorOnly */)); - params.set('agentId', agentId); - if (runId) - params.set('runId', runId); - const ws = new WebSocket(gridURL.replace('http://', 'ws://') + `/registerAgent?` + params.toString()); - ws.on('message', (message: string) => { - log('worker requested ' + message); - const { workerId, browserName } = JSON.parse(message); - if (!workerId) { - log('workerId not specified'); - return; - } - if (!browserName) { - log('browserName not specified'); - return; - } - fork(require.resolve('./gridBrowserWorker.js'), [gridURL, agentId, workerId, browserName], { detached: true }); - }); - ws.on('close', () => process.exit(0)); -} diff --git a/packages/playwright-core/src/grid/gridBrowserWorker.ts b/packages/playwright-core/src/grid/gridBrowserWorker.ts deleted file mode 100644 index 5aa175100e..0000000000 --- a/packages/playwright-core/src/grid/gridBrowserWorker.ts +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { debug } from '../utilsBundle'; -import { ws as WebSocket } from '../utilsBundle'; -import { PlaywrightConnection } from '../remote/playwrightConnection'; -import { gracefullyCloseAll } from '../utils/processLauncher'; - -function launchGridBrowserWorker(gridURL: string, agentId: string, workerId: string, browserName: string) { - const log = debug(`pw:grid:worker:${workerId}`); - log('created'); - const ws = new WebSocket(gridURL.replace('http://', 'ws://') + `/registerWorker?agentId=${agentId}&workerId=${workerId}`); - new PlaywrightConnection(Promise.resolve(), 'launch-browser', ws, { socksProxyPattern: '*', browserName, launchOptions: {} }, { }, log, async () => { - log('exiting process'); - setTimeout(() => process.exit(0), 30000); - // Meanwhile, try to gracefully close all browsers. - await gracefullyCloseAll(); - process.exit(0); - }); -} - -launchGridBrowserWorker(process.argv[2], process.argv[3], process.argv[4], process.argv[5]); diff --git a/packages/playwright-core/src/grid/gridServer.ts b/packages/playwright-core/src/grid/gridServer.ts deleted file mode 100644 index 22ab7d0d5b..0000000000 --- a/packages/playwright-core/src/grid/gridServer.ts +++ /dev/null @@ -1,413 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { debug } from '../utilsBundle'; -import { EventEmitter } from 'events'; -import { URL } from 'url'; -import type { WebSocketServer, WebSocket, WebSocketRawData } from '../utilsBundle'; -import { HttpServer } from '../utils/httpServer'; -import { assert, createGuid } from '../utils'; -import { getPlaywrightVersion } from '../utils/userAgent'; - -const defaultOS = 'linux'; - -export type GridAgentLaunchOptions = { - agentId: string, - gridURL: string, - playwrightVersion: string, - os: string, -}; - -export type GridFactory = { - name?: string, - capacity?: number, - launchTimeout?: number, - retireTimeout?: number, - statusUrl?: (runId: string) => string; - launch: (launchOptions: GridAgentLaunchOptions) => Promise, -}; - -type ErrorCode = { - code: number, - reason: string, -}; - -const WSErrors = { - NO_ERROR: { code: 1000, reason: '' }, - AUTH_FAILED: { code: 1008, reason: 'Grid authentication failed' }, - AGENT_CREATION_FAILED: { code: 1013, reason: 'Grid agent creation failed' }, - AGENT_NOT_FOUND: { code: 1013, reason: 'Grid agent registration failed - agent with given ID not found' }, - AGENT_NOT_CONNECTED: { code: 1013, reason: 'Grid worker registration failed - agent has unsupported status' }, - AGENT_CREATION_TIMED_OUT: { code: 1013, reason: 'Grid agent creation timed out' }, - AGENT_RETIRED: { code: 1000, reason: 'Grid agent was retired' }, - CLIENT_SOCKET_ERROR: { code: 1011, reason: 'Grid client socket error' }, - WORKER_SOCKET_ERROR: { code: 1011, reason: 'Grid worker socket error' }, - CLIENT_PLAYWRIGHT_VERSION_MISMATCH: { code: 1013, reason: 'Grid Playwright and grid client versions are different' }, - AGENT_PLAYWRIGHT_VERSION_MISMATCH: { code: 1013, reason: 'Grid Playwright and grid agent versions are different' }, - CLIENT_UNSUPPORTED_OS: { code: 1013, reason: 'Unsupported OS' }, - GRID_SHUTDOWN: { code: 1000, reason: 'Grid was shutdown' }, - AGENT_MANUALLY_STOPPED: { code: 1000, reason: 'Grid agent was manually stopped' }, -}; - - -type GridWorkerParams = { - browserName?: string; -}; - -class GridWorker extends EventEmitter { - readonly workerId = createGuid(); - readonly params: GridWorkerParams; - private _workerSocket: WebSocket | undefined; - private _clientSocket: WebSocket; - private _log: debug.Debugger; - private _bufferedMessages: WebSocketRawData[] = []; - - constructor(clientSocket: WebSocket, params: GridWorkerParams) { - super(); - this._log = debug(`pw:grid:worker:${this.workerId}`); - this._clientSocket = clientSocket; - this.params = params; - clientSocket.on('close', (code: number, reason: string) => this.closeWorker(WSErrors.NO_ERROR)); - clientSocket.on('error', (error: Error) => this.closeWorker(WSErrors.CLIENT_SOCKET_ERROR)); - // clientSocket.pause() would be preferrable but according to the docs " Some events can still be - // emitted after it is called, until all buffered data is consumed." - this._clientSocket.on('message', data => { - if (this._workerSocket) - this._workerSocket.send(data); - else - this._bufferedMessages.push(data); - }); - } - - workerConnected(workerSocket: WebSocket) { - this._log('connected'); - this._workerSocket = workerSocket; - workerSocket.on('close', (code: number, reason: string) => this.closeWorker(WSErrors.NO_ERROR)); - workerSocket.on('error', (error: Error) => this.closeWorker(WSErrors.WORKER_SOCKET_ERROR)); - workerSocket.on('message', data => this._clientSocket!.send(data)); - for (const data of this._bufferedMessages) - workerSocket.send(data); - this._bufferedMessages = []; - } - - closeWorker(errorCode: ErrorCode) { - this._log(`close ${errorCode.reason}`); - this._workerSocket?.close(errorCode.code, errorCode.reason); - this._clientSocket.close(errorCode.code, errorCode.reason); - this.emit('close'); - } - - debugInfo() { - return { worker: !!this._workerSocket, client: !!this._clientSocket }; - } -} - -type AgentStatus = 'none' | 'created' | 'connected' | 'idle'; - -class GridAgent extends EventEmitter { - private _capacity: number; - readonly agentId = createGuid(); - readonly os: string; - private _ws: WebSocket | undefined; - runId: string | undefined; - readonly _workers = new Map(); - private _status: AgentStatus = 'none'; - private _workersWaitingForAgentConnected: Set = new Set(); - private _retireTimeout = 30000; - private _retireTimeoutId: NodeJS.Timeout | undefined; - private _log: debug.Debugger; - private _agentCreationTimeoutId: NodeJS.Timeout; - - constructor(os: string, capacity = Infinity, creationTimeout = 5 * 60000, retireTimeout = 30000) { - super(); - this.os = os; - this._capacity = capacity; - this._log = debug(`pw:grid:agent:${this.agentId}`); - this.setStatus('created'); - this._retireTimeout = retireTimeout; - this._agentCreationTimeoutId = setTimeout(() => { - this.closeAgent(WSErrors.AGENT_CREATION_TIMED_OUT); - }, creationTimeout); - } - - public status(): AgentStatus { - return this._status; - } - - setStatus(status: AgentStatus) { - this._log(`status ${this._status} => ${status}`); - this._status = status; - } - - agentConnected(ws: WebSocket, runId?: string) { - clearTimeout(this._agentCreationTimeoutId); - this.setStatus('connected'); - this._ws = ws; - this.runId = runId; - for (const worker of this._workersWaitingForAgentConnected) - this._sendStartWorkerMessage(worker); - this._workersWaitingForAgentConnected.clear(); - } - - canCreateWorker(os: string) { - return this.os === os && this._workers.size < this._capacity; - } - - async createWorker(clientSocket: WebSocket, params: GridWorkerParams) { - if (this._retireTimeoutId) - clearTimeout(this._retireTimeoutId); - if (this._ws) - this.setStatus('connected'); - const worker = new GridWorker(clientSocket, params); - this._log(`create worker: ${worker.workerId}`); - this._workers.set(worker.workerId, worker); - worker.on('close', () => { - this._workers.delete(worker.workerId); - this._workersWaitingForAgentConnected.delete(worker); - if (!this._workers.size) { - this.setStatus('idle'); - if (this._retireTimeoutId) - clearTimeout(this._retireTimeoutId); - if (this._retireTimeout && isFinite(this._retireTimeout)) - this._retireTimeoutId = setTimeout(() => this.closeAgent(WSErrors.AGENT_RETIRED), this._retireTimeout); - } - }); - if (this._ws) - this._sendStartWorkerMessage(worker); - else - this._workersWaitingForAgentConnected.add(worker); - } - - workerConnected(workerId: string, ws: WebSocket) { - this._log(`worker connected: ${workerId}`); - const worker = this._workers.get(workerId)!; - worker.workerConnected(ws); - } - - closeAgent(errorCode: ErrorCode) { - for (const worker of this._workersWaitingForAgentConnected) - worker.closeWorker(errorCode); - for (const worker of this._workers.values()) - worker.closeWorker(errorCode); - this._log('close'); - this._ws?.close(errorCode.code, errorCode.reason); - this.emit('close'); - } - - private _sendStartWorkerMessage(worker: GridWorker) { - const message = JSON.stringify({ - ...worker.params, - 'workerId': worker.workerId, - }); - this._log(`start worker message: ${message}`); - assert(this._ws); - this._ws.send(message); - } -} - -export class GridServer { - private _server: HttpServer; - private _wsServer: WebSocketServer; - private _agents = new Map(); - private _log: debug.Debugger; - private _authToken: string; - private _factory: GridFactory; - private _pwVersion: string; - - constructor(factory: GridFactory, authToken: string = '', address: string = '') { - this._log = debug(`pw:grid:server`); - this._log(`using factory ${factory.name}`); - this._authToken = authToken || ''; - this._server = new HttpServer(address); - this._factory = factory; - this._pwVersion = getPlaywrightVersion(true /* majorMinorOnly */); - - this._server.routePath(this._securePath('/'), (request, response) => { - response.statusCode = 200; - response.setHeader('Content-Type', 'text/html'); - response.end(this._state()); - return true; - }); - - this._server.routePath(this._securePath('/stopAll'), (request, response) => { - for (const agent of this._agents.values()) - agent.closeAgent(WSErrors.AGENT_MANUALLY_STOPPED); - response.statusCode = 302; - response.setHeader('Location', this._securePath('/')); - response.end(); - return true; - }); - - this._wsServer = this._server.createWebSocketServer(); - - this._wsServer.shouldHandle = request => { - this._log(request.url); - if (request.url!.startsWith(this._securePath('/claimWorker')) || - request.url!.startsWith(this._securePath('/registerAgent')) || - request.url!.startsWith(this._securePath('/registerWorker'))) { - // shouldHandle claims it accepts promise, except it doesn't. - return true; - } - this._log('rejecting websocket request'); - return false; - }; - - this._wsServer.on('connection', async (ws, request) => { - if (request.url?.startsWith(this._securePath('/claimWorker'))) { - const params = new URL('http://localhost/' + request.url).searchParams; - const version = params.get('pwVersion'); - if (version !== this._pwVersion && !process.env.PWTEST_UNSAFE_GRID_VERSION) { - this._log(`version mismatch: ${version} !== ${this._pwVersion}`); - ws.close(WSErrors.CLIENT_PLAYWRIGHT_VERSION_MISMATCH.code, WSErrors.CLIENT_PLAYWRIGHT_VERSION_MISMATCH.reason); - return; - } - const os = params.get('os') || defaultOS; - const agent = [...this._agents.values()].find(w => w.canCreateWorker(os)) || this._createAgent(os)?.agent; - if (!agent) { - this._log(`failed to get agent`); - ws.close(WSErrors.AGENT_CREATION_FAILED.code, WSErrors.AGENT_CREATION_FAILED.reason); - return; - } - - agent.createWorker(ws, { - browserName: request.headers['x-playwright-browser'] as string, - }); - return; - } - - if (request.url?.startsWith(this._securePath('/registerAgent'))) { - const params = new URL('http://localhost/' + request.url).searchParams; - if (params.get('pwVersion') !== this._pwVersion) { - ws.close(WSErrors.AGENT_PLAYWRIGHT_VERSION_MISMATCH.code, WSErrors.AGENT_PLAYWRIGHT_VERSION_MISMATCH.reason); - return; - } - const agentId = params.get('agentId')!; - const agent = this._agents.get(agentId); - if (!agent) { - ws.close(WSErrors.AGENT_NOT_FOUND.code, WSErrors.AGENT_NOT_FOUND.reason); - return; - } - - const runId = params.get('runId') || undefined; - agent.agentConnected(ws, runId); - return; - } - - if (request.url?.startsWith(this._securePath('/registerWorker'))) { - const params = new URL('http://localhost/' + request.url).searchParams; - const agentId = params.get('agentId')!; - const workerId = params.get('workerId')!; - const agent = this._agents.get(agentId); - if (!agent) - ws.close(WSErrors.AGENT_NOT_FOUND.code, WSErrors.AGENT_NOT_FOUND.reason); - else if (agent.status() !== 'connected') - ws.close(WSErrors.AGENT_NOT_CONNECTED.code, WSErrors.AGENT_NOT_CONNECTED.reason); - else - agent.workerConnected(workerId, ws); - return; - } - }); - } - - public async createAgent(): Promise<{ error: any }> { - const { initPromise } = this._createAgent(defaultOS); - return await initPromise; - } - - private _createAgent(os: string): { agent: GridAgent, initPromise: Promise<{ error: any }> } { - const agent = new GridAgent(os, this._factory.capacity, this._factory.launchTimeout, this._factory.retireTimeout); - this._agents.set(agent.agentId, agent); - agent.on('close', () => { - this._agents.delete(agent.agentId); - }); - const initPromise = Promise.resolve() - .then(() => this._factory.launch({ - agentId: agent.agentId, - gridURL: this.gridURL(), - playwrightVersion: getPlaywrightVersion(), - os - })).then(() => { - this._log('created'); - return { error: undefined }; - }).catch(error => { - this._log('failed to launch agent ' + agent.agentId); - // eslint-disable-next-line no-console - console.error(error); - agent.closeAgent(WSErrors.AGENT_CREATION_FAILED); - return { error }; - }); - return { agent, initPromise }; - } - - _securePath(suffix: string): string { - return this._authToken ? '/' + this._authToken + suffix : suffix; - } - - private _state(): string { - const linkifyStatus = (agent: GridAgent) => { - if (agent.runId && this._factory.statusUrl) - return `${agent.status()}`; - return agent.status(); - }; - return ` -
-
- Grid Playwright Version: - Agent Factory: - Agents: -
-
- ${this._pwVersion} - ${this._factory.name} - ${this._agents.size} (Stop All) -
-
-
-
    - ${[...this._agents].map(([agentId, agent]) => ` -
  • -
    Agent (${agent.os}) ${mangle(agentId)}: ${linkifyStatus(agent)}
    -
    Workers: ${agent._workers.size}
    -
      - ${[...agent._workers].map(([workerId, worker]) => ` -
    • worker ${mangle(workerId)} - ${JSON.stringify(worker.debugInfo())}
    • - `).join('')} -
    -
  • - `).join('')} -
- `; - } - - async start(port?: number) { - await this._server.start({ port }); - } - - gridURL(): string { - return this._server.urlPrefix() + this._securePath(''); - } - - async stop() { - for (const agent of this._agents.values()) - agent.closeAgent(WSErrors.GRID_SHUTDOWN); - assert(this._agents.size === 0); - await this._server.stop(); - } -} - -function mangle(sessionId: string) { - return sessionId.replace(/\w{28}/, 'x'.repeat(28)); -} diff --git a/packages/playwright-core/src/grid/simpleGridFactory.ts b/packages/playwright-core/src/grid/simpleGridFactory.ts deleted file mode 100644 index d865516874..0000000000 --- a/packages/playwright-core/src/grid/simpleGridFactory.ts +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (c) Microsoft Corporation. - * - * Licensed under the Apache License, Version 2.0 (the 'License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import child_process from 'child_process'; -import type { GridAgentLaunchOptions, GridFactory } from './gridServer'; -import path from 'path'; - -const simpleFactory: GridFactory = { - name: 'Agents co-located with grid', - capacity: Infinity, - launchTimeout: 10000, - retireTimeout: 10000, - launch: async (options: GridAgentLaunchOptions) => { - child_process.spawn(process.argv[0], [ - path.join(__dirname, '..', 'cli', 'cli.js'), - 'experimental-grid-agent', - '--grid-url', options.gridURL, - '--agent-id', options.agentId, - ], { - cwd: __dirname, - shell: true, - stdio: 'inherit', - }); - }, -}; - -export default simpleFactory; diff --git a/tests/config/testMode.ts b/tests/config/testMode.ts index 3147cf58d2..ae8f2dde71 100644 --- a/tests/config/testMode.ts +++ b/tests/config/testMode.ts @@ -17,7 +17,7 @@ import { start } from '../../packages/playwright-core/lib/outofprocess'; import type { Playwright } from '../../packages/playwright-core/lib/client/playwright'; -export type TestModeName = 'default' | 'driver' | 'service' | 'service2' | 'docker_remote'; +export type TestModeName = 'default' | 'driver' | 'service' | 'docker_remote'; interface TestMode { setup(): Promise; diff --git a/tests/config/testModeFixtures.ts b/tests/config/testModeFixtures.ts index 2efe6743ee..079522dada 100644 --- a/tests/config/testModeFixtures.ts +++ b/tests/config/testModeFixtures.ts @@ -40,7 +40,6 @@ export const testModeTest = test.extend { return process.env.WKPATH; }; -const mode: TestModeName = (process.env.PWTEST_MODE ?? 'default') as ('default' | 'driver' | 'service' | 'service2' | 'docker_remote'); +const mode: TestModeName = (process.env.PWTEST_MODE ?? 'default') as ('default' | 'driver' | 'service' | 'docker_remote'); const headed = process.argv.includes('--headed'); const channel = process.env.PWTEST_CHANNEL as any; const video = !!process.env.PWTEST_VIDEO; @@ -77,39 +77,6 @@ const config: Config