atagen

macltok

public
Star0
Watch0
96fdf90aacd6dc2b8bd3d63773234245b389d28c
3
ssh://brewery@pls.lobotomise.me:33/atagen/macltok.git

Blame: tests/send_queue.rs

96fdf90aacd6atagen2026-09-08 08:24 UTC1
use std::time::Duration;
96fdf90aacd6atagen2026-09-08 08:24 UTC2
96fdf90aacd6atagen2026-09-08 08:24 UTC3
use macltok::{
96fdf90aacd6atagen2026-09-08 08:24 UTC4
    ClientHandle, Command, CommandErrorKind, CommandId, CommandKind, Engine, EngineConfig, Event,
96fdf90aacd6atagen2026-09-08 08:24 UTC5
    EventStream, LifecycleCommand, MessageContent, RoomCommand, TimelineCommand, TimelineItem,
96fdf90aacd6atagen2026-09-08 08:24 UTC6
};
96fdf90aacd6atagen2026-09-08 08:24 UTC7
use matrix_sdk::{
96fdf90aacd6atagen2026-09-08 08:24 UTC8
    Client,
96fdf90aacd6atagen2026-09-08 08:24 UTC9
    ruma::{OwnedTransactionId, RoomId, api::client::sync::sync_events::v5, event_id, room_id},
96fdf90aacd6atagen2026-09-08 08:24 UTC10
    test_utils::mocks::MatrixMockServer,
96fdf90aacd6atagen2026-09-08 08:24 UTC11
};
96fdf90aacd6atagen2026-09-08 08:24 UTC12
96fdf90aacd6atagen2026-09-08 08:24 UTC13
#[tokio::test]
96fdf90aacd6atagen2026-09-08 08:24 UTC14
async fn cancel_send_uses_transaction_id_from_public_timeline() {
96fdf90aacd6atagen2026-09-08 08:24 UTC15
    let (server, client, handle, mut events, running) = setup().await;
96fdf90aacd6atagen2026-09-08 08:24 UTC16
    let room_id = room_id!("!queue-controls:localhost");
96fdf90aacd6atagen2026-09-08 08:24 UTC17
    client.send_queue().set_enabled(false).await;
96fdf90aacd6atagen2026-09-08 08:24 UTC18
96fdf90aacd6atagen2026-09-08 08:24 UTC19
    let transaction_id = queue_message(&handle, &mut events, room_id, "discard me").await;
96fdf90aacd6atagen2026-09-08 08:24 UTC20
    assert!(
96fdf90aacd6atagen2026-09-08 08:24 UTC21
        handle
96fdf90aacd6atagen2026-09-08 08:24 UTC22
            .pending_send_ids(room_id)
96fdf90aacd6atagen2026-09-08 08:24 UTC23
            .await
96fdf90aacd6atagen2026-09-08 08:24 UTC24
            .unwrap()
96fdf90aacd6atagen2026-09-08 08:24 UTC25
            .contains(&transaction_id)
96fdf90aacd6atagen2026-09-08 08:24 UTC26
    );
96fdf90aacd6atagen2026-09-08 08:24 UTC27
    let id = handle
96fdf90aacd6atagen2026-09-08 08:24 UTC28
        .cancel_send(room_id.to_owned(), transaction_id.clone())
96fdf90aacd6atagen2026-09-08 08:24 UTC29
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC30
        .unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC31
    expect_success(&mut events, id, CommandKind::Room).await;
96fdf90aacd6atagen2026-09-08 08:24 UTC32
96fdf90aacd6atagen2026-09-08 08:24 UTC33
    let (echoes, _) = client
96fdf90aacd6atagen2026-09-08 08:24 UTC34
        .get_room(room_id)
96fdf90aacd6atagen2026-09-08 08:24 UTC35
        .unwrap()
96fdf90aacd6atagen2026-09-08 08:24 UTC36
        .send_queue()
96fdf90aacd6atagen2026-09-08 08:24 UTC37
        .subscribe()
96fdf90aacd6atagen2026-09-08 08:24 UTC38
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC39
        .unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC40
    assert!(
96fdf90aacd6atagen2026-09-08 08:24 UTC41
        !echoes
96fdf90aacd6atagen2026-09-08 08:24 UTC42
            .iter()
96fdf90aacd6atagen2026-09-08 08:24 UTC43
            .any(|echo| echo.transaction_id == transaction_id)
96fdf90aacd6atagen2026-09-08 08:24 UTC44
    );
96fdf90aacd6atagen2026-09-08 08:24 UTC45
96fdf90aacd6atagen2026-09-08 08:24 UTC46
    let id = handle
96fdf90aacd6atagen2026-09-08 08:24 UTC47
        .cancel_send(room_id.to_owned(), transaction_id)
96fdf90aacd6atagen2026-09-08 08:24 UTC48
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC49
        .unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC50
    let failure = receive_until(
96fdf90aacd6atagen2026-09-08 08:24 UTC51
        &mut events,
96fdf90aacd6atagen2026-09-08 08:24 UTC52
        |event| matches!(event, Event::CommandFailed(failure) if failure.id == id),
96fdf90aacd6atagen2026-09-08 08:24 UTC53
    )
96fdf90aacd6atagen2026-09-08 08:24 UTC54
    .await;
96fdf90aacd6atagen2026-09-08 08:24 UTC55
    assert!(
96fdf90aacd6atagen2026-09-08 08:24 UTC56
        matches!(failure, Event::CommandFailed(failure) if failure.kind == CommandErrorKind::Other)
96fdf90aacd6atagen2026-09-08 08:24 UTC57
    );
96fdf90aacd6atagen2026-09-08 08:24 UTC58
96fdf90aacd6atagen2026-09-08 08:24 UTC59
    stop(handle, &mut events, running).await;
96fdf90aacd6atagen2026-09-08 08:24 UTC60
    drop(server);
96fdf90aacd6atagen2026-09-08 08:24 UTC61
}
96fdf90aacd6atagen2026-09-08 08:24 UTC62
96fdf90aacd6atagen2026-09-08 08:24 UTC63
#[tokio::test]
96fdf90aacd6atagen2026-09-08 08:24 UTC64
async fn cancel_queued_attachment_by_pending_send_id() {
96fdf90aacd6atagen2026-09-08 08:24 UTC65
    let (server, client, handle, mut events, running) = setup().await;
96fdf90aacd6atagen2026-09-08 08:24 UTC66
    let room_id = room_id!("!queue-controls:localhost");
96fdf90aacd6atagen2026-09-08 08:24 UTC67
    client.send_queue().set_enabled(false).await;
96fdf90aacd6atagen2026-09-08 08:24 UTC68
96fdf90aacd6atagen2026-09-08 08:24 UTC69
    let id = handle
96fdf90aacd6atagen2026-09-08 08:24 UTC70
        .upload_media(
96fdf90aacd6atagen2026-09-08 08:24 UTC71
            room_id.to_owned().into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC72
            "note.txt".to_owned(),
96fdf90aacd6atagen2026-09-08 08:24 UTC73
            "text/plain".to_owned(),
96fdf90aacd6atagen2026-09-08 08:24 UTC74
            b"attachment".to_vec(),
96fdf90aacd6atagen2026-09-08 08:24 UTC75
            None,
96fdf90aacd6atagen2026-09-08 08:24 UTC76
        )
96fdf90aacd6atagen2026-09-08 08:24 UTC77
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC78
        .unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC79
    expect_success(&mut events, id, CommandKind::Media).await;
96fdf90aacd6atagen2026-09-08 08:24 UTC80
96fdf90aacd6atagen2026-09-08 08:24 UTC81
    let pending = handle.pending_send_ids(room_id).await.unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC82
    assert_eq!(pending.len(), 1);
96fdf90aacd6atagen2026-09-08 08:24 UTC83
    let id = handle
96fdf90aacd6atagen2026-09-08 08:24 UTC84
        .cancel_send(room_id.to_owned(), pending[0].clone())
96fdf90aacd6atagen2026-09-08 08:24 UTC85
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC86
        .unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC87
    expect_success(&mut events, id, CommandKind::Room).await;
96fdf90aacd6atagen2026-09-08 08:24 UTC88
    assert!(handle.pending_send_ids(room_id).await.unwrap().is_empty());
96fdf90aacd6atagen2026-09-08 08:24 UTC89
96fdf90aacd6atagen2026-09-08 08:24 UTC90
    stop(handle, &mut events, running).await;
96fdf90aacd6atagen2026-09-08 08:24 UTC91
    drop(server);
96fdf90aacd6atagen2026-09-08 08:24 UTC92
}
96fdf90aacd6atagen2026-09-08 08:24 UTC93
96fdf90aacd6atagen2026-09-08 08:24 UTC94
#[tokio::test]
96fdf90aacd6atagen2026-09-08 08:24 UTC95
async fn retry_send_wakes_paused_queue() {
96fdf90aacd6atagen2026-09-08 08:24 UTC96
    let (server, client, handle, mut events, running) = setup().await;
96fdf90aacd6atagen2026-09-08 08:24 UTC97
    let room_id = room_id!("!queue-controls:localhost");
96fdf90aacd6atagen2026-09-08 08:24 UTC98
    client.send_queue().set_enabled(false).await;
96fdf90aacd6atagen2026-09-08 08:24 UTC99
    server
96fdf90aacd6atagen2026-09-08 08:24 UTC100
        .mock_room_send()
96fdf90aacd6atagen2026-09-08 08:24 UTC101
        .body_matches_partial_json(serde_json::json!({ "body": "retry me" }))
96fdf90aacd6atagen2026-09-08 08:24 UTC102
        .ok(event_id!("$retried:localhost"))
96fdf90aacd6atagen2026-09-08 08:24 UTC103
        .expect(1)
96fdf90aacd6atagen2026-09-08 08:24 UTC104
        .mount()
96fdf90aacd6atagen2026-09-08 08:24 UTC105
        .await;
96fdf90aacd6atagen2026-09-08 08:24 UTC106
96fdf90aacd6atagen2026-09-08 08:24 UTC107
    let transaction_id = queue_message(&handle, &mut events, room_id, "retry me").await;
96fdf90aacd6atagen2026-09-08 08:24 UTC108
    let id = handle
96fdf90aacd6atagen2026-09-08 08:24 UTC109
        .retry_send(room_id.to_owned(), transaction_id)
96fdf90aacd6atagen2026-09-08 08:24 UTC110
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC111
        .unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC112
    expect_success(&mut events, id, CommandKind::Room).await;
96fdf90aacd6atagen2026-09-08 08:24 UTC113
    assert!(client.send_queue().is_enabled());
96fdf90aacd6atagen2026-09-08 08:24 UTC114
96fdf90aacd6atagen2026-09-08 08:24 UTC115
    tokio::time::timeout(Duration::from_secs(5), async {
96fdf90aacd6atagen2026-09-08 08:24 UTC116
        loop {
96fdf90aacd6atagen2026-09-08 08:24 UTC117
            let (echoes, _) = client
96fdf90aacd6atagen2026-09-08 08:24 UTC118
                .get_room(room_id)
96fdf90aacd6atagen2026-09-08 08:24 UTC119
                .unwrap()
96fdf90aacd6atagen2026-09-08 08:24 UTC120
                .send_queue()
96fdf90aacd6atagen2026-09-08 08:24 UTC121
                .subscribe()
96fdf90aacd6atagen2026-09-08 08:24 UTC122
                .await
96fdf90aacd6atagen2026-09-08 08:24 UTC123
                .unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC124
            if echoes.is_empty() {
96fdf90aacd6atagen2026-09-08 08:24 UTC125
                break;
96fdf90aacd6atagen2026-09-08 08:24 UTC126
            }
96fdf90aacd6atagen2026-09-08 08:24 UTC127
            tokio::task::yield_now().await;
96fdf90aacd6atagen2026-09-08 08:24 UTC128
        }
96fdf90aacd6atagen2026-09-08 08:24 UTC129
    })
96fdf90aacd6atagen2026-09-08 08:24 UTC130
    .await
96fdf90aacd6atagen2026-09-08 08:24 UTC131
    .expect("retried message was not sent");
96fdf90aacd6atagen2026-09-08 08:24 UTC132
96fdf90aacd6atagen2026-09-08 08:24 UTC133
    stop(handle, &mut events, running).await;
96fdf90aacd6atagen2026-09-08 08:24 UTC134
    drop(server);
96fdf90aacd6atagen2026-09-08 08:24 UTC135
}
96fdf90aacd6atagen2026-09-08 08:24 UTC136
96fdf90aacd6atagen2026-09-08 08:24 UTC137
async fn setup() -> (
96fdf90aacd6atagen2026-09-08 08:24 UTC138
    MatrixMockServer,
96fdf90aacd6atagen2026-09-08 08:24 UTC139
    Client,
96fdf90aacd6atagen2026-09-08 08:24 UTC140
    ClientHandle,
96fdf90aacd6atagen2026-09-08 08:24 UTC141
    EventStream,
96fdf90aacd6atagen2026-09-08 08:24 UTC142
    tokio::task::JoinHandle<Result<(), macltok::EngineError>>,
96fdf90aacd6atagen2026-09-08 08:24 UTC143
) {
96fdf90aacd6atagen2026-09-08 08:24 UTC144
    let server = MatrixMockServer::new().await;
96fdf90aacd6atagen2026-09-08 08:24 UTC145
    server
96fdf90aacd6atagen2026-09-08 08:24 UTC146
        .mock_sliding_sync()
96fdf90aacd6atagen2026-09-08 08:24 UTC147
        .ok(v5::Response::new("1".to_owned()))
96fdf90aacd6atagen2026-09-08 08:24 UTC148
        .mount()
96fdf90aacd6atagen2026-09-08 08:24 UTC149
        .await;
96fdf90aacd6atagen2026-09-08 08:24 UTC150
    let client = server.client_builder().build().await;
96fdf90aacd6atagen2026-09-08 08:24 UTC151
    let room_id = room_id!("!queue-controls:localhost");
96fdf90aacd6atagen2026-09-08 08:24 UTC152
    server.mock_room_state_encryption().plain().mount().await;
96fdf90aacd6atagen2026-09-08 08:24 UTC153
    server.sync_joined_room(&client, room_id).await;
96fdf90aacd6atagen2026-09-08 08:24 UTC154
    let (engine, handle, events) = Engine::from_client(
96fdf90aacd6atagen2026-09-08 08:24 UTC155
        client.clone(),
96fdf90aacd6atagen2026-09-08 08:24 UTC156
        EngineConfig::default().with_initial_history_limit(0),
96fdf90aacd6atagen2026-09-08 08:24 UTC157
    )
96fdf90aacd6atagen2026-09-08 08:24 UTC158
    .await
96fdf90aacd6atagen2026-09-08 08:24 UTC159
    .unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC160
    let running = tokio::spawn(engine.run());
96fdf90aacd6atagen2026-09-08 08:24 UTC161
    let mut events = events;
96fdf90aacd6atagen2026-09-08 08:24 UTC162
    let id = handle
96fdf90aacd6atagen2026-09-08 08:24 UTC163
        .send(Command::Room(RoomCommand::Open(room_id.to_owned())))
96fdf90aacd6atagen2026-09-08 08:24 UTC164
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC165
        .unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC166
    expect_success(&mut events, id, CommandKind::Room).await;
96fdf90aacd6atagen2026-09-08 08:24 UTC167
    (server, client, handle, events, running)
96fdf90aacd6atagen2026-09-08 08:24 UTC168
}
96fdf90aacd6atagen2026-09-08 08:24 UTC169
96fdf90aacd6atagen2026-09-08 08:24 UTC170
async fn queue_message(
96fdf90aacd6atagen2026-09-08 08:24 UTC171
    handle: &ClientHandle,
96fdf90aacd6atagen2026-09-08 08:24 UTC172
    events: &mut EventStream,
96fdf90aacd6atagen2026-09-08 08:24 UTC173
    room_id: &RoomId,
96fdf90aacd6atagen2026-09-08 08:24 UTC174
    body: &str,
96fdf90aacd6atagen2026-09-08 08:24 UTC175
) -> OwnedTransactionId {
96fdf90aacd6atagen2026-09-08 08:24 UTC176
    let id = handle
96fdf90aacd6atagen2026-09-08 08:24 UTC177
        .send(Command::Timeline(TimelineCommand::Send {
96fdf90aacd6atagen2026-09-08 08:24 UTC178
            timeline_id: room_id.to_owned().into(),
96fdf90aacd6atagen2026-09-08 08:24 UTC179
            content: MessageContent::text(body),
96fdf90aacd6atagen2026-09-08 08:24 UTC180
        }))
96fdf90aacd6atagen2026-09-08 08:24 UTC181
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC182
        .unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC183
    let mut succeeded = false;
96fdf90aacd6atagen2026-09-08 08:24 UTC184
    let mut items = Vec::new();
96fdf90aacd6atagen2026-09-08 08:24 UTC185
    tokio::time::timeout(Duration::from_secs(5), async {
96fdf90aacd6atagen2026-09-08 08:24 UTC186
        loop {
96fdf90aacd6atagen2026-09-08 08:24 UTC187
            match events.recv().await.expect("event stream closed") {
96fdf90aacd6atagen2026-09-08 08:24 UTC188
                Event::TimelineChanged { diffs, .. } => {
96fdf90aacd6atagen2026-09-08 08:24 UTC189
                    for diff in diffs {
96fdf90aacd6atagen2026-09-08 08:24 UTC190
                        diff.try_apply(&mut items).unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC191
                    }
96fdf90aacd6atagen2026-09-08 08:24 UTC192
                    let transaction = items.iter().find_map(|item| match item {
96fdf90aacd6atagen2026-09-08 08:24 UTC193
                        TimelineItem::Message(message) if message.body == body => {
96fdf90aacd6atagen2026-09-08 08:24 UTC194
                            message.transaction_id.clone()
96fdf90aacd6atagen2026-09-08 08:24 UTC195
                        }
96fdf90aacd6atagen2026-09-08 08:24 UTC196
                        _ => None,
96fdf90aacd6atagen2026-09-08 08:24 UTC197
                    });
96fdf90aacd6atagen2026-09-08 08:24 UTC198
                    if let Some(transaction) = transaction {
96fdf90aacd6atagen2026-09-08 08:24 UTC199
                        if !succeeded {
96fdf90aacd6atagen2026-09-08 08:24 UTC200
                            expect_success(events, id, CommandKind::Timeline).await;
96fdf90aacd6atagen2026-09-08 08:24 UTC201
                        }
96fdf90aacd6atagen2026-09-08 08:24 UTC202
                        return transaction;
96fdf90aacd6atagen2026-09-08 08:24 UTC203
                    }
96fdf90aacd6atagen2026-09-08 08:24 UTC204
                }
96fdf90aacd6atagen2026-09-08 08:24 UTC205
                Event::CommandSucceeded {
96fdf90aacd6atagen2026-09-08 08:24 UTC206
                    id: completed,
96fdf90aacd6atagen2026-09-08 08:24 UTC207
                    command: CommandKind::Timeline,
96fdf90aacd6atagen2026-09-08 08:24 UTC208
                } if completed == id => succeeded = true,
96fdf90aacd6atagen2026-09-08 08:24 UTC209
                Event::CommandFailed(failure) if failure.id == id => {
96fdf90aacd6atagen2026-09-08 08:24 UTC210
                    panic!("send failed {failure:?}")
96fdf90aacd6atagen2026-09-08 08:24 UTC211
                }
96fdf90aacd6atagen2026-09-08 08:24 UTC212
                _ => {}
96fdf90aacd6atagen2026-09-08 08:24 UTC213
            }
96fdf90aacd6atagen2026-09-08 08:24 UTC214
        }
96fdf90aacd6atagen2026-09-08 08:24 UTC215
    })
96fdf90aacd6atagen2026-09-08 08:24 UTC216
    .await
96fdf90aacd6atagen2026-09-08 08:24 UTC217
    .expect("local echo did not appear")
96fdf90aacd6atagen2026-09-08 08:24 UTC218
}
96fdf90aacd6atagen2026-09-08 08:24 UTC219
96fdf90aacd6atagen2026-09-08 08:24 UTC220
async fn expect_success(events: &mut EventStream, id: CommandId, command: CommandKind) {
96fdf90aacd6atagen2026-09-08 08:24 UTC221
    receive_until(events, |event| {
96fdf90aacd6atagen2026-09-08 08:24 UTC222
        matches!(event, Event::CommandSucceeded { id: completed, command: kind } if *completed == id && *kind == command)
96fdf90aacd6atagen2026-09-08 08:24 UTC223
    })
96fdf90aacd6atagen2026-09-08 08:24 UTC224
    .await;
96fdf90aacd6atagen2026-09-08 08:24 UTC225
}
96fdf90aacd6atagen2026-09-08 08:24 UTC226
96fdf90aacd6atagen2026-09-08 08:24 UTC227
async fn receive_until(events: &mut EventStream, predicate: impl Fn(&Event) -> bool) -> Event {
96fdf90aacd6atagen2026-09-08 08:24 UTC228
    tokio::time::timeout(Duration::from_secs(5), async {
96fdf90aacd6atagen2026-09-08 08:24 UTC229
        loop {
96fdf90aacd6atagen2026-09-08 08:24 UTC230
            let event = events.recv().await.expect("event stream closed");
96fdf90aacd6atagen2026-09-08 08:24 UTC231
            if predicate(&event) {
96fdf90aacd6atagen2026-09-08 08:24 UTC232
                return event;
96fdf90aacd6atagen2026-09-08 08:24 UTC233
            }
96fdf90aacd6atagen2026-09-08 08:24 UTC234
        }
96fdf90aacd6atagen2026-09-08 08:24 UTC235
    })
96fdf90aacd6atagen2026-09-08 08:24 UTC236
    .await
96fdf90aacd6atagen2026-09-08 08:24 UTC237
    .expect("expected event did not arrive")
96fdf90aacd6atagen2026-09-08 08:24 UTC238
}
96fdf90aacd6atagen2026-09-08 08:24 UTC239
96fdf90aacd6atagen2026-09-08 08:24 UTC240
async fn stop(
96fdf90aacd6atagen2026-09-08 08:24 UTC241
    handle: ClientHandle,
96fdf90aacd6atagen2026-09-08 08:24 UTC242
    events: &mut EventStream,
96fdf90aacd6atagen2026-09-08 08:24 UTC243
    running: tokio::task::JoinHandle<Result<(), macltok::EngineError>>,
96fdf90aacd6atagen2026-09-08 08:24 UTC244
) {
96fdf90aacd6atagen2026-09-08 08:24 UTC245
    let id = handle
96fdf90aacd6atagen2026-09-08 08:24 UTC246
        .send(Command::Lifecycle(LifecycleCommand::Shutdown))
96fdf90aacd6atagen2026-09-08 08:24 UTC247
        .await
96fdf90aacd6atagen2026-09-08 08:24 UTC248
        .unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC249
    expect_success(events, id, CommandKind::Lifecycle).await;
96fdf90aacd6atagen2026-09-08 08:24 UTC250
    running.await.unwrap().unwrap();
96fdf90aacd6atagen2026-09-08 08:24 UTC251
}