Changeset 62099 for trunk/tests/phpunit/tests/rest-api/rest-sync-server.php
- Timestamp:
- 03/24/2026 09:07:04 AM (7 months ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/tests/phpunit/tests/rest-api/rest-sync-server.php
r62064 r62099 566 566 } 567 567 568 public function test_sync_cursor_does_not_skip_update_inserted_during_fetch_window() {569 global $wpdb;570 571 wp_set_current_user( self::$editor_id );572 573 $room = $this->get_post_room();574 $storage = new WP_Sync_Post_Meta_Storage();575 576 $seed_update = array(577 'client_id' => 1,578 'type' => 'update',579 'data' => 'c2VlZA==',580 );581 582 $this->assertTrue( $storage->add_update( $room, $seed_update ) );583 584 $initial_updates = $storage->get_updates_after_cursor( $room, 0 );585 $baseline_cursor = $storage->get_cursor( $room );586 587 $this->assertCount( 1, $initial_updates );588 $this->assertSame( $seed_update, $initial_updates[0] );589 $this->assertGreaterThan( 0, $baseline_cursor );590 591 $storage_posts = get_posts(592 array(593 'post_type' => WP_Sync_Post_Meta_Storage::POST_TYPE,594 'posts_per_page' => 1,595 'post_status' => 'publish',596 'name' => md5( $room ),597 'fields' => 'ids',598 )599 );600 $storage_post_id = array_first( $storage_posts );601 602 $this->assertIsInt( $storage_post_id );603 604 $injected_update = array(605 'client_id' => 9999,606 'type' => 'update',607 'data' => base64_encode( 'injected-during-fetch' ),608 );609 610 $original_wpdb = $wpdb;611 $proxy_wpdb = new class( $original_wpdb, $storage_post_id, $injected_update ) {612 private $wpdb;613 private $storage_post_id;614 private $injected_update;615 public $postmeta;616 public $did_inject = false;617 618 public function __construct( $wpdb, int $storage_post_id, array $injected_update ) {619 $this->wpdb = $wpdb;620 $this->storage_post_id = $storage_post_id;621 $this->injected_update = $injected_update;622 $this->postmeta = $wpdb->postmeta;623 }624 625 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- Proxy forwards fully prepared core queries.626 public function prepare( ...$args ) {627 return $this->wpdb->prepare( ...$args );628 }629 630 public function get_row( $query = null, $output = OBJECT, $y = 0 ) {631 $result = $this->wpdb->get_row( $query, $output, $y );632 633 $this->maybe_inject_after_sync_query( $query );634 635 return $result;636 }637 638 public function get_var( $query = null, $x = 0, $y = 0 ) {639 $result = $this->wpdb->get_var( $query, $x, $y );640 641 $this->maybe_inject_after_sync_query( $query );642 643 return $result;644 }645 646 public function get_results( $query = null, $output = OBJECT ) {647 return $this->wpdb->get_results( $query, $output );648 }649 // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared650 651 public function __call( $name, $arguments ) {652 return $this->wpdb->$name( ...$arguments );653 }654 655 public function __get( $name ) {656 return $this->wpdb->$name;657 }658 659 public function __set( $name, $value ) {660 $this->wpdb->$name = $value;661 }662 663 private function inject_update(): void {664 if ( $this->did_inject ) {665 return;666 }667 668 $this->did_inject = true;669 670 add_post_meta(671 $this->storage_post_id,672 WP_Sync_Post_Meta_Storage::SYNC_UPDATE_META_KEY,673 $this->injected_update,674 false675 );676 }677 678 private function maybe_inject_after_sync_query( $query ): void {679 if ( $this->did_inject || ! is_string( $query ) ) {680 return;681 }682 683 $targets_postmeta = false !== strpos( $query, $this->postmeta );684 $targets_post_id = 1 === preg_match( '/\bpost_id\s*=\s*' . (int) $this->storage_post_id . '\b/', $query );685 $targets_meta_key = 1 === preg_match(686 "/\bmeta_key\s*=\s*'" . preg_quote( WP_Sync_Post_Meta_Storage::SYNC_UPDATE_META_KEY, '/' ) . "'/",687 $query688 );689 690 if ( $targets_postmeta && $targets_post_id && $targets_meta_key ) {691 $this->inject_update();692 }693 }694 };695 696 $wpdb = $proxy_wpdb;697 try {698 $race_updates = $storage->get_updates_after_cursor( $room, $baseline_cursor );699 $race_cursor = $storage->get_cursor( $room );700 } finally {701 $wpdb = $original_wpdb;702 }703 704 $this->assertTrue( $proxy_wpdb->did_inject, 'Expected race-window update injection to occur.' );705 $this->assertEmpty( $race_updates );706 $this->assertSame( $baseline_cursor, $race_cursor );707 708 $follow_up_updates = $storage->get_updates_after_cursor( $room, $race_cursor );709 $follow_up_cursor = $storage->get_cursor( $room );710 711 $this->assertCount( 1, $follow_up_updates );712 $this->assertSame( $injected_update, $follow_up_updates[0] );713 $this->assertGreaterThan( $race_cursor, $follow_up_cursor );714 }715 716 568 /* 717 569 * Compaction tests. … … 855 707 } 856 708 857 public function test_sync_compaction_does_not_delete_update_inserted_during_delete() {858 global $wpdb;859 860 wp_set_current_user( self::$editor_id );861 862 $room = $this->get_post_room();863 $storage = new WP_Sync_Post_Meta_Storage();864 865 // Seed three updates so there's something to compact.866 for ( $i = 1; $i <= 3; $i++ ) {867 $this->assertTrue(868 $storage->add_update(869 $room,870 array(871 'client_id' => $i,872 'type' => 'update',873 'data' => base64_encode( "seed-$i" ),874 )875 )876 );877 }878 879 // Capture the cursor after all seeds are in place.880 $storage->get_updates_after_cursor( $room, 0 );881 $compaction_cursor = $storage->get_cursor( $room );882 $this->assertGreaterThan( 0, $compaction_cursor );883 884 $storage_posts = get_posts(885 array(886 'post_type' => WP_Sync_Post_Meta_Storage::POST_TYPE,887 'posts_per_page' => 1,888 'post_status' => 'publish',889 'name' => md5( $room ),890 'fields' => 'ids',891 )892 );893 $storage_post_id = array_first( $storage_posts );894 $this->assertIsInt( $storage_post_id );895 896 $concurrent_update = array(897 'client_id' => 9999,898 'type' => 'update',899 'data' => base64_encode( 'arrived-during-compaction' ),900 );901 902 $original_wpdb = $wpdb;903 $proxy_wpdb = new class( $original_wpdb, $storage_post_id, $concurrent_update ) {904 private $wpdb;905 private $storage_post_id;906 private $concurrent_update;907 public $did_inject = false;908 909 public function __construct( $wpdb, int $storage_post_id, array $concurrent_update ) {910 $this->wpdb = $wpdb;911 $this->storage_post_id = $storage_post_id;912 $this->concurrent_update = $concurrent_update;913 }914 915 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared -- Proxy forwards fully prepared core queries.916 public function prepare( ...$args ) {917 return $this->wpdb->prepare( ...$args );918 }919 920 public function query( $query ) {921 $result = $this->wpdb->query( $query );922 923 // After the DELETE executes, inject a concurrent update via924 // raw SQL through the real $wpdb to avoid metadata cache925 // interactions while the proxy is active.926 if ( ! $this->did_inject927 && is_string( $query )928 && 0 === strpos( $query, "DELETE FROM {$this->wpdb->postmeta}" )929 && false !== strpos( $query, "post_id = {$this->storage_post_id}" )930 ) {931 $this->did_inject = true;932 $this->wpdb->insert(933 $this->wpdb->postmeta,934 array(935 'post_id' => $this->storage_post_id,936 'meta_key' => WP_Sync_Post_Meta_Storage::SYNC_UPDATE_META_KEY,937 'meta_value' => maybe_serialize( $this->concurrent_update ),938 ),939 array( '%d', '%s', '%s' )940 );941 }942 943 return $result;944 }945 // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared946 947 public function __call( $name, $arguments ) {948 return $this->wpdb->$name( ...$arguments );949 }950 951 public function __get( $name ) {952 return $this->wpdb->$name;953 }954 955 public function __set( $name, $value ) {956 $this->wpdb->$name = $value;957 }958 };959 960 // Run compaction through the proxy so the concurrent update961 // is injected immediately after the DELETE executes.962 $wpdb = $proxy_wpdb;963 try {964 $result = $storage->remove_updates_before_cursor( $room, $compaction_cursor );965 } finally {966 $wpdb = $original_wpdb;967 }968 969 $this->assertTrue( $result );970 $this->assertTrue( $proxy_wpdb->did_inject, 'Expected concurrent update injection to occur.' );971 972 // The concurrent update must survive the compaction delete.973 $updates = $storage->get_updates_after_cursor( $room, 0 );974 975 $update_data = wp_list_pluck( $updates, 'data' );976 $this->assertContains(977 $concurrent_update['data'],978 $update_data,979 'Concurrent update should survive compaction.'980 );981 }982 983 709 /* 984 710 * Awareness tests.
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)