@@ -623,6 +623,63 @@ public function test_sync_should_compact_is_false_for_non_compactor() {
623623 $ this ->assertFalse ( $ data ['rooms ' ][0 ]['should_compact ' ] );
624624 }
625625
626+ public function test_sync_stale_compaction_succeeds_when_newer_compaction_exists () {
627+ wp_set_current_user ( self ::$ editor_id );
628+
629+ $ room = $ this ->get_post_room ();
630+ $ update = array (
631+ 'type ' => 'update ' ,
632+ 'data ' => 'dGVzdA== ' ,
633+ );
634+
635+ // Client 1 sends an update to seed the room.
636+ $ response = $ this ->dispatch_sync (
637+ array (
638+ $ this ->build_room ( $ room , 1 , 0 , array ( 'user ' => 'c1 ' ), array ( $ update ) ),
639+ )
640+ );
641+
642+ $ end_cursor = $ response ->get_data ()['rooms ' ][0 ]['end_cursor ' ];
643+
644+ // Client 2 sends a compaction at the current cursor.
645+ $ compaction = array (
646+ 'type ' => 'compaction ' ,
647+ 'data ' => 'Y29tcGFjdGVk ' ,
648+ );
649+
650+ $ this ->dispatch_sync (
651+ array (
652+ $ this ->build_room ( $ room , 2 , $ end_cursor , array ( 'user ' => 'c2 ' ), array ( $ compaction ) ),
653+ )
654+ );
655+
656+ // Client 3 sends a stale compaction at cursor 0. The server should find
657+ // client 2's compaction in the updates after cursor 0 and silently discard
658+ // this one.
659+ $ stale_compaction = array (
660+ 'type ' => 'compaction ' ,
661+ 'data ' => 'c3RhbGU= ' ,
662+ );
663+ $ response = $ this ->dispatch_sync (
664+ array (
665+ $ this ->build_room ( $ room , 3 , 0 , array ( 'user ' => 'c3 ' ), array ( $ stale_compaction ) ),
666+ )
667+ );
668+
669+ $ this ->assertSame ( 200 , $ response ->get_status () );
670+
671+ // Verify the newer compaction is preserved and the stale one was not stored.
672+ $ response = $ this ->dispatch_sync (
673+ array (
674+ $ this ->build_room ( $ room , 4 , 0 , array ( 'user ' => 'c4 ' ) ),
675+ )
676+ );
677+ $ update_data = wp_list_pluck ( $ response ->get_data ()['rooms ' ][0 ]['updates ' ], 'data ' );
678+
679+ $ this ->assertContains ( 'Y29tcGFjdGVk ' , $ update_data , 'The newer compaction should be preserved. ' );
680+ $ this ->assertNotContains ( 'c3RhbGU= ' , $ update_data , 'The stale compaction should not be stored. ' );
681+ }
682+
626683 /*
627684 * Awareness tests.
628685 */
@@ -697,6 +754,31 @@ public function test_sync_awareness_updates_existing_client() {
697754 $ this ->assertSame ( array ( 'cursor ' => 'updated ' ), $ awareness [1 ] );
698755 }
699756
757+ public function test_sync_awareness_client_id_cannot_be_used_by_another_user () {
758+ wp_set_current_user ( self ::$ editor_id );
759+
760+ $ room = $ this ->get_post_room ();
761+
762+ // Editor establishes awareness with client_id 1.
763+ $ this ->dispatch_sync (
764+ array (
765+ $ this ->build_room ( $ room , 1 , 0 , array ( 'name ' => 'Editor ' ) ),
766+ )
767+ );
768+
769+ // A different user tries to use the same client_id.
770+ $ editor_id_2 = self ::factory ()->user ->create ( array ( 'role ' => 'editor ' ) );
771+ wp_set_current_user ( $ editor_id_2 );
772+
773+ $ response = $ this ->dispatch_sync (
774+ array (
775+ $ this ->build_room ( $ room , 1 , 0 , array ( 'name ' => 'Impostor ' ) ),
776+ )
777+ );
778+
779+ $ this ->assertErrorResponse ( 'rest_cannot_edit ' , $ response , 403 );
780+ }
781+
700782 /*
701783 * Multiple rooms tests.
702784 */
0 commit comments