@@ -30,6 +30,8 @@ export interface PhpunitRunCodeOptions {
3030 resultFile ?: string
3131}
3232
33+ export type PhpunitMultisitePreinstallCodeOptions = Pick < PhpunitRunCodeOptions , "testsDir" | "env" | "wpConfigDefines" | "databaseType" | "resultFile" >
34+
3335export interface CorePhpunitRunCodeOptions {
3436 coreRoot : string
3537 testsDir : string
@@ -334,6 +336,101 @@ function ${functionName}(array $argv) {
334336}`
335337}
336338
339+ function managedPhpunitConfigWriterPhp ( ) : string {
340+ return `function pg_write_managed_test_config(array $extra_defines, string $table_prefix, string $database_type): string {
341+ $config_path = '/tmp/wp-tests-config.php';
342+ $config = "<?php\n";
343+ pg_append_wp_config_defines($config, $extra_defines);
344+ $config .= '$table_prefix = ' . var_export($table_prefix, true) . ";\n";
345+ if ($database_type === 'mysql') {
346+ $db_host = getenv('DB_HOST');
347+ if (!is_string($db_host) || $db_host === '') {
348+ throw new RuntimeException('Managed PHPUnit requires DB_HOST when database-type=mysql; declare a MySQL runtime service with canonical DB_* outputs.');
349+ }
350+ $db_port = getenv('DB_PORT');
351+ if (is_string($db_port) && $db_port !== '') {
352+ $db_host .= ':' . $db_port;
353+ }
354+ foreach (array(
355+ 'DB_NAME' => getenv('DB_NAME') ?: 'runtime',
356+ 'DB_USER' => getenv('DB_USER') ?: 'runtime',
357+ 'DB_PASSWORD' => getenv('DB_PASSWORD') ?: '',
358+ 'DB_HOST' => $db_host,
359+ ) as $name => $value) {
360+ $config .= 'define(' . var_export($name, true) . ', ' . var_export($value, true) . ");\n";
361+ }
362+ } else {
363+ $config .= <<<'CONFIG'
364+ define('DB_NAME', ':memory:');
365+ define('DB_USER', 'root');
366+ define('DB_PASSWORD', '');
367+ define('DB_HOST', 'localhost');
368+ CONFIG;
369+ }
370+ $config .= <<<'CONFIG'
371+ define('DB_CHARSET', 'utf8');
372+ define('WP_TESTS_DOMAIN', 'example.org');
373+ define('WP_TESTS_EMAIL', 'admin@example.org');
374+ define('WP_TESTS_TITLE', 'Test Blog');
375+ define('WP_PHP_BINARY', 'php');
376+ define('ABSPATH', '/wordpress/');
377+ define('FS_CHMOD_FILE', 0644);
378+ define('FS_CHMOD_DIR', 0755);
379+ define('FS_METHOD', 'direct');
380+ CONFIG;
381+ file_put_contents($config_path, $config);
382+ return $config_path;
383+ }`
384+ }
385+
386+ export function phpunitMultisitePreinstallCode ( options : PhpunitMultisitePreinstallCodeOptions ) : string {
387+ const wpConfigDefines = { ...options . wpConfigDefines }
388+ for ( const name of [ "MULTISITE" , "SUBDOMAIN_INSTALL" , "DOMAIN_CURRENT_SITE" , "PATH_CURRENT_SITE" , "SITE_ID_CURRENT_SITE" , "BLOG_ID_CURRENT_SITE" ] ) {
389+ delete wpConfigDefines [ name ]
390+ }
391+ return `error_reporting(E_ALL);
392+ ini_set('display_errors', '1');
393+ ini_set('display_startup_errors', '1');
394+
395+ $tests_dir = ${ JSON . stringify ( options . testsDir ) } ;
396+ $bench_env = json_decode(${ JSON . stringify ( JSON . stringify ( options . env ) ) } , true);
397+ $wp_config_defines = json_decode(${ JSON . stringify ( JSON . stringify ( wpConfigDefines ) ) } , true);
398+ $database_type = ${ JSON . stringify ( options . databaseType ) } ;
399+ $result_file = ${ JSON . stringify ( options . resultFile ?? PLUGIN_PHPUNIT_RESULT_FILE ) } ;
400+ $preinstall_complete = false;
401+
402+ @file_put_contents($result_file, '');
403+ register_shutdown_function(static function () use (&$preinstall_complete, $result_file): void {
404+ if ($preinstall_complete) {
405+ return;
406+ }
407+ $failure = error_get_last();
408+ if (is_array($failure) && in_array($failure['type'] ?? 0, array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR), true)) {
409+ @file_put_contents($result_file, 'STAGE_FATAL:preinstall:' . (string) ($failure['message'] ?? '') . ' at ' . (string) ($failure['file'] ?? '') . ':' . (int) ($failure['line'] ?? 0) . "\n", FILE_APPEND);
410+ }
411+ });
412+
413+ ${ phpEnvAssignmentFunction ( "pg_apply_env" , "json_encode" , "error_log('Skipping invalid environment key: ' . var_export($name, true));" ) }
414+ ${ phpWpConfigDefineAppenderFunction ( "pg_append_wp_config_defines" , "error_log('Skipping invalid wp_config_defines key: ' . var_export($name, true));" ) }
415+ ${ managedPhpunitConfigWriterPhp ( ) }
416+
417+ pg_apply_env($bench_env);
418+ $config_path = pg_write_managed_test_config($wp_config_defines, 'wptests_', $database_type);
419+ if (!defined('WP_TESTS_MULTISITE')) {
420+ define('WP_TESTS_MULTISITE', true);
421+ }
422+ $argv = array('install.php', $config_path, 'run_ms_tests', 'no_core_tests');
423+ $_SERVER['argv'] = $argv;
424+ $_SERVER['argc'] = count($argv);
425+ try {
426+ require $tests_dir . '/includes/install.php';
427+ $preinstall_complete = true;
428+ } catch (Throwable $error) {
429+ @file_put_contents($result_file, 'STAGE_FAIL:preinstall:' . get_class($error) . ': ' . $error->getMessage() . ' at ' . $error->getFile() . ':' . $error->getLine() . "\n", FILE_APPEND);
430+ throw $error;
431+ }`
432+ }
433+
337434export function phpunitRunCode ( options : PhpunitRunCodeOptions ) : string {
338435 return `error_reporting(E_ALL);
339436ini_set('display_errors', '1');
@@ -415,6 +512,8 @@ ${phpEnvAssignmentFunction("pg_apply_env", "json_encode", "pg_log('NOTICE: skipp
415512
416513${ phpWpConfigDefineAppenderFunction ( "pg_append_wp_config_defines" , "pg_log('NOTICE: skipping invalid wp_config_defines key: ' . var_export($name, true));" ) }
417514
515+ ${ managedPhpunitConfigWriterPhp ( ) }
516+
418517function pg_diagnostic_context(): string {
419518 global $current_stage;
420519 $hook = function_exists('current_filter') ? current_filter() : null;
@@ -661,48 +760,8 @@ function pg_run_boot_stage(array $cfg = []): ?string {
661760 $autoload_required = !empty($cfg['autoload_required']);
662761 $extra_defines = $cfg['extra_defines'] ?? array();
663762 $table_prefix = isset($cfg['table_prefix']) && is_string($cfg['table_prefix']) && $cfg['table_prefix'] !== '' ? $cfg['table_prefix'] : 'wptests_';
664- $config_path = '/tmp/wp-tests-config.php';
665- $config = "<?php\n";
666- pg_append_wp_config_defines($config, $extra_defines);
667- $config .= '$table_prefix = ' . var_export($table_prefix, true) . ";\n";
668763 $database_type = (string) ($cfg['database_type'] ?? 'sqlite');
669- if ($database_type === 'mysql') {
670- $db_host = getenv('DB_HOST');
671- if (!is_string($db_host) || $db_host === '') {
672- throw new RuntimeException('Managed PHPUnit requires DB_HOST when database-type=mysql; declare a MySQL runtime service with canonical DB_* outputs.');
673- }
674- $db_port = getenv('DB_PORT');
675- if (is_string($db_port) && $db_port !== '') {
676- $db_host .= ':' . $db_port;
677- }
678- foreach (array(
679- 'DB_NAME' => getenv('DB_NAME') ?: 'runtime',
680- 'DB_USER' => getenv('DB_USER') ?: 'runtime',
681- 'DB_PASSWORD' => getenv('DB_PASSWORD') ?: '',
682- 'DB_HOST' => $db_host,
683- ) as $name => $value) {
684- $config .= 'define(' . var_export($name, true) . ', ' . var_export($value, true) . ");\n";
685- }
686- } else {
687- $config .= <<<'CONFIG'
688- define('DB_NAME', ':memory:');
689- define('DB_USER', 'root');
690- define('DB_PASSWORD', '');
691- define('DB_HOST', 'localhost');
692- CONFIG;
693- }
694- $config .= <<<'CONFIG'
695- define('DB_CHARSET', 'utf8');
696- define('WP_TESTS_DOMAIN', 'example.org');
697- define('WP_TESTS_EMAIL', 'admin@example.org');
698- define('WP_TESTS_TITLE', 'Test Blog');
699- define('WP_PHP_BINARY', 'php');
700- define('ABSPATH', '/wordpress/');
701- define('FS_CHMOD_FILE', 0644);
702- define('FS_CHMOD_DIR', 0755);
703- define('FS_METHOD', 'direct');
704- CONFIG;
705- file_put_contents($config_path, $config);
764+ $config_path = pg_write_managed_test_config($extra_defines, $table_prefix, $database_type);
706765 if ($harness_autoload !== '' && is_readable($harness_autoload)) {
707766 pg_preload_wp_cli_namespaced_functions($harness_autoload);
708767 require_once $harness_autoload;
0 commit comments