Skip to content

Commit

Permalink
test(send queue): add a test for the ordering of media vs other events
Browse files Browse the repository at this point in the history
  • Loading branch information
bnjbvr committed Nov 13, 2024
1 parent 0509236 commit 1cde8af
Showing 1 changed file with 104 additions and 16 deletions.
120 changes: 104 additions & 16 deletions crates/matrix-sdk/tests/integration/send_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use matrix_sdk::{
config::StoreConfig,
media::{MediaFormat, MediaRequestParameters, MediaThumbnailSettings},
send_queue::{
LocalEcho, LocalEchoContent, RoomSendQueueError, RoomSendQueueStorageError,
LocalEcho, LocalEchoContent, RoomSendQueue, RoomSendQueueError, RoomSendQueueStorageError,
RoomSendQueueUpdate,
},
test_utils::{
Expand Down Expand Up @@ -40,6 +40,25 @@ use tokio::{
};
use wiremock::{Request, ResponseTemplate};

/// Queues an attachment whenever the actual data/mime type etc. don't matter.
///
/// Returns the filename, for sanity check purposes.
async fn queue_attachment_no_thumbnail(q: &RoomSendQueue) -> &'static str {
let filename = "surprise.jpeg.exe";
let content_type = mime::IMAGE_JPEG;
let data = b"hello world".to_vec();
let config = AttachmentConfig::new().info(AttachmentInfo::Image(BaseImageInfo {
height: Some(uint!(13)),
width: Some(uint!(37)),
size: Some(uint!(42)),
blurhash: None,
}));
q.send_attachment(filename, content_type, data, config)
.await
.expect("queuing the attachment works");
filename
}

fn mock_jpeg_upload<'a>(
mock: &'a MatrixMockServer,
mxc: &MxcUri,
Expand Down Expand Up @@ -1936,18 +1955,6 @@ async fn test_media_upload_retry() {
let (local_echoes, mut watch) = q.subscribe().await.unwrap();
assert!(local_echoes.is_empty());

// Create the media to send (no thumbnails).
let filename = "surprise.jpeg.exe";
let content_type = mime::IMAGE_JPEG;
let data = b"hello world".to_vec();

let config = AttachmentConfig::new().info(AttachmentInfo::Image(BaseImageInfo {
height: Some(uint!(13)),
width: Some(uint!(37)),
size: Some(uint!(42)),
blurhash: None,
}));

// Prepare endpoints.
mock.mock_room_state_encryption().plain().mount().await;

Expand All @@ -1962,9 +1969,7 @@ async fn test_media_upload_retry() {

// Send the media.
assert!(watch.is_empty());
q.send_attachment(filename, content_type, data, config)
.await
.expect("queuing the attachment works");
let filename = queue_attachment_no_thumbnail(&q).await;

// Observe the local echo.
let (event_txn, _send_handle, content) = assert_update!(watch => local echo event);
Expand Down Expand Up @@ -2010,3 +2015,86 @@ async fn test_media_upload_retry() {
// That's all, folks!
assert!(watch.is_empty());
}

#[async_test]
async fn test_media_upload_ordering() {
// Test that despite happening in multiple requests, sending a media maintains
// the ordering.

let mock = MatrixMockServer::new().await;

// Mark the room as joined.
let room_id = room_id!("!a:b.c");
let client = mock.client_builder().build().await;
let room = mock.sync_joined_room(&client, room_id).await;

let q = room.send_queue();
let (local_echoes, mut watch) = q.subscribe().await.unwrap();
assert!(local_echoes.is_empty());

// Prepare endpoints.
mock.mock_room_state_encryption().plain().mount().await;
mock.mock_upload().ok(mxc_uri!("mxc://sdk.rs/media")).mock_once().mount().await;

assert!(watch.is_empty());

{
// 1. Send a text message that will get wedged.
mock.mock_room_send().error_too_large().mock_once().mount().await;
q.send(RoomMessageEventContent::text_plain("error").into()).await.unwrap();
let (text_txn, _send_handle) = assert_update!(watch => local echo { body = "error" });
assert_update!(watch => error { recoverable = false, txn = text_txn });
}

// We'll then send a media event, and then a text event with success.
mock.mock_room_send().ok(event_id!("$media")).mock_once().mount().await;
mock.mock_room_send().ok(event_id!("$text")).mock_once().mount().await;

// 2. Queue the media.
let filename = queue_attachment_no_thumbnail(&q).await;

// 3. Queue the message.
q.send(RoomMessageEventContent::text_plain("hello world").into()).await.unwrap();

// Observe the local echo for the media.
let (event_txn, _send_handle, content) = assert_update!(watch => local echo event);
assert_let!(MessageType::Image(img_content) = content.msgtype);
assert_eq!(img_content.body, filename);

// Observe the local echo for the message.
let (text_txn, _send_handle) = assert_update!(watch => local echo { body = "hello world" });

// The media gets uploaded.
assert_update!(watch => uploaded {
related_to = event_txn,
mxc = mxc_uri!("mxc://sdk.rs/media")
});

let edit_msg = assert_update!(watch => edit local echo {
txn = event_txn
});
assert_let!(MessageType::Image(new_content) = edit_msg.msgtype);
assert_let!(MediaSource::Plain(new_uri) = &new_content.source);
assert_eq!(new_uri, mxc_uri!("mxc://sdk.rs/media"));

// The media event is sent, at some point.
assert_update!(watch => sent {
txn = event_txn,
event_id = event_id!("$media")
});

// Then the text event is sent.
assert_update!(watch => sent {
txn = text_txn,
event_id = event_id!("$text")
});

// That's all, folks!
assert!(watch.is_empty());

// When reopening the send queue, we still see the wedged event.
let (local_echoes, _watch) = q.subscribe().await.unwrap();
assert_eq!(local_echoes.len(), 1);
assert_let!(LocalEchoContent::Event { send_error, .. } = &local_echoes[0].content);
assert!(send_error.is_some());
}

0 comments on commit 1cde8af

Please sign in to comment.