From 98bcf84bc687c7c68d611413876bda6bbd570e79 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Tue, 25 Jun 2024 12:33:05 +0200 Subject: [PATCH] chore: enable ESRP CDN --- packages/playwright-core/src/cli/program.ts | 8 +--- .../src/server/registry/browserFetcher.ts | 8 ++-- .../src/server/registry/index.ts | 46 +++++++------------ tests/installation/playwright-cdn.spec.ts | 31 ------------- 4 files changed, 23 insertions(+), 70 deletions(-) diff --git a/packages/playwright-core/src/cli/program.ts b/packages/playwright-core/src/cli/program.ts index ad943c049e..9a888d702d 100644 --- a/packages/playwright-core/src/cli/program.ts +++ b/packages/playwright-core/src/cli/program.ts @@ -149,12 +149,8 @@ program const version = executable.browserVersion ? `version ` + executable.browserVersion : ''; console.log(`browser: ${executable.name}${version ? ' ' + version : ''}`); console.log(` Install location: ${executable.directory ?? ''}`); - if (executable.downloadURLs?.length) { - const [url, ...fallbacks] = executable.downloadURLs; - console.log(` Download url: ${url}`); - for (let i = 0; i < fallbacks.length; ++i) - console.log(` Download fallback ${i + 1}: ${fallbacks[i]}`); - } + if (executable.downloadURL) + console.log(` Download url: ${executable.downloadURL}`); console.log(``); } } else { diff --git a/packages/playwright-core/src/server/registry/browserFetcher.ts b/packages/playwright-core/src/server/registry/browserFetcher.ts index 6f8da6e825..965a6e1644 100644 --- a/packages/playwright-core/src/server/registry/browserFetcher.ts +++ b/packages/playwright-core/src/server/registry/browserFetcher.ts @@ -27,7 +27,7 @@ import { browserDirectoryToMarkerFilePath } from '.'; import { getUserAgent } from '../../utils/userAgent'; import type { DownloadParams } from './oopDownloadBrowserMain'; -export async function downloadBrowserWithProgressBar(title: string, browserDirectory: string, executablePath: string | undefined, downloadURLs: string[], downloadFileName: string, downloadConnectionTimeout: number): Promise { +export async function downloadBrowserWithProgressBar(title: string, browserDirectory: string, executablePath: string | undefined, downloadURLs: string, downloadFileName: string, downloadConnectionTimeout: number): Promise { if (await existsAsync(browserDirectoryToMarkerFilePath(browserDirectory))) { // Already downloaded. debugLogger.log('install', `${title} is already downloaded.`); @@ -39,9 +39,8 @@ export async function downloadBrowserWithProgressBar(title: string, browserDirec const retryCount = 3; for (let attempt = 1; attempt <= retryCount; ++attempt) { debugLogger.log('install', `downloading ${title} - attempt #${attempt}`); - const url = downloadURLs[(attempt - 1) % downloadURLs.length]; - logPolitely(`Downloading ${title}` + colors.dim(` from ${url}`)); - const { error } = await downloadBrowserWithProgressBarOutOfProcess(title, browserDirectory, url, zipPath, executablePath, downloadConnectionTimeout); + logPolitely(`Downloading ${title}` + colors.dim(` from ${downloadURLs}`)); + const { error } = await downloadBrowserWithProgressBarOutOfProcess(title, browserDirectory, downloadURLs, zipPath, executablePath, downloadConnectionTimeout); if (!error) { debugLogger.log('install', `SUCCESS installing ${title}`); break; @@ -96,6 +95,7 @@ function downloadBrowserWithProgressBarOutOfProcess(title: string, browserDirect promise.resolve({ error }); }); + debugLogger.log('install', `running download:`); debugLogger.log('install', `-- from url: ${url}`); debugLogger.log('install', `-- to location: ${zipPath}`); diff --git a/packages/playwright-core/src/server/registry/index.ts b/packages/playwright-core/src/server/registry/index.ts index c7ce3a2e7e..984e1e56fe 100644 --- a/packages/playwright-core/src/server/registry/index.ts +++ b/packages/playwright-core/src/server/registry/index.ts @@ -36,19 +36,7 @@ import { debugLogger } from '../../utils/debugLogger'; const PACKAGE_PATH = path.join(__dirname, '..', '..', '..'); const BIN_PATH = path.join(__dirname, '..', '..', '..', 'bin'); -const PLAYWRIGHT_CDN_MIRRORS = [ - 'https://playwright.azureedge.net', - 'https://playwright-akamai.azureedge.net', - 'https://playwright-verizon.azureedge.net', -]; - -if (process.env.PW_TEST_CDN_THAT_SHOULD_WORK) { - for (let i = 0; i < PLAYWRIGHT_CDN_MIRRORS.length; i++) { - const cdn = PLAYWRIGHT_CDN_MIRRORS[i]; - if (cdn !== process.env.PW_TEST_CDN_THAT_SHOULD_WORK) - PLAYWRIGHT_CDN_MIRRORS[i] = cdn + '.does-not-resolve.playwright.dev'; - } -} +const PLAYWRIGHT_CDN_MIRROR = 'https://playwright.azureedge.net'; const EXECUTABLE_PATHS = { 'chromium': { @@ -360,7 +348,7 @@ export interface Executable { browserName: BrowserName | undefined; installType: 'download-by-default' | 'download-on-demand' | 'install-script' | 'none'; directory: string | undefined; - downloadURLs?: string[], + downloadURL?: string, browserVersion?: string, executablePathOrDie(sdkLanguage: string): string; executablePath(sdkLanguage: string): string | undefined; @@ -428,7 +416,7 @@ export class Registry { executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('chromium', chromiumExecutable, chromium.installByDefault, sdkLanguage), installType: chromium.installByDefault ? 'download-by-default' : 'download-on-demand', _validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'chromium', chromium.dir, ['chrome-linux'], [], ['chrome-win']), - downloadURLs: this._downloadURLs(chromium), + downloadURL: this._downloadURL(chromium), browserVersion: chromium.browserVersion, _install: () => this._downloadExecutable(chromium, chromiumExecutable), _dependencyGroup: 'chromium', @@ -446,7 +434,7 @@ export class Registry { executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('chromium-tip-of-tree', chromiumTipOfTreeExecutable, chromiumTipOfTree.installByDefault, sdkLanguage), installType: chromiumTipOfTree.installByDefault ? 'download-by-default' : 'download-on-demand', _validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'chromium', chromiumTipOfTree.dir, ['chrome-linux'], [], ['chrome-win']), - downloadURLs: this._downloadURLs(chromiumTipOfTree), + downloadURL: this._downloadURL(chromiumTipOfTree), browserVersion: chromiumTipOfTree.browserVersion, _install: () => this._downloadExecutable(chromiumTipOfTree, chromiumTipOfTreeExecutable), _dependencyGroup: 'chromium', @@ -532,7 +520,7 @@ export class Registry { executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('firefox', firefoxExecutable, firefox.installByDefault, sdkLanguage), installType: firefox.installByDefault ? 'download-by-default' : 'download-on-demand', _validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'firefox', firefox.dir, ['firefox'], [], ['firefox']), - downloadURLs: this._downloadURLs(firefox), + downloadURL: this._downloadURL(firefox), browserVersion: firefox.browserVersion, _install: () => this._downloadExecutable(firefox, firefoxExecutable), _dependencyGroup: 'firefox', @@ -550,7 +538,7 @@ export class Registry { executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('firefox-beta', firefoxBetaExecutable, firefoxBeta.installByDefault, sdkLanguage), installType: firefoxBeta.installByDefault ? 'download-by-default' : 'download-on-demand', _validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'firefox', firefoxBeta.dir, ['firefox'], [], ['firefox']), - downloadURLs: this._downloadURLs(firefoxBeta), + downloadURL: this._downloadURL(firefoxBeta), browserVersion: firefoxBeta.browserVersion, _install: () => this._downloadExecutable(firefoxBeta, firefoxBetaExecutable), _dependencyGroup: 'firefox', @@ -578,7 +566,7 @@ export class Registry { executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('webkit', webkitExecutable, webkit.installByDefault, sdkLanguage), installType: webkit.installByDefault ? 'download-by-default' : 'download-on-demand', _validateHostRequirements: (sdkLanguage: string) => this._validateHostRequirements(sdkLanguage, 'webkit', webkit.dir, webkitLinuxLddDirectories, ['libGLESv2.so.2', 'libx264.so'], ['']), - downloadURLs: this._downloadURLs(webkit), + downloadURL: this._downloadURL(webkit), browserVersion: webkit.browserVersion, _install: () => this._downloadExecutable(webkit, webkitExecutable), _dependencyGroup: 'webkit', @@ -596,7 +584,7 @@ export class Registry { executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('ffmpeg', ffmpegExecutable, ffmpeg.installByDefault, sdkLanguage), installType: ffmpeg.installByDefault ? 'download-by-default' : 'download-on-demand', _validateHostRequirements: () => Promise.resolve(), - downloadURLs: this._downloadURLs(ffmpeg), + downloadURL: this._downloadURL(ffmpeg), _install: () => this._downloadExecutable(ffmpeg, ffmpegExecutable), _dependencyGroup: 'tools', _isHermeticInstallation: true, @@ -611,7 +599,7 @@ export class Registry { executablePathOrDie: () => '', installType: 'download-on-demand', _validateHostRequirements: () => Promise.resolve(), - downloadURLs: this._downloadURLs(android), + downloadURL: this._downloadURL(android), _install: () => this._downloadExecutable(android), _dependencyGroup: 'tools', _isHermeticInstallation: true, @@ -828,14 +816,14 @@ export class Registry { await fs.promises.writeFile(markerFile, '').catch(() => {}); } - private _downloadURLs(descriptor: BrowsersJSONDescriptor): string[] { + private _downloadURL(descriptor: BrowsersJSONDescriptor): string | undefined { const paths = (DOWNLOAD_PATHS as any)[descriptor.name]; const downloadPathTemplate: string|undefined = paths[hostPlatform] || paths['']; if (!downloadPathTemplate) - return []; + return undefined; const downloadPath = util.format(downloadPathTemplate, descriptor.revision); - let downloadURLs = PLAYWRIGHT_CDN_MIRRORS.map(mirror => `${mirror}/${downloadPath}`) ; + let downloadURL = `${PLAYWRIGHT_CDN_MIRROR}/download/playwright/${downloadPath}`; let downloadHostEnv; if (descriptor.name.startsWith('chromium')) downloadHostEnv = 'PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST'; @@ -846,13 +834,13 @@ export class Registry { const customHostOverride = (downloadHostEnv && getFromENV(downloadHostEnv)) || getFromENV('PLAYWRIGHT_DOWNLOAD_HOST'); if (customHostOverride) - downloadURLs = [`${customHostOverride}/${downloadPath}`]; - return downloadURLs; + downloadURL = `${customHostOverride}/${downloadPath}`; + return downloadURL; } private async _downloadExecutable(descriptor: BrowsersJSONDescriptor, executablePath?: string) { - const downloadURLs = this._downloadURLs(descriptor); - if (!downloadURLs.length) + const downloadURL = this._downloadURL(descriptor); + if (!downloadURL) throw new Error(`ERROR: Playwright does not support ${descriptor.name} on ${hostPlatform}`); if (!isOfficiallySupportedPlatform) logPolitely(`BEWARE: your OS is not officially supported by Playwright; downloading fallback build for ${hostPlatform}.`); @@ -867,7 +855,7 @@ export class Registry { const downloadFileName = `playwright-download-${descriptor.name}-${hostPlatform}-${descriptor.revision}.zip`; const downloadConnectionTimeoutEnv = getFromENV('PLAYWRIGHT_DOWNLOAD_CONNECTION_TIMEOUT'); const downloadConnectionTimeout = +(downloadConnectionTimeoutEnv || '0') || 30_000; - await downloadBrowserWithProgressBar(title, descriptor.dir, executablePath, downloadURLs, downloadFileName, downloadConnectionTimeout).catch(e => { + await downloadBrowserWithProgressBar(title, descriptor.dir, executablePath, downloadURL, downloadFileName, downloadConnectionTimeout).catch(e => { throw new Error(`Failed to download ${title}, caused by\n${e.stack}`); }); } diff --git a/tests/installation/playwright-cdn.spec.ts b/tests/installation/playwright-cdn.spec.ts index e1e438ecdc..67a4c1182e 100644 --- a/tests/installation/playwright-cdn.spec.ts +++ b/tests/installation/playwright-cdn.spec.ts @@ -18,39 +18,8 @@ import http from 'http'; import net from 'net'; import type { AddressInfo } from 'net'; -const CDNS = [ - 'https://playwright.azureedge.net', - 'https://playwright-akamai.azureedge.net', - 'https://playwright-verizon.azureedge.net', -]; - -const DL_STAT_BLOCK = /^.*from url: (.*)$\n^.*to location: (.*)$\n^.*response status code: (.*)$\n^.*total bytes: (\d+)$\n^.*download complete, size: (\d+)$\n^.*SUCCESS downloading (\w+) .*$/gm; - -const parsedDownloads = (rawLogs: string) => { - const out: { url: string, status: number, name: string }[] = []; - for (const match of rawLogs.matchAll(DL_STAT_BLOCK)) { - const [, url, /* filepath */, status, /* size */, /* receivedBytes */, name] = match; - out.push({ url, status: Number.parseInt(status, 10), name: name.toLocaleLowerCase() }); - } - return out; -}; - test.use({ isolateBrowsers: true }); -for (const cdn of CDNS) { - test(`playwright cdn failover should work (${cdn})`, async ({ exec, installedSoftwareOnDisk }) => { - await exec('npm i playwright'); - const result = await exec('npx playwright install', { env: { PW_TEST_CDN_THAT_SHOULD_WORK: cdn, DEBUG: 'pw:install' } }); - expect(result).toHaveLoggedSoftwareDownload(['chromium', 'ffmpeg', 'firefox', 'webkit']); - expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'ffmpeg', 'firefox', 'webkit']); - const dls = parsedDownloads(result); - for (const software of ['chromium', 'ffmpeg', 'firefox', 'webkit']) - expect(dls).toContainEqual({ status: 200, name: software, url: expect.stringContaining(cdn) }); - await exec('node sanity.js playwright chromium firefox webkit'); - await exec('node esm-playwright.mjs'); - }); -} - test(`playwright cdn should race with a timeout`, async ({ exec }) => { const server = http.createServer(() => {}); await new Promise(resolve => server.listen(0, resolve));