diff --git a/src/Command/BrowserCommand.php b/src/Command/BrowserCommand.php index fe6a521..74950f1 100644 --- a/src/Command/BrowserCommand.php +++ b/src/Command/BrowserCommand.php @@ -83,7 +83,7 @@ final protected function execute(InputInterface $input, OutputInterface $output) $filePath = $driverDownloader->download($driver, $installPath); $io->success( - sprintf('%s %s installed to %s', $driver->name->value, $driver->version->toBuildString(), $filePath), + sprintf('%s %s%s installed to %s', $driver->name->value, $driver->version->toBuildString(), $driver->cpuArchitecture->toString(), $filePath), ); return self::SUCCESS; diff --git a/src/Command/DriverCommand.php b/src/Command/DriverCommand.php index 4d95bce..383acf4 100644 --- a/src/Command/DriverCommand.php +++ b/src/Command/DriverCommand.php @@ -40,6 +40,7 @@ final protected function configure(): void new Input\InstallPathArgument(), new Input\VersionOption(), new Input\OperatingSystemOption(), + new Input\CpuArchitectureOption(), ], ), ); @@ -54,6 +55,7 @@ final protected function execute(InputInterface $input, OutputInterface $output) $installPath = Input\InstallPathArgument::value($input); $versionString = Input\VersionOption::value($input); $operatingSystem = Input\OperatingSystemOption::value($input); + $cpuArchitecture = Input\CpuArchitectureOption::value($input); // TODO: move this into VersionOption class if ($versionString === Input\VersionOption::LATEST) { @@ -68,7 +70,7 @@ final protected function execute(InputInterface $input, OutputInterface $output) $version = Version::fromString($versionString); } - $driver = new Driver($driverName, $version, $operatingSystem); + $driver = new Driver($driverName, $version, $operatingSystem, $cpuArchitecture); if ($io->isVerbose()) { $io->writeln( @@ -81,9 +83,10 @@ final protected function execute(InputInterface $input, OutputInterface $output) $io->success( sprintf( - '%s %s installed to %s', + '%s %s%s installed to %s', $driver->name->value, $driver->version->toBuildString(), + $driver->cpuArchitecture->toString(), $filePath, ), ); diff --git a/src/Command/Input/CpuArchitectureOption.php b/src/Command/Input/CpuArchitectureOption.php new file mode 100644 index 0000000..d457c06 --- /dev/null +++ b/src/Command/Input/CpuArchitectureOption.php @@ -0,0 +1,80 @@ + */ +final class CpuArchitectureOption extends InputOption implements Option +{ + public function __construct() + { + parent::__construct( + self::name(), + $this->shortcut(), + $this->mode()->value, + $this->description(), + $this->default(), + ); + } + + public static function name(): string + { + return 'arch'; + } + + public function shortcut(): string|null + { + return null; + } + + public function mode(): OptionMode + { + return OptionMode::REQUIRED; + } + + public function description(): string + { + return sprintf( + 'CPU architecture for which to install the driver (%s)', + implode('|', array_map(static fn ($case) => $case->value, CpuArchitecture::cases())), + ); + } + + public function default(): string|null + { + return CpuArchitecture::AMD64->value; + } + + public static function value(InputInterface $input): CpuArchitecture + { + $value = $input->getOption(self::name()); + + if (! is_string($value)) { + throw UnexpectedType::expected('string', $value); + } + + if (CpuArchitecture::tryFrom($value) === null) { + throw new UnexpectedValueException( + sprintf( + 'Unexpected value %s. Expected one of: %s', + $value, + implode(', ', array_map(static fn ($case) => $case->value, CpuArchitecture::cases())), + ), + ); + } + + return CpuArchitecture::from($value); + } +} diff --git a/src/Cpu/CpuArchitecture.php b/src/Cpu/CpuArchitecture.php new file mode 100644 index 0000000..7846fe9 --- /dev/null +++ b/src/Cpu/CpuArchitecture.php @@ -0,0 +1,29 @@ + ' amd64', + self::ARM64 => ' arm64', + }; + } + + public static function detectFromPhp(): CpuArchitecture + { + return match (php_uname('m')) { + 'arm64', 'aarch64' => CpuArchitecture::ARM64, + default => CpuArchitecture::AMD64, + }; + } +} diff --git a/src/Driver/ChromeDriver/DownloadUrlResolver.php b/src/Driver/ChromeDriver/DownloadUrlResolver.php index 2a5bbb5..3591e17 100644 --- a/src/Driver/ChromeDriver/DownloadUrlResolver.php +++ b/src/Driver/ChromeDriver/DownloadUrlResolver.php @@ -4,6 +4,7 @@ namespace DBrekelmans\BrowserDriverInstaller\Driver\ChromeDriver; +use DBrekelmans\BrowserDriverInstaller\Cpu\CpuArchitecture; use DBrekelmans\BrowserDriverInstaller\Driver\DownloadUrlResolver as DownloadUrlResolverInterface; use DBrekelmans\BrowserDriverInstaller\Driver\Driver; use DBrekelmans\BrowserDriverInstaller\OperatingSystem\OperatingSystem; @@ -40,6 +41,10 @@ public function byDriver(Driver $driver): string throw new UnexpectedValueException(sprintf('Could not find the chromedriver downloads for version %s', $driver->version->toString())); } + if ($driver->cpuArchitecture === CpuArchitecture::ARM64 && $driver->operatingSystem !== OperatingSystem::MACOS) { + throw new UnexpectedValueException('Chromedriver ARM64 is only available on macOS.'); + } + $platformName = $this->getPlatformName($driver); $downloads = $versions['builds'][$driver->version->toString()]['downloads']['chromedriver']; foreach ($downloads as $download) { @@ -59,6 +64,10 @@ public function byDriver(Driver $driver): string private function getBinaryName(Driver $driver): string { + if ($driver->operatingSystem === OperatingSystem::MACOS && $driver->cpuArchitecture === CpuArchitecture::ARM64) { + return 'chromedriver_mac_arm64'; + } + return match ($driver->operatingSystem) { OperatingSystem::LINUX => 'chromedriver_linux64', OperatingSystem::MACOS => 'chromedriver_mac64', @@ -68,6 +77,10 @@ private function getBinaryName(Driver $driver): string private function getPlatformName(Driver $driver): string { + if ($driver->cpuArchitecture === CpuArchitecture::ARM64) { + return 'mac-arm64'; + } + return match ($driver->operatingSystem) { OperatingSystem::LINUX => 'linux64', OperatingSystem::MACOS => 'mac-x64', diff --git a/src/Driver/ChromeDriver/Downloader.php b/src/Driver/ChromeDriver/Downloader.php index 128e30f..0b0c200 100644 --- a/src/Driver/ChromeDriver/Downloader.php +++ b/src/Driver/ChromeDriver/Downloader.php @@ -5,6 +5,7 @@ namespace DBrekelmans\BrowserDriverInstaller\Driver\ChromeDriver; use DBrekelmans\BrowserDriverInstaller\Archive\Extractor; +use DBrekelmans\BrowserDriverInstaller\Cpu\CpuArchitecture; use DBrekelmans\BrowserDriverInstaller\Driver\Downloader as DownloaderInterface; use DBrekelmans\BrowserDriverInstaller\Driver\DownloadUrlResolver; use DBrekelmans\BrowserDriverInstaller\Driver\Driver; @@ -44,6 +45,10 @@ public function __construct( public function supports(Driver $driver): bool { + if ($driver->cpuArchitecture === CpuArchitecture::ARM64 && $driver->operatingSystem !== OperatingSystem::MACOS) { + return false; + } + return $driver->name === DriverName::CHROME; } @@ -179,7 +184,7 @@ private function getFileName(OperatingSystem $operatingSystem): string */ public function cleanArchiveStructure(Driver $driver, string $unzipLocation, array $extractedFiles): array { - $archiveDirectory = $this->getArchiveDirectory($driver->operatingSystem); + $archiveDirectory = $this->getArchiveDirectory($driver); $filename = $this->getFileName($driver->operatingSystem); $this->filesystem->rename( $unzipLocation . DIRECTORY_SEPARATOR . $archiveDirectory . $filename, @@ -190,9 +195,13 @@ public function cleanArchiveStructure(Driver $driver, string $unzipLocation, arr return str_replace($archiveDirectory, '', $extractedFiles); } - private function getArchiveDirectory(OperatingSystem $operatingSystem): string + private function getArchiveDirectory(Driver $driver): string { - return match ($operatingSystem) { + if ($driver->operatingSystem === OperatingSystem::MACOS && $driver->cpuArchitecture === CpuArchitecture::ARM64) { + return 'chromedriver-mac-arm64/'; + } + + return match ($driver->operatingSystem) { OperatingSystem::LINUX => 'chromedriver-linux64/', OperatingSystem::WINDOWS => 'chromedriver-win32/', // This weirdly contains a forward slash on windows OperatingSystem::MACOS => 'chromedriver-mac-x64/', diff --git a/src/Driver/DownloaderFactory.php b/src/Driver/DownloaderFactory.php index 3f27848..6a4dd94 100644 --- a/src/Driver/DownloaderFactory.php +++ b/src/Driver/DownloaderFactory.php @@ -21,7 +21,7 @@ public function createFromDriver(Driver $driver): Downloader } } - throw NotImplemented::feature(sprintf('Downloader for %s', $driver->name->value)); + throw NotImplemented::feature(sprintf('Downloader for %s %s', $driver->name->value, $driver->cpuArchitecture->value)); } public function register(Downloader $downloader, string|null $identifier = null): void diff --git a/src/Driver/Driver.php b/src/Driver/Driver.php index 24853c8..a31d2fb 100644 --- a/src/Driver/Driver.php +++ b/src/Driver/Driver.php @@ -4,6 +4,7 @@ namespace DBrekelmans\BrowserDriverInstaller\Driver; +use DBrekelmans\BrowserDriverInstaller\Cpu\CpuArchitecture; use DBrekelmans\BrowserDriverInstaller\OperatingSystem\OperatingSystem; use DBrekelmans\BrowserDriverInstaller\Version; @@ -13,6 +14,7 @@ public function __construct( public readonly DriverName $name, public readonly Version $version, public readonly OperatingSystem $operatingSystem, + public readonly CpuArchitecture $cpuArchitecture, ) { } } diff --git a/src/Driver/DriverFactory.php b/src/Driver/DriverFactory.php index d676c83..f8e5b99 100644 --- a/src/Driver/DriverFactory.php +++ b/src/Driver/DriverFactory.php @@ -6,6 +6,7 @@ use DBrekelmans\BrowserDriverInstaller\Browser\Browser; use DBrekelmans\BrowserDriverInstaller\Browser\BrowserName; +use DBrekelmans\BrowserDriverInstaller\Cpu\CpuArchitecture; final class DriverFactory { @@ -20,7 +21,10 @@ public function createFromBrowser(Browser $browser): Driver $name = $this->getDriverNameForBrowser($browser); - return new Driver($name, $version, $browser->operatingSystem); + // Detect CPU arch + $cpuArchitecture = CpuArchitecture::detectFromPhp(); + + return new Driver($name, $version, $browser->operatingSystem, $cpuArchitecture); } private function getDriverNameForBrowser(Browser $browser): DriverName diff --git a/src/Driver/GeckoDriver/Downloader.php b/src/Driver/GeckoDriver/Downloader.php index 662242b..e080827 100644 --- a/src/Driver/GeckoDriver/Downloader.php +++ b/src/Driver/GeckoDriver/Downloader.php @@ -5,6 +5,7 @@ namespace DBrekelmans\BrowserDriverInstaller\Driver\GeckoDriver; use DBrekelmans\BrowserDriverInstaller\Archive\Extractor; +use DBrekelmans\BrowserDriverInstaller\Cpu\CpuArchitecture; use DBrekelmans\BrowserDriverInstaller\Driver\Downloader as DownloaderInterface; use DBrekelmans\BrowserDriverInstaller\Driver\Driver; use DBrekelmans\BrowserDriverInstaller\Driver\DriverName; @@ -30,9 +31,9 @@ final class Downloader implements DownloaderInterface { - private const DOWNLOAD_PATH_OS_PART_WINDOWS = 'win64'; + private const DOWNLOAD_PATH_OS_PART_WINDOWS = 'win'; private const DOWNLOAD_PATH_OS_PART_MACOS = 'macos'; - private const DOWNLOAD_PATH_OS_PART_LINUX = 'linux64'; + private const DOWNLOAD_PATH_OS_PART_LINUX = 'linux'; private const DOWNLOAD_BASE_PATH = 'https://github.com/mozilla/geckodriver/releases/download/'; public function __construct( @@ -112,10 +113,11 @@ private function downloadArchive(Driver $driver): string private function getDownloadPath(Driver $driver): string { return self::DOWNLOAD_BASE_PATH . sprintf( - 'v%s/geckodriver-v%s-%s%s', + 'v%s/geckodriver-v%s-%s%s%s', $driver->version->toString(), $driver->version->toString(), $this->getOsForDownloadPath($driver), + $this->getCpuArchForDownloadPath($driver), $this->getArchiveExtension($driver), ); } @@ -129,6 +131,29 @@ private function getOsForDownloadPath(Driver $driver): string }; } + private function getCpuArchForDownloadPath(Driver $driver): string + { + if ($driver->operatingSystem === OperatingSystem::LINUX) { + return match ($driver->cpuArchitecture) { + CpuArchitecture::AMD64 => '64', + CpuArchitecture::ARM64 => '-aarch64', + }; + } + + if ($driver->operatingSystem === OperatingSystem::MACOS) { + return match ($driver->cpuArchitecture) { + CpuArchitecture::AMD64 => '', + CpuArchitecture::ARM64 => '-aarch64', + }; + } + + // Windows + return match ($driver->cpuArchitecture) { + CpuArchitecture::AMD64 => '64', + CpuArchitecture::ARM64 => '-aarch64', + }; + } + private function extractArchive(string $archive): string { $extractedFiles = $this->archiveExtractor->extract($archive, dirname($archive)); diff --git a/tests/Driver/ChromeDriver/DownloadUrlResolverTest.php b/tests/Driver/ChromeDriver/DownloadUrlResolverTest.php index 4ff197f..994bb4a 100644 --- a/tests/Driver/ChromeDriver/DownloadUrlResolverTest.php +++ b/tests/Driver/ChromeDriver/DownloadUrlResolverTest.php @@ -4,6 +4,7 @@ namespace DBrekelmans\BrowserDriverInstaller\Tests\Driver\ChromeDriver; +use DBrekelmans\BrowserDriverInstaller\Cpu\CpuArchitecture; use DBrekelmans\BrowserDriverInstaller\Driver\ChromeDriver\DownloadUrlResolver; use DBrekelmans\BrowserDriverInstaller\Driver\Driver; use DBrekelmans\BrowserDriverInstaller\Driver\DriverName; @@ -24,32 +25,37 @@ final class DownloadUrlResolverTest extends TestCase public static function byDriverDataProvider(): iterable { yield 'legacy version linux' => [ - new Driver(DriverName::CHROME, Version::fromString('88.0.4299.0'), OperatingSystem::LINUX), + new Driver(DriverName::CHROME, Version::fromString('88.0.4299.0'), OperatingSystem::LINUX, CpuArchitecture::AMD64), 'https://chromedriver.storage.googleapis.com/88.0.4299.0/chromedriver_linux64.zip', ]; yield 'legacy version macos' => [ - new Driver(DriverName::CHROME, Version::fromString('88.0.4299.0'), OperatingSystem::MACOS), + new Driver(DriverName::CHROME, Version::fromString('88.0.4299.0'), OperatingSystem::MACOS, CpuArchitecture::AMD64), 'https://chromedriver.storage.googleapis.com/88.0.4299.0/chromedriver_mac64.zip', ]; yield 'legacy version windows' => [ - new Driver(DriverName::CHROME, Version::fromString('88.0.4299.0'), OperatingSystem::WINDOWS), + new Driver(DriverName::CHROME, Version::fromString('88.0.4299.0'), OperatingSystem::WINDOWS, CpuArchitecture::AMD64), 'https://chromedriver.storage.googleapis.com/88.0.4299.0/chromedriver_win32.zip', ]; yield 'new version linux' => [ - new Driver(DriverName::CHROME, Version::fromString('115.0.5790.170'), OperatingSystem::LINUX), + new Driver(DriverName::CHROME, Version::fromString('115.0.5790.170'), OperatingSystem::LINUX, CpuArchitecture::AMD64), 'https://dynamic-url-2/', ]; - yield 'new version macos' => [ - new Driver(DriverName::CHROME, Version::fromString('115.0.5790.170'), OperatingSystem::MACOS), + yield 'new version macos x86_64' => [ + new Driver(DriverName::CHROME, Version::fromString('115.0.5790.170'), OperatingSystem::MACOS, CpuArchitecture::AMD64), 'https://dynamic-url-3/', ]; + yield 'new version macos arm64' => [ + new Driver(DriverName::CHROME, Version::fromString('115.0.5790.170'), OperatingSystem::MACOS, CpuArchitecture::ARM64), + 'https://dynamic-url-4/', + ]; + yield 'new version windows' => [ - new Driver(DriverName::CHROME, Version::fromString('115.0.5790.170'), OperatingSystem::WINDOWS), + new Driver(DriverName::CHROME, Version::fromString('115.0.5790.170'), OperatingSystem::WINDOWS, CpuArchitecture::AMD64), 'https://dynamic-url-1/', ]; } @@ -75,6 +81,7 @@ static function (string $method, string $url): MockResponse { ['platform' => 'win32', 'url' => 'https://dynamic-url-1/'], ['platform' => 'linux64', 'url' => 'https://dynamic-url-2/'], ['platform' => 'mac-x64', 'url' => 'https://dynamic-url-3/'], + ['platform' => 'mac-arm64', 'url' => 'https://dynamic-url-4/'], ], ], ], diff --git a/tests/Driver/ChromeDriver/DownloaderTest.php b/tests/Driver/ChromeDriver/DownloaderTest.php index cf7d485..2cbe1a6 100644 --- a/tests/Driver/ChromeDriver/DownloaderTest.php +++ b/tests/Driver/ChromeDriver/DownloaderTest.php @@ -5,6 +5,7 @@ namespace DBrekelmans\BrowserDriverInstaller\Tests\Driver\ChromeDriver; use DBrekelmans\BrowserDriverInstaller\Archive\Extractor; +use DBrekelmans\BrowserDriverInstaller\Cpu\CpuArchitecture; use DBrekelmans\BrowserDriverInstaller\Driver\ChromeDriver\Downloader; use DBrekelmans\BrowserDriverInstaller\Driver\DownloadUrlResolver; use DBrekelmans\BrowserDriverInstaller\Driver\Driver; @@ -35,13 +36,19 @@ class DownloaderTest extends TestCase public function testSupportChrome(): void { - $chromeDriverLinux = new Driver(DriverName::CHROME, Version::fromString('86.0.4240.22'), OperatingSystem::LINUX); + $chromeDriverLinux = new Driver(DriverName::CHROME, Version::fromString('86.0.4240.22'), OperatingSystem::LINUX, CpuArchitecture::AMD64); self::assertTrue($this->downloader->supports($chromeDriverLinux)); } + public function testDoesNotSupportChromeArm64(): void + { + $chromeDriverLinux = new Driver(DriverName::CHROME, Version::fromString('86.0.4240.22'), OperatingSystem::LINUX, CpuArchitecture::ARM64); + self::assertFalse($this->downloader->supports($chromeDriverLinux)); + } + public function testDoesNotSupportGecko(): void { - $geckoDriver = new Driver(DriverName::GECKO, Version::fromString('0.27.0'), OperatingSystem::LINUX); + $geckoDriver = new Driver(DriverName::GECKO, Version::fromString('0.27.0'), OperatingSystem::LINUX, CpuArchitecture::AMD64); self::assertFalse($this->downloader->supports($geckoDriver)); } @@ -49,7 +56,7 @@ public function testDownloadMac(): void { $this->mockFsAndArchiveExtractorForSuccessfulDownload(OperatingSystem::MACOS); - $chromeDriverMac = new Driver(DriverName::CHROME, Version::fromString('86.0.4240.22'), OperatingSystem::MACOS); + $chromeDriverMac = new Driver(DriverName::CHROME, Version::fromString('86.0.4240.22'), OperatingSystem::MACOS, CpuArchitecture::AMD64); $this->downloadUrlResolver ->expects(self::once()) @@ -67,11 +74,33 @@ public function testDownloadMac(): void self::assertEquals('./chromedriver', $filePath); } + public function testDownloadMacARM64(): void + { + $this->mockFsAndArchiveExtractorForSuccessfulDownload(OperatingSystem::MACOS); + + $chromeDriverMac = new Driver(DriverName::CHROME, Version::fromString('106.0.5249.61'), OperatingSystem::MACOS, CpuArchitecture::ARM64); + + $this->downloadUrlResolver + ->expects(self::once()) + ->method('byDriver') + ->with($chromeDriverMac) + ->willReturn('https://chromedriver.storage.googleapis.com/106.0.5249.61/chromedriver_mac_arm64.zip'); + + $this->httpClient + ->expects(self::atLeastOnce()) + ->method('request') + ->with('GET', 'https://chromedriver.storage.googleapis.com/106.0.5249.61/chromedriver_mac_arm64.zip'); + + $filePath = $this->downloader->download($chromeDriverMac, '.'); + + self::assertEquals('./chromedriver', $filePath); + } + public function testDownloadMacJson(): void { $this->mockFsAndArchiveExtractorForSuccessfulDownload(OperatingSystem::MACOS, true); - $chromeDriverMac = new Driver(DriverName::CHROME, Version::fromString('115.0.5790.170'), OperatingSystem::MACOS); + $chromeDriverMac = new Driver(DriverName::CHROME, Version::fromString('115.0.5790.170'), OperatingSystem::MACOS, CpuArchitecture::AMD64); $this->downloadUrlResolver ->expects(self::once()) @@ -93,7 +122,7 @@ public function testDownloadLinux(): void { $this->mockFsAndArchiveExtractorForSuccessfulDownload(OperatingSystem::LINUX); - $chromeDriverLinux = new Driver(DriverName::CHROME, Version::fromString('86.0.4240.22'), OperatingSystem::LINUX); + $chromeDriverLinux = new Driver(DriverName::CHROME, Version::fromString('86.0.4240.22'), OperatingSystem::LINUX, CpuArchitecture::AMD64); $this->downloadUrlResolver ->expects(self::once()) @@ -115,7 +144,7 @@ public function testDownloadLinuxJson(): void { $this->mockFsAndArchiveExtractorForSuccessfulDownload(OperatingSystem::LINUX, true); - $chromeDriverLinux = new Driver(DriverName::CHROME, Version::fromString('115.0.5790.170'), OperatingSystem::LINUX); + $chromeDriverLinux = new Driver(DriverName::CHROME, Version::fromString('115.0.5790.170'), OperatingSystem::LINUX, CpuArchitecture::AMD64); $this->downloadUrlResolver ->expects(self::once()) @@ -137,7 +166,7 @@ public function testDownloadWindows(): void { $this->mockFsAndArchiveExtractorForSuccessfulDownload(OperatingSystem::WINDOWS); - $chromeDriverWindows = new Driver(DriverName::CHROME, Version::fromString('86.0.4240.22'), OperatingSystem::WINDOWS); + $chromeDriverWindows = new Driver(DriverName::CHROME, Version::fromString('86.0.4240.22'), OperatingSystem::WINDOWS, CpuArchitecture::AMD64); $this->downloadUrlResolver ->expects(self::once()) @@ -159,7 +188,7 @@ public function testDownloadWindowsJson(): void { $this->mockFsAndArchiveExtractorForSuccessfulDownload(OperatingSystem::WINDOWS, true); - $chromeDriverWindows = new Driver(DriverName::CHROME, Version::fromString('115.0.5790.170'), OperatingSystem::WINDOWS); + $chromeDriverWindows = new Driver(DriverName::CHROME, Version::fromString('115.0.5790.170'), OperatingSystem::WINDOWS, CpuArchitecture::AMD64); $this->downloadUrlResolver ->expects(self::once()) diff --git a/tests/Driver/DownloaderFactoryTest.php b/tests/Driver/DownloaderFactoryTest.php index 477d5f0..9199f67 100644 --- a/tests/Driver/DownloaderFactoryTest.php +++ b/tests/Driver/DownloaderFactoryTest.php @@ -4,6 +4,7 @@ namespace DBrekelmans\BrowserDriverInstaller\Tests\Driver; +use DBrekelmans\BrowserDriverInstaller\Cpu\CpuArchitecture; use DBrekelmans\BrowserDriverInstaller\Driver\Downloader; use DBrekelmans\BrowserDriverInstaller\Driver\DownloaderFactory; use DBrekelmans\BrowserDriverInstaller\Driver\Driver; @@ -21,7 +22,7 @@ public function testNoDownloaderImplemented(): void $this->expectException(NotImplemented::class); $factory->createFromDriver( - new Driver(DriverName::CHROME, Version::fromString('1.0.0'), OperatingSystem::LINUX), + new Driver(DriverName::CHROME, Version::fromString('1.0.0'), OperatingSystem::LINUX, CpuArchitecture::AMD64), ); } @@ -36,7 +37,7 @@ public function testRegisteredDownloaderIsReturned(): void self::assertSame( $downloader, $factory->createFromDriver( - new Driver(DriverName::CHROME, Version::fromString('1.0.0'), OperatingSystem::LINUX), + new Driver(DriverName::CHROME, Version::fromString('1.0.0'), OperatingSystem::LINUX, CpuArchitecture::AMD64), ), ); } @@ -60,7 +61,7 @@ public function testSupportedDownloaderIsReturned(): void self::assertSame( $downloaderB, $factory->createFromDriver( - new Driver(DriverName::CHROME, Version::fromString('1.0.0'), OperatingSystem::LINUX), + new Driver(DriverName::CHROME, Version::fromString('1.0.0'), OperatingSystem::LINUX, CpuArchitecture::AMD64), ), ); } @@ -80,7 +81,7 @@ public function testFirstSupportedDownloaderIsReturned(): void self::assertSame( $downloaderA, $factory->createFromDriver( - new Driver(DriverName::CHROME, Version::fromString('1.0.0'), OperatingSystem::LINUX), + new Driver(DriverName::CHROME, Version::fromString('1.0.0'), OperatingSystem::LINUX, CpuArchitecture::AMD64), ), ); } diff --git a/tests/Driver/DriverFactoryTest.php b/tests/Driver/DriverFactoryTest.php index f3a5243..be6efc1 100644 --- a/tests/Driver/DriverFactoryTest.php +++ b/tests/Driver/DriverFactoryTest.php @@ -6,6 +6,7 @@ use DBrekelmans\BrowserDriverInstaller\Browser\Browser; use DBrekelmans\BrowserDriverInstaller\Browser\BrowserName; +use DBrekelmans\BrowserDriverInstaller\Cpu\CpuArchitecture; use DBrekelmans\BrowserDriverInstaller\Driver\Driver; use DBrekelmans\BrowserDriverInstaller\Driver\DriverFactory; use DBrekelmans\BrowserDriverInstaller\Driver\DriverName; @@ -39,22 +40,25 @@ private static function assertSameDriver(Driver $expected, Driver $actual): void self::assertSame($expected->name, $actual->name); self::assertSame($expected->version->toBuildString(), $actual->version->toBuildString()); self::assertSame($expected->operatingSystem, $actual->operatingSystem); + self::assertSame($expected->cpuArchitecture, $actual->cpuArchitecture); } /** @return array */ public static function createFromBrowserDataProvider(): array { + $cpuArchitecture = CpuArchitecture::detectFromPhp(); + return [ 'google_chrome' => [ - new Driver(DriverName::CHROME, Version::fromString('1.0.0'), OperatingSystem::LINUX), + new Driver(DriverName::CHROME, Version::fromString('1.0.0'), OperatingSystem::LINUX, $cpuArchitecture), new Browser(BrowserName::GOOGLE_CHROME, Version::fromString('1.0.0'), OperatingSystem::LINUX), ], 'chromium' => [ - new Driver(DriverName::CHROME, Version::fromString('1.0.0'), OperatingSystem::LINUX), + new Driver(DriverName::CHROME, Version::fromString('1.0.0'), OperatingSystem::LINUX, $cpuArchitecture), new Browser(BrowserName::CHROMIUM, Version::fromString('1.0.0'), OperatingSystem::LINUX), ], 'firefox' => [ - new Driver(DriverName::GECKO, Version::fromString('1.0.0'), OperatingSystem::LINUX), + new Driver(DriverName::GECKO, Version::fromString('1.0.0'), OperatingSystem::LINUX, $cpuArchitecture), new Browser(BrowserName::FIREFOX, Version::fromString('1.0.0'), OperatingSystem::LINUX), ], ]; diff --git a/tests/Driver/GeckoDriver/DownloaderTest.php b/tests/Driver/GeckoDriver/DownloaderTest.php index 8a0bd02..9821d28 100644 --- a/tests/Driver/GeckoDriver/DownloaderTest.php +++ b/tests/Driver/GeckoDriver/DownloaderTest.php @@ -5,6 +5,7 @@ namespace DBrekelmans\BrowserDriverInstaller\Tests\Driver\GeckoDriver; use DBrekelmans\BrowserDriverInstaller\Archive\Extractor; +use DBrekelmans\BrowserDriverInstaller\Cpu\CpuArchitecture; use DBrekelmans\BrowserDriverInstaller\Driver\Driver; use DBrekelmans\BrowserDriverInstaller\Driver\DriverName; use DBrekelmans\BrowserDriverInstaller\Driver\GeckoDriver\Downloader; @@ -24,6 +25,7 @@ class DownloaderTest extends TestCase { private Downloader $downloader; private Driver $geckoMac; + private Driver $geckoMacArm64; private Stub&Filesystem $filesystem; private MockObject&HttpClientInterface $httpClient; private Extractor&MockObject $archiveExtractor; @@ -34,17 +36,19 @@ public function setUp(): void $this->httpClient = $this->createMock(HttpClientInterface::class); $this->archiveExtractor = $this->createMock(Extractor::class); $this->downloader = new Downloader($this->filesystem, $this->httpClient, $this->archiveExtractor); - $this->geckoMac = new Driver(DriverName::GECKO, Version::fromString('0.27.0'), OperatingSystem::MACOS); + $this->geckoMac = new Driver(DriverName::GECKO, Version::fromString('0.27.0'), OperatingSystem::MACOS, CpuArchitecture::AMD64); + $this->geckoMacArm64 = new Driver(DriverName::GECKO, Version::fromString('0.35.0'), OperatingSystem::MACOS, CpuArchitecture::ARM64); } public function testSupportGecko(): void { self::assertTrue($this->downloader->supports($this->geckoMac)); + self::assertTrue($this->downloader->supports($this->geckoMacArm64)); } public function testDoesNotSupportChromeDriver(): void { - $chromeDriver = new Driver(DriverName::CHROME, Version::fromString('86.0.4240.22'), OperatingSystem::MACOS); + $chromeDriver = new Driver(DriverName::CHROME, Version::fromString('86.0.4240.22'), OperatingSystem::MACOS, CpuArchitecture::AMD64); self::assertFalse($this->downloader->supports($chromeDriver)); } @@ -62,6 +66,20 @@ public function testDownloadMac(): void self::assertEquals('./geckodriver', $filePath); } + public function testDownloadMacArm64(): void + { + $this->mockFsAndArchiveExtractorForSuccessfulDownload(); + + $this->httpClient + ->expects(self::atLeastOnce()) + ->method('request') + ->with('GET', 'https://github.com/mozilla/geckodriver/releases/download/v0.35.0/geckodriver-v0.35.0-macos-aarch64.tar.gz'); + + $filePath = $this->downloader->download($this->geckoMacArm64, '.'); + + self::assertEquals('./geckodriver', $filePath); + } + public function testDownloadLinux(): void { $this->mockFsAndArchiveExtractorForSuccessfulDownload(); @@ -71,7 +89,22 @@ public function testDownloadLinux(): void ->method('request') ->with('GET', 'https://github.com/mozilla/geckodriver/releases/download/v0.27.0/geckodriver-v0.27.0-linux64.tar.gz'); - $geckoLinux = new Driver(DriverName::GECKO, Version::fromString('0.27.0'), OperatingSystem::LINUX); + $geckoLinux = new Driver(DriverName::GECKO, Version::fromString('0.27.0'), OperatingSystem::LINUX, CpuArchitecture::AMD64); + $filePath = $this->downloader->download($geckoLinux, '.'); + + self::assertEquals('./geckodriver', $filePath); + } + + public function testDownloadLinuxArm64(): void + { + $this->mockFsAndArchiveExtractorForSuccessfulDownload(); + + $this->httpClient + ->expects(self::atLeastOnce()) + ->method('request') + ->with('GET', 'https://github.com/mozilla/geckodriver/releases/download/v0.35.0/geckodriver-v0.35.0-linux-aarch64.tar.gz'); + + $geckoLinux = new Driver(DriverName::GECKO, Version::fromString('0.35.0'), OperatingSystem::LINUX, CpuArchitecture::ARM64); $filePath = $this->downloader->download($geckoLinux, '.'); self::assertEquals('./geckodriver', $filePath); @@ -92,7 +125,7 @@ public function testDownloadWindows(): void ->method('request') ->with('GET', 'https://github.com/mozilla/geckodriver/releases/download/v0.27.0/geckodriver-v0.27.0-win64.zip'); - $geckoWindows = new Driver(DriverName::GECKO, Version::fromString('0.27.0'), OperatingSystem::WINDOWS); + $geckoWindows = new Driver(DriverName::GECKO, Version::fromString('0.27.0'), OperatingSystem::WINDOWS, CpuArchitecture::AMD64); $filePath = $this->downloader->download($geckoWindows, '.'); self::assertEquals('./geckodriver.exe', $filePath);