@@ -10,12 +10,13 @@ use matrix_sdk::{
10
10
deserialized_responses:: TimelineEvent ,
11
11
event_cache:: {
12
12
BackPaginationOutcome , EventCacheError , RoomEventCacheUpdate , RoomPaginationStatus ,
13
+ ThreadEventCacheUpdate ,
13
14
} ,
14
15
linked_chunk:: { ChunkIdentifier , LinkedChunkId , Position , Update } ,
15
16
store:: StoreConfig ,
16
17
test_utils:: {
17
18
assert_event_matches_msg,
18
- mocks:: { MatrixMockServer , RoomMessagesResponseTemplate } ,
19
+ mocks:: { MatrixMockServer , RoomMessagesResponseTemplate , RoomRelationsResponseTemplate } ,
19
20
} ,
20
21
} ;
21
22
use matrix_sdk_base:: event_cache:: {
@@ -2682,3 +2683,78 @@ async fn test_relations_ordering() {
2682
2683
assert_eq ! ( relations[ 2 ] . event_id( ) . unwrap( ) , edit3) ;
2683
2684
assert_eq ! ( relations[ 3 ] . event_id( ) . unwrap( ) , edit4) ;
2684
2685
}
2686
+
2687
+ #[ async_test]
2688
+ async fn test_thread_can_paginate_even_if_seen_sync_event ( ) {
2689
+ let server = MatrixMockServer :: new ( ) . await ;
2690
+ let client = server. client_builder ( ) . build ( ) . await ;
2691
+
2692
+ let room_id = room_id ! ( "!galette:saucisse.bzh" ) ;
2693
+
2694
+ let event_cache = client. event_cache ( ) ;
2695
+ event_cache. subscribe ( ) . unwrap ( ) ;
2696
+
2697
+ let thread_root_id = event_id ! ( "$thread_root" ) ;
2698
+ let thread_resp_id = event_id ! ( "$thread_resp" ) ;
2699
+
2700
+ // Receive an in-thread event.
2701
+ let f = EventFactory :: new ( ) . room ( room_id) . sender ( * ALICE ) ;
2702
+ let room = server
2703
+ . sync_room (
2704
+ & client,
2705
+ JoinedRoomBuilder :: new ( room_id) . add_timeline_event (
2706
+ f. text_msg ( "that's a good point" )
2707
+ . in_thread ( thread_root_id, thread_root_id)
2708
+ . event_id ( thread_resp_id) ,
2709
+ ) ,
2710
+ )
2711
+ . await ;
2712
+
2713
+ let ( room_event_cache, _drop_handles) = room. event_cache ( ) . await . unwrap ( ) ;
2714
+
2715
+ let ( mut thread_events, mut thread_stream) =
2716
+ room_event_cache. subscribe_to_thread ( thread_root_id. to_owned ( ) ) . await ;
2717
+
2718
+ // Sanity check: the sync event is added to the thread. This is racy because the
2719
+ // update might not have been handled by the event cache yet.
2720
+ let first_event = if thread_events. is_empty ( ) {
2721
+ assert_let_timeout ! ( Ok ( ThreadEventCacheUpdate { diffs, .. } ) = thread_stream. recv( ) ) ;
2722
+ assert_eq ! ( diffs. len( ) , 1 ) ;
2723
+ let mut diffs = diffs;
2724
+ assert_let ! ( VectorDiff :: Append { values } = diffs. remove( 0 ) ) ;
2725
+ assert_eq ! ( values. len( ) , 1 ) ;
2726
+ let mut values = values;
2727
+ values. remove ( 0 )
2728
+ } else {
2729
+ assert_eq ! ( thread_events. len( ) , 1 ) ;
2730
+ thread_events. remove ( 0 )
2731
+ } ;
2732
+ assert_eq ! ( first_event. event_id( ) . as_deref( ) , Some ( thread_resp_id) ) ;
2733
+
2734
+ // It's possible to paginate the thread, and this will push the thread root
2735
+ // because there's no prev-batch token.
2736
+ server
2737
+ . mock_room_relations ( )
2738
+ . match_target_event ( thread_root_id. to_owned ( ) )
2739
+ . ok ( RoomRelationsResponseTemplate :: default ( ) )
2740
+ . mock_once ( )
2741
+ . mount ( )
2742
+ . await ;
2743
+
2744
+ server
2745
+ . mock_room_event ( )
2746
+ . match_event_id ( )
2747
+ . ok ( f. text_msg ( "Thread root" ) . event_id ( thread_root_id) . into ( ) )
2748
+ . mock_once ( )
2749
+ . mount ( )
2750
+ . await ;
2751
+
2752
+ let hit_start =
2753
+ room_event_cache. paginate_thread_backwards ( thread_root_id. to_owned ( ) , 42 ) . await . unwrap ( ) ;
2754
+ assert ! ( hit_start) ;
2755
+
2756
+ assert_let_timeout ! ( Ok ( ThreadEventCacheUpdate { diffs, .. } ) = thread_stream. recv( ) ) ;
2757
+ assert_eq ! ( diffs. len( ) , 1 ) ;
2758
+ assert_let ! ( VectorDiff :: Insert { index: 0 , value } = & diffs[ 0 ] ) ;
2759
+ assert_eq ! ( value. event_id( ) . as_deref( ) , Some ( thread_root_id) ) ;
2760
+ }
0 commit comments