atagen

macltok

public
Star0
Watch0
62fe32759529d8db8bc39738189399cea0f4511d
3
ssh://brewery@pls.lobotomise.me:33/atagen/macltok.git
tests/nonblocking.rsRust127 lines4.1 KB
1
mod support;
2
3
use std::time::Duration;
4
5
use macltok::{
6
    Command, Engine, EngineConfig, ErrorKind, Event, MediaSize, MessageContent, TimelineCommand,
7
};
8
use matrix_sdk::{
9
    ruma::{api::client::sync::sync_events::v5, mxc_uri, room_id},
10
    test_utils::mocks::MatrixMockServer,
11
};
12
use matrix_sdk_test::{ALICE, JoinedRoomBuilder, event_factory::EventFactory};
13
use support::{event_messages, receive_until, shut_down};
14
use wiremock::ResponseTemplate;
15
16
#[tokio::test]
17
async fn delayed_media_fetch_does_not_block_timeline_command() {
18
    let server = MatrixMockServer::new().await;
19
    server
20
        .mock_sliding_sync()
21
        .ok(v5::Response::new("1".to_owned()))
22
        .mount()
23
        .await;
24
    let client = server.client_builder().build().await;
25
    let sync_client = client.clone();
26
    let room_id = room_id!("!nonblocking:localhost");
27
    server.mock_room_state_encryption().plain().mount().await;
28
    server.sync_joined_room(&client, room_id).await;
29
    let config = EngineConfig::default().with_initial_history_limit(0);
30
    let (engine, handle, mut events) = Engine::from_client(client, config).await.unwrap();
31
    let running = tokio::spawn(engine.run());
32
33
    handle.open_room(room_id.to_owned()).await.unwrap();
34
    receive_until(
35
        &mut events,
36
        |event| matches!(event, Event::TimelineReset { timeline_id: reset, .. } if reset.room_id() == room_id),
37
    )
38
    .await;
39
40
    server
41
        .sync_room(
42
            &sync_client,
43
            JoinedRoomBuilder::new(room_id).add_timeline_event(
44
                EventFactory::new()
45
                    .image(
46
                        "image.jpg".into(),
47
                        mxc_uri!("mxc://localhost/image").to_owned(),
48
                    )
49
                    .sender(&ALICE),
50
            ),
51
        )
52
        .await;
53
    let media_event = receive_until(&mut events, |event| {
54
        event_messages(event)
55
            .into_iter()
56
            .any(|event| support::media_of(event).is_some())
57
    })
58
    .await;
59
    let media_id = event_messages(&media_event)
60
        .into_iter()
61
        .find_map(|event| support::media_of(event).map(|media| media.id.clone()))
62
        .unwrap();
63
64
    let delayed_image = || {
65
        ResponseTemplate::new(200)
66
            .set_body_raw(b"binaryjpegfullimagedata", "image/jpeg")
67
            .set_delay(Duration::from_millis(500))
68
    };
69
    server
70
        .mock_media_download()
71
        .respond_with(delayed_image())
72
        .mount()
73
        .await;
74
    server
75
        .mock_authed_media_download()
76
        .respond_with(delayed_image())
77
        .mount()
78
        .await;
79
80
    // media no longer travels through the command queue, so driving it on its
81
    // own task is what puts the request in flight concurrently with the send below
82
    let media_task = tokio::spawn({
83
        let handle = handle.clone();
84
        async move { handle.media(&media_id, MediaSize::Full).await }
85
    });
86
    wait_for_media_request(&server).await;
87
88
    let error = tokio::time::timeout(
89
        Duration::from_millis(300),
90
        handle.execute(Command::Timeline(TimelineCommand::Send {
91
            timeline_id: room_id.to_owned().into(),
92
            content: MessageContent::text(String::new()),
93
        })),
94
    )
95
    .await
96
    .expect("timeline command was blocked by media fetch")
97
    .expect_err("empty body command unexpectedly succeeded");
98
    assert_eq!(error.kind, ErrorKind::EmptyBody);
99
100
    let media = tokio::time::timeout(Duration::from_secs(2), media_task)
101
        .await
102
        .expect("media fetch did not complete")
103
        .unwrap()
104
        .unwrap();
105
    assert!(!media.bytes.is_empty());
106
107
    shut_down(&handle, &mut events, running).await;
108
}
109
110
async fn wait_for_media_request(server: &MatrixMockServer) {
111
    tokio::time::timeout(Duration::from_secs(2), async {
112
        loop {
113
            if server
114
                .received_requests()
115
                .await
116
                .unwrap()
117
                .iter()
118
                .any(|request| request.url.path().ends_with("/download/localhost/image"))
119
            {
120
                break;
121
            }
122
            tokio::task::yield_now().await;
123
        }
124
    })
125
    .await
126
    .expect("media request did not reach the homeserver");
127
}