From 63772ce2d3d1438f7bdffb6961d6cca8d1c62940 Mon Sep 17 00:00:00 2001 From: Andron Ocean Date: Sat, 5 Oct 2024 22:27:32 -0400 Subject: [PATCH 1/7] Handle Codeception early exit condition This provides a better debug message and error log when Codeception's ErrorHandler exits with `COMMAND DID NOT FINISH PROPERLY.` Plugins or WP-CLI packages may call `exit()` early in various scenarios before WordPress has loaded, which triggers Codeception's ErrorHandler::shutdownHandler() method, and emits this output. --- src/WordPress/InstallationException.php | 9 +++++++++ src/WordPress/LoadSandbox.php | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/WordPress/InstallationException.php b/src/WordPress/InstallationException.php index 320bbc7b8..7662e394c 100644 --- a/src/WordPress/InstallationException.php +++ b/src/WordPress/InstallationException.php @@ -43,6 +43,7 @@ class InstallationException extends Exception public const SQLITE_PLUGIN_NOT_FOUND = 37; public const DB_DROPIN_ALREADY_EXISTS = 38; public const WORDPRESS_NOT_FOUND = 39; + public const COMMAND_DID_NOT_FINISH_PROPERLY = 40; public static function becauseWordPressFailedToLoad(string $bodyContent): self { @@ -71,4 +72,12 @@ public static function becauseWordPressMultsiteIsNotInstalled(bool $isSubdomainI return new self('WordPress multisite (sub-folder) is not installed.', self::MULTISITE_SUBFOLDER_NOT_INSTALLED); } + + public static function becauseCodeceptionCommandDidNotFinish(): self + { + return new self( + "Codeception `run` command did not finish properly; WordPress exited early prior to wp_loaded.\n", + self::COMMAND_DID_NOT_FINISH_PROPERLY + ); + } } diff --git a/src/WordPress/LoadSandbox.php b/src/WordPress/LoadSandbox.php index ffa55dce7..366633ed2 100644 --- a/src/WordPress/LoadSandbox.php +++ b/src/WordPress/LoadSandbox.php @@ -123,6 +123,16 @@ class_exists(InstallationException::class); } } + if ($bodyContent === 'COMMAND DID NOT FINISH PROPERLY.') { + // we got here from \Codeception\Subscriber\ErrorHandler::shutdownHandler() + codecept_debug('Codeception error: ' .$bodyContent); + codecept_debug( + 'DEBUG: Something caused WordPress to exit early. If there is output above, it may provide clues. ' + .'(For instance, a WP-CLI package mistakenly attempting to handle the `codecept run` command.)' + ); + throw InstallationException::becauseCodeceptionCommandDidNotFinish(); + } + // We do not know what happened, throw and try to be helpful. throw InstallationException::becauseWordPressFailedToLoad($bodyContent ?: $reason); } From ec97151c7e94fb3c6d1a61ac892e967c6a4bfe09 Mon Sep 17 00:00:00 2001 From: Andron Ocean Date: Thu, 10 Oct 2024 16:25:22 -0400 Subject: [PATCH 2/7] Clarify debug and error log messages --- src/WordPress/InstallationException.php | 3 ++- src/WordPress/LoadSandbox.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/WordPress/InstallationException.php b/src/WordPress/InstallationException.php index 7662e394c..0b7a85a21 100644 --- a/src/WordPress/InstallationException.php +++ b/src/WordPress/InstallationException.php @@ -76,7 +76,8 @@ public static function becauseWordPressMultsiteIsNotInstalled(bool $isSubdomainI public static function becauseCodeceptionCommandDidNotFinish(): self { return new self( - "Codeception `run` command did not finish properly; WordPress exited early prior to wp_loaded.\n", + "Codeception `run` command did not finish properly; WordPress exited early during sandbox installation. " + ."A plugin, theme, or WP-CLI package may have exited before the wp_loaded action could run.", self::COMMAND_DID_NOT_FINISH_PROPERLY ); } diff --git a/src/WordPress/LoadSandbox.php b/src/WordPress/LoadSandbox.php index 366633ed2..c41f161cf 100644 --- a/src/WordPress/LoadSandbox.php +++ b/src/WordPress/LoadSandbox.php @@ -127,7 +127,7 @@ class_exists(InstallationException::class); // we got here from \Codeception\Subscriber\ErrorHandler::shutdownHandler() codecept_debug('Codeception error: ' .$bodyContent); codecept_debug( - 'DEBUG: Something caused WordPress to exit early. If there is output above, it may provide clues. ' + 'DEBUG: Something caused WordPress to exit early. If there is error output above, it may provide clues. ' .'(For instance, a WP-CLI package mistakenly attempting to handle the `codecept run` command.)' ); throw InstallationException::becauseCodeceptionCommandDidNotFinish(); From e18119f9793a63558493da601b0c7aa40b044d9e Mon Sep 17 00:00:00 2001 From: Andron Ocean Date: Sun, 6 Oct 2024 11:33:57 -0400 Subject: [PATCH 3/7] Try adding unit test for Codeception early exit --- .../WPBrowser/WordPress/LoadSandboxTest.php | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/tests/unit/lucatume/WPBrowser/WordPress/LoadSandboxTest.php b/tests/unit/lucatume/WPBrowser/WordPress/LoadSandboxTest.php index f4d38aad0..596c78392 100644 --- a/tests/unit/lucatume/WPBrowser/WordPress/LoadSandboxTest.php +++ b/tests/unit/lucatume/WPBrowser/WordPress/LoadSandboxTest.php @@ -3,10 +3,14 @@ namespace Unit\lucatume\WPBrowser\WordPress; +use Codeception\Subscriber\ErrorHandler; use Codeception\Test\Unit; use Exception; +use lucatume\WPBrowser\Process\ProcessException; +use lucatume\WPBrowser\Process\WorkerException; use lucatume\WPBrowser\Tests\Traits\LoopIsolation; use lucatume\WPBrowser\Tests\Traits\TmpFilesCleanup; +use lucatume\WPBrowser\Traits\UopzFunctions; use lucatume\WPBrowser\Utils\Env; use lucatume\WPBrowser\Utils\Filesystem as FS; use lucatume\WPBrowser\Utils\Random; @@ -24,6 +28,7 @@ class LoadSandboxTest extends Unit { use LoopIsolation; use TmpFilesCleanup; + use UopzFunctions; /** * It should correctly load installed WordPress @@ -322,4 +327,62 @@ public function should_handle_wp_die_called_during_loading(): void $loadSandbox->load(); }); } + + /** + * It should handle an unexpected early exit if something interferes with Codeception + * + * @test + */ + public function should_handle_codeception_command_not_finished_error(): void { + $wpRootDir = FS::tmpDir('sandbox_'); + $dbName = Random::dbName(); + $dbHost = Env::get('WORDPRESS_DB_HOST'); + $dbUser = Env::get('WORDPRESS_DB_USER'); + $dbPassword = Env::get('WORDPRESS_DB_PASSWORD'); + $db = new MysqlDatabase($dbName, $dbUser, $dbPassword, $dbHost, 'wp_'); + $installation = Installation::scaffold($wpRootDir, '6.1.1') + ->configure($db) + ->install( + 'http://wordpress.test', + 'admin', + 'admin', + 'admin@wordpress.test', + 'Sandbox' + ); + + $exitingPluginCode = <<<'PHP' +getMuPluginsDir())) { + mkdir($installation->getMuPluginsDir()); + } + file_put_contents($installation->getMuPluginsDir() . '/exiting-mu-plugin.php', $exitingPluginCode); + + $this->preventExit(); + + $this->expectException(InstallationException::class); + $this->expectExceptionMessageMatches('WordPress exited early during sandbox installation'); + + $loadSandbox = new LoadSandbox($wpRootDir, 'wordpress.test'); + + $this->assertInIsolation(static function () use ($loadSandbox) { + $loadSandbox->load(); + }); + } } From 95babfeb7bedbd611a590187c893e191fd784f7e Mon Sep 17 00:00:00 2001 From: Luca Tumedei Date: Mon, 14 Oct 2024 08:57:28 +0200 Subject: [PATCH 4/7] refactor(LoadSandbox) move debug information to exception Since the output of `codecept_debug` will only show if the user is running the Codeception command using the `--debug` output, I've moved the information that will help the user debug the issue to the exception to make sure it will always print. I've changed the wording a bit to be more general and cover other commands (e.g. the `console` one) that will use the LoadSandbox class and might fail like the `run` command does. Fix test. --- src/WordPress/InstallationException.php | 5 ++-- src/WordPress/LoadSandbox.php | 8 ++--- .../WPBrowser/WordPress/LoadSandboxTest.php | 30 +++++++++++-------- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/WordPress/InstallationException.php b/src/WordPress/InstallationException.php index 0b7a85a21..4a713b8cc 100644 --- a/src/WordPress/InstallationException.php +++ b/src/WordPress/InstallationException.php @@ -76,8 +76,9 @@ public static function becauseWordPressMultsiteIsNotInstalled(bool $isSubdomainI public static function becauseCodeceptionCommandDidNotFinish(): self { return new self( - "Codeception `run` command did not finish properly; WordPress exited early during sandbox installation. " - ."A plugin, theme, or WP-CLI package may have exited before the wp_loaded action could run.", + "The current Codeception command did not finish properly. WordPress exited early while loading. " + ."A plugin, theme, or WP-CLI package may have exited before the wp_loaded action could be fired. " . + "If there is error output above, it may provide clues.", self::COMMAND_DID_NOT_FINISH_PROPERLY ); } diff --git a/src/WordPress/LoadSandbox.php b/src/WordPress/LoadSandbox.php index c41f161cf..92fcbc5a1 100644 --- a/src/WordPress/LoadSandbox.php +++ b/src/WordPress/LoadSandbox.php @@ -124,12 +124,8 @@ class_exists(InstallationException::class); } if ($bodyContent === 'COMMAND DID NOT FINISH PROPERLY.') { - // we got here from \Codeception\Subscriber\ErrorHandler::shutdownHandler() - codecept_debug('Codeception error: ' .$bodyContent); - codecept_debug( - 'DEBUG: Something caused WordPress to exit early. If there is error output above, it may provide clues. ' - .'(For instance, a WP-CLI package mistakenly attempting to handle the `codecept run` command.)' - ); + // We got here from \Codeception\Subscriber\ErrorHandler::shutdownHandler(). + // We'll try to provide some clues to the user by adding some debug output. throw InstallationException::becauseCodeceptionCommandDidNotFinish(); } diff --git a/tests/unit/lucatume/WPBrowser/WordPress/LoadSandboxTest.php b/tests/unit/lucatume/WPBrowser/WordPress/LoadSandboxTest.php index 596c78392..fb44690b9 100644 --- a/tests/unit/lucatume/WPBrowser/WordPress/LoadSandboxTest.php +++ b/tests/unit/lucatume/WPBrowser/WordPress/LoadSandboxTest.php @@ -3,11 +3,9 @@ namespace Unit\lucatume\WPBrowser\WordPress; -use Codeception\Subscriber\ErrorHandler; use Codeception\Test\Unit; use Exception; -use lucatume\WPBrowser\Process\ProcessException; -use lucatume\WPBrowser\Process\WorkerException; +use lucatume\WPBrowser\Tests\Traits\Fork; use lucatume\WPBrowser\Tests\Traits\LoopIsolation; use lucatume\WPBrowser\Tests\Traits\TmpFilesCleanup; use lucatume\WPBrowser\Traits\UopzFunctions; @@ -363,25 +361,31 @@ public function should_handle_codeception_command_not_finished_error(): void { * @see \Codeception\Subscriber\ErrorHandler::shutdownHandler() */ add_action('after_setup_theme', function () { - // Output and exit from \Codeception\Subscriber\ErrorHandler::shutdownHandler + // Output and exit from \Codeception\Subscriber\ErrorHandler::shutdownHandler. echo "\n\n\nCOMMAND DID NOT FINISH PROPERLY.\n"; exit(125); }); PHP; - if (!file_exists($installation->getMuPluginsDir())) { - mkdir($installation->getMuPluginsDir()); + $muPluginsDir = $installation->getMuPluginsDir(); + if ( + !is_dir($muPluginsDir) + && !( + mkdir($muPluginsDir, 0755, true) + && is_dir($muPluginsDir) + ) + ) { + throw new \RuntimeException('Could not create mu-plugins directory.'); + } + if(!file_put_contents($muPluginsDir . '/exiting-mu-plugin.php', $exitingPluginCode)){ + throw new \RuntimeException('Could not write exiting-mu-plugin.php.'); } - file_put_contents($installation->getMuPluginsDir() . '/exiting-mu-plugin.php', $exitingPluginCode); - - $this->preventExit(); $this->expectException(InstallationException::class); - $this->expectExceptionMessageMatches('WordPress exited early during sandbox installation'); + $this->expectExceptionMessage(InstallationException::becauseCodeceptionCommandDidNotFinish()->getMessage()); - $loadSandbox = new LoadSandbox($wpRootDir, 'wordpress.test'); - - $this->assertInIsolation(static function () use ($loadSandbox) { + $this->assertInIsolation(static function () use ($wpRootDir) { + $loadSandbox = new LoadSandbox($wpRootDir, 'wordpress.test'); $loadSandbox->load(); }); } From 4f2633b3c16e0eed759e3cf6def66d31fc6952b1 Mon Sep 17 00:00:00 2001 From: Luca Tumedei Date: Mon, 14 Oct 2024 09:00:51 +0200 Subject: [PATCH 5/7] fix typos --- config/typos.toml | 1 + includes/airplane-mode/README.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/config/typos.toml b/config/typos.toml index ebfed29b6..bc23dd4a9 100644 --- a/config/typos.toml +++ b/config/typos.toml @@ -12,3 +12,4 @@ ignore-hidden = false [default.extend-words] # To handle the hipster default blog content about bike messengers gettin' caught in the rain. "gettin" = "gettin" +"Automattic" = "Automattic" diff --git a/includes/airplane-mode/README.md b/includes/airplane-mode/README.md index 3b1c3bcac..fcd570492 100755 --- a/includes/airplane-mode/README.md +++ b/includes/airplane-mode/README.md @@ -10,7 +10,7 @@ Airplane Mode * [Mark Jaquith](https://github.com/markjaquith) ## About -Control loading of external files when developing locally. WP loads certain external files (fonts, Gravatar, etc.) and makes external HTTP calls. This isn't usually an issue, unless you're working in an evironment without a web connection. This plugin removes/unhooks those actions to reduce load time and avoid errors due to missing files. +Control loading of external files when developing locally. WP loads certain external files (fonts, Gravatar, etc.) and makes external HTTP calls. This isn't usually an issue, unless you're working in an environment without a web connection. This plugin removes/unhooks those actions to reduce load time and avoid errors due to missing files. ## Current Actions * removes external JS and CSS files from loading From 3c21adc5b7c984f604e070018e5b438ca8e05429 Mon Sep 17 00:00:00 2001 From: Luca Tumedei Date: Mon, 14 Oct 2024 09:04:22 +0200 Subject: [PATCH 6/7] doc(CHANGELOG.md) add changelog entry --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9783602ac..c8a37a060 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [unreleased] Unreleased +### Changed + +- Improve `LoadSandbox` errol and messaging (used by the `WPLoader` module when `loadOnly: true`) around Codeception early exits. (thanks @andronocean) + ## [4.3.4] 2024-09-13; ## Fixed From 7b8d0b920ac3385c05e3f853a8ad73fde9b20a9b Mon Sep 17 00:00:00 2001 From: "theAverageDev (Luca Tumedei)" Date: Wed, 16 Oct 2024 10:22:41 +0200 Subject: [PATCH 7/7] udpate(LoadSandbox) add debug message Co-authored-by: Andron Ocean --- src/WordPress/LoadSandbox.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/WordPress/LoadSandbox.php b/src/WordPress/LoadSandbox.php index 92fcbc5a1..a4d863988 100644 --- a/src/WordPress/LoadSandbox.php +++ b/src/WordPress/LoadSandbox.php @@ -125,7 +125,8 @@ class_exists(InstallationException::class); if ($bodyContent === 'COMMAND DID NOT FINISH PROPERLY.') { // We got here from \Codeception\Subscriber\ErrorHandler::shutdownHandler(). - // We'll try to provide some clues to the user by adding some debug output. + // We'll try to provide some clues to the user in the exception message. + codecept_debug('Codeception error: ' . $bodyContent . ' Check logs for details.'); throw InstallationException::becauseCodeceptionCommandDidNotFinish(); }