Skip to content

Commit 6f3dff3

Browse files
committed
Tests: Cover drop-in and must-use plugin discovery.
Add coverage for `_get_dropins()`, `get_dropins()`, and `get_mu_plugins()`, including metadata, filtering, fallback names, sorting, and the 30-byte `index.php` threshold. Back up and restore existing drop-ins and must-use plugins to isolate filesystem fixtures. Developed in: #14211 Props noruzzaman. See #65819. git-svn-id: https://develop.svn.wordpress.org/trunk@64325 602fd350-edb4-49c9-b593-d223f7449a82
1 parent 8eb72b9 commit 6f3dff3

2 files changed

Lines changed: 524 additions & 0 deletions

File tree

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
<?php
2+
3+
/**
4+
* Tests for get_dropins() and _get_dropins().
5+
*
6+
* @group admin
7+
* @group plugins
8+
*
9+
* @covers ::get_dropins
10+
* @covers ::_get_dropins
11+
*/
12+
class Tests_Admin_Includes_Plugin_GetDropins extends WP_UnitTestCase {
13+
14+
/**
15+
* Created test files to clean up in tear_down.
16+
*
17+
* @var string[]
18+
*/
19+
private $created_files = array();
20+
21+
/**
22+
* Sets up the environment before any tests in this class run.
23+
*/
24+
public static function wpSetUpBeforeClass() {
25+
self::_back_up_drop_ins();
26+
}
27+
28+
/**
29+
* Restores the environment after all tests in this class have run.
30+
*/
31+
public static function wpTearDownAfterClass() {
32+
self::_restore_drop_ins();
33+
}
34+
35+
/**
36+
* Sets up the environment before each test.
37+
*/
38+
public function set_up() {
39+
parent::set_up();
40+
41+
require_once ABSPATH . 'wp-admin/includes/plugin.php';
42+
}
43+
44+
/**
45+
* Cleans up the environment after each test.
46+
*/
47+
public function tear_down() {
48+
foreach ( $this->created_files as $file ) {
49+
if ( file_exists( $file ) ) {
50+
unlink( $file );
51+
}
52+
}
53+
54+
$this->created_files = array();
55+
56+
wp_cache_delete( 'plugins', 'plugins' );
57+
58+
parent::tear_down();
59+
}
60+
61+
/**
62+
* Helper to create a test drop-in file in WP_CONTENT_DIR.
63+
*
64+
* @param string $filename File name in WP_CONTENT_DIR.
65+
* @param string $content File contents.
66+
* @return string Full path to the created file.
67+
*/
68+
private function create_dropin_file( $filename, $content ) {
69+
$full_path = WP_CONTENT_DIR . '/' . $filename;
70+
71+
$this->assertFileDoesNotExist( $full_path, "Drop-in fixture already exists: {$full_path}" );
72+
73+
$this->assertNotFalse( file_put_contents( $full_path, $content ), "Failed to write drop-in fixture: {$full_path}" );
74+
$this->created_files[] = $full_path;
75+
76+
wp_cache_delete( 'plugins', 'plugins' );
77+
78+
return $full_path;
79+
}
80+
81+
/**
82+
* Tests that _get_dropins() returns expected standard drop-ins.
83+
*
84+
* @ticket 65819
85+
*/
86+
public function test_get_dropins_definitions_contain_standard_dropins() {
87+
$dropins = _get_dropins();
88+
89+
$expected_standard_keys = array(
90+
'advanced-cache.php',
91+
'db.php',
92+
'db-error.php',
93+
'install.php',
94+
'maintenance.php',
95+
'object-cache.php',
96+
'php-error.php',
97+
'fatal-error-handler.php',
98+
);
99+
100+
foreach ( $expected_standard_keys as $key ) {
101+
$this->assertArrayHasKey( $key, $dropins, "Expected drop-in key {$key} not found." );
102+
$this->assertIsArray( $dropins[ $key ], "Drop-in value for {$key} should be an array." );
103+
$this->assertCount( 2, $dropins[ $key ], "Drop-in value for {$key} should contain 2 elements." );
104+
$this->assertIsString( $dropins[ $key ][0], "Description for {$key} should be a string." );
105+
}
106+
107+
$this->assertSame( 'WP_CACHE', $dropins['advanced-cache.php'][1] );
108+
$this->assertTrue( $dropins['db.php'][1] );
109+
$this->assertTrue( $dropins['db-error.php'][1] );
110+
$this->assertTrue( $dropins['install.php'][1] );
111+
$this->assertTrue( $dropins['maintenance.php'][1] );
112+
$this->assertTrue( $dropins['object-cache.php'][1] );
113+
$this->assertTrue( $dropins['php-error.php'][1] );
114+
$this->assertTrue( $dropins['fatal-error-handler.php'][1] );
115+
}
116+
117+
/**
118+
* Tests multisite drop-in definitions in _get_dropins().
119+
*
120+
* @ticket 65819
121+
*/
122+
public function test_get_dropins_definitions_multisite() {
123+
$dropins = _get_dropins();
124+
125+
$multisite_keys = array(
126+
'sunrise.php',
127+
'blog-deleted.php',
128+
'blog-inactive.php',
129+
'blog-suspended.php',
130+
);
131+
132+
if ( is_multisite() ) {
133+
foreach ( $multisite_keys as $key ) {
134+
$this->assertArrayHasKey( $key, $dropins, "Multisite drop-in key {$key} should be defined." );
135+
}
136+
$this->assertSame( 'SUNRISE', $dropins['sunrise.php'][1] );
137+
$this->assertTrue( $dropins['blog-deleted.php'][1] );
138+
$this->assertTrue( $dropins['blog-inactive.php'][1] );
139+
$this->assertTrue( $dropins['blog-suspended.php'][1] );
140+
} else {
141+
foreach ( $multisite_keys as $key ) {
142+
$this->assertArrayNotHasKey( $key, $dropins, "Multisite drop-in key {$key} should not be defined on single site." );
143+
}
144+
}
145+
}
146+
147+
/**
148+
* Tests that get_dropins() detects a valid drop-in file and parses its header metadata.
149+
*
150+
* @ticket 65819
151+
*/
152+
public function test_get_dropins_detects_file_and_extracts_headers() {
153+
$content = "<?php\n/**\n * Plugin Name: Custom Maintenance\n * Description: Drop-in maintenance screen.\n * Version: 2.1.0\n * Author: WordPress Team\n */\n";
154+
$this->create_dropin_file( 'maintenance.php', $content );
155+
156+
$dropins = get_dropins();
157+
158+
$this->assertArrayHasKey( 'maintenance.php', $dropins );
159+
$this->assertSame( 'Custom Maintenance', $dropins['maintenance.php']['Name'] );
160+
$this->assertSame( 'Drop-in maintenance screen.', $dropins['maintenance.php']['Description'] );
161+
$this->assertSame( '2.1.0', $dropins['maintenance.php']['Version'] );
162+
$this->assertSame( 'WordPress Team', $dropins['maintenance.php']['Author'] );
163+
}
164+
165+
/**
166+
* Tests that get_dropins() falls back to using the file name when no Plugin Name header is present.
167+
*
168+
* @ticket 65819
169+
*/
170+
public function test_get_dropins_falls_back_to_filename_when_header_empty() {
171+
$content = "<?php\n// Simple drop-in script with no plugin header comments.\necho 'Database error';\n";
172+
$this->create_dropin_file( 'db-error.php', $content );
173+
174+
$dropins = get_dropins();
175+
176+
$this->assertArrayHasKey( 'db-error.php', $dropins );
177+
$this->assertSame( 'db-error.php', $dropins['db-error.php']['Name'] );
178+
}
179+
180+
/**
181+
* Tests that get_dropins() ignores non-dropin files in WP_CONTENT_DIR.
182+
*
183+
* @ticket 65819
184+
*/
185+
public function test_get_dropins_ignores_non_dropin_files() {
186+
$content = "<?php\n/**\n * Plugin Name: Ignored File\n */\n";
187+
$this->create_dropin_file( 'custom-non-dropin.php', $content );
188+
189+
$dropins = get_dropins();
190+
191+
$this->assertArrayNotHasKey( 'custom-non-dropin.php', $dropins );
192+
}
193+
194+
/**
195+
* Tests that get_dropins() returns items sorted using natural case-insensitive comparison.
196+
*
197+
* @ticket 65819
198+
*/
199+
public function test_get_dropins_sorts_keys_naturally() {
200+
$this->create_dropin_file( 'maintenance.php', "<?php\n/**\n * Plugin Name: Maintenance\n */\n" );
201+
$this->create_dropin_file( 'db-error.php', "<?php\n/**\n * Plugin Name: DB Error\n */\n" );
202+
203+
$dropins = get_dropins();
204+
$keys = array_keys( $dropins );
205+
206+
$db_error_pos = array_search( 'db-error.php', $keys, true );
207+
$maintenance_pos = array_search( 'maintenance.php', $keys, true );
208+
209+
$this->assertNotFalse( $db_error_pos );
210+
$this->assertNotFalse( $maintenance_pos );
211+
$this->assertLessThan( $maintenance_pos, $db_error_pos, 'db-error.php should precede maintenance.php when sorted.' );
212+
}
213+
214+
/**
215+
* Tests that get_dropins() returns an empty array when no drop-ins exist.
216+
*
217+
* @ticket 65819
218+
*/
219+
public function test_get_dropins_when_no_dropins_exist() {
220+
$this->assertSame( array(), get_dropins() );
221+
}
222+
223+
/**
224+
* Moves existing drop-ins to wp-content/drop-ins-backup.
225+
*/
226+
private static function _back_up_drop_ins() {
227+
require_once ABSPATH . 'wp-admin/includes/plugin.php';
228+
229+
$di_bu_dir = WP_CONTENT_DIR . '/drop-ins-backup';
230+
if ( ! is_dir( $di_bu_dir ) ) {
231+
mkdir( $di_bu_dir );
232+
}
233+
234+
foreach ( _get_dropins() as $file_to_move => $v ) {
235+
if ( file_exists( WP_CONTENT_DIR . '/' . $file_to_move ) ) {
236+
rename( WP_CONTENT_DIR . '/' . $file_to_move, $di_bu_dir . '/' . $file_to_move );
237+
}
238+
}
239+
}
240+
241+
/**
242+
* Restores backed-up drop-ins.
243+
*/
244+
private static function _restore_drop_ins() {
245+
require_once ABSPATH . 'wp-admin/includes/plugin.php';
246+
247+
$di_bu_dir = WP_CONTENT_DIR . '/drop-ins-backup';
248+
249+
if ( ! is_dir( $di_bu_dir ) ) {
250+
return;
251+
}
252+
253+
foreach ( _get_dropins() as $file_to_move => $v ) {
254+
if ( file_exists( $di_bu_dir . '/' . $file_to_move ) ) {
255+
if ( file_exists( WP_CONTENT_DIR . '/' . $file_to_move ) ) {
256+
unlink( WP_CONTENT_DIR . '/' . $file_to_move );
257+
}
258+
rename( $di_bu_dir . '/' . $file_to_move, WP_CONTENT_DIR . '/' . $file_to_move );
259+
}
260+
}
261+
262+
if ( is_dir( $di_bu_dir ) ) {
263+
rmdir( $di_bu_dir );
264+
}
265+
}
266+
}

0 commit comments

Comments
 (0)