@@ -2627,3 +2627,113 @@ async fn test_clear_all_rooms() {
2627
2627
event_cache_store. load_last_chunk ( sleeping_room_id) . await . unwrap ( ) ;
2628
2628
assert ! ( maybe_last_chunk. is_none( ) ) ;
2629
2629
}
2630
+
2631
+ #[ async_test]
2632
+ async fn test_sync_while_back_paginate ( ) {
2633
+ let server = MatrixMockServer :: new ( ) . await ;
2634
+
2635
+ let room_id = room_id ! ( "!galette:saucisse.bzh" ) ;
2636
+ let f = EventFactory :: new ( ) . room ( room_id) . sender ( user_id ! ( "@ben:saucisse.bzh" ) ) ;
2637
+
2638
+ // Previous batch of events which will be received via /messages, in reverse
2639
+ // chronological order.
2640
+ let prev_events = vec ! [
2641
+ f. text_msg( "messages3" ) . event_id( event_id!( "$messages3" ) ) . into_raw_timeline( ) ,
2642
+ f. text_msg( "messages2" ) . event_id( event_id!( "$messages2" ) ) . into_raw_timeline( ) ,
2643
+ f. text_msg( "messages1" ) . event_id( event_id!( "$messages1" ) ) . into_raw_timeline( ) ,
2644
+ ] ;
2645
+
2646
+ // Batch of events which will be received via /sync, in chronological
2647
+ // order.
2648
+ let sync_events = [
2649
+ f. text_msg ( "sync1" ) . event_id ( event_id ! ( "$sync1" ) ) . into_raw_timeline ( ) ,
2650
+ f. text_msg ( "sync2" ) . event_id ( event_id ! ( "$sync2" ) ) . into_raw_timeline ( ) ,
2651
+ f. text_msg ( "sync3" ) . event_id ( event_id ! ( "$sync3" ) ) . into_raw_timeline ( ) ,
2652
+ ] ;
2653
+
2654
+ let state_memory_store = matrix_sdk_base:: store:: MemoryStore :: new ( ) ;
2655
+ let store_config = StoreConfig :: new ( "le_store" . to_owned ( ) )
2656
+ . event_cache_store ( Arc :: new ( MemoryStore :: new ( ) ) )
2657
+ . state_store ( state_memory_store) ;
2658
+
2659
+ {
2660
+ // First, initialize the sync so the client is aware of the room, in the state
2661
+ // store.
2662
+ let client = server. client_builder ( ) . store_config ( store_config. clone ( ) ) . build ( ) . await ;
2663
+ server. sync_joined_room ( & client, room_id) . await ;
2664
+ }
2665
+
2666
+ // Then, use a new client that will restore the state from the state store, and
2667
+ // with an empty event cache store.
2668
+ let client = server. client_builder ( ) . store_config ( store_config) . build ( ) . await ;
2669
+ let room = client. get_room ( room_id) . unwrap ( ) ;
2670
+
2671
+ client. event_cache ( ) . subscribe ( ) . unwrap ( ) ;
2672
+ client. event_cache ( ) . enable_storage ( ) . unwrap ( ) ;
2673
+
2674
+ let ( room_event_cache, _drop_handles) = room. event_cache ( ) . await . unwrap ( ) ;
2675
+ let ( initial_events, mut subscriber) = room_event_cache. subscribe ( ) . await ;
2676
+ assert ! ( initial_events. is_empty( ) ) ;
2677
+
2678
+ // Mock /messages in case we use the prev_batch token from sync.
2679
+ server
2680
+ . mock_room_messages ( )
2681
+ . match_from ( "token-before-sync-from-sync" )
2682
+ . ok ( RoomMessagesResponseTemplate :: default ( )
2683
+ . end_token ( "token-before-messages" )
2684
+ . events ( prev_events) )
2685
+ . named ( "messages" )
2686
+ . mount ( )
2687
+ . await ;
2688
+ // Mock /messages in case we use no token.
2689
+ server
2690
+ . mock_room_messages ( )
2691
+ . ok ( RoomMessagesResponseTemplate :: default ( )
2692
+ . end_token ( "token-before-sync-from-messages" )
2693
+ . events ( sync_events. clone ( ) . into_iter ( ) . rev ( ) . collect ( ) ) )
2694
+ . named ( "messages" )
2695
+ . mount ( )
2696
+ . await ;
2697
+
2698
+ // Spawn back pagination.
2699
+ let pagination = room_event_cache. pagination ( ) ;
2700
+ let back_pagination_handle =
2701
+ spawn ( async move { pagination. run_backwards_once ( 3 ) . await . unwrap ( ) } ) ;
2702
+
2703
+ // Receive a non-limited sync while back pagination is happening.
2704
+ server
2705
+ . sync_room (
2706
+ & client,
2707
+ JoinedRoomBuilder :: new ( room_id)
2708
+ . set_timeline_prev_batch ( "token-before-sync-from-sync" )
2709
+ . add_timeline_bulk ( sync_events. into_iter ( ) . map ( ruma:: serde:: Raw :: cast) ) ,
2710
+ )
2711
+ . await ;
2712
+
2713
+ assert_let_timeout ! (
2714
+ Ok ( RoomEventCacheUpdate :: UpdateTimelineEvents { diffs, .. } ) = subscriber. recv( )
2715
+ ) ;
2716
+ assert_eq ! ( diffs. len( ) , 1 ) ;
2717
+ assert_let ! ( VectorDiff :: Append { values } = & diffs[ 0 ] ) ;
2718
+
2719
+ assert_eq ! ( values. len( ) , 3 ) ;
2720
+ assert_event_matches_msg ( & values[ 0 ] , "sync1" ) ;
2721
+ assert_event_matches_msg ( & values[ 1 ] , "sync2" ) ;
2722
+ assert_event_matches_msg ( & values[ 2 ] , "sync3" ) ;
2723
+
2724
+ // Back pagination should succeed, and we don't have reached the start.
2725
+ let outcome = back_pagination_handle. await . unwrap ( ) ;
2726
+ assert ! ( outcome. reached_start. not( ) ) ;
2727
+ assert_eq ! ( outcome. events. len( ) , 3 ) ;
2728
+
2729
+ // And the back-paginated events come down from the subscriber too.
2730
+ assert_let_timeout ! (
2731
+ Ok ( RoomEventCacheUpdate :: UpdateTimelineEvents { diffs, .. } ) = subscriber. recv( )
2732
+ ) ;
2733
+ assert_eq ! ( diffs. len( ) , 3 ) ;
2734
+ assert_let ! ( VectorDiff :: Insert { index: 0 , value: _ } = & diffs[ 0 ] ) ;
2735
+ assert_let ! ( VectorDiff :: Insert { index: 1 , value: _ } = & diffs[ 1 ] ) ;
2736
+ assert_let ! ( VectorDiff :: Insert { index: 2 , value: _ } = & diffs[ 2 ] ) ;
2737
+
2738
+ assert ! ( subscriber. is_empty( ) ) ;
2739
+ }
0 commit comments