From da9baa998f9d1d141a930d71ada5b54f72a40b12 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 19:29:29 +0000 Subject: [PATCH 01/13] Initial plan From 6da51c53950539c51a640f9619c8ae92e86cb4d6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 19:36:21 +0000 Subject: [PATCH 02/13] Fix duplicate /sites/{blog_id} in upload paths Remove manual addition of /sites/{blog_id} suffix that WordPress core already handles automatically, preventing duplication like /uploads/sites/136/sites/136/ Co-authored-by: JJJ <88951+JJJ@users.noreply.github.com> --- wp-multi-network/includes/functions.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/wp-multi-network/includes/functions.php b/wp-multi-network/includes/functions.php index f8cd9ae..1c3d9e0 100644 --- a/wp-multi-network/includes/functions.php +++ b/wp-multi-network/includes/functions.php @@ -622,15 +622,6 @@ function add_network( $args = array() ) { } $upload_dir .= '/uploads'; - if ( defined( 'MULTISITE' ) ) { - $ms_dir = '/sites/' . $new_blog_id; - } else { - $ms_dir = '/' . $new_blog_id; - } - - $upload_dir .= $ms_dir; - $upload_url .= $ms_dir; - update_blog_option( $new_blog_id, 'upload_path', $upload_dir ); update_blog_option( $new_blog_id, 'upload_url_path', $upload_url ); } From 78da09e423421483d299763904573f752f5f3914 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 19:38:47 +0000 Subject: [PATCH 03/13] Update comment to correctly reflect WordPress version requirement Fix misleading comment that said 'WP < 3.7' when the code actually handles WordPress > 3.7 Co-authored-by: JJJ <88951+JJJ@users.noreply.github.com> --- wp-multi-network/includes/functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wp-multi-network/includes/functions.php b/wp-multi-network/includes/functions.php index 1c3d9e0..634cc3c 100644 --- a/wp-multi-network/includes/functions.php +++ b/wp-multi-network/includes/functions.php @@ -600,7 +600,7 @@ function add_network( $args = array() ) { update_network_option( $new_network_id, $key, $value ); } - // Fix upload path and URLs in WP < 3.7. + // Fix upload path and URLs for WordPress > 3.7. $use_files_rewriting = defined( 'SITE_ID_CURRENT_SITE' ) && get_network( SITE_ID_CURRENT_SITE ) ? get_network_option( SITE_ID_CURRENT_SITE, 'ms_files_rewriting' ) : get_site_option( 'ms_files_rewriting' ); From 13b4dc3bf49e9e033659b73348ee96d30f475c7b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 19:48:47 +0000 Subject: [PATCH 04/13] Check for existing site path before appending to prevent duplication Instead of blindly appending /sites/{blog_id}, check if wpmu_create_blog() already set it in upload_path to avoid duplication like /uploads/sites/136/sites/136/ Co-authored-by: JJJ <88951+JJJ@users.noreply.github.com> --- wp-multi-network/includes/functions.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/wp-multi-network/includes/functions.php b/wp-multi-network/includes/functions.php index 634cc3c..98cccae 100644 --- a/wp-multi-network/includes/functions.php +++ b/wp-multi-network/includes/functions.php @@ -600,7 +600,7 @@ function add_network( $args = array() ) { update_network_option( $new_network_id, $key, $value ); } - // Fix upload path and URLs for WordPress > 3.7. + // Fix upload path and URLs in WP < 3.7. $use_files_rewriting = defined( 'SITE_ID_CURRENT_SITE' ) && get_network( SITE_ID_CURRENT_SITE ) ? get_network_option( SITE_ID_CURRENT_SITE, 'ms_files_rewriting' ) : get_site_option( 'ms_files_rewriting' ); @@ -622,6 +622,16 @@ function add_network( $args = array() ) { } $upload_dir .= '/uploads'; + // Check if wpmu_create_blog() already set the site-specific path. + $existing_upload_path = get_blog_option( $new_blog_id, 'upload_path' ); + $site_path_suffix = defined( 'MULTISITE' ) ? '/sites/' . $new_blog_id : '/' . $new_blog_id; + + // Only add the site-specific path if it's not already present. + if ( empty( $existing_upload_path ) || false === strpos( $existing_upload_path, $site_path_suffix ) ) { + $upload_dir .= $site_path_suffix; + $upload_url .= $site_path_suffix; + } + update_blog_option( $new_blog_id, 'upload_path', $upload_dir ); update_blog_option( $new_blog_id, 'upload_url_path', $upload_url ); } From 13cbf4c3a21c6e49f548a893eb90774325f1ef9a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 21:16:16 +0000 Subject: [PATCH 05/13] Fix logic error: only update upload_path when adding suffix Move update_blog_option() calls inside conditional to prevent overwriting correct paths already set by wpmu_create_blog() with incomplete paths Co-authored-by: JJJ <88951+JJJ@users.noreply.github.com> --- wp-multi-network/includes/functions.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/wp-multi-network/includes/functions.php b/wp-multi-network/includes/functions.php index 98cccae..70c4766 100644 --- a/wp-multi-network/includes/functions.php +++ b/wp-multi-network/includes/functions.php @@ -630,10 +630,9 @@ function add_network( $args = array() ) { if ( empty( $existing_upload_path ) || false === strpos( $existing_upload_path, $site_path_suffix ) ) { $upload_dir .= $site_path_suffix; $upload_url .= $site_path_suffix; + update_blog_option( $new_blog_id, 'upload_path', $upload_dir ); + update_blog_option( $new_blog_id, 'upload_url_path', $upload_url ); } - - update_blog_option( $new_blog_id, 'upload_path', $upload_dir ); - update_blog_option( $new_blog_id, 'upload_url_path', $upload_url ); } // Clone network meta from existing network. From e9871f46cbdaa39c61dd9c8ef3609a874019d554 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 21:25:48 +0000 Subject: [PATCH 06/13] Add unit tests for upload path handling Add comprehensive tests to verify upload paths are set correctly: - Test without duplication in standard scenarios - Test with ms_files_rewriting enabled/disabled - Test multisite configuration - Test path structure and preservation - Verify no duplicate /sites/{blog_id} segments Co-authored-by: JJJ <88951+JJJ@users.noreply.github.com> --- tests/integration/tests/test-upload-paths.php | 232 ++++++++++++++++++ 1 file changed, 232 insertions(+) create mode 100644 tests/integration/tests/test-upload-paths.php diff --git a/tests/integration/tests/test-upload-paths.php b/tests/integration/tests/test-upload-paths.php new file mode 100644 index 0000000..68df776 --- /dev/null +++ b/tests/integration/tests/test-upload-paths.php @@ -0,0 +1,232 @@ + 'example.org', + 'path' => '/', + 'site_name' => 'Test Network', + 'network_name' => 'Test Network', + ) + ); + + $this->assertNotWPError( $network_id, 'Network should be created successfully' ); + + // Get the main site for the network. + $main_site_id = get_main_site_for_network( $network_id ); + $this->assertNotEmpty( $main_site_id, 'Main site should exist for the network' ); + + // Get the upload path. + $upload_path = get_blog_option( $main_site_id, 'upload_path' ); + + // Check that the path doesn't contain duplicate site-specific directories. + $site_suffix = '/sites/' . $main_site_id; + $count = substr_count( $upload_path, $site_suffix ); + + $this->assertLessThanOrEqual( 1, $count, 'Upload path should not contain duplicate site-specific directories' ); + + // If the path contains the suffix, it should only appear once. + if ( false !== strpos( $upload_path, $site_suffix ) ) { + $this->assertEquals( 1, $count, 'Site-specific directory should appear exactly once in upload path' ); + } + } + + /** + * Test upload path when ms_files_rewriting is enabled. + */ + public function test_upload_path_with_files_rewriting() { + // Enable files rewriting. + update_site_option( 'ms_files_rewriting', 1 ); + + // Create a new network. + $network_id = add_network( + array( + 'domain' => 'example.net', + 'path' => '/', + 'site_name' => 'Test Network with Rewriting', + 'network_name' => 'Test Network with Rewriting', + ) + ); + + $this->assertNotWPError( $network_id, 'Network should be created successfully with files rewriting' ); + + // Get the main site for the network. + $main_site_id = get_main_site_for_network( $network_id ); + $this->assertNotEmpty( $main_site_id, 'Main site should exist for the network' ); + + // With files rewriting enabled, the upload path may not be set or may be empty. + $upload_path = get_blog_option( $main_site_id, 'upload_path' ); + + // The behavior with files rewriting may vary, but it should not contain duplicates. + if ( ! empty( $upload_path ) ) { + $site_suffix = '/sites/' . $main_site_id; + $count = substr_count( $upload_path, $site_suffix ); + $this->assertLessThanOrEqual( 1, $count, 'Upload path should not contain duplicate site-specific directories with files rewriting' ); + } + + // Clean up. + update_site_option( 'ms_files_rewriting', 0 ); + } + + /** + * Test upload path in multisite environment. + */ + public function test_upload_path_multisite() { + // Verify we're in a multisite environment. + $this->assertTrue( is_multisite(), 'Tests should run in multisite environment' ); + + // Create a new network. + $network_id = add_network( + array( + 'domain' => 'multisite.test', + 'path' => '/', + 'site_name' => 'Multisite Test', + 'network_name' => 'Multisite Test', + ) + ); + + $this->assertNotWPError( $network_id, 'Network should be created in multisite environment' ); + + // Get the main site for the network. + $main_site_id = get_main_site_for_network( $network_id ); + $this->assertNotEmpty( $main_site_id, 'Main site should exist' ); + + // Get the upload path. + $upload_path = get_blog_option( $main_site_id, 'upload_path' ); + + // In multisite, the path should use /sites/ prefix if present. + if ( ! empty( $upload_path ) && false !== strpos( $upload_path, '/sites/' ) ) { + $this->assertStringContainsString( '/sites/' . $main_site_id, $upload_path, 'Upload path should contain /sites/{blog_id} format in multisite' ); + + // Ensure no duplication. + $count = substr_count( $upload_path, '/sites/' . $main_site_id ); + $this->assertEquals( 1, $count, 'Site-specific path should appear exactly once' ); + } + } + + /** + * Test that upload_path is set correctly without files rewriting. + */ + public function test_upload_path_without_files_rewriting() { + // Ensure files rewriting is disabled. + update_site_option( 'ms_files_rewriting', 0 ); + + // Create a new network. + $network_id = add_network( + array( + 'domain' => 'no-rewrite.test', + 'path' => '/', + 'site_name' => 'No Rewrite Test', + 'network_name' => 'No Rewrite Test', + ) + ); + + $this->assertNotWPError( $network_id, 'Network should be created without files rewriting' ); + + // Get the main site for the network. + $main_site_id = get_main_site_for_network( $network_id ); + $this->assertNotEmpty( $main_site_id, 'Main site should exist' ); + + // Get the upload path and URL. + $upload_path = get_blog_option( $main_site_id, 'upload_path' ); + $upload_url_path = get_blog_option( $main_site_id, 'upload_url_path' ); + + // Without files rewriting in WordPress > 3.7, paths should be set. + global $wp_version; + if ( version_compare( $wp_version, '3.7', '>' ) ) { + $this->assertNotEmpty( $upload_path, 'Upload path should be set without files rewriting in WP > 3.7' ); + + // Check for proper path structure. + $this->assertStringContainsString( '/uploads', $upload_path, 'Upload path should contain /uploads' ); + + // Verify no duplication of site-specific path. + if ( defined( 'MULTISITE' ) && MULTISITE ) { + $site_suffix = '/sites/' . $main_site_id; + if ( false !== strpos( $upload_path, $site_suffix ) ) { + $count = substr_count( $upload_path, $site_suffix ); + $this->assertEquals( 1, $count, 'Site-specific directory should not be duplicated' ); + } + } + } + } + + /** + * Test upload path structure for consistency. + */ + public function test_upload_path_structure() { + // Create a new network. + $network_id = add_network( + array( + 'domain' => 'structure.test', + 'path' => '/', + 'site_name' => 'Structure Test', + 'network_name' => 'Structure Test', + ) + ); + + $this->assertNotWPError( $network_id, 'Network should be created successfully' ); + + // Get the main site for the network. + $main_site_id = get_main_site_for_network( $network_id ); + $upload_path = get_blog_option( $main_site_id, 'upload_path' ); + + if ( ! empty( $upload_path ) ) { + // Path should not have consecutive slashes (except in protocol). + $path_without_protocol = preg_replace( '#^[a-z]+://#', '', $upload_path ); + $this->assertStringNotContainsString( '//', $path_without_protocol, 'Upload path should not contain consecutive slashes' ); + + // Path should not end with a slash. + $this->assertStringEndsNotWith( '/', $upload_path, 'Upload path should not end with a slash' ); + + // If it contains /sites/, it should be followed by a number. + if ( false !== strpos( $upload_path, '/sites/' ) ) { + $this->assertMatchesRegularExpression( '#/sites/\d+#', $upload_path, 'Sites path should be followed by a numeric blog ID' ); + } + } + } + + /** + * Test that existing correct paths are not overwritten. + */ + public function test_upload_path_preservation() { + // Disable files rewriting to ensure the code path is exercised. + update_site_option( 'ms_files_rewriting', 0 ); + + // Create a new network. + $network_id = add_network( + array( + 'domain' => 'preserve.test', + 'path' => '/', + 'site_name' => 'Preserve Test', + 'network_name' => 'Preserve Test', + ) + ); + + $this->assertNotWPError( $network_id, 'Network should be created successfully' ); + + // Get the main site for the network. + $main_site_id = get_main_site_for_network( $network_id ); + + // Get the initial upload path. + $initial_upload_path = get_blog_option( $main_site_id, 'upload_path' ); + + // If a path was set and contains the site-specific directory, verify it's correct. + if ( ! empty( $initial_upload_path ) && false !== strpos( $initial_upload_path, '/sites/' . $main_site_id ) ) { + // Verify no duplication. + $count = substr_count( $initial_upload_path, '/sites/' . $main_site_id ); + $this->assertEquals( 1, $count, 'Initial upload path should not have duplicated site-specific directory' ); + + // The path should be preserved and not contain any doubled segments. + $this->assertStringNotContainsString( '/sites/' . $main_site_id . '/sites/' . $main_site_id, $initial_upload_path, 'Upload path should never contain doubled site-specific directories' ); + } + } +} From 109a258c87671fbe1e3316354cf652ea32f00d36 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 21:27:01 +0000 Subject: [PATCH 07/13] Improve test code: fix regex pattern and clarify comment - Use case-insensitive regex for protocol detection - Clarify comment about /sites/ directory usage Co-authored-by: JJJ <88951+JJJ@users.noreply.github.com> --- tests/integration/tests/test-upload-paths.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration/tests/test-upload-paths.php b/tests/integration/tests/test-upload-paths.php index 68df776..fce09b0 100644 --- a/tests/integration/tests/test-upload-paths.php +++ b/tests/integration/tests/test-upload-paths.php @@ -103,7 +103,7 @@ public function test_upload_path_multisite() { // Get the upload path. $upload_path = get_blog_option( $main_site_id, 'upload_path' ); - // In multisite, the path should use /sites/ prefix if present. + // In multisite, the path should use /sites/ directory if present. if ( ! empty( $upload_path ) && false !== strpos( $upload_path, '/sites/' ) ) { $this->assertStringContainsString( '/sites/' . $main_site_id, $upload_path, 'Upload path should contain /sites/{blog_id} format in multisite' ); @@ -181,7 +181,7 @@ public function test_upload_path_structure() { if ( ! empty( $upload_path ) ) { // Path should not have consecutive slashes (except in protocol). - $path_without_protocol = preg_replace( '#^[a-z]+://#', '', $upload_path ); + $path_without_protocol = preg_replace( '#^[a-zA-Z]+://#i', '', $upload_path ); $this->assertStringNotContainsString( '//', $path_without_protocol, 'Upload path should not contain consecutive slashes' ); // Path should not end with a slash. From 868e80ee5904de0fbd2ab3d0c51660d8626428d2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 21:42:52 +0000 Subject: [PATCH 08/13] Enhance upload path tests with groups, tickets, and efficiency improvements - Add @group and @ticket annotations for easy test filtering - Add wpSetUpBeforeClass for shared network to reduce redundant creation - Add 5 new test cases for additional installation permutations: * Subdirectory installations * Multiple sites in same network * Upload URL/path consistency * Network cloning scenarios - Create README-upload-tests.md with examples for running specific tests - Tests can now be run with: phpunit --group=upload or --group=136 Co-authored-by: JJJ <88951+JJJ@users.noreply.github.com> --- .../integration/tests/README-upload-tests.md | 111 +++++++++ tests/integration/tests/test-upload-paths.php | 227 ++++++++++++++++++ 2 files changed, 338 insertions(+) create mode 100644 tests/integration/tests/README-upload-tests.md diff --git a/tests/integration/tests/README-upload-tests.md b/tests/integration/tests/README-upload-tests.md new file mode 100644 index 0000000..3b02392 --- /dev/null +++ b/tests/integration/tests/README-upload-tests.md @@ -0,0 +1,111 @@ +# Upload Path Tests + +This document describes how to run the upload path tests for issue #136. + +## Running All Upload Path Tests + +To run all upload path tests: + +```bash +vendor/bin/phpunit --group=upload +``` + +## Running Specific Test Groups + +### All upload path tests (core functionality) +```bash +vendor/bin/phpunit --group=upload-paths +``` + +### Files rewriting tests +```bash +vendor/bin/phpunit --group=files-rewriting +``` + +### Tests without files rewriting +```bash +vendor/bin/phpunit --group=no-files-rewriting +``` + +### Path structure validation tests +```bash +vendor/bin/phpunit --group=path-structure +``` + +### Path preservation tests +```bash +vendor/bin/phpunit --group=path-preservation +``` + +### Subdirectory installation tests +```bash +vendor/bin/phpunit --group=subdirectory +``` + +### Multiple sites tests +```bash +vendor/bin/phpunit --group=multiple-sites +``` + +### Upload URL tests +```bash +vendor/bin/phpunit --group=upload-urls +``` + +### Network cloning tests +```bash +vendor/bin/phpunit --group=network-cloning +``` + +## Running Tests by Ticket Number + +To run all tests related to ticket/issue #136: + +```bash +vendor/bin/phpunit --group=136 +``` + +## Running a Single Test Class + +To run only the upload path test class: + +```bash +vendor/bin/phpunit tests/integration/tests/test-upload-paths.php +``` + +## Running a Single Test Method + +To run a specific test method: + +```bash +vendor/bin/phpunit --filter test_upload_path_without_duplication +``` + +## Test Coverage + +The upload path tests cover: + +- **Basic functionality**: Upload paths are set correctly without duplication +- **Files rewriting**: Behavior with `ms_files_rewriting` enabled and disabled +- **Multisite configurations**: Standard multisite setups +- **WordPress versions**: Tests run on modern WordPress (3.7+) +- **Path structure**: Validation of proper path format (no consecutive slashes, proper structure) +- **Path preservation**: Existing correct paths are not overwritten +- **Subdirectory installs**: Networks with subdirectory paths +- **Multiple sites**: Consistency across multiple sites in the same network +- **Upload URLs**: Consistency between upload paths and URLs +- **Network cloning**: Upload paths when cloning networks + +## Debugging + +To see more verbose output while running tests: + +```bash +vendor/bin/phpunit --group=upload --verbose +``` + +To run tests with debug output: + +```bash +vendor/bin/phpunit --group=upload --debug +``` diff --git a/tests/integration/tests/test-upload-paths.php b/tests/integration/tests/test-upload-paths.php index fce09b0..456966a 100644 --- a/tests/integration/tests/test-upload-paths.php +++ b/tests/integration/tests/test-upload-paths.php @@ -1,12 +1,49 @@ 'shared-test.example', + 'path' => '/', + 'site_name' => 'Shared Test Network', + 'network_name' => 'Shared Test Network', + ) + ); + } + + /** + * Clean up after class. + */ + public static function wpTearDownAfterClass() { + if ( ! empty( self::$network_id ) ) { + delete_network( self::$network_id, true ); + } + } + /** * Test that upload paths are correctly set when creating a new network. + * + * @group upload-paths + * @ticket 136 */ public function test_upload_path_without_duplication() { // Create a new network. @@ -42,6 +79,10 @@ public function test_upload_path_without_duplication() { /** * Test upload path when ms_files_rewriting is enabled. + * + * @group upload-paths + * @group files-rewriting + * @ticket 136 */ public function test_upload_path_with_files_rewriting() { // Enable files rewriting. @@ -79,6 +120,10 @@ public function test_upload_path_with_files_rewriting() { /** * Test upload path in multisite environment. + * + * @group upload-paths + * @group multisite + * @ticket 136 */ public function test_upload_path_multisite() { // Verify we're in a multisite environment. @@ -115,6 +160,10 @@ public function test_upload_path_multisite() { /** * Test that upload_path is set correctly without files rewriting. + * + * @group upload-paths + * @group no-files-rewriting + * @ticket 136 */ public function test_upload_path_without_files_rewriting() { // Ensure files rewriting is disabled. @@ -161,6 +210,10 @@ public function test_upload_path_without_files_rewriting() { /** * Test upload path structure for consistency. + * + * @group upload-paths + * @group path-structure + * @ticket 136 */ public function test_upload_path_structure() { // Create a new network. @@ -196,6 +249,10 @@ public function test_upload_path_structure() { /** * Test that existing correct paths are not overwritten. + * + * @group upload-paths + * @group path-preservation + * @ticket 136 */ public function test_upload_path_preservation() { // Disable files rewriting to ensure the code path is exercised. @@ -229,4 +286,174 @@ public function test_upload_path_preservation() { $this->assertStringNotContainsString( '/sites/' . $main_site_id . '/sites/' . $main_site_id, $initial_upload_path, 'Upload path should never contain doubled site-specific directories' ); } } + + /** + * Test upload path with subdirectory installation. + * + * @group upload-paths + * @group subdirectory + * @ticket 136 + */ + public function test_upload_path_subdirectory_install() { + // Create a network with a subdirectory path. + $network_id = add_network( + array( + 'domain' => 'subdir.example.com', + 'path' => '/subdir/', + 'site_name' => 'Subdirectory Network', + 'network_name' => 'Subdirectory Network', + ) + ); + + $this->assertNotWPError( $network_id, 'Network with subdirectory should be created' ); + + $main_site_id = get_main_site_for_network( $network_id ); + $upload_path = get_blog_option( $main_site_id, 'upload_path' ); + + // Verify path doesn't have duplicates. + if ( ! empty( $upload_path ) ) { + $site_suffix = '/sites/' . $main_site_id; + $count = substr_count( $upload_path, $site_suffix ); + $this->assertLessThanOrEqual( 1, $count, 'Subdirectory network upload path should not duplicate site-specific directories' ); + } + } + + /** + * Test upload path consistency across multiple sites in the same network. + * + * @group upload-paths + * @group multiple-sites + * @ticket 136 + */ + public function test_upload_path_multiple_sites() { + if ( empty( self::$network_id ) ) { + $this->markTestSkipped( 'Shared network not available' ); + } + + // Create multiple sites in the same network. + $site_ids = array(); + for ( $i = 0; $i < 3; $i++ ) { + switch_to_network( self::$network_id ); + $site_id = wpmu_create_blog( + 'site' . $i . '.shared-test.example', + '/', + 'Test Site ' . $i, + get_current_user_id(), + array(), + self::$network_id + ); + restore_current_network(); + + if ( ! is_wp_error( $site_id ) ) { + $site_ids[] = $site_id; + } + } + + // Verify each site has proper upload path without duplication. + foreach ( $site_ids as $site_id ) { + $upload_path = get_blog_option( $site_id, 'upload_path' ); + + if ( ! empty( $upload_path ) ) { + $site_suffix = '/sites/' . $site_id; + $count = substr_count( $upload_path, $site_suffix ); + $this->assertLessThanOrEqual( 1, $count, "Site {$site_id} upload path should not have duplicate site-specific directories" ); + } + } + } + + /** + * Test upload URL path consistency with upload path. + * + * @group upload-paths + * @group upload-urls + * @ticket 136 + */ + public function test_upload_url_path_consistency() { + $network_id = add_network( + array( + 'domain' => 'url-test.example', + 'path' => '/', + 'site_name' => 'URL Test Network', + 'network_name' => 'URL Test Network', + ) + ); + + $this->assertNotWPError( $network_id, 'Network should be created' ); + + $main_site_id = get_main_site_for_network( $network_id ); + $upload_path = get_blog_option( $main_site_id, 'upload_path' ); + $upload_url_path = get_blog_option( $main_site_id, 'upload_url_path' ); + + // If both paths are set, they should have consistent site-specific segments. + if ( ! empty( $upload_path ) && ! empty( $upload_url_path ) ) { + $path_suffix = '/sites/' . $main_site_id; + $path_has_suffix = false !== strpos( $upload_path, $path_suffix ); + $url_has_suffix = false !== strpos( $upload_url_path, $path_suffix ); + + // Both should either have or not have the suffix. + $this->assertEquals( $path_has_suffix, $url_has_suffix, 'Upload path and URL path should have consistent site-specific segments' ); + + // Neither should have duplicates. + if ( $path_has_suffix ) { + $path_count = substr_count( $upload_path, $path_suffix ); + $url_count = substr_count( $upload_url_path, $path_suffix ); + $this->assertEquals( 1, $path_count, 'Upload path should not have duplicate site-specific directories' ); + $this->assertEquals( 1, $url_count, 'Upload URL path should not have duplicate site-specific directories' ); + } + } + } + + /** + * Test upload path with network-level cloning. + * + * @group upload-paths + * @group network-cloning + * @ticket 136 + */ + public function test_upload_path_with_network_cloning() { + // Create a source network. + $source_network_id = add_network( + array( + 'domain' => 'source.example.com', + 'path' => '/', + 'site_name' => 'Source Network', + 'network_name' => 'Source Network', + ) + ); + + $this->assertNotWPError( $source_network_id, 'Source network should be created' ); + + // Create a cloned network. + $cloned_network_id = add_network( + array( + 'domain' => 'cloned.example.com', + 'path' => '/', + 'site_name' => 'Cloned Network', + 'network_name' => 'Cloned Network', + 'clone_network' => $source_network_id, + ) + ); + + $this->assertNotWPError( $cloned_network_id, 'Cloned network should be created' ); + + // Get upload paths for both networks. + $source_site_id = get_main_site_for_network( $source_network_id ); + $cloned_site_id = get_main_site_for_network( $cloned_network_id ); + + $source_upload_path = get_blog_option( $source_site_id, 'upload_path' ); + $cloned_upload_path = get_blog_option( $cloned_site_id, 'upload_path' ); + + // Both should have proper paths without duplication. + if ( ! empty( $source_upload_path ) ) { + $source_suffix = '/sites/' . $source_site_id; + $source_count = substr_count( $source_upload_path, $source_suffix ); + $this->assertLessThanOrEqual( 1, $source_count, 'Source network upload path should not have duplicates' ); + } + + if ( ! empty( $cloned_upload_path ) ) { + $cloned_suffix = '/sites/' . $cloned_site_id; + $cloned_count = substr_count( $cloned_upload_path, $cloned_suffix ); + $this->assertLessThanOrEqual( 1, $cloned_count, 'Cloned network upload path should not have duplicates' ); + } + } } From 9b388df21f792ac4f708c2fb97ee144a1b3dc048 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 21:44:46 +0000 Subject: [PATCH 09/13] Refactor tests: add helper method to eliminate code duplication Add assertUploadPathNoDuplicates() helper method to reduce repeated code patterns across all test methods, improving maintainability Co-authored-by: JJJ <88951+JJJ@users.noreply.github.com> --- tests/integration/tests/test-upload-paths.php | 98 ++++++++----------- 1 file changed, 43 insertions(+), 55 deletions(-) diff --git a/tests/integration/tests/test-upload-paths.php b/tests/integration/tests/test-upload-paths.php index 456966a..40d9007 100644 --- a/tests/integration/tests/test-upload-paths.php +++ b/tests/integration/tests/test-upload-paths.php @@ -39,6 +39,33 @@ public static function wpTearDownAfterClass() { } } + /** + * Helper method to assert upload path has no duplicate site-specific directories. + * + * @param int $site_id The site ID to check. + * @param string $upload_path The upload path to verify. + * @param string $message Custom assertion message. + */ + protected function assertUploadPathNoDuplicates( $site_id, $upload_path, $message = '' ) { + if ( empty( $upload_path ) ) { + return; + } + + $site_suffix = '/sites/' . $site_id; + $count = substr_count( $upload_path, $site_suffix ); + + if ( empty( $message ) ) { + $message = "Upload path should not contain duplicate site-specific directories for site {$site_id}"; + } + + $this->assertLessThanOrEqual( 1, $count, $message ); + + // If the path contains the suffix, it should appear exactly once. + if ( false !== strpos( $upload_path, $site_suffix ) ) { + $this->assertEquals( 1, $count, "Site-specific directory should appear exactly once in upload path for site {$site_id}" ); + } + } + /** * Test that upload paths are correctly set when creating a new network. * @@ -66,15 +93,7 @@ public function test_upload_path_without_duplication() { $upload_path = get_blog_option( $main_site_id, 'upload_path' ); // Check that the path doesn't contain duplicate site-specific directories. - $site_suffix = '/sites/' . $main_site_id; - $count = substr_count( $upload_path, $site_suffix ); - - $this->assertLessThanOrEqual( 1, $count, 'Upload path should not contain duplicate site-specific directories' ); - - // If the path contains the suffix, it should only appear once. - if ( false !== strpos( $upload_path, $site_suffix ) ) { - $this->assertEquals( 1, $count, 'Site-specific directory should appear exactly once in upload path' ); - } + $this->assertUploadPathNoDuplicates( $main_site_id, $upload_path, 'Upload path should not contain duplicate site-specific directories' ); } /** @@ -108,11 +127,7 @@ public function test_upload_path_with_files_rewriting() { $upload_path = get_blog_option( $main_site_id, 'upload_path' ); // The behavior with files rewriting may vary, but it should not contain duplicates. - if ( ! empty( $upload_path ) ) { - $site_suffix = '/sites/' . $main_site_id; - $count = substr_count( $upload_path, $site_suffix ); - $this->assertLessThanOrEqual( 1, $count, 'Upload path should not contain duplicate site-specific directories with files rewriting' ); - } + $this->assertUploadPathNoDuplicates( $main_site_id, $upload_path, 'Upload path should not contain duplicate site-specific directories with files rewriting' ); // Clean up. update_site_option( 'ms_files_rewriting', 0 ); @@ -151,11 +166,10 @@ public function test_upload_path_multisite() { // In multisite, the path should use /sites/ directory if present. if ( ! empty( $upload_path ) && false !== strpos( $upload_path, '/sites/' ) ) { $this->assertStringContainsString( '/sites/' . $main_site_id, $upload_path, 'Upload path should contain /sites/{blog_id} format in multisite' ); - - // Ensure no duplication. - $count = substr_count( $upload_path, '/sites/' . $main_site_id ); - $this->assertEquals( 1, $count, 'Site-specific path should appear exactly once' ); } + + // Ensure no duplication. + $this->assertUploadPathNoDuplicates( $main_site_id, $upload_path, 'Site-specific path should appear exactly once' ); } /** @@ -199,11 +213,7 @@ public function test_upload_path_without_files_rewriting() { // Verify no duplication of site-specific path. if ( defined( 'MULTISITE' ) && MULTISITE ) { - $site_suffix = '/sites/' . $main_site_id; - if ( false !== strpos( $upload_path, $site_suffix ) ) { - $count = substr_count( $upload_path, $site_suffix ); - $this->assertEquals( 1, $count, 'Site-specific directory should not be duplicated' ); - } + $this->assertUploadPathNoDuplicates( $main_site_id, $upload_path, 'Site-specific directory should not be duplicated' ); } } } @@ -276,13 +286,11 @@ public function test_upload_path_preservation() { // Get the initial upload path. $initial_upload_path = get_blog_option( $main_site_id, 'upload_path' ); - // If a path was set and contains the site-specific directory, verify it's correct. - if ( ! empty( $initial_upload_path ) && false !== strpos( $initial_upload_path, '/sites/' . $main_site_id ) ) { - // Verify no duplication. - $count = substr_count( $initial_upload_path, '/sites/' . $main_site_id ); - $this->assertEquals( 1, $count, 'Initial upload path should not have duplicated site-specific directory' ); + // Verify no duplication. + $this->assertUploadPathNoDuplicates( $main_site_id, $initial_upload_path, 'Initial upload path should not have duplicated site-specific directory' ); - // The path should be preserved and not contain any doubled segments. + // The path should be preserved and not contain any doubled segments. + if ( ! empty( $initial_upload_path ) ) { $this->assertStringNotContainsString( '/sites/' . $main_site_id . '/sites/' . $main_site_id, $initial_upload_path, 'Upload path should never contain doubled site-specific directories' ); } } @@ -311,11 +319,7 @@ public function test_upload_path_subdirectory_install() { $upload_path = get_blog_option( $main_site_id, 'upload_path' ); // Verify path doesn't have duplicates. - if ( ! empty( $upload_path ) ) { - $site_suffix = '/sites/' . $main_site_id; - $count = substr_count( $upload_path, $site_suffix ); - $this->assertLessThanOrEqual( 1, $count, 'Subdirectory network upload path should not duplicate site-specific directories' ); - } + $this->assertUploadPathNoDuplicates( $main_site_id, $upload_path, 'Subdirectory network upload path should not duplicate site-specific directories' ); } /** @@ -352,12 +356,7 @@ public function test_upload_path_multiple_sites() { // Verify each site has proper upload path without duplication. foreach ( $site_ids as $site_id ) { $upload_path = get_blog_option( $site_id, 'upload_path' ); - - if ( ! empty( $upload_path ) ) { - $site_suffix = '/sites/' . $site_id; - $count = substr_count( $upload_path, $site_suffix ); - $this->assertLessThanOrEqual( 1, $count, "Site {$site_id} upload path should not have duplicate site-specific directories" ); - } + $this->assertUploadPathNoDuplicates( $site_id, $upload_path, "Site {$site_id} upload path should not have duplicate site-specific directories" ); } } @@ -395,10 +394,8 @@ public function test_upload_url_path_consistency() { // Neither should have duplicates. if ( $path_has_suffix ) { - $path_count = substr_count( $upload_path, $path_suffix ); - $url_count = substr_count( $upload_url_path, $path_suffix ); - $this->assertEquals( 1, $path_count, 'Upload path should not have duplicate site-specific directories' ); - $this->assertEquals( 1, $url_count, 'Upload URL path should not have duplicate site-specific directories' ); + $this->assertUploadPathNoDuplicates( $main_site_id, $upload_path, 'Upload path should not have duplicate site-specific directories' ); + $this->assertUploadPathNoDuplicates( $main_site_id, $upload_url_path, 'Upload URL path should not have duplicate site-specific directories' ); } } } @@ -444,16 +441,7 @@ public function test_upload_path_with_network_cloning() { $cloned_upload_path = get_blog_option( $cloned_site_id, 'upload_path' ); // Both should have proper paths without duplication. - if ( ! empty( $source_upload_path ) ) { - $source_suffix = '/sites/' . $source_site_id; - $source_count = substr_count( $source_upload_path, $source_suffix ); - $this->assertLessThanOrEqual( 1, $source_count, 'Source network upload path should not have duplicates' ); - } - - if ( ! empty( $cloned_upload_path ) ) { - $cloned_suffix = '/sites/' . $cloned_site_id; - $cloned_count = substr_count( $cloned_upload_path, $cloned_suffix ); - $this->assertLessThanOrEqual( 1, $cloned_count, 'Cloned network upload path should not have duplicates' ); - } + $this->assertUploadPathNoDuplicates( $source_site_id, $source_upload_path, 'Source network upload path should not have duplicates' ); + $this->assertUploadPathNoDuplicates( $cloned_site_id, $cloned_upload_path, 'Cloned network upload path should not have duplicates' ); } } From f6407503f7906ff9a925190c22e8d9b2fd87126b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 21:51:58 +0000 Subject: [PATCH 10/13] Remove README-upload-tests.md and merge content into TESTING.md Removed the standalone test documentation file and integrated relevant test group examples into the main TESTING.md file Co-authored-by: JJJ <88951+JJJ@users.noreply.github.com> --- TESTING.md | 48 ++++++++ .../integration/tests/README-upload-tests.md | 111 ------------------ 2 files changed, 48 insertions(+), 111 deletions(-) delete mode 100644 tests/integration/tests/README-upload-tests.md diff --git a/TESTING.md b/TESTING.md index 8035bbc..459fb6f 100644 --- a/TESTING.md +++ b/TESTING.md @@ -111,6 +111,54 @@ bash bin/install-wp-tests.sh wordpress_test wp wp localhost $WP_VERSION ./vendor/bin/phpunit ``` +### Running Specific Test Groups + +Tests are organized using PHPUnit groups for easy filtering: + +**Run all upload path tests:** + +```bash +./vendor/bin/phpunit --group=upload +``` + +**Run tests by ticket number:** + +```bash +./vendor/bin/phpunit --group=136 +``` + +**Run specific test groups:** + +```bash +# Files rewriting tests +./vendor/bin/phpunit --group=files-rewriting + +# Multisite configuration tests +./vendor/bin/phpunit --group=multisite + +# Subdirectory installation tests +./vendor/bin/phpunit --group=subdirectory +``` + +**Run a single test class:** + +```bash +./vendor/bin/phpunit tests/integration/tests/test-upload-paths.php +``` + +**Run a specific test method:** + +```bash +./vendor/bin/phpunit --filter test_upload_path_without_duplication +``` + +**Verbose and debug output:** + +```bash +./vendor/bin/phpunit --group=upload --verbose +./vendor/bin/phpunit --group=upload --debug +``` + ### Testing with Docker You can test different PHP versions using Docker: diff --git a/tests/integration/tests/README-upload-tests.md b/tests/integration/tests/README-upload-tests.md deleted file mode 100644 index 3b02392..0000000 --- a/tests/integration/tests/README-upload-tests.md +++ /dev/null @@ -1,111 +0,0 @@ -# Upload Path Tests - -This document describes how to run the upload path tests for issue #136. - -## Running All Upload Path Tests - -To run all upload path tests: - -```bash -vendor/bin/phpunit --group=upload -``` - -## Running Specific Test Groups - -### All upload path tests (core functionality) -```bash -vendor/bin/phpunit --group=upload-paths -``` - -### Files rewriting tests -```bash -vendor/bin/phpunit --group=files-rewriting -``` - -### Tests without files rewriting -```bash -vendor/bin/phpunit --group=no-files-rewriting -``` - -### Path structure validation tests -```bash -vendor/bin/phpunit --group=path-structure -``` - -### Path preservation tests -```bash -vendor/bin/phpunit --group=path-preservation -``` - -### Subdirectory installation tests -```bash -vendor/bin/phpunit --group=subdirectory -``` - -### Multiple sites tests -```bash -vendor/bin/phpunit --group=multiple-sites -``` - -### Upload URL tests -```bash -vendor/bin/phpunit --group=upload-urls -``` - -### Network cloning tests -```bash -vendor/bin/phpunit --group=network-cloning -``` - -## Running Tests by Ticket Number - -To run all tests related to ticket/issue #136: - -```bash -vendor/bin/phpunit --group=136 -``` - -## Running a Single Test Class - -To run only the upload path test class: - -```bash -vendor/bin/phpunit tests/integration/tests/test-upload-paths.php -``` - -## Running a Single Test Method - -To run a specific test method: - -```bash -vendor/bin/phpunit --filter test_upload_path_without_duplication -``` - -## Test Coverage - -The upload path tests cover: - -- **Basic functionality**: Upload paths are set correctly without duplication -- **Files rewriting**: Behavior with `ms_files_rewriting` enabled and disabled -- **Multisite configurations**: Standard multisite setups -- **WordPress versions**: Tests run on modern WordPress (3.7+) -- **Path structure**: Validation of proper path format (no consecutive slashes, proper structure) -- **Path preservation**: Existing correct paths are not overwritten -- **Subdirectory installs**: Networks with subdirectory paths -- **Multiple sites**: Consistency across multiple sites in the same network -- **Upload URLs**: Consistency between upload paths and URLs -- **Network cloning**: Upload paths when cloning networks - -## Debugging - -To see more verbose output while running tests: - -```bash -vendor/bin/phpunit --group=upload --verbose -``` - -To run tests with debug output: - -```bash -vendor/bin/phpunit --group=upload --debug -``` From 3c59f354d8ccdce069da6d67bd74dc5e647cc916 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 22:16:13 +0000 Subject: [PATCH 11/13] Fix test failures: add user_id to all add_network() calls All tests were failing with "User does not exist" because add_network() requires valid user IDs. Added user creation in wpSetUpBeforeClass and passed user_id to all network creation calls. Co-authored-by: JJJ <88951+JJJ@users.noreply.github.com> --- tests/integration/tests/test-upload-paths.php | 136 ++++++++++++------ 1 file changed, 89 insertions(+), 47 deletions(-) diff --git a/tests/integration/tests/test-upload-paths.php b/tests/integration/tests/test-upload-paths.php index 40d9007..0ad3312 100644 --- a/tests/integration/tests/test-upload-paths.php +++ b/tests/integration/tests/test-upload-paths.php @@ -16,16 +16,34 @@ class WPMN_Tests_Upload_Paths extends WPMN_UnitTestCase { */ protected static $network_id; + /** + * User ID for network operations. + * + * @var int + */ + protected static $user_id; + /** * Set up before class to create a shared test network. + * + * @param WP_UnitTest_Factory $factory Test factory. */ - public static function wpSetUpBeforeClass() { + public static function wpSetUpBeforeClass( $factory ) { + // Create a user for network operations. + self::$user_id = $factory->user->create( + array( + 'role' => 'administrator', + ) + ); + self::$network_id = add_network( array( - 'domain' => 'shared-test.example', - 'path' => '/', - 'site_name' => 'Shared Test Network', - 'network_name' => 'Shared Test Network', + 'domain' => 'shared-test.example', + 'path' => '/', + 'site_name' => 'Shared Test Network', + 'network_name' => 'Shared Test Network', + 'user_id' => self::$user_id, + 'network_admin_id' => self::$user_id, ) ); } @@ -37,6 +55,10 @@ public static function wpTearDownAfterClass() { if ( ! empty( self::$network_id ) ) { delete_network( self::$network_id, true ); } + + if ( ! empty( self::$user_id ) ) { + self::delete_user( self::$user_id ); + } } /** @@ -76,10 +98,12 @@ public function test_upload_path_without_duplication() { // Create a new network. $network_id = add_network( array( - 'domain' => 'example.org', - 'path' => '/', - 'site_name' => 'Test Network', - 'network_name' => 'Test Network', + 'domain' => 'example.org', + 'path' => '/', + 'site_name' => 'Test Network', + 'network_name' => 'Test Network', + 'user_id' => self::$user_id, + 'network_admin_id' => self::$user_id, ) ); @@ -110,10 +134,12 @@ public function test_upload_path_with_files_rewriting() { // Create a new network. $network_id = add_network( array( - 'domain' => 'example.net', - 'path' => '/', - 'site_name' => 'Test Network with Rewriting', - 'network_name' => 'Test Network with Rewriting', + 'domain' => 'example.net', + 'path' => '/', + 'site_name' => 'Test Network with Rewriting', + 'network_name' => 'Test Network with Rewriting', + 'user_id' => self::$user_id, + 'network_admin_id' => self::$user_id, ) ); @@ -147,10 +173,12 @@ public function test_upload_path_multisite() { // Create a new network. $network_id = add_network( array( - 'domain' => 'multisite.test', - 'path' => '/', - 'site_name' => 'Multisite Test', - 'network_name' => 'Multisite Test', + 'domain' => 'multisite.test', + 'path' => '/', + 'site_name' => 'Multisite Test', + 'network_name' => 'Multisite Test', + 'user_id' => self::$user_id, + 'network_admin_id' => self::$user_id, ) ); @@ -186,10 +214,12 @@ public function test_upload_path_without_files_rewriting() { // Create a new network. $network_id = add_network( array( - 'domain' => 'no-rewrite.test', - 'path' => '/', - 'site_name' => 'No Rewrite Test', - 'network_name' => 'No Rewrite Test', + 'domain' => 'no-rewrite.test', + 'path' => '/', + 'site_name' => 'No Rewrite Test', + 'network_name' => 'No Rewrite Test', + 'user_id' => self::$user_id, + 'network_admin_id' => self::$user_id, ) ); @@ -229,10 +259,12 @@ public function test_upload_path_structure() { // Create a new network. $network_id = add_network( array( - 'domain' => 'structure.test', - 'path' => '/', - 'site_name' => 'Structure Test', - 'network_name' => 'Structure Test', + 'domain' => 'structure.test', + 'path' => '/', + 'site_name' => 'Structure Test', + 'network_name' => 'Structure Test', + 'user_id' => self::$user_id, + 'network_admin_id' => self::$user_id, ) ); @@ -271,10 +303,12 @@ public function test_upload_path_preservation() { // Create a new network. $network_id = add_network( array( - 'domain' => 'preserve.test', - 'path' => '/', - 'site_name' => 'Preserve Test', - 'network_name' => 'Preserve Test', + 'domain' => 'preserve.test', + 'path' => '/', + 'site_name' => 'Preserve Test', + 'network_name' => 'Preserve Test', + 'user_id' => self::$user_id, + 'network_admin_id' => self::$user_id, ) ); @@ -306,10 +340,12 @@ public function test_upload_path_subdirectory_install() { // Create a network with a subdirectory path. $network_id = add_network( array( - 'domain' => 'subdir.example.com', - 'path' => '/subdir/', - 'site_name' => 'Subdirectory Network', - 'network_name' => 'Subdirectory Network', + 'domain' => 'subdir.example.com', + 'path' => '/subdir/', + 'site_name' => 'Subdirectory Network', + 'network_name' => 'Subdirectory Network', + 'user_id' => self::$user_id, + 'network_admin_id' => self::$user_id, ) ); @@ -342,7 +378,7 @@ public function test_upload_path_multiple_sites() { 'site' . $i . '.shared-test.example', '/', 'Test Site ' . $i, - get_current_user_id(), + self::$user_id, array(), self::$network_id ); @@ -370,10 +406,12 @@ public function test_upload_path_multiple_sites() { public function test_upload_url_path_consistency() { $network_id = add_network( array( - 'domain' => 'url-test.example', - 'path' => '/', - 'site_name' => 'URL Test Network', - 'network_name' => 'URL Test Network', + 'domain' => 'url-test.example', + 'path' => '/', + 'site_name' => 'URL Test Network', + 'network_name' => 'URL Test Network', + 'user_id' => self::$user_id, + 'network_admin_id' => self::$user_id, ) ); @@ -411,10 +449,12 @@ public function test_upload_path_with_network_cloning() { // Create a source network. $source_network_id = add_network( array( - 'domain' => 'source.example.com', - 'path' => '/', - 'site_name' => 'Source Network', - 'network_name' => 'Source Network', + 'domain' => 'source.example.com', + 'path' => '/', + 'site_name' => 'Source Network', + 'network_name' => 'Source Network', + 'user_id' => self::$user_id, + 'network_admin_id' => self::$user_id, ) ); @@ -423,11 +463,13 @@ public function test_upload_path_with_network_cloning() { // Create a cloned network. $cloned_network_id = add_network( array( - 'domain' => 'cloned.example.com', - 'path' => '/', - 'site_name' => 'Cloned Network', - 'network_name' => 'Cloned Network', - 'clone_network' => $source_network_id, + 'domain' => 'cloned.example.com', + 'path' => '/', + 'site_name' => 'Cloned Network', + 'network_name' => 'Cloned Network', + 'clone_network' => $source_network_id, + 'user_id' => self::$user_id, + 'network_admin_id' => self::$user_id, ) ); From 902da850ab62b6adf69812fd357c416b813787d7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 22:24:40 +0000 Subject: [PATCH 12/13] Grant super admin privileges and rename user_id to superadmin_id - Added grant_super_admin() call after user creation to allow network creation - Renamed $user_id to $superadmin_id throughout test class for clarity and consistency with existing tests Co-authored-by: JJJ <88951+JJJ@users.noreply.github.com> --- tests/integration/tests/test-upload-paths.php | 59 ++++++++++--------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/tests/integration/tests/test-upload-paths.php b/tests/integration/tests/test-upload-paths.php index 0ad3312..7357ec7 100644 --- a/tests/integration/tests/test-upload-paths.php +++ b/tests/integration/tests/test-upload-paths.php @@ -17,11 +17,11 @@ class WPMN_Tests_Upload_Paths extends WPMN_UnitTestCase { protected static $network_id; /** - * User ID for network operations. + * Super admin user ID for network operations. * * @var int */ - protected static $user_id; + protected static $superadmin_id; /** * Set up before class to create a shared test network. @@ -29,12 +29,13 @@ class WPMN_Tests_Upload_Paths extends WPMN_UnitTestCase { * @param WP_UnitTest_Factory $factory Test factory. */ public static function wpSetUpBeforeClass( $factory ) { - // Create a user for network operations. - self::$user_id = $factory->user->create( + // Create a super admin user for network operations. + self::$superadmin_id = $factory->user->create( array( 'role' => 'administrator', ) ); + grant_super_admin( self::$superadmin_id ); self::$network_id = add_network( array( @@ -42,8 +43,8 @@ public static function wpSetUpBeforeClass( $factory ) { 'path' => '/', 'site_name' => 'Shared Test Network', 'network_name' => 'Shared Test Network', - 'user_id' => self::$user_id, - 'network_admin_id' => self::$user_id, + 'user_id' => self::$superadmin_id, + 'network_admin_id' => self::$superadmin_id, ) ); } @@ -56,8 +57,8 @@ public static function wpTearDownAfterClass() { delete_network( self::$network_id, true ); } - if ( ! empty( self::$user_id ) ) { - self::delete_user( self::$user_id ); + if ( ! empty( self::$superadmin_id ) ) { + self::delete_user( self::$superadmin_id ); } } @@ -102,8 +103,8 @@ public function test_upload_path_without_duplication() { 'path' => '/', 'site_name' => 'Test Network', 'network_name' => 'Test Network', - 'user_id' => self::$user_id, - 'network_admin_id' => self::$user_id, + 'user_id' => self::$superadmin_id, + 'network_admin_id' => self::$superadmin_id, ) ); @@ -138,8 +139,8 @@ public function test_upload_path_with_files_rewriting() { 'path' => '/', 'site_name' => 'Test Network with Rewriting', 'network_name' => 'Test Network with Rewriting', - 'user_id' => self::$user_id, - 'network_admin_id' => self::$user_id, + 'user_id' => self::$superadmin_id, + 'network_admin_id' => self::$superadmin_id, ) ); @@ -177,8 +178,8 @@ public function test_upload_path_multisite() { 'path' => '/', 'site_name' => 'Multisite Test', 'network_name' => 'Multisite Test', - 'user_id' => self::$user_id, - 'network_admin_id' => self::$user_id, + 'user_id' => self::$superadmin_id, + 'network_admin_id' => self::$superadmin_id, ) ); @@ -218,8 +219,8 @@ public function test_upload_path_without_files_rewriting() { 'path' => '/', 'site_name' => 'No Rewrite Test', 'network_name' => 'No Rewrite Test', - 'user_id' => self::$user_id, - 'network_admin_id' => self::$user_id, + 'user_id' => self::$superadmin_id, + 'network_admin_id' => self::$superadmin_id, ) ); @@ -263,8 +264,8 @@ public function test_upload_path_structure() { 'path' => '/', 'site_name' => 'Structure Test', 'network_name' => 'Structure Test', - 'user_id' => self::$user_id, - 'network_admin_id' => self::$user_id, + 'user_id' => self::$superadmin_id, + 'network_admin_id' => self::$superadmin_id, ) ); @@ -307,8 +308,8 @@ public function test_upload_path_preservation() { 'path' => '/', 'site_name' => 'Preserve Test', 'network_name' => 'Preserve Test', - 'user_id' => self::$user_id, - 'network_admin_id' => self::$user_id, + 'user_id' => self::$superadmin_id, + 'network_admin_id' => self::$superadmin_id, ) ); @@ -344,8 +345,8 @@ public function test_upload_path_subdirectory_install() { 'path' => '/subdir/', 'site_name' => 'Subdirectory Network', 'network_name' => 'Subdirectory Network', - 'user_id' => self::$user_id, - 'network_admin_id' => self::$user_id, + 'user_id' => self::$superadmin_id, + 'network_admin_id' => self::$superadmin_id, ) ); @@ -378,7 +379,7 @@ public function test_upload_path_multiple_sites() { 'site' . $i . '.shared-test.example', '/', 'Test Site ' . $i, - self::$user_id, + self::$superadmin_id, array(), self::$network_id ); @@ -410,8 +411,8 @@ public function test_upload_url_path_consistency() { 'path' => '/', 'site_name' => 'URL Test Network', 'network_name' => 'URL Test Network', - 'user_id' => self::$user_id, - 'network_admin_id' => self::$user_id, + 'user_id' => self::$superadmin_id, + 'network_admin_id' => self::$superadmin_id, ) ); @@ -453,8 +454,8 @@ public function test_upload_path_with_network_cloning() { 'path' => '/', 'site_name' => 'Source Network', 'network_name' => 'Source Network', - 'user_id' => self::$user_id, - 'network_admin_id' => self::$user_id, + 'user_id' => self::$superadmin_id, + 'network_admin_id' => self::$superadmin_id, ) ); @@ -468,8 +469,8 @@ public function test_upload_path_with_network_cloning() { 'site_name' => 'Cloned Network', 'network_name' => 'Cloned Network', 'clone_network' => $source_network_id, - 'user_id' => self::$user_id, - 'network_admin_id' => self::$user_id, + 'user_id' => self::$superadmin_id, + 'network_admin_id' => self::$superadmin_id, ) ); From 89512ff7b76ad31719603e6f544a3d3bdf6dc040 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 8 Dec 2025 22:36:20 +0000 Subject: [PATCH 13/13] Fix network domain conflict in test_upload_path_without_duplication Changed domain from 'example.org' to 'unique-test.example.org' to avoid conflict with default WordPress test environment network Co-authored-by: JJJ <88951+JJJ@users.noreply.github.com> --- tests/integration/tests/test-upload-paths.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/tests/test-upload-paths.php b/tests/integration/tests/test-upload-paths.php index 7357ec7..dccc1bb 100644 --- a/tests/integration/tests/test-upload-paths.php +++ b/tests/integration/tests/test-upload-paths.php @@ -99,7 +99,7 @@ public function test_upload_path_without_duplication() { // Create a new network. $network_id = add_network( array( - 'domain' => 'example.org', + 'domain' => 'unique-test.example.org', 'path' => '/', 'site_name' => 'Test Network', 'network_name' => 'Test Network',