From de3f6311f99b1ae88a9d83ef2ca57ff8cda91508 Mon Sep 17 00:00:00 2001 From: Luca Tumedei Date: Mon, 9 Dec 2024 15:41:55 +0100 Subject: [PATCH] fix(Module/WPLoader) ensure active_plugins Depending on the set up, some plugins might deactivate, or activate, other plugins during their activation. This ensures the plugins set in the `plugins` configuration parameter of the `WPLoader` module will always be loaded, no matter what other plugins might do during their activation. --- CHANGELOG.md | 4 + src/Module/WPLoader.php | 16 +++- src/Process/SerializableThrowable.php | 4 +- .../WPLoaderArbitraryPluginLocationTest.php | 95 ++++++++++++++++++- .../WPBrowser/Module/WPTestCaseStrictTest.php | 2 +- 5 files changed, 111 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f39fd607c..dbf5b91af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [unreleased] Unreleased +### Fixed + +- Ensure plugin activation is respected indifferent of plugins that might deactivate others during activation. + ## [4.4.0] 2024-12-08; ## Added diff --git a/src/Module/WPLoader.php b/src/Module/WPLoader.php index b2034c918..b0510c57e 100644 --- a/src/Module/WPLoader.php +++ b/src/Module/WPLoader.php @@ -437,7 +437,7 @@ public function _initialize(): void if (empty($config['dbHost']) && str_starts_with($config['dbName'], codecept_root_dir())) { $dbFile = (array_reverse(explode(DIRECTORY_SEPARATOR, $config['dbName']))[0]); $dbDir = rtrim(str_replace($dbFile, '', $config['dbName']), DIRECTORY_SEPARATOR); - $db = new SqliteDatabase($dbDir, $dbFile); + $db = new SqliteDatabase($dbDir, $dbFile, $config['tablePrefix']); } else { $db = new MysqlDatabase( $config['dbName'], @@ -1140,18 +1140,24 @@ private function activatePluginsTheme(array $plugins): array $database->updateOption('stylesheet', $database->getOption('stylesheet')); } - // Flush the cache to force the refetch of the options' value. - wp_cache_delete('alloptions', 'options'); - // Do not include external plugins, it would create issues at this stage. $pluginsDir = $this->getPluginsFolder(); - return array_values( + $activePlugins = array_values( array_filter( $plugins, static fn(string $plugin) => is_file($pluginsDir . "/$plugin") ) ); + + // During activation some plugins could deactivate other plugins: protect from it. + $database->updateOption('active_plugins', $activePlugins); + + // Flush the cache to force the refetch of the options' value. + wp_cache_delete('alloptions', 'options'); + + + return $activePlugins; } /** diff --git a/src/Process/SerializableThrowable.php b/src/Process/SerializableThrowable.php index ef935dda3..706767650 100644 --- a/src/Process/SerializableThrowable.php +++ b/src/Process/SerializableThrowable.php @@ -18,7 +18,7 @@ class SerializableThrowable private array $trace; private string $file; private int $line; - private int $code; + private int|string $code; private string $message; private bool $colorize = true; @@ -42,7 +42,7 @@ public function __construct(Throwable $throwable) * colorize: bool, * throwable: Throwable, * message: string, - * code: int, + * code: int|string, * file: string, * line: int, * trace: array> diff --git a/tests/unit/lucatume/WPBrowser/Module/WPLoaderArbitraryPluginLocationTest.php b/tests/unit/lucatume/WPBrowser/Module/WPLoaderArbitraryPluginLocationTest.php index b236daa47..71fa377ad 100644 --- a/tests/unit/lucatume/WPBrowser/Module/WPLoaderArbitraryPluginLocationTest.php +++ b/tests/unit/lucatume/WPBrowser/Module/WPLoaderArbitraryPluginLocationTest.php @@ -74,8 +74,83 @@ public function test_loads_plugins_from_default_location_correctly(): void /** * Plugin Name: Test One */ + +function test_one_loaded(){} +PHP + )) { + throw new \RuntimeException('Unable to create test plugin file for plugin test-one'); + } + if (!mkdir($projectDir . '/wp-content/plugins/test-two', 0777, true)) { + throw new \RuntimeException('Unable to create test directory for plugin test-two'); + } + if (!file_put_contents( + $projectDir . '/wp-content/plugins/test-two/plugin.php', + <<< PHP +config = [ + 'wpRootFolder' => $projectDir, + 'dbUrl' => $installationDb->getDbUrl(), + 'tablePrefix' => 'test_', + 'plugins' => [ + 'test-one/plugin.php', + 'test-two/plugin.php', + ] + ]; + $wpLoader = $this->module(); + $projectDirname = basename($projectDir); + + $this->assertInIsolation( + static function () use ($wpLoader, $projectDir) { + chdir($projectDir); + + $wpLoader->_initialize(); + + Assert::assertTrue(function_exists('test_one_loaded')); + Assert::assertTrue(function_exists('test_two_loaded')); + Assert::assertEquals( + ['test-one/plugin.php','test-two/plugin.php'], + get_option('active_plugins') + ); + global $wpdb; + Assert::assertEquals( + serialize(['test-one/plugin.php','test-two/plugin.php']), + $wpdb->get_var("select option_value from {$wpdb->prefix}options where option_name = 'active_plugins'") + ); + } + ); + } + + public function test_loads_plugins_and_ensures_them_loaded(): void + { + $projectDir = FS::tmpDir('wploader_'); + $installation = Installation::scaffold($projectDir); + $dbName = Random::dbName(); + $dbHost = Env::get('WORDPRESS_DB_HOST'); + $dbUser = Env::get('WORDPRESS_DB_USER'); + $dbPassword = Env::get('WORDPRESS_DB_PASSWORD'); + $installationDb = new MysqlDatabase($dbName, $dbUser, $dbPassword, $dbHost, 'wp_'); + if (!mkdir($projectDir . '/wp-content/plugins/test-one', 0777, true)) { + throw new \RuntimeException('Unable to create test directory for plugin test-one'); + } + if (!file_put_contents( + $projectDir . '/wp-content/plugins/test-one/plugin.php', + <<< PHP +get_var("select option_value from {$wpdb->prefix}options where option_name = 'active_plugins'") + ); } ); } diff --git a/tests/unit/lucatume/WPBrowser/Module/WPTestCaseStrictTest.php b/tests/unit/lucatume/WPBrowser/Module/WPTestCaseStrictTest.php index 1cd57f22a..42ad9f1df 100644 --- a/tests/unit/lucatume/WPBrowser/Module/WPTestCaseStrictTest.php +++ b/tests/unit/lucatume/WPBrowser/Module/WPTestCaseStrictTest.php @@ -180,7 +180,7 @@ public function test_something():void{ public function should_not_be_strict_about_wpdb_connection_id_in_sq_lite_database(): void { $wpRootDir = FS::tmpDir('wploader_'); - $db = new SQLiteDatabase($wpRootDir, 'db.sqlite', 'wp_'); + $db = new SQLiteDatabase($wpRootDir, 'db.sqlite', 'wptests_'); Installation::scaffold($wpRootDir); $db->create(); $testcaseFile = $wpRootDir . '/BreakingTest.php';