Skip to content

Commit 6c1131d

Browse files
committed
fix: provision multisite PHPUnit runtimes
1 parent f8a3f3b commit 6c1131d

4 files changed

Lines changed: 49 additions & 4 deletions

File tree

packages/runtime-core/src/recipe-builders.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { WorkspaceRecipe, WorkspaceRecipeExtraPlugin, WorkspaceRecipeMount, WorkspaceRecipePHPWasmExtensionManifest, WorkspaceRecipeRuntimeBackendPackage, WorkspaceRecipeRuntimeService, WorkspaceRecipeStep } from "./runtime-contracts.js"
1+
import type { RuntimePreviewSpec, WorkspaceRecipe, WorkspaceRecipeExtraPlugin, WorkspaceRecipeMount, WorkspaceRecipePHPWasmExtensionManifest, WorkspaceRecipeRuntimeBackendPackage, WorkspaceRecipeRuntimeService, WorkspaceRecipeStep } from "./runtime-contracts.js"
22
import { commandArg, commandJsonArg, commandStringListArg } from "./command-codecs.js"
33
export { buildRuntimePackageRunRecipe, CODEBOX_RUN_RUNTIME_PACKAGE_ABILITY, RUNTIME_PACKAGE_ARTIFACT_DECLARATION_SCHEMA, RUNTIME_PACKAGE_EXECUTION_INPUT_SCHEMA, RUNTIME_PACKAGE_EXECUTION_RESULT_SCHEMA, RUNTIME_PACKAGE_OUTPUT_PROJECTION_SCHEMA, runtimePackageExecutionInput, type RuntimePackageArtifactDeclaration, type RuntimePackageExecutionInput, type RuntimePackageOutputProjection, type RuntimePackageRunRecipeOptions } from "./runtime-package-execution.js"
44
export { RUNTIME_PACKAGE_DIAGNOSTIC_SCHEMA, RUNTIME_PACKAGE_RESULT_SCHEMA, RUNTIME_PACKAGE_TASK_SCHEMA, normalizeRuntimePackageResult, normalizeRuntimePackageTask, validateRuntimePackageTask, type RuntimePackageDiagnostic, type RuntimePackageResult, type RuntimePackageTask } from "./runtime-package-contracts.js"
@@ -17,6 +17,7 @@ export interface WordPressPhpunitRecipeOptions {
1717
blueprint?: unknown
1818
extensions?: WorkspaceRecipePHPWasmExtensionManifest[]
1919
backendPackage?: WorkspaceRecipeRuntimeBackendPackage
20+
preview?: RuntimePreviewSpec
2021
mounts?: WorkspaceRecipeMount[]
2122
services?: WorkspaceRecipeRuntimeService[]
2223
extra_plugins?: WorkspaceRecipeExtraPlugin[]
@@ -77,7 +78,8 @@ export function buildWordPressPhpunitRecipe(options: WordPressPhpunitRecipeOptio
7778
runtime: {
7879
wp: options.wordpressVersion ?? DEFAULT_WORDPRESS_VERSION,
7980
...(options.phpVersion ? { phpVersion: options.phpVersion } : {}),
80-
blueprint: options.blueprint ?? { steps: [] },
81+
blueprint: blueprintWithMultisite(options.blueprint ?? { steps: [] }, options.multisite ?? false),
82+
...(options.preview || options.multisite ? { preview: multisitePreview(options.preview, options.multisite ?? false) } : {}),
8183
...(options.extensions?.length ? { extensions: options.extensions } : {}),
8284
...(options.backendPackage ? { backendPackage: options.backendPackage } : {}),
8385
},
@@ -226,6 +228,35 @@ function blueprintWithWpConfigDefines(blueprint: unknown, defines: JsonObject):
226228
}
227229
}
228230

