Skip to content

Commit 7d9a507

Browse files
committed
transpile 4.3.9, 4.3.10 from v4
1 parent a3a48eb commit 7d9a507

15 files changed

+353
-10
lines changed

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ This project adheres to [Semantic Versioning](http://semver.org/).
44

55
## [unreleased] Unreleased
66

7+
## Fixed
8+
9+
- Check the PID file for the PHP built-in server, MySQL and Chromedriver controllers to make sure the PID maps to an actually running process.
10+
11+
## Changed
12+
13+
- Inherit environment variables while parsing configuration files in the `WPConfigFile` class.
14+
715
## [3.7.9] 2024-11-27;
816

917
## Added

src/Extension/BuiltInServerController.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public function start(OutputInterface $output): void
1919
{
2020
$pidFile = $this->getPidFile();
2121

22-
if (is_file($pidFile)) {
22+
if ($this->isProcessRunning($pidFile)) {
2323
$output->writeln('PHP built-in server already running.');
2424
return;
2525
}

src/Extension/ChromeDriverController.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public function start(OutputInterface $output): void
2020
{
2121
$pidFile = $this->getPidFile();
2222

23-
if (is_file($pidFile)) {
23+
if ($this->isProcessRunning($pidFile)) {
2424
$output->writeln('ChromeDriver already running.');
2525

2626
return;

src/Extension/MysqlServerController.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public function start(OutputInterface $output): void
2323
{
2424
$pidFile = $this->getPidFile();
2525

26-
if (is_file($pidFile)) {
26+
if ($this->isProcessRunning($pidFile)) {
2727
$output->writeln('MySQL server already running.');
2828

2929
return;

src/Extension/PidBasedController.php

+50
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace lucatume\WPBrowser\Extension;
44

55
use Codeception\Exception\ExtensionException;
6+
use lucatume\WPBrowser\Exceptions\RuntimeException;
67

78
trait PidBasedController
89
{
@@ -49,4 +50,53 @@ protected function removePidFile(string $pidFile): void
4950
);
5051
}
5152
}
53+
54+
/**
55+
* @throws RuntimeException
56+
*/
57+
protected function isProcessRunning(string $pidFile):bool
58+
{
59+
if (!is_file($pidFile)) {
60+
return false;
61+
}
62+
63+
try {
64+
$pidFileContents = file_get_contents($pidFile);
65+
if ($pidFileContents === false) {
66+
throw new \Exception();
67+
}
68+
} catch (\Exception $e) {
69+
if (!unlink($pidFile)) {
70+
throw new RuntimeException("Failed to delete PID file: $pidFile");
71+
}
72+
73+
return false;
74+
}
75+
76+
$pid = trim($pidFileContents);
77+
78+
if (!is_numeric($pid) || (int)$pid === 0) {
79+
return false;
80+
}
81+
82+
if (PHP_OS_FAMILY === 'Windows') {
83+
$output = [];
84+
exec("tasklist /FI \"PID eq $pid\" 2>NUL", $output);
85+
86+
return strpos(implode("\n", $output), $pid) !== false;
87+
} else {
88+
// Check if the process is running on POSIX (Mac or Linux)
89+
exec("ps -p $pid", $output, $resultCode);
90+
if ($resultCode === 0 && count($output) > 1) {
91+
// Process is running
92+
return true;
93+
}
94+
}
95+
96+
if (!unlink($pidFile)) {
97+
throw new RuntimeException("Failed to delete PID file: $pidFile");
98+
}
99+
100+
return false;
101+
}
52102
}

src/Process/Loop.php

+17-3
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ class Loop
6262
* @var bool
6363
*/
6464
private $useFilePayloads = false;
65+
/**
66+
* @var bool
67+
*/
68+
private $inheritEnv = false;
6569

6670
/**
6771
* @param array<int|string,Worker|callable> $workers
@@ -91,7 +95,8 @@ public function __construct(
9195
* rethrow?: bool,
9296
* requireFiles?: array<string>,
9397
* cwd?: string,
94-
* use_file_payloads?: bool,
98+
* useFilePayloads?: bool,
99+
* inheritEnv?: bool
95100
* } $options
96101
*
97102
* @throws ProcessException
@@ -102,10 +107,14 @@ public static function executeClosure(Closure $closure, int $timeout = 30, array
102107
{
103108
$loop = new self([$closure], 1, true, $timeout, $options);
104109

105-
if (!empty($options['use_file_payloads'])) {
110+
if (!empty($options['useFilePayloads'])) {
106111
$loop->setUseFilePayloads(true);
107112
}
108113

114+
if (!empty($options['inheritEnv'])) {
115+
$loop->setInheritEnv(true);
116+
}
117+
109118
$loop->run();
110119
$results = $loop->getResults();
111120
$result = $results[0];
@@ -215,7 +224,7 @@ private function startWorker(): void
215224
}
216225

217226
try {
218-
$w = Running::fromWorker($runnableWorker, $this->useFilePayloads);
227+
$w = Running::fromWorker($runnableWorker, $this->useFilePayloads, $this->inheritEnv);
219228
$this->started[$w->getId()] = $w;
220229
$this->running[$w->getId()] = $w;
221230
$this->peakParallelism = max((int)$this->peakParallelism, count($this->running));
@@ -407,4 +416,9 @@ private function buildWorker(string $id, callable $worker): Worker
407416
{
408417
return new Worker($id, $worker, [], []);
409418
}
419+
420+
public function setInheritEnv(bool $inheritEnv):void
421+
{
422+
$this->inheritEnv = $inheritEnv;
423+
}
410424
}

src/Process/Worker/Running.php

+7-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public function __construct(string $id, WorkerProcess $proc, array $requiredReso
5757
/**
5858
* @throws ConfigurationException|ProcessException
5959
*/
60-
public static function fromWorker(Worker $worker, bool $useFilePayloads = false): Running
60+
public static function fromWorker(Worker $worker, bool $useFilePayloads = false, bool $inheritEnv = false): Running
6161
{
6262
$workerCallable = $worker->getCallable();
6363
$workerClosure = $workerCallable instanceof Closure ?
@@ -69,11 +69,17 @@ public static function fromWorker(Worker $worker, bool $useFilePayloads = false)
6969

7070
$workerScriptPathname = __DIR__ . '/worker-script.php';
7171
$control = $worker->getControl();
72+
73+
if ($inheritEnv) {
74+
$control['env'] = array_merge($control['env'] ?? [], getenv());
75+
}
76+
7277
$workerSerializableClosure = new SerializableClosure($workerClosure);
7378

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

82+
7783
try {
7884
$workerProcess = new WorkerProcess([PHP_BINARY, $workerScriptPathname, $request->getPayload()]);
7985
$workerProcess->start();

src/WordPress/WPConfigFile.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ private function includeFile(): void
129129
try {
130130
$result = Loop::executeClosure(function () use ($wpSettingsFile, $wpConfigFile): array {
131131
return $this->toIncludeFile($wpConfigFile, $wpSettingsFile);
132-
});
132+
}, 30, ['inheritEnv' => true]);
133133

134134
$returnValue = $result->getReturnValue();
135135

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
/**
3+
* #ddev-generated: Automatically generated WordPress settings file.
4+
* ddev manages this file and may delete or overwrite the file unless this comment is removed.
5+
*
6+
* @package ddevapp
7+
*/
8+
9+
if ( getenv( 'IS_DDEV_PROJECT' ) == 'true' ) {
10+
/** The name of the database for WordPress */
11+
defined( 'DB_NAME' ) || define( 'DB_NAME', 'db' );
12+
13+
/** MySQL database username */
14+
defined( 'DB_USER' ) || define( 'DB_USER', 'db' );
15+
16+
/** MySQL database password */
17+
defined( 'DB_PASSWORD' ) || define( 'DB_PASSWORD', 'db' );
18+
19+
/** MySQL hostname */
20+
defined( 'DB_HOST' ) || define( 'DB_HOST', 'ddev-ddev-project-db' );
21+
22+
/** WP_HOME URL */
23+
defined( 'WP_HOME' ) || define( 'WP_HOME', 'https://ddev-project.ddev.site:33001' );
24+
25+
/** WP_SITEURL location */
26+
defined( 'WP_SITEURL' ) || define( 'WP_SITEURL', WP_HOME . '/' );
27+
28+
/** Enable debug */
29+
defined( 'WP_DEBUG' ) || define( 'WP_DEBUG', true );
30+
31+
/**
32+
* Set WordPress Database Table prefix if not already set.
33+
*
34+
* @global string $table_prefix
35+
*/
36+
if ( ! isset( $table_prefix ) || empty( $table_prefix ) ) {
37+
// phpcs:disable WordPress.WP.GlobalVariablesOverride.Prohibited
38+
$table_prefix = 'wp_';
39+
// phpcs:enable
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
/**
3+
* #ddev-generated: Automatically generated WordPress settings file.
4+
* ddev manages this file and may delete or overwrite the file unless this comment is removed.
5+
* It is recommended that you leave this file alone.
6+
*
7+
* @package ddevapp
8+
*/
9+
10+
/** Database charset to use in creating database tables. */
11+
define( 'DB_CHARSET', 'utf8' );
12+
13+
/** The database collate type. Don't change this if in doubt. */
14+
define( 'DB_COLLATE', '' );
15+
16+
/** Authentication Unique Keys and Salts. */
17+
define( 'AUTH_KEY', 'tCGZUeKbIdopaFexrGoPqNNlLNsfaJPrHlXPBoPwhGZFvguTIpelFEFsNwCgyQWP' );
18+
define( 'SECURE_AUTH_KEY', 'EdTQtDpfrFpzuwMOIFljwQcyusSTVPtqMfpGhBfKEAJwFxDmFaBdOKiNGPwJsDWA' );
19+
define( 'LOGGED_IN_KEY', 'oWUgUNaIPqTZAeTAAyPALbLWwnRHFVSPYSJooRBpuRlphdjogVDIYLYRRqhwZXIm' );
20+
define( 'NONCE_KEY', 'kHzVnpmLOgkzfNyESZslNHZNzxsatEAJVVnmxJqbKjnooSmdSoVJHzxcWxAxNUwA' );
21+
define( 'AUTH_SALT', 'kGENEUGicWfvwDvjjMtncIOmLQAJztohoqSMRumqjlmhexnRLocvZCjfXGnftfTL' );
22+
define( 'SECURE_AUTH_SALT', 'WLPqqvorXIIPCnPOBPLopTADMtDVGYpvJDSMHOvpgaIpTADVZYNNWakSKtiXhJKg' );
23+
define( 'LOGGED_IN_SALT', 'KZTqsQCEnJMPaYMGHOkpSEBsjnMznCPdzKVxFCHWldfnlNSYpdRaWzXFsBxiTcsk' );
24+
define( 'NONCE_SALT', 'jeBUcIcVAFQjsWbOpomcvjIBARyiEQWwHWSGDzUyLIBixJnHJPtZTdjNUkIgDFow' );
25+
26+
/* Add any custom values between this line and the "stop editing" line. */
27+
28+
29+
30+
/* That's all, stop editing! Happy publishing. */
31+
32+
/** Absolute path to the WordPress directory. */
33+
defined( 'ABSPATH' ) || define( 'ABSPATH', dirname( __FILE__ ) . '/' );
34+
35+
// Include for settings managed by ddev.
36+
$ddev_settings = __DIR__ . '/wp-config-ddev.php';
37+
if ( ! defined( 'DB_USER' ) && getenv( 'IS_DDEV_PROJECT' ) == 'true' && is_readable( $ddev_settings ) ) {
38+
require_once( $ddev_settings );
39+
}
40+
41+
/** Include wp-settings.php */
42+
if ( file_exists( ABSPATH . '/wp-settings.php' ) ) {
43+
require_once ABSPATH . '/wp-settings.php';
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<?php
2+
// Nothing to see here.

tests/_support/Traits/LoopIsolation.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ protected function assertInIsolation(Closure $runAssertions, string $cwd = null,
2828
$options['requireFiles'][] = $callerFile;
2929
}
3030
$options['cwd'] = !empty($options['cwd']) ? $options['cwd'] : getcwd();
31-
$options['use_file_payloads'] = true;
31+
$options['useFilePayloads'] = true;
3232
$timeout = Debug::isEnabled() ? PHP_INT_MAX : 30;
3333
$result = Loop::executeClosure($runAssertions, $timeout, $options);
3434
$returnValue = $result->getReturnValue();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
4+
namespace Unit\lucatume\WPBrowser\Extension;
5+
6+
use lucatume\WPBrowser\Extension\PidBasedController;
7+
use lucatume\WPBrowser\Exceptions\RuntimeException;
8+
use Symfony\Component\Process\Process;
9+
10+
class PidBasedControllerTest extends \Codeception\Test\Unit
11+
{
12+
public function test_isProcessRunning_on_posix():void{
13+
$testClass = new class {
14+
use PidBasedController;
15+
16+
public function openIsProcessRunning(string $pidFile):bool{
17+
return $this->isProcessRunning($pidFile);
18+
}
19+
};
20+
$hash = md5(microtime());
21+
$pidFile = sys_get_temp_dir()."/test-{$hash}.pid";
22+
$pid = posix_getpid();
23+
if(!file_put_contents($pidFile,$pid)){
24+
$this->fail('Could not write pid to file '.$pidFile);
25+
}
26+
27+
$this->assertTrue($testClass->openIsProcessRunning($pidFile));
28+
$this->assertFileExists($pidFile);
29+
}
30+
31+
public function test_isProcessRunning_returns_false_if_pid_file_not_exists():void{
32+
$testClass = new class {
33+
use PidBasedController;
34+
35+
public function openIsProcessRunning(string $pidFile):bool{
36+
return $this->isProcessRunning($pidFile);
37+
}
38+
};
39+
$pid = posix_getpid();
40+
41+
$this->assertFalse($testClass->openIsProcessRunning(__DIR__ .'/test.pid'));
42+
}
43+
44+
public function test_isProcessRunning_throws_if_pid_file_cannot_be_read():void{
45+
$testClass = new class {
46+
use PidBasedController;
47+
48+
public function openIsProcessRunning(string $pidFile):bool{
49+
return $this->isProcessRunning($pidFile);
50+
}
51+
};
52+
$pid = posix_getpid();
53+
$hash = md5(microtime());
54+
$pidFile = sys_get_temp_dir()."/test-{$hash}.pid";
55+
$pid = posix_getpid();
56+
if(!file_put_contents($pidFile,$pid)){
57+
$this->fail('Could not write pid to file '.$pidFile);
58+
}
59+
// Change the file mode to not be readable by the current user.
60+
chmod($pidFile,0000);
61+
62+
$this->assertFalse($testClass->openIsProcessRunning($pidFile));
63+
}
64+
65+
public function test_isProcessRunning_returns_false_if_process_is_not_running():void{
66+
$testClass = new class {
67+
use PidBasedController;
68+
69+
public function openIsProcessRunning(string $pidFile):bool{
70+
return $this->isProcessRunning($pidFile);
71+
}
72+
};
73+
$hash = md5(microtime());
74+
$pidFile = sys_get_temp_dir()."/test-{$hash}.pid";
75+
$process = new Process(['echo', '23']);
76+
$process->start();
77+
$pid = $process->getPid();
78+
$process->wait();
79+
if(!file_put_contents($pidFile,$pid)){
80+
$this->fail('Could not write pid to file '.$pidFile);
81+
}
82+
83+
$this->assertFalse($testClass->openIsProcessRunning($pidFile));
84+
$this->assertFileNotExists($pidFile);
85+
}
86+
}

0 commit comments

Comments
 (0)