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