@@ -12,7 +12,9 @@ use matrix_sdk::{
12
12
use matrix_sdk_base:: deserialized_responses:: TimelineEvent ;
13
13
use matrix_sdk_test:: { async_test, JoinedRoomBuilder , StateTestEvent , SyncResponseBuilder , BOB } ;
14
14
use matrix_sdk_ui:: {
15
- timeline:: { TimelineFocus , TimelineItemContent } ,
15
+ timeline:: {
16
+ RoomExt , TimelineFocus , TimelineItemContent , MAX_PINNED_EVENTS_CONCURRENT_REQUESTS ,
17
+ } ,
16
18
Timeline ,
17
19
} ;
18
20
use ruma:: {
@@ -21,7 +23,11 @@ use ruma::{
21
23
} ;
22
24
use serde_json:: json;
23
25
use stream_assert:: assert_pending;
24
- use wiremock:: MockServer ;
26
+ use tokio:: time:: sleep;
27
+ use wiremock:: {
28
+ matchers:: { header, method, path_regex} ,
29
+ Mock , MockServer , ResponseTemplate ,
30
+ } ;
25
31
26
32
use crate :: { mock_event, mock_sync} ;
27
33
@@ -635,6 +641,78 @@ async fn test_edited_events_survive_pinned_event_ids_change() {
635
641
assert_pending ! ( timeline_stream) ;
636
642
}
637
643
644
+ #[ async_test]
645
+ async fn test_ensure_max_concurrency_is_observed ( ) {
646
+ let ( client, server) = logged_in_client_with_server ( ) . await ;
647
+ let room_id = owned_room_id ! ( "!a_room:example.org" ) ;
648
+
649
+ let pinned_event_ids: Vec < String > = ( 0 ..100 ) . map ( |idx| format ! ( "${idx}" ) ) . collect ( ) ;
650
+
651
+ let joined_room_builder = JoinedRoomBuilder :: new ( & room_id)
652
+ // Set up encryption
653
+ . add_state_event ( StateTestEvent :: Encryption )
654
+ // Add 100 pinned events
655
+ . add_state_event ( StateTestEvent :: Custom ( json ! (
656
+ {
657
+ "content" : {
658
+ "pinned" : pinned_event_ids
659
+ } ,
660
+ "event_id" : "$15139375513VdeRF:localhost" ,
661
+ "origin_server_ts" : 151393755 ,
662
+ "sender" : "@example:localhost" ,
663
+ "state_key" : "" ,
664
+ "type" : "m.room.pinned_events" ,
665
+ "unsigned" : {
666
+ "age" : 703422
667
+ }
668
+ }
669
+ ) ) ) ;
670
+
671
+ // Amount of time to delay the response of an /event mock request, in ms.
672
+ let request_delay = 50 ;
673
+ let pinned_event =
674
+ EventFactory :: new ( ) . room ( & room_id) . sender ( * BOB ) . text_msg ( "A message" ) . into_raw_timeline ( ) ;
675
+ Mock :: given ( method ( "GET" ) )
676
+ . and ( path_regex ( r"/_matrix/client/r0/rooms/.*/event/.*" ) )
677
+ . and ( header ( "authorization" , "Bearer 1234" ) )
678
+ . respond_with (
679
+ ResponseTemplate :: new ( 200 )
680
+ . set_delay ( Duration :: from_millis ( request_delay) )
681
+ . set_body_json ( pinned_event. json ( ) ) ,
682
+ )
683
+ // Verify this endpoint is only called the max concurrent amount of times.
684
+ . expect ( MAX_PINNED_EVENTS_CONCURRENT_REQUESTS as u64 )
685
+ . mount ( & server)
686
+ . await ;
687
+
688
+ let mut sync_response_builder = SyncResponseBuilder :: new ( ) ;
689
+ let sync_settings = SyncSettings :: new ( ) . timeout ( Duration :: from_millis ( 3000 ) ) ;
690
+ let json_response =
691
+ sync_response_builder. add_joined_room ( joined_room_builder) . build_json_sync_response ( ) ;
692
+ mock_sync ( & server, json_response, None ) . await ;
693
+ let _ = client. sync_once ( sync_settings. clone ( ) ) . await ;
694
+
695
+ let room = client. get_room ( & room_id) . unwrap ( ) ;
696
+
697
+ // Start loading the pinned event timeline asynchronously.
698
+ let handle = tokio:: spawn ( {
699
+ let timeline_builder = room
700
+ . timeline_builder ( )
701
+ . with_focus ( TimelineFocus :: PinnedEvents { max_events_to_load : 100 } ) ;
702
+ async {
703
+ let _ = timeline_builder. build ( ) . await ;
704
+ }
705
+ } ) ;
706
+
707
+ // Give it time to load events. As each request takes `request_delay`, we should
708
+ // have exactly `MAX_PINNED_EVENTS_CONCURRENT_REQUESTS` if the max
709
+ // concurrency setting is honoured.
710
+ sleep ( Duration :: from_millis ( request_delay / 2 ) ) . await ;
711
+
712
+ // Abort handle to stop requests from being processed.
713
+ handle. abort ( ) ;
714
+ }
715
+
638
716
struct TestHelper {
639
717
pub client : Client ,
640
718
pub server : MockServer ,
0 commit comments