atagen

macltok

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

Blame: tests/mentions_checkpoint.rs

cbb715e11963atagen2026-10-24 23:24 UTC1
use std::{sync::Arc, time::Duration};
cbb715e11963atagen2026-10-24 23:24 UTC2
cbb715e11963atagen2026-10-24 23:24 UTC3
use matrix_sdk::{
cbb715e11963atagen2026-10-24 23:24 UTC4
    Client, Room,
cbb715e11963atagen2026-10-24 23:24 UTC5
    ruma::{api::client::sync::sync_events::v5, events::AnySyncTimelineEvent, room_id, serde::Raw},
cbb715e11963atagen2026-10-24 23:24 UTC6
    sliding_sync::{SlidingSyncList, SlidingSyncMode},
cbb715e11963atagen2026-10-24 23:24 UTC7
    test_utils::mocks::MatrixMockServer,
cbb715e11963atagen2026-10-24 23:24 UTC8
};
cbb715e11963atagen2026-10-24 23:24 UTC9
use serde_json::{Value, json};
cbb715e11963atagen2026-10-24 23:24 UTC10
use tokio::sync::{Notify, Semaphore};
cbb715e11963atagen2026-10-24 23:24 UTC11
cbb715e11963atagen2026-10-24 23:24 UTC12
async fn saved_position(client: &Client) -> Option<String> {
cbb715e11963atagen2026-10-24 23:24 UTC13
    let machine = client.olm_machine_for_testing().await;
cbb715e11963atagen2026-10-24 23:24 UTC14
    let key = format!(
cbb715e11963atagen2026-10-24 23:24 UTC15
        "sliding_sync_store::mentions-spike::{}::instance",
cbb715e11963atagen2026-10-24 23:24 UTC16
        client.user_id().unwrap()
cbb715e11963atagen2026-10-24 23:24 UTC17
    );
cbb715e11963atagen2026-10-24 23:24 UTC18
    let saved = machine
cbb715e11963atagen2026-10-24 23:24 UTC19
        .as_ref()
cbb715e11963atagen2026-10-24 23:24 UTC20
        .unwrap()
cbb715e11963atagen2026-10-24 23:24 UTC21
        .store()
cbb715e11963atagen2026-10-24 23:24 UTC22
        .get_custom_value(&key)
cbb715e11963atagen2026-10-24 23:24 UTC23
        .await
cbb715e11963atagen2026-10-24 23:24 UTC24
        .unwrap()?;
cbb715e11963atagen2026-10-24 23:24 UTC25
    serde_json::from_slice::<Value>(&saved).unwrap()["pos"]
cbb715e11963atagen2026-10-24 23:24 UTC26
        .as_str()
cbb715e11963atagen2026-10-24 23:24 UTC27
        .map(ToOwned::to_owned)
cbb715e11963atagen2026-10-24 23:24 UTC28
}
cbb715e11963atagen2026-10-24 23:24 UTC29
cbb715e11963atagen2026-10-24 23:24 UTC30
async fn server_with_mention() -> (MatrixMockServer, Client) {
cbb715e11963atagen2026-10-24 23:24 UTC31
    let server = MatrixMockServer::new().await;
cbb715e11963atagen2026-10-24 23:24 UTC32
    let client = server.client_builder().build().await;
cbb715e11963atagen2026-10-24 23:24 UTC33
    let mut response = v5::Response::new("position-1".to_owned());
cbb715e11963atagen2026-10-24 23:24 UTC34
    response.rooms.insert(
cbb715e11963atagen2026-10-24 23:24 UTC35
        room_id!("!checkpoint:localhost").to_owned(),
cbb715e11963atagen2026-10-24 23:24 UTC36
        serde_json::from_value(json!({
cbb715e11963atagen2026-10-24 23:24 UTC37
                "initial": true,
cbb715e11963atagen2026-10-24 23:24 UTC38
                "required_state": [],
cbb715e11963atagen2026-10-24 23:24 UTC39
                "timeline": [{
cbb715e11963atagen2026-10-24 23:24 UTC40
                    "type": "m.room.message",
cbb715e11963atagen2026-10-24 23:24 UTC41
                    "event_id": "$checkpoint-mention",
cbb715e11963atagen2026-10-24 23:24 UTC42
                    "sender": "@sender:localhost",
cbb715e11963atagen2026-10-24 23:24 UTC43
                    "origin_server_ts": 1,
cbb715e11963atagen2026-10-24 23:24 UTC44
                    "content": {
cbb715e11963atagen2026-10-24 23:24 UTC45
                        "msgtype": "m.text",
cbb715e11963atagen2026-10-24 23:24 UTC46
                        "body": "checkpoint candidate",
cbb715e11963atagen2026-10-24 23:24 UTC47
                        "m.mentions": { "user_ids": [client.user_id().unwrap()] }
cbb715e11963atagen2026-10-24 23:24 UTC48
                    }
cbb715e11963atagen2026-10-24 23:24 UTC49
                }]
cbb715e11963atagen2026-10-24 23:24 UTC50
        }))
cbb715e11963atagen2026-10-24 23:24 UTC51
        .unwrap(),
cbb715e11963atagen2026-10-24 23:24 UTC52
    );
cbb715e11963atagen2026-10-24 23:24 UTC53
    server.mock_sliding_sync().ok(response).mount().await;
cbb715e11963atagen2026-10-24 23:24 UTC54
    (server, client)
cbb715e11963atagen2026-10-24 23:24 UTC55
}
cbb715e11963atagen2026-10-24 23:24 UTC56
cbb715e11963atagen2026-10-24 23:24 UTC57
async fn new_sync(client: &Client) -> matrix_sdk::sliding_sync::SlidingSync {
cbb715e11963atagen2026-10-24 23:24 UTC58
    client
cbb715e11963atagen2026-10-24 23:24 UTC59
        .sliding_sync("mentions-spike")
cbb715e11963atagen2026-10-24 23:24 UTC60
        .unwrap()
cbb715e11963atagen2026-10-24 23:24 UTC61
        .share_pos()
cbb715e11963atagen2026-10-24 23:24 UTC62
        .add_list(
cbb715e11963atagen2026-10-24 23:24 UTC63
            SlidingSyncList::builder("mentions")
cbb715e11963atagen2026-10-24 23:24 UTC64
                .sync_mode(SlidingSyncMode::new_selective().add_range(0..=0)),
cbb715e11963atagen2026-10-24 23:24 UTC65
        )
cbb715e11963atagen2026-10-24 23:24 UTC66
        .build()
cbb715e11963atagen2026-10-24 23:24 UTC67
        .await
cbb715e11963atagen2026-10-24 23:24 UTC68
        .unwrap()
cbb715e11963atagen2026-10-24 23:24 UTC69
}
cbb715e11963atagen2026-10-24 23:24 UTC70
cbb715e11963atagen2026-10-24 23:24 UTC71
#[tokio::test]
cbb715e11963atagen2026-10-24 23:24 UTC72
async fn awaited_event_handler_fences_position_even_after_caller_cancellation() {
cbb715e11963atagen2026-10-24 23:24 UTC73
    let (server, client) = server_with_mention().await;
cbb715e11963atagen2026-10-24 23:24 UTC74
cbb715e11963atagen2026-10-24 23:24 UTC75
    let entered = Arc::new(Notify::new());
cbb715e11963atagen2026-10-24 23:24 UTC76
    let committed = Arc::new(Semaphore::new(0));
cbb715e11963atagen2026-10-24 23:24 UTC77
    let handler = client.add_event_handler({
cbb715e11963atagen2026-10-24 23:24 UTC78
        let entered = entered.clone();
cbb715e11963atagen2026-10-24 23:24 UTC79
        let committed = committed.clone();
cbb715e11963atagen2026-10-24 23:24 UTC80
        move |event: Raw<AnySyncTimelineEvent>, room: Room| {
cbb715e11963atagen2026-10-24 23:24 UTC81
            let entered = entered.clone();
cbb715e11963atagen2026-10-24 23:24 UTC82
            let committed = committed.clone();
cbb715e11963atagen2026-10-24 23:24 UTC83
            async move {
cbb715e11963atagen2026-10-24 23:24 UTC84
                assert_eq!(room.room_id().as_str(), "!checkpoint:localhost");
cbb715e11963atagen2026-10-24 23:24 UTC85
                assert_eq!(
cbb715e11963atagen2026-10-24 23:24 UTC86
                    event.get_field::<String>("event_id").unwrap().as_deref(),
cbb715e11963atagen2026-10-24 23:24 UTC87
                    Some("$checkpoint-mention")
cbb715e11963atagen2026-10-24 23:24 UTC88
                );
cbb715e11963atagen2026-10-24 23:24 UTC89
                entered.notify_one();
cbb715e11963atagen2026-10-24 23:24 UTC90
                committed.acquire().await.unwrap().forget();
cbb715e11963atagen2026-10-24 23:24 UTC91
            }
cbb715e11963atagen2026-10-24 23:24 UTC92
        }
cbb715e11963atagen2026-10-24 23:24 UTC93
    });
cbb715e11963atagen2026-10-24 23:24 UTC94
    let sync = new_sync(&client).await;
cbb715e11963atagen2026-10-24 23:24 UTC95
    let processing = tokio::spawn(async move { sync.sync_once().await });
cbb715e11963atagen2026-10-24 23:24 UTC96
    tokio::time::timeout(Duration::from_secs(5), entered.notified())
cbb715e11963atagen2026-10-24 23:24 UTC97
        .await
cbb715e11963atagen2026-10-24 23:24 UTC98
        .unwrap();
cbb715e11963atagen2026-10-24 23:24 UTC99
    assert!(!processing.is_finished());
cbb715e11963atagen2026-10-24 23:24 UTC100
    assert!(saved_position(&client).await.is_none());
cbb715e11963atagen2026-10-24 23:24 UTC101
    processing.abort();
cbb715e11963atagen2026-10-24 23:24 UTC102
    assert!(processing.await.unwrap_err().is_cancelled());
cbb715e11963atagen2026-10-24 23:24 UTC103
    assert!(saved_position(&client).await.is_none());
cbb715e11963atagen2026-10-24 23:24 UTC104
cbb715e11963atagen2026-10-24 23:24 UTC105
    committed.add_permits(1);
cbb715e11963atagen2026-10-24 23:24 UTC106
    tokio::time::timeout(Duration::from_secs(5), async {
cbb715e11963atagen2026-10-24 23:24 UTC107
        while saved_position(&client).await.as_deref() != Some("position-1") {
cbb715e11963atagen2026-10-24 23:24 UTC108
            tokio::task::yield_now().await;
cbb715e11963atagen2026-10-24 23:24 UTC109
        }
cbb715e11963atagen2026-10-24 23:24 UTC110
    })
cbb715e11963atagen2026-10-24 23:24 UTC111
    .await
cbb715e11963atagen2026-10-24 23:24 UTC112
    .unwrap();
cbb715e11963atagen2026-10-24 23:24 UTC113
    client.remove_event_handler(handler);
cbb715e11963atagen2026-10-24 23:24 UTC114
cbb715e11963atagen2026-10-24 23:24 UTC115
    let restored = new_sync(&client).await;
cbb715e11963atagen2026-10-24 23:24 UTC116
    tokio::time::timeout(Duration::from_secs(5), restored.sync_once())
cbb715e11963atagen2026-10-24 23:24 UTC117
        .await
cbb715e11963atagen2026-10-24 23:24 UTC118
        .unwrap()
cbb715e11963atagen2026-10-24 23:24 UTC119
        .unwrap();
cbb715e11963atagen2026-10-24 23:24 UTC120
    let requests: Vec<_> = server
cbb715e11963atagen2026-10-24 23:24 UTC121
        .received_requests()
cbb715e11963atagen2026-10-24 23:24 UTC122
        .await
cbb715e11963atagen2026-10-24 23:24 UTC123
        .unwrap()
cbb715e11963atagen2026-10-24 23:24 UTC124
        .into_iter()
cbb715e11963atagen2026-10-24 23:24 UTC125
        .filter_map(|request| {
cbb715e11963atagen2026-10-24 23:24 UTC126
            let body = serde_json::from_slice::<Value>(&request.body).ok()?;
cbb715e11963atagen2026-10-24 23:24 UTC127
            let pos = request
cbb715e11963atagen2026-10-24 23:24 UTC128
                .url
cbb715e11963atagen2026-10-24 23:24 UTC129
                .query_pairs()
cbb715e11963atagen2026-10-24 23:24 UTC130
                .find(|(key, _)| key == "pos")
cbb715e11963atagen2026-10-24 23:24 UTC131
                .map(|(_, value)| value.into_owned());
cbb715e11963atagen2026-10-24 23:24 UTC132
            Some((body, pos))
cbb715e11963atagen2026-10-24 23:24 UTC133
        })
cbb715e11963atagen2026-10-24 23:24 UTC134
        .filter(|(body, _)| body["conn_id"] == "mentions-spike")
cbb715e11963atagen2026-10-24 23:24 UTC135
        .collect();
cbb715e11963atagen2026-10-24 23:24 UTC136
    assert_eq!(requests.len(), 2);
cbb715e11963atagen2026-10-24 23:24 UTC137
    assert!(requests[0].1.is_none());
cbb715e11963atagen2026-10-24 23:24 UTC138
    assert_eq!(requests[1].1.as_deref(), Some("position-1"));
cbb715e11963atagen2026-10-24 23:24 UTC139
}
cbb715e11963atagen2026-10-24 23:24 UTC140
cbb715e11963atagen2026-10-24 23:24 UTC141
#[tokio::test]
cbb715e11963atagen2026-10-24 23:24 UTC142
async fn event_handler_error_does_not_prevent_position_persistence() {
cbb715e11963atagen2026-10-24 23:24 UTC143
    let (_server, client) = server_with_mention().await;
cbb715e11963atagen2026-10-24 23:24 UTC144
    let handler =
cbb715e11963atagen2026-10-24 23:24 UTC145
        client.add_event_handler(|_event: Raw<AnySyncTimelineEvent>, _room: Room| async {
cbb715e11963atagen2026-10-24 23:24 UTC146
            Err::<(), _>("the candidate transaction failed")
cbb715e11963atagen2026-10-24 23:24 UTC147
        });
cbb715e11963atagen2026-10-24 23:24 UTC148
    let sync = new_sync(&client).await;
cbb715e11963atagen2026-10-24 23:24 UTC149
    tokio::time::timeout(Duration::from_secs(5), sync.sync_once())
cbb715e11963atagen2026-10-24 23:24 UTC150
        .await
cbb715e11963atagen2026-10-24 23:24 UTC151
        .unwrap()
cbb715e11963atagen2026-10-24 23:24 UTC152
        .unwrap();
cbb715e11963atagen2026-10-24 23:24 UTC153
    assert_eq!(saved_position(&client).await.as_deref(), Some("position-1"));
cbb715e11963atagen2026-10-24 23:24 UTC154
    client.remove_event_handler(handler);
cbb715e11963atagen2026-10-24 23:24 UTC155
}