@@ -9,7 +9,7 @@ use std::{
99use assert_matches2:: { assert_let, assert_matches} ;
1010use matrix_sdk:: {
1111 send_queue:: { LocalEcho , RoomSendQueueError , RoomSendQueueUpdate } ,
12- test_utils:: logged_in_client_with_server,
12+ test_utils:: { logged_in_client , logged_in_client_with_server} ,
1313} ;
1414use matrix_sdk_test:: { async_test, InvitedRoomBuilder , JoinedRoomBuilder , LeftRoomBuilder } ;
1515use ruma:: {
@@ -974,3 +974,77 @@ async fn test_unrecoverable_errors() {
974974 assert ! ( room. send_queue( ) . is_enabled( ) ) ;
975975 assert ! ( client. send_queue( ) . is_enabled( ) ) ;
976976}
977+
978+ #[ async_test]
979+ async fn test_no_network_access_error_is_recoverable ( ) {
980+ // This is subtle, but for the `drop(server)` below to be effectful, it needs to
981+ // not be a pooled wiremock server (the default), which will keep the dropped
982+ // server in a static. Using the line below will create a "bare" server,
983+ // which is effectively dropped upon `drop()`.
984+ let server = wiremock:: MockServer :: builder ( ) . start ( ) . await ;
985+
986+ let client = logged_in_client ( Some ( server. uri ( ) . to_string ( ) ) ) . await ;
987+
988+ // Mark the room as joined.
989+ let room_id = room_id ! ( "!a:b.c" ) ;
990+
991+ let room = mock_sync_with_new_room (
992+ |builder| {
993+ builder. add_joined_room ( JoinedRoomBuilder :: new ( room_id) ) ;
994+ } ,
995+ & client,
996+ & server,
997+ room_id,
998+ )
999+ . await ;
1000+
1001+ // Dropping the server: any subsequent attempt to connect mimics an unreachable
1002+ // server, which might be caused by missing network.
1003+ drop ( server) ;
1004+
1005+ let mut errors = client. send_queue ( ) . subscribe_errors ( ) ;
1006+ assert ! ( errors. is_empty( ) ) ;
1007+
1008+ // Start with an enabled sending queue.
1009+ client. send_queue ( ) . set_enabled ( true ) ;
1010+ assert ! ( client. send_queue( ) . is_enabled( ) ) ;
1011+
1012+ let q = room. send_queue ( ) ;
1013+ let ( local_echoes, mut watch) = q. subscribe ( ) . await ;
1014+
1015+ assert ! ( local_echoes. is_empty( ) ) ;
1016+ assert ! ( watch. is_empty( ) ) ;
1017+
1018+ // Queue two messages.
1019+ q. send ( RoomMessageEventContent :: text_plain ( "is there anyone around here" ) . into ( ) )
1020+ . await
1021+ . unwrap ( ) ;
1022+
1023+ // First message is seen as a local echo.
1024+ assert_let ! (
1025+ Ok ( Ok ( RoomSendQueueUpdate :: NewLocalEvent ( LocalEcho {
1026+ content: AnyMessageLikeEventContent :: RoomMessage ( msg) ,
1027+ transaction_id: txn1,
1028+ ..
1029+ } ) ) ) = timeout( Duration :: from_secs( 1 ) , watch. recv( ) ) . await
1030+ ) ;
1031+ assert_eq ! ( msg. body( ) , format!( "is there anyone around here" ) ) ;
1032+
1033+ // There will be an error report for the first message, indicating that the
1034+ // error is recoverable: because network is unreachable.
1035+ let report = errors. recv ( ) . await . unwrap ( ) ;
1036+ assert_eq ! ( report. room_id, room. room_id( ) ) ;
1037+ assert ! ( report. is_recoverable) ;
1038+
1039+ // The room updates will report the error for the first message as recoverable
1040+ // too.
1041+ assert_let ! (
1042+ Ok ( Ok ( RoomSendQueueUpdate :: SendError { is_recoverable: true , transaction_id, .. } ) ) =
1043+ timeout( Duration :: from_secs( 1 ) , watch. recv( ) ) . await
1044+ ) ;
1045+ assert_eq ! ( transaction_id, txn1) ;
1046+
1047+ // The room queue is disabled, because the error was recoverable.
1048+ assert ! ( !room. send_queue( ) . is_enabled( ) ) ;
1049+ assert ! ( client. send_queue( ) . is_enabled( ) ) ;
1050+ }
0 commit comments