diff --git a/packages/playwright-core/src/utils/tar.ts b/packages/playwright-core/src/utils/tar.ts index 7d6098b45a..0210bcaec5 100644 --- a/packages/playwright-core/src/utils/tar.ts +++ b/packages/playwright-core/src/utils/tar.ts @@ -16,6 +16,7 @@ import fs from 'fs'; import { Writable, once } from 'stream'; import assert from 'assert'; +import { join } from 'path'; enum TarType { REGTYPE, @@ -36,6 +37,7 @@ class TarEntry { linkname: string; uid: number; gid: number; + prefix: string; fileStream: fs.WriteStream | null = null; remainingBytes = 0; @@ -53,10 +55,11 @@ class TarEntry { this.uid = parseInt(header.toString('ascii', 108, 116).trim(), 8); this.gid = parseInt(header.toString('ascii', 116, 124).trim(), 8); + this.prefix = header.toString('utf8', 345, 500).replace(/\0/g, ''); } async writeToDisk(outputPath: (path: string) => string) { - const fullPath = outputPath(this.name); + const fullPath = outputPath(this.prefix ? join(this.prefix, this.name) : this.name); switch (this.type) { case TarType.DIRTYPE: await fs.promises.mkdir(fullPath, { recursive: true, mode: 0o755 }); diff --git a/tests/library/unit/tar.spec.ts b/tests/library/unit/tar.spec.ts index 5ffaa43ecd..f741749ef3 100644 --- a/tests/library/unit/tar.spec.ts +++ b/tests/library/unit/tar.spec.ts @@ -36,85 +36,107 @@ test('tar extractor', async () => { expect(await readFile(test.info().outputPath('tar-example/symlink'), { encoding: 'utf-8' })).toEqual('foo-content'); }); -test('extract browser', async () => { - // not run by default because it's not hermetic. i'll remove this once we use the TAR extractor in our code. +test.describe('browser downloads', () => { + // not run by default because they're not hermetic. i'll remove them once we use the TAR extractor in our code. test.skip(process.env.TEST_TAR_BROWSER !== '1'); - const response = await fetch('https://playwright.azureedge.net/download-for-internal-testing/playwright/builds/chromium/1152/chromium-headless-shell-linux-arm64.tar.br'); - const input = Readable.fromWeb(response.body as any); - const decompressor = createBrotliDecompress(); - const extractor = new TarExtractor(name => test.info().outputPath(name)); - await finished(input.pipe(decompressor).pipe(extractor)); + test('chromium-headless-shell', async () => { + const response = await fetch('https://playwright.azureedge.net/download-for-internal-testing/playwright/builds/chromium/1152/chromium-headless-shell-linux-arm64.tar.br'); + const input = Readable.fromWeb(response.body as any); + const decompressor = createBrotliDecompress(); + const extractor = new TarExtractor(name => test.info().outputPath(name)); + await finished(input.pipe(decompressor).pipe(extractor)); - expect(await readdir(test.info().outputPath('chrome-linux'))).toEqual([ - 'headless_command_resources.pak', - 'headless_lib_data.pak', - 'headless_lib_strings.pak', - 'headless_shell', - 'hyphen-data', - 'icudtl.dat', - 'libEGL.so', - 'libGLESv2.so', - 'libvk_swiftshader.so', - 'libvulkan.so.1', - 'v8_context_snapshot.bin', - 'vk_swiftshader_icd.json', - ]); - expect(await readFile(test.info().outputPath('chrome-linux/vk_swiftshader_icd.json'), { encoding: 'utf-8' })).toEqual(`{"file_format_version": "1.0.0", "ICD": {"library_path": "./libvk_swiftshader.so", "api_version": "1.0.5"}}`); - expect(await readdir(test.info().outputPath('chrome-linux/hyphen-data'))).toEqual([ - 'hyph-af.hyb', - 'hyph-as.hyb', - 'hyph-be.hyb', - 'hyph-bg.hyb', - 'hyph-bn.hyb', - 'hyph-cs.hyb', - 'hyph-cu.hyb', - 'hyph-cy.hyb', - 'hyph-da.hyb', - 'hyph-de-1901.hyb', - 'hyph-de-1996.hyb', - 'hyph-de-ch-1901.hyb', - 'hyph-el.hyb', - 'hyph-en-gb.hyb', - 'hyph-en-us.hyb', - 'hyph-es.hyb', - 'hyph-et.hyb', - 'hyph-eu.hyb', - 'hyph-fr.hyb', - 'hyph-ga.hyb', - 'hyph-gl.hyb', - 'hyph-gu.hyb', - 'hyph-hi.hyb', - 'hyph-hr.hyb', - 'hyph-hu.hyb', - 'hyph-hy.hyb', - 'hyph-it.hyb', - 'hyph-ka.hyb', - 'hyph-kn.hyb', - 'hyph-la.hyb', - 'hyph-lt.hyb', - 'hyph-lv.hyb', - 'hyph-ml.hyb', - 'hyph-mn-cyrl.hyb', - 'hyph-mr.hyb', - 'hyph-mul-ethi.hyb', - 'hyph-nb.hyb', - 'hyph-nl.hyb', - 'hyph-nn.hyb', - 'hyph-or.hyb', - 'hyph-pa.hyb', - 'hyph-pt.hyb', - 'hyph-ru.hyb', - 'hyph-sk.hyb', - 'hyph-sl.hyb', - 'hyph-sq.hyb', - 'hyph-sv.hyb', - 'hyph-ta.hyb', - 'hyph-te.hyb', - 'hyph-tk.hyb', - 'hyph-uk.hyb', - 'hyph-und-ethi.hyb', - 'manifest.json', - ]); + expect(await readdir(test.info().outputPath('chrome-linux'))).toEqual([ + 'headless_command_resources.pak', + 'headless_lib_data.pak', + 'headless_lib_strings.pak', + 'headless_shell', + 'hyphen-data', + 'icudtl.dat', + 'libEGL.so', + 'libGLESv2.so', + 'libvk_swiftshader.so', + 'libvulkan.so.1', + 'v8_context_snapshot.bin', + 'vk_swiftshader_icd.json', + ]); + expect(await readFile(test.info().outputPath('chrome-linux/vk_swiftshader_icd.json'), { encoding: 'utf-8' })).toEqual(`{"file_format_version": "1.0.0", "ICD": {"library_path": "./libvk_swiftshader.so", "api_version": "1.0.5"}}`); + expect(await readdir(test.info().outputPath('chrome-linux/hyphen-data'))).toEqual([ + 'hyph-af.hyb', + 'hyph-as.hyb', + 'hyph-be.hyb', + 'hyph-bg.hyb', + 'hyph-bn.hyb', + 'hyph-cs.hyb', + 'hyph-cu.hyb', + 'hyph-cy.hyb', + 'hyph-da.hyb', + 'hyph-de-1901.hyb', + 'hyph-de-1996.hyb', + 'hyph-de-ch-1901.hyb', + 'hyph-el.hyb', + 'hyph-en-gb.hyb', + 'hyph-en-us.hyb', + 'hyph-es.hyb', + 'hyph-et.hyb', + 'hyph-eu.hyb', + 'hyph-fr.hyb', + 'hyph-ga.hyb', + 'hyph-gl.hyb', + 'hyph-gu.hyb', + 'hyph-hi.hyb', + 'hyph-hr.hyb', + 'hyph-hu.hyb', + 'hyph-hy.hyb', + 'hyph-it.hyb', + 'hyph-ka.hyb', + 'hyph-kn.hyb', + 'hyph-la.hyb', + 'hyph-lt.hyb', + 'hyph-lv.hyb', + 'hyph-ml.hyb', + 'hyph-mn-cyrl.hyb', + 'hyph-mr.hyb', + 'hyph-mul-ethi.hyb', + 'hyph-nb.hyb', + 'hyph-nl.hyb', + 'hyph-nn.hyb', + 'hyph-or.hyb', + 'hyph-pa.hyb', + 'hyph-pt.hyb', + 'hyph-ru.hyb', + 'hyph-sk.hyb', + 'hyph-sl.hyb', + 'hyph-sq.hyb', + 'hyph-sv.hyb', + 'hyph-ta.hyb', + 'hyph-te.hyb', + 'hyph-tk.hyb', + 'hyph-uk.hyb', + 'hyph-und-ethi.hyb', + 'manifest.json', + ]); + }); + + test('chromium-mac-arm64', async () => { + const response = await fetch('https://playwright.azureedge.net/download-for-internal-testing/playwright/builds/chromium/1152/chromium-mac-arm64.tar.br'); + const input = Readable.fromWeb(response.body as any); + const decompressor = createBrotliDecompress(); + const extractor = new TarExtractor(name => test.info().outputPath(name)); + await finished(input.pipe(decompressor).pipe(extractor)); + + + expect(await readdir(test.info().outputPath('chrome-mac'))).toEqual(['Chromium.app']); + expect(await readdir(test.info().outputPath('chrome-mac/Chromium.app'))).toEqual(['Contents']); + expect(await readdir(test.info().outputPath('chrome-mac/Chromium.app/Contents'))).toEqual([ + 'Frameworks', + 'Info.plist', + 'MacOS', + 'PkgInfo', + 'Resources', + ]); + expect(await readFile(test.info().outputPath('chrome-mac/Chromium.app/Contents/Info.plist'), { encoding: 'utf-8' })).toHaveLength(10903); + }); });