From 4f5d20b7cdd9c309fc67607166320a9ff470f623 Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Sat, 13 Jun 2026 20:08:03 -0400 Subject: [PATCH] Fix bench component load before dependencies --- examples/bench-dependency/dependency-main.php | 10 ++++++++ examples/bench-plugin/tests/bench/noop.php | 1 + .../src/bench-command-handlers.ts | 24 ++++++++++++++----- scripts/bench-bootstrap-files-smoke.ts | 8 +++++++ scripts/recipe-bench-smoke.ts | 4 +++- 5 files changed, 40 insertions(+), 7 deletions(-) diff --git a/examples/bench-dependency/dependency-main.php b/examples/bench-dependency/dependency-main.php index 7ace56be..4c4df936 100644 --- a/examples/bench-dependency/dependency-main.php +++ b/examples/bench-dependency/dependency-main.php @@ -34,6 +34,16 @@ static function (): void { } ); +register_activation_hook( + __FILE__, + static function (): void { + if ( ! function_exists( 'wp_codebox_bench_plugin_value' ) ) { + wp_die( 'Bench dependency requires the component plugin to be loaded before activation.' ); + } + update_option( 'wp_codebox_bench_dependency_activation_saw_component', 'yes' ); + } +); + function wp_codebox_bench_dependency_value(): int { return WP_Codebox_Bench_Dependency_Fixture::value(); } diff --git a/examples/bench-plugin/tests/bench/noop.php b/examples/bench-plugin/tests/bench/noop.php index 507d25ef..8589714a 100644 --- a/examples/bench-plugin/tests/bench/noop.php +++ b/examples/bench-plugin/tests/bench/noop.php @@ -11,6 +11,7 @@ 'dependency_class_visible' => class_exists( 'WP_Codebox_Bench_Dependency_Fixture' ) ? 1 : 0, 'dependency_active' => is_plugin_active( 'bench-dependency/dependency-main.php' ) ? 1 : 0, 'dependency_active_at_include' => (int) $GLOBALS['wp_codebox_bench_dependency_boot']['active_at_include'], + 'dependency_activation_saw_component' => 'yes' === get_option( 'wp_codebox_bench_dependency_activation_saw_component' ) ? 1 : 0, 'dependency_plugins_loaded_callback_count' => (int) $GLOBALS['wp_codebox_bench_dependency_boot']['plugins_loaded_callbacks'], 'dependency_init_callback_count' => (int) $GLOBALS['wp_codebox_bench_dependency_boot']['init_callbacks'], 'rest_route_visible' => isset( $data['value'] ) && 7 === (int) $data['value'] ? 1 : 0, diff --git a/packages/runtime-playground/src/bench-command-handlers.ts b/packages/runtime-playground/src/bench-command-handlers.ts index 72975654..78c1d249 100644 --- a/packages/runtime-playground/src/bench-command-handlers.ts +++ b/packages/runtime-playground/src/bench-command-handlers.ts @@ -516,21 +516,33 @@ $plugins_to_activate = array_values(array_unique($plugins_to_activate)); foreach ($plugins_to_activate as $plugin_to_activate) { wp_codebox_bench_assert_plugin_autoload_ready($plugin_to_activate); } + +$pre_plugins_loaded_callbacks = wp_codebox_bench_snapshot_wordpress_hook_callbacks('plugins_loaded'); +$pre_init_callbacks = wp_codebox_bench_snapshot_wordpress_hook_callbacks('init'); + +if (!is_plugin_active($plugin_file)) { + $activation = activate_plugin($plugin_file); + if (is_wp_error($activation)) { + throw new RuntimeException('wordpress.bench failed to activate plugin "' . $plugin_file . '". ' . wp_codebox_bench_plugin_load_diagnostic($plugin_file, $plugin_roles[$plugin_file] ?? 'plugin', $activation->get_error_message())); + } + $activated_plugins[] = $plugin_file; +} +wp_codebox_bench_include_plugin_file($plugin_file, $plugin_roles[$plugin_file] ?? 'component'); + foreach ($plugins_to_activate as $plugin_to_activate) { + if ($plugin_to_activate === $plugin_file) { + continue; + } if (is_plugin_active($plugin_to_activate)) { + wp_codebox_bench_include_plugin_file($plugin_to_activate, $plugin_roles[$plugin_to_activate] ?? 'plugin'); continue; } $activation = activate_plugin($plugin_to_activate); if (is_wp_error($activation)) { throw new RuntimeException('wordpress.bench failed to activate plugin "' . $plugin_to_activate . '". ' . wp_codebox_bench_plugin_load_diagnostic($plugin_to_activate, $plugin_roles[$plugin_to_activate] ?? 'plugin', $activation->get_error_message())); } - $activated_plugins[] = $plugin_to_activate; -} - -$pre_plugins_loaded_callbacks = wp_codebox_bench_snapshot_wordpress_hook_callbacks('plugins_loaded'); -$pre_init_callbacks = wp_codebox_bench_snapshot_wordpress_hook_callbacks('init'); -foreach ($plugins_to_activate as $plugin_to_activate) { wp_codebox_bench_include_plugin_file($plugin_to_activate, $plugin_roles[$plugin_to_activate] ?? 'plugin'); + $activated_plugins[] = $plugin_to_activate; } $loaded_bootstrap_file = ''; foreach (is_array($bootstrap_files) ? $bootstrap_files : array() as $bootstrap_file) { diff --git a/scripts/bench-bootstrap-files-smoke.ts b/scripts/bench-bootstrap-files-smoke.ts index 48f2967b..6c1d2c63 100644 --- a/scripts/bench-bootstrap-files-smoke.ts +++ b/scripts/bench-bootstrap-files-smoke.ts @@ -42,5 +42,13 @@ assert.ok( code.indexOf("require_once $bootstrap_path") < code.indexOf("wp_codebox_bench_run_deferred_wordpress_hook_callbacks($deferred_plugins_loaded_callbacks"), "bootstrap files should load before synthetic plugins_loaded/init hooks" ) +assert.ok( + code.indexOf("wp_codebox_bench_include_plugin_file($plugin_file") < code.indexOf("if ($plugin_to_activate === $plugin_file)"), + "the component plugin should be included before dependency activation" +) +assert.ok( + code.indexOf("$pre_plugins_loaded_callbacks = wp_codebox_bench_snapshot_wordpress_hook_callbacks('plugins_loaded')") < code.indexOf("wp_codebox_bench_include_plugin_file($plugin_file"), + "hook snapshots should still capture callbacks registered by component loading" +) console.log("Bench bootstrap files smoke passed") diff --git a/scripts/recipe-bench-smoke.ts b/scripts/recipe-bench-smoke.ts index 9c5baa1a..f7270e58 100644 --- a/scripts/recipe-bench-smoke.ts +++ b/scripts/recipe-bench-smoke.ts @@ -35,6 +35,7 @@ writeFileSync(recipePath, `${JSON.stringify({ source: dependency, slug: "bench-dependency", pluginFile: "bench-dependency/dependency-main.php", + activate: false, }, ], }, @@ -128,7 +129,8 @@ assert.equal(scenario.metrics.init_callback_count.samples.mean, 1) assert.equal(scenario.metrics.dependency_value.samples.mean, 11) assert.equal(scenario.metrics.dependency_class_visible.samples.mean, 1) assert.equal(scenario.metrics.dependency_active.samples.mean, 1) -assert.equal(scenario.metrics.dependency_active_at_include.samples.mean, 1) +assert.equal(scenario.metrics.dependency_active_at_include.samples.mean, 0) +assert.equal(scenario.metrics.dependency_activation_saw_component.samples.mean, 1) assert.equal(scenario.metrics.dependency_plugins_loaded_callback_count.samples.mean, 1) assert.equal(scenario.metrics.dependency_init_callback_count.samples.mean, 1) assert.equal(scenario.metrics.duration.samples.values.length, 2)