Repository navigation
Tests: Add unit test coverage for validate_active_plugins() #14608
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Changes from all commits
4332714
7d99d5d
f8932ec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,203 @@ | ||
| <?php | ||
|
|
||
| /** | ||
| * Tests for validate_active_plugins(). | ||
| * | ||
| * @group admin | ||
| * @group plugins | ||
| * | ||
| * @covers ::validate_active_plugins | ||
| * @covers ::validate_plugin | ||
| */ | ||
| class Tests_Admin_Includes_Plugin_ValidateActivePlugins extends WP_UnitTestCase { | ||
|
|
||
| /** | ||
| * The directory of the test plugin without a header. | ||
| * | ||
| * @var string | ||
| */ | ||
| const NO_HEADER_DIR = 'validate-test-no-header'; | ||
|
|
||
| /** | ||
| * Super admin user ID. | ||
| * | ||
| * @var int | ||
| */ | ||
| private static $super_admin_id; | ||
|
|
||
| /** | ||
| * Sets up the user. | ||
| * | ||
| * @param WP_UnitTest_Factory $factory Test factory. | ||
| */ | ||
| public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) { | ||
| self::$super_admin_id = $factory->user->create( array( 'role' => 'administrator' ) ); | ||
|
|
||
| if ( is_multisite() ) { | ||
| grant_super_admin( self::$super_admin_id ); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Revokes the super admin grant before the fixture users are deleted. | ||
| */ | ||
| public static function wpTearDownAfterClass() { | ||
| if ( is_multisite() ) { | ||
| revoke_super_admin( self::$super_admin_id ); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Removes stale plugin files and resets the active plugins. | ||
| */ | ||
| public function set_up() { | ||
| parent::set_up(); | ||
|
|
||
| $this->remove_plugin(); | ||
|
|
||
| wp_cache_delete( 'plugins', 'plugins' ); | ||
| update_site_option( 'active_sitewide_plugins', array() ); | ||
| } | ||
|
|
||
| /** | ||
| * Removes the plugin file without a header. | ||
| */ | ||
| public function tear_down() { | ||
| $this->remove_plugin(); | ||
|
|
||
| wp_cache_delete( 'plugins', 'plugins' ); | ||
|
|
||
| parent::tear_down(); | ||
| } | ||
|
|
||
| /** | ||
| * Tests that an active plugins option that is not an array is reset. | ||
| * | ||
| * @ticket 65819 | ||
| * | ||
| * @dataProvider data_invalid_options | ||
| * | ||
| * @param mixed $value The option value. | ||
| */ | ||
| public function test_should_reset_option_that_is_not_an_array( $value ) { | ||
| update_option( 'active_plugins', $value ); | ||
|
|
||
| $this->assertSame( array(), validate_active_plugins(), 'No invalid plugins should be returned.' ); | ||
| $this->assertSame( array(), get_option( 'active_plugins' ), 'The option should be reset.' ); | ||
| } | ||
|
|
||
| /** | ||
| * Data provider. | ||
| * | ||
| * @return array[] | ||
| */ | ||
| public static function data_invalid_options() { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could this also cover |
||
| return array( | ||
| 'string' => array( 'hello.php' ), | ||
| 'integer' => array( 1 ), | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Tests that valid active plugins are kept. | ||
| * | ||
| * @ticket 65819 | ||
| */ | ||
| public function test_should_keep_valid_plugins() { | ||
| update_option( 'active_plugins', array( 'hello.php', 'internationalized-plugin.php' ) ); | ||
|
|
||
| $this->assertSame( array(), validate_active_plugins(), 'No invalid plugins should be returned.' ); | ||
| $this->assertSame( array( 'hello.php', 'internationalized-plugin.php' ), get_option( 'active_plugins' ), 'The plugins should stay active.' ); | ||
| } | ||
|
|
||
| /** | ||
| * Tests that invalid active plugins are reported and deactivated silently. | ||
| * | ||
| * @ticket 65819 | ||
| */ | ||
| public function test_should_report_and_deactivate_invalid_plugins() { | ||
| $dir = WP_PLUGIN_DIR . '/' . self::NO_HEADER_DIR; | ||
| $this->assertTrue( mkdir( $dir ), 'The test directory should be created.' ); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| $this->assertNotFalse( file_put_contents( $dir . '/functions.php', "<?php\n// No plugin header.\n" ), 'The file should be written.' ); | ||
|
|
||
| wp_cache_delete( 'plugins', 'plugins' ); | ||
|
|
||
| $no_header = self::NO_HEADER_DIR . '/functions.php'; | ||
| update_option( 'active_plugins', array( 'hello.php', '../outside.php', 'missing/missing.php', $no_header ) ); | ||
|
|
||
| $deactivate = new MockAction(); | ||
| add_action( 'deactivate_plugin', array( $deactivate, 'action' ) ); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| $invalid = validate_active_plugins(); | ||
|
|
||
| $this->assertSame( array( '../outside.php', 'missing/missing.php', $no_header ), array_keys( $invalid ), 'Each invalid plugin should be reported.' ); | ||
| $this->assertSame( | ||
| array( | ||
| '../outside.php' => array( 'plugin_invalid', 'Invalid plugin path.' ), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These messages come from translated |
||
| 'missing/missing.php' => array( 'plugin_not_found', 'Plugin file does not exist.' ), | ||
| $no_header => array( 'no_plugin_header', 'The plugin does not have a valid header.' ), | ||
| ), | ||
| array_map( | ||
| static function ( $error ) { | ||
| return array( $error->get_error_code(), $error->get_error_message() ); | ||
| }, | ||
| $invalid | ||
| ), | ||
| 'Each invalid plugin should have its error.' | ||
| ); | ||
| $this->assertSame( array( 'hello.php' ), array_values( get_option( 'active_plugins' ) ), 'Only the valid plugin should stay active.' ); | ||
| $this->assertSame( 0, $deactivate->get_call_count(), 'Invalid plugins should be deactivated silently.' ); | ||
| } | ||
|
|
||
| /** | ||
| * Tests that network-active plugins are validated for a user who can manage network plugins. | ||
| * | ||
| * @ticket 65819 | ||
| * | ||
| * @group ms-required | ||
| */ | ||
| public function test_should_validate_network_plugins_for_network_admin() { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could a case be added where the same missing plugin is in both |
||
| wp_set_current_user( self::$super_admin_id ); | ||
|
|
||
| update_option( 'active_plugins', array() ); | ||
| update_site_option( | ||
| 'active_sitewide_plugins', | ||
| array( | ||
| 'hello.php' => 1000, | ||
| 'missing/missing.php' => 1000, | ||
| ) | ||
| ); | ||
|
|
||
| $this->assertSame( array( 'missing/missing.php' ), array_keys( validate_active_plugins() ), 'The invalid network plugin should be reported.' ); | ||
| $this->assertSame( array( 'hello.php' => 1000 ), get_site_option( 'active_sitewide_plugins' ), 'The invalid network plugin should be deactivated.' ); | ||
| } | ||
|
|
||
| /** | ||
| * Tests that network-active plugins are not validated for other users. | ||
| * | ||
| * @ticket 65819 | ||
| * | ||
| * @group ms-required | ||
| */ | ||
| public function test_should_not_validate_network_plugins_for_other_users() { | ||
| wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) ); | ||
|
|
||
| update_option( 'active_plugins', array() ); | ||
| update_site_option( 'active_sitewide_plugins', array( 'missing/missing.php' => 1000 ) ); | ||
|
|
||
| $this->assertSame( array(), validate_active_plugins(), 'No plugins should be validated.' ); | ||
| $this->assertSame( array( 'missing/missing.php' => 1000 ), get_site_option( 'active_sitewide_plugins' ), 'The network plugins should not change.' ); | ||
| } | ||
|
|
||
| /** | ||
| * Removes the plugin file without a header, including one left over by an interrupted run. | ||
| */ | ||
| private function remove_plugin() { | ||
| $dir = WP_PLUGIN_DIR . '/' . self::NO_HEADER_DIR; | ||
|
|
||
| if ( is_dir( $dir ) ) { | ||
| $this->rmdir( $dir ); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A raw |
||
| rmdir( $dir ); | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wp_clean_plugins_cache( false )is the core helper for clearing this cache. Using it here, intear_down(), and at line 123 would keep the tests in step if core changes how the plugins cache is stored.