Skip to content

Commit

Permalink
Merge pull request #650 from lucatume/v4-fix-windows-issues
Browse files Browse the repository at this point in the history
v4 fix windows issues
  • Loading branch information
lucatume authored Oct 4, 2023
2 parents 7adff1c + 8cbc904 commit b9eca99
Show file tree
Hide file tree
Showing 21 changed files with 188 additions and 36 deletions.
5 changes: 4 additions & 1 deletion src/ManagedProcess/ChromeDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ public function __construct(
private array $arguments = ['--url-base=/wd/hub'],
?string $chromeDriverBinary = null
) {
$chromeDriverBinary = $chromeDriverBinary ?? Composer::binDir('/chromedriver');
if ($chromeDriverBinary === null) {
$chromedriverBinaryFile = DIRECTORY_SEPARATOR === '\\' ? 'chromedriver.exe' : 'chromedriver';
$chromeDriverBinary = Composer::binDir($chromedriverBinaryFile);
}

if (!(file_exists($chromeDriverBinary) && is_executable($chromeDriverBinary))) {
throw new RuntimeException(
Expand Down
11 changes: 9 additions & 2 deletions src/Process/Loop.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class Loop
private array $workers = [];

private bool $fastFailureFlagRaised = false;
private bool $useFilePayloads = false;

/**
* @param array<int|string,Worker|callable> $workers
Expand Down Expand Up @@ -113,7 +114,7 @@ public static function executeClosureOrFail(
* cwd?: string
* } $options
*/
public function addWorkers(array $workers, array $options): Loop
public function addWorkers(array $workers, array $options = []): Loop
{
$builtWorkers = array_map([$this, 'ensureWorker'], array_keys($workers), $workers);

Expand Down Expand Up @@ -181,7 +182,7 @@ private function startWorker(): void
}

try {
$w = Running::fromWorker($runnableWorker);
$w = Running::fromWorker($runnableWorker, $this->useFilePayloads);
$this->started[$w->getId()] = $w;
$this->running[$w->getId()] = $w;
$this->peakParallelism = max((int)$this->peakParallelism, count($this->running));
Expand Down Expand Up @@ -347,6 +348,12 @@ public function failed(): bool
return $this->fastFailure && $this->fastFailureFlagRaised;
}

public function setUseFilePayloads(bool $useFilePayloads): Loop
{
$this->useFilePayloads = $useFilePayloads;
return $this;
}

/**
* @throws ConfigurationException
*/
Expand Down
28 changes: 27 additions & 1 deletion src/Process/Protocol/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
class Request
{
private Control $control;
private bool $useFilePayloads = false;

/**
* @param array{
Expand All @@ -27,9 +28,27 @@ public function __construct(array $controlArray, private SerializableClosure $se
$this->control = new Control($controlArray);
}

/**
* @throws ProtocolException
*/
public function getPayload(): string
{
return Parser::encode([$this->control->toArray(), $this->serializableClosure]);
$payload = Parser::encode([$this->control->toArray(), $this->serializableClosure]);

if (DIRECTORY_SEPARATOR === '\\' || $this->useFilePayloads) {
// On Windows the maximum length of the command line is 8191 characters.
// Any expanded env var, any path (e.g. to the PHP binary or the worker script) counts towards that limit.
// To avoid running into that limit we pass the payload through a temp file.
$payloadFile = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid('wpb_worker_payload_', true);

if (file_put_contents($payloadFile, $payload, LOCK_EX) === false) {
throw new ProtocolException("Could not write payload to file $payloadFile");
}

return $payloadFile;
}

return $payload;
}

/**
Expand Down Expand Up @@ -65,4 +84,11 @@ public function getControl(): Control
{
return clone $this->control;
}

public function setUseFilePayloads(bool $useFilePayloads): Request
{
$this->useFilePayloads = $useFilePayloads;

return $this;
}
}
3 changes: 2 additions & 1 deletion src/Process/Worker/Running.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public function __construct(
/**
* @throws ConfigurationException|ProcessException
*/
public static function fromWorker(Worker $worker): Running
public static function fromWorker(Worker $worker, bool $useFilePayloads = false): Running
{
$workerCallable = $worker->getCallable();
$workerClosure = $workerCallable instanceof Closure ?
Expand All @@ -51,6 +51,7 @@ public static function fromWorker(Worker $worker): Running
$workerSerializableClosure = new SerializableClosure($workerClosure);

$request = new Request($control, $workerSerializableClosure);
$request->setUseFilePayloads($useFilePayloads);

try {
$workerProcess = new WorkerProcess([PHP_BINARY, $workerScriptPathname, $request->getPayload()]);
Expand Down
16 changes: 16 additions & 0 deletions src/Process/Worker/Worker.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

namespace lucatume\WPBrowser\Process\Worker;

use Closure;
use Codeception\Exception\ConfigurationException;
use lucatume\WPBrowser\Process\Protocol\Control;
use ReflectionFunction;

class Worker implements WorkerInterface
{
Expand Down Expand Up @@ -52,6 +54,20 @@ public function __construct(
} else {
$cwd = getcwd() ?: codecept_root_dir();
}

if ($callable instanceof Closure) {
// Closures might come from files that are not autoloaded (e.g. test cases); include them in the required
// files to make sure the Closure will be bound to a valid scope.
$closureFile = (new ReflectionFunction($callable))->getFileName();
if ($closureFile !== false) {
if (!isset($control['requireFiles'])) {
$control['requireFiles'] = [];
}
$control['requireFiles'][] = $closureFile;
$control['requireFiles'] = array_values(array_unique($control['requireFiles']));
}
}

$this->control = [
'autoloadFile' => $control['autoloadFile'] ?? $defaultControl['autoloadFile'],
'requireFiles' => $control['requireFiles'] ?? $defaultControl['requireFiles'],
Expand Down
12 changes: 11 additions & 1 deletion src/Process/Worker/worker-script.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,17 @@
require_once $processSrcRoot . '/Protocol/ProtocolException.php';

try {
$request = Request::fromPayload($argv[1]);
if (!isset($argv[1])) {
throw new RuntimeException('Payload empty.');
}

if (str_starts_with($argv[1], '$')) {
$payload = $argv[1];
} elseif (($payload = @file_get_contents($argv[1])) === false) {
throw new RuntimeException("Could not read payload from file $argv[1]");
}

$request = Request::fromPayload($payload);
$serializableClosure = $request->getSerializableClosure();
$returnValue = $serializableClosure();
} catch (Throwable $throwable) {
Expand Down
7 changes: 5 additions & 2 deletions src/Project/ContentProject.php
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ public function setup(): void
'env' => [
'DATABASE_TYPE' => 'sqlite',
'DB_ENGINE' => 'sqlite',
'DB_DIR' => '%codecept_root_dir%/tests/Support/Data',
'DB_DIR' => implode(DIRECTORY_SEPARATOR, ['%codecept_root_dir%','tests','Support','Data']),
'DB_FILE' => 'db.sqlite'
]
]
Expand All @@ -161,7 +161,10 @@ public function setup(): void
$this->testEnvironment->customCommands[] = DevRestart::class;
$this->testEnvironment->customCommands[] = ChromedriverUpdate::class;
$this->testEnvironment->wpRootDir = FS::relativePath($this->workDir, $wpRootDir);
$this->testEnvironment->dbUrl = 'sqlite://%codecept_root_dir%/tests/_wordpress/data/db.sqlite';
$this->testEnvironment->dbUrl = 'sqlite://' . implode(
DIRECTORY_SEPARATOR,
['%codecept_root_dir%', 'tests', '_wordpress', 'data', 'db.sqlite']
);

$this->testEnvironment->afterSuccess = $this->getAfterSuccessClosure($activated);
}
Expand Down
13 changes: 9 additions & 4 deletions src/Project/SiteProject.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@ public function getType(): string
*/
public function setup(): void
{
$this->say('You can use a portable configuration based on PHP built-in server, Chromedriver ' .
'and SQLite.');
$this->say(
'You can use a portable configuration based on PHP built-in server, Chromedriver ' .
'and SQLite.'
);
$useDefaultConfiguration = $this->ask('Do you want to use this configuration?', true);

if (!$useDefaultConfiguration) {
Expand Down Expand Up @@ -144,7 +146,7 @@ public function setup(): void
'env' => [
'DATABASE_TYPE' => 'sqlite',
'DB_ENGINE' => 'sqlite',
'DB_DIR' => '%codecept_root_dir%/tests/Support/Data',
'DB_DIR' => implode(DIRECTORY_SEPARATOR, ['%codecept_root_dir%', 'tests', 'Support', 'Data']),
'DB_FILE' => 'db.sqlite'
]
]
Expand All @@ -156,7 +158,10 @@ public function setup(): void
$this->testEnvironment->customCommands[] = DevRestart::class;
$this->testEnvironment->customCommands[] = ChromedriverUpdate::class;
$this->testEnvironment->wpRootDir = '.';
$this->testEnvironment->dbUrl = 'sqlite://%codecept_root_dir%/tests/Support/Data/db.sqlite';
$this->testEnvironment->dbUrl = 'sqlite://' . implode(
DIRECTORY_SEPARATOR,
['%codecept_root_dir%', 'tests', 'Support', 'Data', 'db.sqlite']
);

$this->testEnvironment->afterSuccess = function (): void {
$this->scaffoldEndToEndActivationCest();
Expand Down
1 change: 1 addition & 0 deletions src/Template/Wpbrowser.php
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ private function createEndToEndSuite(ProjectInterface $project): void
browser: chrome
host: '%CHROMEDRIVER_HOST%'
port: '%CHROMEDRIVER_PORT%'
path: '/'
window_size: 1200x1000
capabilities:
"goog:chromeOptions":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ modules:
browser: chrome
host: '%CHROMEDRIVER_HOST%'
port: '%CHROMEDRIVER_PORT%'
path: '/'
window_size: 1200x1000
capabilities:
"goog:chromeOptions":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ modules:
browser: chrome
host: '%CHROMEDRIVER_HOST%'
port: '%CHROMEDRIVER_PORT%'
path: '/'
window_size: 1200x1000
capabilities:
"goog:chromeOptions":
Expand Down Expand Up @@ -196,19 +197,19 @@ TEST_TABLE_PREFIX=test_
WORDPRESS_TABLE_PREFIX=wp_

# The URL and domain of the WordPress site used in end-to-end tests.
WORDPRESS_URL=http://localhost:64918
WORDPRESS_DOMAIN=localhost:64918
WORDPRESS_URL=http://localhost:52118
WORDPRESS_DOMAIN=localhost:52118

# The username and password of the administrator user of the WordPress site used in end-to-end tests.
WORDPRESS_ADMIN_USER=admin
WORDPRESS_ADMIN_PASSWORD=password

# The host and port of the ChromeDriver server that will be used in end-to-end tests.
CHROMEDRIVER_HOST=localhost
CHROMEDRIVER_PORT=64931
CHROMEDRIVER_PORT=52138

# The port on which the PHP built-in server will serve the WordPress installation.
BUILTIN_SERVER_PORT=64918
BUILTIN_SERVER_PORT=52118

<<< /tests/.env <<<

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ modules:
browser: chrome
host: '%CHROMEDRIVER_HOST%'
port: '%CHROMEDRIVER_PORT%'
path: '/'
window_size: 1200x1000
capabilities:
"goog:chromeOptions":
Expand Down Expand Up @@ -266,19 +267,19 @@ TEST_TABLE_PREFIX=test_
WORDPRESS_TABLE_PREFIX=wp_

# The URL and domain of the WordPress site used in end-to-end tests.
WORDPRESS_URL=http://localhost:59900
WORDPRESS_DOMAIN=localhost:59900
WORDPRESS_URL=http://localhost:52214
WORDPRESS_DOMAIN=localhost:52214

# The username and password of the administrator user of the WordPress site used in end-to-end tests.
WORDPRESS_ADMIN_USER=admin
WORDPRESS_ADMIN_PASSWORD=password

# The host and port of the ChromeDriver server that will be used in end-to-end tests.
CHROMEDRIVER_HOST=localhost
CHROMEDRIVER_PORT=59916
CHROMEDRIVER_PORT=52233

# The port on which the PHP built-in server will serve the WordPress installation.
BUILTIN_SERVER_PORT=59900
BUILTIN_SERVER_PORT=52214

<<< /.env <<<

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ modules:
browser: chrome
host: '%CHROMEDRIVER_HOST%'
port: '%CHROMEDRIVER_PORT%'
path: '/'
window_size: 1200x1000
capabilities:
"goog:chromeOptions":
Expand Down Expand Up @@ -264,19 +265,19 @@ TEST_TABLE_PREFIX=test_
WORDPRESS_TABLE_PREFIX=wp_

# The URL and domain of the WordPress site used in end-to-end tests.
WORDPRESS_URL=http://localhost:64881
WORDPRESS_DOMAIN=localhost:64881
WORDPRESS_URL=http://localhost:52011
WORDPRESS_DOMAIN=localhost:52011

# The username and password of the administrator user of the WordPress site used in end-to-end tests.
WORDPRESS_ADMIN_USER=admin
WORDPRESS_ADMIN_PASSWORD=password

# The host and port of the ChromeDriver server that will be used in end-to-end tests.
CHROMEDRIVER_HOST=localhost
CHROMEDRIVER_PORT=64894
CHROMEDRIVER_PORT=52030

# The port on which the PHP built-in server will serve the WordPress installation.
BUILTIN_SERVER_PORT=64881
BUILTIN_SERVER_PORT=52011

<<< /tests/.env <<<

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ modules:
browser: chrome
host: '%CHROMEDRIVER_HOST%'
port: '%CHROMEDRIVER_PORT%'
path: '/'
window_size: 1200x1000
capabilities:
"goog:chromeOptions":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ modules:
browser: chrome
host: '%CHROMEDRIVER_HOST%'
port: '%CHROMEDRIVER_PORT%'
path: '/'
window_size: 1200x1000
capabilities:
"goog:chromeOptions":
Expand Down Expand Up @@ -269,19 +270,19 @@ TEST_TABLE_PREFIX=test_
WORDPRESS_TABLE_PREFIX=wp_

# The URL and domain of the WordPress site used in end-to-end tests.
WORDPRESS_URL=http://localhost:64864
WORDPRESS_DOMAIN=localhost:64864
WORDPRESS_URL=http://localhost:51968
WORDPRESS_DOMAIN=localhost:51968

# The username and password of the administrator user of the WordPress site used in end-to-end tests.
WORDPRESS_ADMIN_USER=admin
WORDPRESS_ADMIN_PASSWORD=password

# The host and port of the ChromeDriver server that will be used in end-to-end tests.
CHROMEDRIVER_HOST=localhost
CHROMEDRIVER_PORT=64877
CHROMEDRIVER_PORT=51983

# The port on which the PHP built-in server will serve the WordPress installation.
BUILTIN_SERVER_PORT=64864
BUILTIN_SERVER_PORT=51968

<<< /tests/.env <<<

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ modules:
browser: chrome
host: '%CHROMEDRIVER_HOST%'
port: '%CHROMEDRIVER_PORT%'
path: '/'
window_size: 1200x1000
capabilities:
"goog:chromeOptions":
Expand Down
Loading

0 comments on commit b9eca99

Please sign in to comment.