231+
function blueprintWithMultisite(blueprint: unknown, multisite: boolean): unknown {
232+
if (!multisite) {
233+
return blueprint
234+
}
235+
236+
if (!isPlainObject(blueprint)) {
237+
return { steps: [{ step: "enableMultisite" }] }
238+
}
239+
240+
const existingSteps = Array.isArray(blueprint.steps) ? blueprint.steps : []
241+
if (existingSteps.some((step) => isPlainObject(step) && step.step === "enableMultisite")) {
242+
return blueprint
243+
}
244+
return {
245+
...blueprint,
246+
steps: [{ step: "enableMultisite" }, ...existingSteps],
247+
}
248+
}
249+
250+
function multisitePreview(preview: RuntimePreviewSpec | undefined, multisite: boolean): RuntimePreviewSpec {
251+
if (!multisite || preview?.siteUrl) {
252+
return preview ?? {}
253+
}
254+
return {
255+
...preview,
256+
siteUrl: "http://localhost",
257+
}
258+
}
259+
229260
function requiredPluginSlug(value: string, caller: string): string {
230261
const slug = value.trim()
231262
if (!slug) {

packages/runtime-playground/src/phpunit-command-handlers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -896,7 +896,7 @@ function pg_ensure_phpunit_harness_loaded(): void {
896896
}
897897
898898
function pg_run_install_stage(array $cfg) {
899-
global $argv, $pg_stage_output_buffering;
899+
global $argv, $pg_stage_output_buffering, $wp_rewrite;
900900
pg_stage_begin('install');
901901
try {
902902
$tests_dir = $cfg['tests_dir'];

tests/phpunit-project-autoload.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,7 @@ const managedModeCode = phpunitRunCode({
410410

411411
assert.ok(managedModeCode.includes("configured PHPUnit harness autoload file is not readable"))
412412
assert.ok(managedModeCode.includes("'cacheResult' => false"))
413+
assert.ok(managedModeCode.includes("global $argv, $pg_stage_output_buffering, $wp_rewrite;"), "managed WordPress installation must expose the rewrite global required by multisite setup")
413414
assert.ok(managedModeCode.includes('$dep_mounts = "/wordpress/wp-content/plugins/demo-plugin\\n/wordpress/wp-content/plugins/dependency";'), "dependency mounts must be newline-delimited for the generated PHP runner")
414415
const installStageIndex = managedModeCode.indexOf("pg_run_install_stage(array(")
415416
const dependencyLoadStageIndex = managedModeCode.indexOf("$loaded_dep_files = pg_run_load_deps_stage", installStageIndex)
@@ -442,6 +443,18 @@ assert.deepEqual(dependencyRecipe.inputs.extra_plugins, [{
442443
}])
443444
assert.ok(dependencyRecipe.workflow.steps[0].args.includes("dependency-mounts=/wordpress/wp-content/plugins/dependency"))
444445

446+
const multisiteRecipe = buildWordPressPhpunitRecipe({
447+
pluginSlug: "network-plugin",
448+
multisite: true,
449+
blueprint: { steps: [{ step: "setSiteOptions", options: { blogname: "Network tests" } }] },
450+
})
451+
assert.deepEqual((multisiteRecipe.runtime.blueprint as { steps: unknown[] }).steps, [
452+
{ step: "enableMultisite" },
453+
{ step: "setSiteOptions", options: { blogname: "Network tests" } },
454+
], "multisite PHPUnit recipes must boot Playground as multisite before running tests")
455+
assert.equal(multisiteRecipe.runtime.preview?.siteUrl, "http://localhost", "multisite PHPUnit recipes need a canonical site URL without the dynamic Playground port")
456+
assert.ok(multisiteRecipe.workflow.steps[0].args.includes("multisite=1"))
457+
445458
const phpunitCacheAllocator = extractPhpFunction(managedModeCode, "wp_codebox_phpunit_args_private_cache_result_file")
446459
const phpunitArgsFunction = extractPhpFunction(managedModeCode, "wp_codebox_phpunit_args")
447460
const phpunitArgsProbe = join(mkdtempSync(join(tmpdir(), "wp-codebox-phpunit-cache-args-")), "probe.php")

tests/playground-phpunit-readonly-cache.integration.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ try {
2525

2626
const recipe = buildWordPressPhpunitRecipe({
2727
pluginSlug: "readonly-phpunit-fixture",
28+
multisite: true,
2829
extra_plugins: [{
2930
source: plugin,
3031
slug: "readonly-phpunit-fixture",
@@ -62,7 +63,7 @@ async function writeFixture(): Promise<void> {
6263
await mkdir(dependency, { recursive: true })
6364
await writeFile(join(plugin, "readonly-phpunit-fixture.php"), "<?php\n/**\n * Plugin Name: Readonly PHPUnit Fixture\n */\n")
6465
await writeFile(join(plugin, "source-sentinel.bin"), sentinel)
65-
await writeFile(join(plugin, "tests", "ReadonlyCacheTest.php"), "<?php\nclass ReadonlyCacheTest extends WP_UnitTestCase { public function test_sentinel_is_available(): void { $this->assertGreaterThan(0, filesize(dirname(__DIR__) . \'/source-sentinel.bin\')); } public function test_dependency_activation_runs_after_install(): void { $this->assertGreaterThanOrEqual(1, get_option(\'wp_codebox_dependency_activation_users\')); } public function test_dependency_plugins_loaded_runs_once(): void { $this->assertSame(1, (int) get_option(\'wp_codebox_dependency_plugins_loaded_count\')); } }\n")
66+
await writeFile(join(plugin, "tests", "ReadonlyCacheTest.php"), "<?php\nclass ReadonlyCacheTest extends WP_UnitTestCase { public function test_multisite_runtime_is_active(): void { $this->assertTrue(is_multisite()); } public function test_sentinel_is_available(): void { $this->assertGreaterThan(0, filesize(dirname(__DIR__) . \'/source-sentinel.bin\')); } public function test_dependency_activation_runs_after_install(): void { $this->assertGreaterThanOrEqual(1, get_option(\'wp_codebox_dependency_activation_users\')); } public function test_dependency_plugins_loaded_runs_once(): void { $this->assertSame(1, (int) get_option(\'wp_codebox_dependency_plugins_loaded_count\')); } }\n")
6667
await writeFile(join(dependency, "activation-dependency.php"), "<?php\n/**\n * Plugin Name: Activation Dependency\n */\nadd_action('plugins_loaded', static function (): void { update_option('wp_codebox_dependency_plugins_loaded_count', (int) get_option('wp_codebox_dependency_plugins_loaded_count', 0) + 1); });\nregister_activation_hook(__FILE__, static function (): void { update_option('wp_codebox_dependency_activation_users', count(get_users(array('number' => 1)))); });\n")
6768
}
6869

0 commit comments

Comments
 (0)