@@ -6,7 +6,7 @@ use matrix_sdk::{
66 config:: StoreConfig ,
77 media:: { MediaFormat , MediaRequestParameters , MediaThumbnailSettings } ,
88 send_queue:: {
9- LocalEcho , LocalEchoContent , RoomSendQueueError , RoomSendQueueStorageError ,
9+ LocalEcho , LocalEchoContent , RoomSendQueue , RoomSendQueueError , RoomSendQueueStorageError ,
1010 RoomSendQueueUpdate ,
1111 } ,
1212 test_utils:: {
@@ -40,6 +40,25 @@ use tokio::{
4040} ;
4141use wiremock:: { Request , ResponseTemplate } ;
4242
43+ /// Queues an attachment whenever the actual data/mime type etc. don't matter.
44+ ///
45+ /// Returns the filename, for sanity check purposes.
46+ async fn queue_attachment_no_thumbnail ( q : & RoomSendQueue ) -> & ' static str {
47+ let filename = "surprise.jpeg.exe" ;
48+ let content_type = mime:: IMAGE_JPEG ;
49+ let data = b"hello world" . to_vec ( ) ;
50+ let config = AttachmentConfig :: new ( ) . info ( AttachmentInfo :: Image ( BaseImageInfo {
51+ height : Some ( uint ! ( 13 ) ) ,
52+ width : Some ( uint ! ( 37 ) ) ,
53+ size : Some ( uint ! ( 42 ) ) ,
54+ blurhash : None ,
55+ } ) ) ;
56+ q. send_attachment ( filename, content_type, data, config)
57+ . await
58+ . expect ( "queuing the attachment works" ) ;
59+ filename
60+ }
61+
4362fn mock_jpeg_upload < ' a > (
4463 mock : & ' a MatrixMockServer ,
4564 mxc : & MxcUri ,
@@ -1936,18 +1955,6 @@ async fn test_media_upload_retry() {
19361955 let ( local_echoes, mut watch) = q. subscribe ( ) . await . unwrap ( ) ;
19371956 assert ! ( local_echoes. is_empty( ) ) ;
19381957
1939- // Create the media to send (no thumbnails).
1940- let filename = "surprise.jpeg.exe" ;
1941- let content_type = mime:: IMAGE_JPEG ;
1942- let data = b"hello world" . to_vec ( ) ;
1943-
1944- let config = AttachmentConfig :: new ( ) . info ( AttachmentInfo :: Image ( BaseImageInfo {
1945- height : Some ( uint ! ( 13 ) ) ,
1946- width : Some ( uint ! ( 37 ) ) ,
1947- size : Some ( uint ! ( 42 ) ) ,
1948- blurhash : None ,
1949- } ) ) ;
1950-
19511958 // Prepare endpoints.
19521959 mock. mock_room_state_encryption ( ) . plain ( ) . mount ( ) . await ;
19531960
@@ -1962,9 +1969,7 @@ async fn test_media_upload_retry() {
19621969
19631970 // Send the media.
19641971 assert ! ( watch. is_empty( ) ) ;
1965- q. send_attachment ( filename, content_type, data, config)
1966- . await
1967- . expect ( "queuing the attachment works" ) ;
1972+ let filename = queue_attachment_no_thumbnail ( & q) . await ;
19681973
19691974 // Observe the local echo.
19701975 let ( event_txn, _send_handle, content) = assert_update ! ( watch => local echo event) ;
@@ -2024,18 +2029,6 @@ async fn test_unwedging_media_upload() {
20242029 let ( local_echoes, mut watch) = q. subscribe ( ) . await . unwrap ( ) ;
20252030 assert ! ( local_echoes. is_empty( ) ) ;
20262031
2027- // Create the media to send (no thumbnails).
2028- let filename = "rickroll.gif" ;
2029- let content_type = mime:: IMAGE_JPEG ;
2030- let data = b"Never gonna give you up" . to_vec ( ) ;
2031-
2032- let config = AttachmentConfig :: new ( ) . info ( AttachmentInfo :: Image ( BaseImageInfo {
2033- height : Some ( uint ! ( 13 ) ) ,
2034- width : Some ( uint ! ( 37 ) ) ,
2035- size : Some ( uint ! ( 42 ) ) ,
2036- blurhash : None ,
2037- } ) ) ;
2038-
20392032 // Prepare endpoints.
20402033 mock. mock_room_state_encryption ( ) . plain ( ) . mount ( ) . await ;
20412034
@@ -2045,9 +2038,7 @@ async fn test_unwedging_media_upload() {
20452038
20462039 // Send the media.
20472040 assert ! ( watch. is_empty( ) ) ;
2048- q. send_attachment ( filename, content_type, data, config)
2049- . await
2050- . expect ( "queuing the attachment works" ) ;
2041+ let filename = queue_attachment_no_thumbnail ( & q) . await ;
20512042
20522043 // Observe the local echo.
20532044 let ( event_txn, send_handle, content) = assert_update ! ( watch => local echo event) ;
@@ -2085,3 +2076,74 @@ async fn test_unwedging_media_upload() {
20852076 // That's all, folks!
20862077 assert ! ( watch. is_empty( ) ) ;
20872078}
2079+
2080+ #[ async_test]
2081+ async fn test_media_event_is_sent_in_order ( ) {
2082+ // Test that despite happening in multiple requests, sending a media maintains
2083+ // the ordering.
2084+
2085+ let mock = MatrixMockServer :: new ( ) . await ;
2086+
2087+ // Mark the room as joined.
2088+ let room_id = room_id ! ( "!a:b.c" ) ;
2089+ let client = mock. client_builder ( ) . build ( ) . await ;
2090+ let room = mock. sync_joined_room ( & client, room_id) . await ;
2091+
2092+ let q = room. send_queue ( ) ;
2093+ let ( local_echoes, mut watch) = q. subscribe ( ) . await . unwrap ( ) ;
2094+ assert ! ( local_echoes. is_empty( ) ) ;
2095+
2096+ // Prepare endpoints.
2097+ mock. mock_room_state_encryption ( ) . plain ( ) . mount ( ) . await ;
2098+ mock. mock_upload ( ) . ok ( mxc_uri ! ( "mxc://sdk.rs/media" ) ) . mock_once ( ) . mount ( ) . await ;
2099+
2100+ assert ! ( watch. is_empty( ) ) ;
2101+
2102+ {
2103+ // 1. Send a text message that will get wedged.
2104+ mock. mock_room_send ( ) . error_too_large ( ) . mock_once ( ) . mount ( ) . await ;
2105+ q. send ( RoomMessageEventContent :: text_plain ( "error" ) . into ( ) ) . await . unwrap ( ) ;
2106+ let ( text_txn, _send_handle) = assert_update ! ( watch => local echo { body = "error" } ) ;
2107+ assert_update ! ( watch => error { recoverable = false , txn = text_txn } ) ;
2108+ }
2109+
2110+ // We'll then send a media event, and then a text event with success.
2111+ mock. mock_room_send ( ) . ok ( event_id ! ( "$media" ) ) . mock_once ( ) . mount ( ) . await ;
2112+ mock. mock_room_send ( ) . ok ( event_id ! ( "$text" ) ) . mock_once ( ) . mount ( ) . await ;
2113+
2114+ // 2. Queue the media.
2115+ let filename = queue_attachment_no_thumbnail ( & q) . await ;
2116+
2117+ // 3. Queue the message.
2118+ q. send ( RoomMessageEventContent :: text_plain ( "hello world" ) . into ( ) ) . await . unwrap ( ) ;
2119+
2120+ // Observe the local echo for the media.
2121+ let ( event_txn, _send_handle, content) = assert_update ! ( watch => local echo event) ;
2122+ assert_let ! ( MessageType :: Image ( img_content) = content. msgtype) ;
2123+ assert_eq ! ( img_content. body, filename) ;
2124+
2125+ // Observe the local echo for the message.
2126+ let ( text_txn, _send_handle) = assert_update ! ( watch => local echo { body = "hello world" } ) ;
2127+
2128+ // The media gets uploaded.
2129+ assert_update ! ( watch => uploaded { related_to = event_txn, mxc = mxc_uri!( "mxc://sdk.rs/media" ) } ) ;
2130+
2131+ // The media event gets updated with the final MXC IDs.
2132+ assert_update ! ( watch => edit local echo { txn = event_txn } ) ;
2133+
2134+ // This is the main thing we're testing: the media must be effectively sent
2135+ // *before* the text message, despite implementation details (the media is
2136+ // sent over multiple send queue requests).
2137+
2138+ assert_update ! ( watch => sent { txn = event_txn, event_id = event_id!( "$media" ) } ) ;
2139+ assert_update ! ( watch => sent { txn = text_txn, event_id = event_id!( "$text" ) } ) ;
2140+
2141+ // That's all, folks!
2142+ assert ! ( watch. is_empty( ) ) ;
2143+
2144+ // When reopening the send queue, we still see the wedged event.
2145+ let ( local_echoes, _watch) = q. subscribe ( ) . await . unwrap ( ) ;
2146+ assert_eq ! ( local_echoes. len( ) , 1 ) ;
2147+ assert_let ! ( LocalEchoContent :: Event { send_error, .. } = & local_echoes[ 0 ] . content) ;
2148+ assert ! ( send_error. is_some( ) ) ;
2149+ }
0 commit comments