atagen

macltok

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

Blame: tests/mentions_discovery.rs

cbb715e11963atagen2026-10-24 23:24 UTC1
use matrix_sdk::{
cbb715e11963atagen2026-10-24 23:24 UTC2
    Room,
cbb715e11963atagen2026-10-24 23:24 UTC3
    ruma::{
cbb715e11963atagen2026-10-24 23:24 UTC4
        UInt,
cbb715e11963atagen2026-10-24 23:24 UTC5
        api::client::push::get_notifications::v3,
cbb715e11963atagen2026-10-24 23:24 UTC6
        event_id,
cbb715e11963atagen2026-10-24 23:24 UTC7
        events::{AnySyncTimelineEvent, Mentions},
cbb715e11963atagen2026-10-24 23:24 UTC8
        owned_user_id,
cbb715e11963atagen2026-10-24 23:24 UTC9
        push::{Action, EventMatchConditionData, NewConditionalPushRule, PushCondition, Ruleset},
cbb715e11963atagen2026-10-24 23:24 UTC10
        room_id,
cbb715e11963atagen2026-10-24 23:24 UTC11
        serde::Raw,
cbb715e11963atagen2026-10-24 23:24 UTC12
    },
cbb715e11963atagen2026-10-24 23:24 UTC13
    test_utils::mocks::MatrixMockServer,
cbb715e11963atagen2026-10-24 23:24 UTC14
};
cbb715e11963atagen2026-10-24 23:24 UTC15
use matrix_sdk_test::{JoinedRoomBuilder, event_factory::EventFactory};
cbb715e11963atagen2026-10-24 23:24 UTC16
use serde_json::json;
cbb715e11963atagen2026-10-24 23:24 UTC17
use std::time::Duration;
cbb715e11963atagen2026-10-24 23:24 UTC18
use wiremock::{
cbb715e11963atagen2026-10-24 23:24 UTC19
    Mock, ResponseTemplate,
cbb715e11963atagen2026-10-24 23:24 UTC20
    matchers::{method, path, query_param},
cbb715e11963atagen2026-10-24 23:24 UTC21
};
cbb715e11963atagen2026-10-24 23:24 UTC22
cbb715e11963atagen2026-10-24 23:24 UTC23
fn explicit_mention(
cbb715e11963atagen2026-10-24 23:24 UTC24
    room_id: &matrix_sdk::ruma::RoomId,
cbb715e11963atagen2026-10-24 23:24 UTC25
    event_id: &matrix_sdk::ruma::EventId,
cbb715e11963atagen2026-10-24 23:24 UTC26
    sender: &matrix_sdk::ruma::UserId,
cbb715e11963atagen2026-10-24 23:24 UTC27
    mentioned: &matrix_sdk::ruma::UserId,
cbb715e11963atagen2026-10-24 23:24 UTC28
) -> Raw<AnySyncTimelineEvent> {
cbb715e11963atagen2026-10-24 23:24 UTC29
    EventFactory::new()
cbb715e11963atagen2026-10-24 23:24 UTC30
        .room(room_id)
cbb715e11963atagen2026-10-24 23:24 UTC31
        .text_msg("hello")
cbb715e11963atagen2026-10-24 23:24 UTC32
        .mentions(Mentions::with_user_ids([mentioned.to_owned()]))
cbb715e11963atagen2026-10-24 23:24 UTC33
        .event_id(event_id)
cbb715e11963atagen2026-10-24 23:24 UTC34
        .sender(sender)
cbb715e11963atagen2026-10-24 23:24 UTC35
        .into_raw_sync()
cbb715e11963atagen2026-10-24 23:24 UTC36
}
cbb715e11963atagen2026-10-24 23:24 UTC37
cbb715e11963atagen2026-10-24 23:24 UTC38
fn assert_mention_actions(actions: &[Action]) {
cbb715e11963atagen2026-10-24 23:24 UTC39
    assert!(
cbb715e11963atagen2026-10-24 23:24 UTC40
        actions
cbb715e11963atagen2026-10-24 23:24 UTC41
            .iter()
cbb715e11963atagen2026-10-24 23:24 UTC42
            .any(|action| matches!(action, Action::Notify))
cbb715e11963atagen2026-10-24 23:24 UTC43
    );
cbb715e11963atagen2026-10-24 23:24 UTC44
    assert!(actions.iter().any(Action::is_highlight));
cbb715e11963atagen2026-10-24 23:24 UTC45
}
cbb715e11963atagen2026-10-24 23:24 UTC46
cbb715e11963atagen2026-10-24 23:24 UTC47
async fn sync_room_with_mention(
cbb715e11963atagen2026-10-24 23:24 UTC48
    server: &MatrixMockServer,
cbb715e11963atagen2026-10-24 23:24 UTC49
    client: &matrix_sdk::Client,
cbb715e11963atagen2026-10-24 23:24 UTC50
    room_id: &matrix_sdk::ruma::RoomId,
cbb715e11963atagen2026-10-24 23:24 UTC51
    event_id: &matrix_sdk::ruma::EventId,
cbb715e11963atagen2026-10-24 23:24 UTC52
) {
cbb715e11963atagen2026-10-24 23:24 UTC53
    let user_id = client.user_id().unwrap();
cbb715e11963atagen2026-10-24 23:24 UTC54
    let factory = EventFactory::new().room(room_id);
cbb715e11963atagen2026-10-24 23:24 UTC55
    let sender = owned_user_id!("@alice:localhost");
cbb715e11963atagen2026-10-24 23:24 UTC56
    let event = explicit_mention(room_id, event_id, &sender, user_id);
cbb715e11963atagen2026-10-24 23:24 UTC57
    let rules = Ruleset::server_default(user_id);
cbb715e11963atagen2026-10-24 23:24 UTC58
cbb715e11963atagen2026-10-24 23:24 UTC59
    server
cbb715e11963atagen2026-10-24 23:24 UTC60
        .mock_sync()
cbb715e11963atagen2026-10-24 23:24 UTC61
        .ok_and_run(client, |builder| {
cbb715e11963atagen2026-10-24 23:24 UTC62
            builder.add_global_account_data(factory.push_rules(rules));
cbb715e11963atagen2026-10-24 23:24 UTC63
            builder.add_joined_room(
cbb715e11963atagen2026-10-24 23:24 UTC64
                JoinedRoomBuilder::new(room_id)
cbb715e11963atagen2026-10-24 23:24 UTC65
                    .add_state_event(factory.member(user_id))
cbb715e11963atagen2026-10-24 23:24 UTC66
                    .add_timeline_event(event),
cbb715e11963atagen2026-10-24 23:24 UTC67
            );
cbb715e11963atagen2026-10-24 23:24 UTC68
        })
cbb715e11963atagen2026-10-24 23:24 UTC69
        .await;
cbb715e11963atagen2026-10-24 23:24 UTC70
}
cbb715e11963atagen2026-10-24 23:24 UTC71
cbb715e11963atagen2026-10-24 23:24 UTC72
async fn actions_for(room: &Room, event: &Raw<AnySyncTimelineEvent>) -> Option<Vec<Action>> {
cbb715e11963atagen2026-10-24 23:24 UTC73
    room.event_push_actions(event).await.unwrap()
cbb715e11963atagen2026-10-24 23:24 UTC74
}
cbb715e11963atagen2026-10-24 23:24 UTC75
cbb715e11963atagen2026-10-24 23:24 UTC76
#[tokio::test]
cbb715e11963atagen2026-10-24 23:24 UTC77
async fn joined_room_update_exposes_mention_actions_without_opening_a_ui_timeline() {
cbb715e11963atagen2026-10-24 23:24 UTC78
    let server = MatrixMockServer::new().await;
cbb715e11963atagen2026-10-24 23:24 UTC79
    let client = server.client_builder().build().await;
cbb715e11963atagen2026-10-24 23:24 UTC80
    let room_id = room_id!("!mentions:localhost");
cbb715e11963atagen2026-10-24 23:24 UTC81
    let event_id = event_id!("$mention:localhost");
cbb715e11963atagen2026-10-24 23:24 UTC82
    let mut updates = client.subscribe_to_all_room_updates();
cbb715e11963atagen2026-10-24 23:24 UTC83
cbb715e11963atagen2026-10-24 23:24 UTC84
    sync_room_with_mention(&server, &client, room_id, event_id).await;
cbb715e11963atagen2026-10-24 23:24 UTC85
cbb715e11963atagen2026-10-24 23:24 UTC86
    let room_updates = tokio::time::timeout(Duration::from_secs(2), updates.recv())
cbb715e11963atagen2026-10-24 23:24 UTC87
        .await
cbb715e11963atagen2026-10-24 23:24 UTC88
        .unwrap()
cbb715e11963atagen2026-10-24 23:24 UTC89
        .unwrap();
cbb715e11963atagen2026-10-24 23:24 UTC90
    let joined = room_updates
cbb715e11963atagen2026-10-24 23:24 UTC91
        .joined
cbb715e11963atagen2026-10-24 23:24 UTC92
        .get(room_id)
cbb715e11963atagen2026-10-24 23:24 UTC93
        .expect("the joined room update was absent");
cbb715e11963atagen2026-10-24 23:24 UTC94
    let event = joined
cbb715e11963atagen2026-10-24 23:24 UTC95
        .timeline
cbb715e11963atagen2026-10-24 23:24 UTC96
        .events
cbb715e11963atagen2026-10-24 23:24 UTC97
        .iter()
cbb715e11963atagen2026-10-24 23:24 UTC98
        .find(|event| event.event_id().as_deref().map(|id| id.as_str()) == Some(event_id.as_str()))
cbb715e11963atagen2026-10-24 23:24 UTC99
        .expect("the explicit mention was absent from the room update");
cbb715e11963atagen2026-10-24 23:24 UTC100
    let event_json: serde_json::Value =
cbb715e11963atagen2026-10-24 23:24 UTC101
        serde_json::from_str(event.kind.raw().json().get()).unwrap();
cbb715e11963atagen2026-10-24 23:24 UTC102
cbb715e11963atagen2026-10-24 23:24 UTC103
    assert_eq!(
cbb715e11963atagen2026-10-24 23:24 UTC104
        event_json["content"]["m.mentions"]["user_ids"],
cbb715e11963atagen2026-10-24 23:24 UTC105
        json!([client.user_id().unwrap().as_str()])
cbb715e11963atagen2026-10-24 23:24 UTC106
    );
cbb715e11963atagen2026-10-24 23:24 UTC107
    assert_mention_actions(
cbb715e11963atagen2026-10-24 23:24 UTC108
        event
cbb715e11963atagen2026-10-24 23:24 UTC109
            .push_actions()
cbb715e11963atagen2026-10-24 23:24 UTC110
            .expect("push actions were not computed"),
cbb715e11963atagen2026-10-24 23:24 UTC111
    );
cbb715e11963atagen2026-10-24 23:24 UTC112
}
cbb715e11963atagen2026-10-24 23:24 UTC113
cbb715e11963atagen2026-10-24 23:24 UTC114
#[tokio::test]
cbb715e11963atagen2026-10-24 23:24 UTC115
async fn event_cache_generic_update_finds_the_mention_without_opening_a_ui_timeline() {
cbb715e11963atagen2026-10-24 23:24 UTC116
    let server = MatrixMockServer::new().await;
cbb715e11963atagen2026-10-24 23:24 UTC117
    let client = server.client_builder().build().await;
cbb715e11963atagen2026-10-24 23:24 UTC118
    let room_id = room_id!("!cached-mentions:localhost");
cbb715e11963atagen2026-10-24 23:24 UTC119
    let event_id = event_id!("$cached-mention:localhost");
cbb715e11963atagen2026-10-24 23:24 UTC120
    client.event_cache().subscribe().unwrap();
cbb715e11963atagen2026-10-24 23:24 UTC121
    let mut updates = client.event_cache().subscribe_to_room_generic_updates();
cbb715e11963atagen2026-10-24 23:24 UTC122
cbb715e11963atagen2026-10-24 23:24 UTC123
    sync_room_with_mention(&server, &client, room_id, event_id).await;
cbb715e11963atagen2026-10-24 23:24 UTC124
cbb715e11963atagen2026-10-24 23:24 UTC125
    let update = tokio::time::timeout(Duration::from_secs(2), updates.recv())
cbb715e11963atagen2026-10-24 23:24 UTC126
        .await
cbb715e11963atagen2026-10-24 23:24 UTC127
        .unwrap()
cbb715e11963atagen2026-10-24 23:24 UTC128
        .unwrap();
cbb715e11963atagen2026-10-24 23:24 UTC129
    assert_eq!(update.room_id, room_id);
cbb715e11963atagen2026-10-24 23:24 UTC130
    let room = client.get_room(room_id).unwrap();
cbb715e11963atagen2026-10-24 23:24 UTC131
    let (event_cache, _drop_handles) = room.event_cache().await.unwrap();
cbb715e11963atagen2026-10-24 23:24 UTC132
    let event = event_cache.find_event(event_id).await.unwrap().unwrap();
cbb715e11963atagen2026-10-24 23:24 UTC133
    assert_eq!(
cbb715e11963atagen2026-10-24 23:24 UTC134
        event.event_id().as_deref().map(|id| id.as_str()),
cbb715e11963atagen2026-10-24 23:24 UTC135
        Some(event_id.as_str())
cbb715e11963atagen2026-10-24 23:24 UTC136
    );
cbb715e11963atagen2026-10-24 23:24 UTC137
    assert_mention_actions(
cbb715e11963atagen2026-10-24 23:24 UTC138
        event
cbb715e11963atagen2026-10-24 23:24 UTC139
            .push_actions()
cbb715e11963atagen2026-10-24 23:24 UTC140
            .expect("cached push actions were absent"),
cbb715e11963atagen2026-10-24 23:24 UTC141
    );
cbb715e11963atagen2026-10-24 23:24 UTC142
}
cbb715e11963atagen2026-10-24 23:24 UTC143
cbb715e11963atagen2026-10-24 23:24 UTC144
#[tokio::test]
cbb715e11963atagen2026-10-24 23:24 UTC145
async fn ignored_sender_and_muted_room_actions_remain_sdk_push_rule_results() {
cbb715e11963atagen2026-10-24 23:24 UTC146
    let server = MatrixMockServer::new().await;
cbb715e11963atagen2026-10-24 23:24 UTC147
    let client = server.client_builder().build().await;
cbb715e11963atagen2026-10-24 23:24 UTC148
    let ignored_room_id = room_id!("!ignored-sender:localhost");
cbb715e11963atagen2026-10-24 23:24 UTC149
    let muted_room_id = room_id!("!muted-room:localhost");
cbb715e11963atagen2026-10-24 23:24 UTC150
    let ignored_sender = owned_user_id!("@ignored:localhost");
cbb715e11963atagen2026-10-24 23:24 UTC151
    let own_user = client.user_id().unwrap();
cbb715e11963atagen2026-10-24 23:24 UTC152
    let factory = EventFactory::new();
cbb715e11963atagen2026-10-24 23:24 UTC153
    let ignored_event_id = event_id!("$ignored-mention:localhost");
cbb715e11963atagen2026-10-24 23:24 UTC154
    let muted_event_id = event_id!("$muted-message:localhost");
cbb715e11963atagen2026-10-24 23:24 UTC155
    let ignored_event =
cbb715e11963atagen2026-10-24 23:24 UTC156
        explicit_mention(ignored_room_id, ignored_event_id, &ignored_sender, own_user);
cbb715e11963atagen2026-10-24 23:24 UTC157
    let sender = owned_user_id!("@alice:localhost");
cbb715e11963atagen2026-10-24 23:24 UTC158
    let muted_event = explicit_mention(muted_room_id, muted_event_id, &sender, own_user);
cbb715e11963atagen2026-10-24 23:24 UTC159
    let mut rules = Ruleset::server_default(own_user);
cbb715e11963atagen2026-10-24 23:24 UTC160
    rules.override_.shift_insert(
cbb715e11963atagen2026-10-24 23:24 UTC161
        1,
cbb715e11963atagen2026-10-24 23:24 UTC162
        NewConditionalPushRule::new(
cbb715e11963atagen2026-10-24 23:24 UTC163
            "mute-room".to_owned(),
cbb715e11963atagen2026-10-24 23:24 UTC164
            vec![PushCondition::EventMatch(EventMatchConditionData::new(
cbb715e11963atagen2026-10-24 23:24 UTC165
                "room_id".to_owned(),
cbb715e11963atagen2026-10-24 23:24 UTC166
                muted_room_id.to_string(),
cbb715e11963atagen2026-10-24 23:24 UTC167
            ))],
cbb715e11963atagen2026-10-24 23:24 UTC168
            Vec::new(),
cbb715e11963atagen2026-10-24 23:24 UTC169
        )
cbb715e11963atagen2026-10-24 23:24 UTC170
        .into(),
cbb715e11963atagen2026-10-24 23:24 UTC171
    );
cbb715e11963atagen2026-10-24 23:24 UTC172
cbb715e11963atagen2026-10-24 23:24 UTC173
    server
cbb715e11963atagen2026-10-24 23:24 UTC174
        .mock_sync()
cbb715e11963atagen2026-10-24 23:24 UTC175
        .ok_and_run(&client, |builder| {
cbb715e11963atagen2026-10-24 23:24 UTC176
            builder.add_global_account_data(factory.ignored_user_list([ignored_sender.clone()]));
cbb715e11963atagen2026-10-24 23:24 UTC177
            builder.add_global_account_data(factory.push_rules(rules));
cbb715e11963atagen2026-10-24 23:24 UTC178
            builder.add_joined_room(
cbb715e11963atagen2026-10-24 23:24 UTC179
                JoinedRoomBuilder::new(ignored_room_id)
cbb715e11963atagen2026-10-24 23:24 UTC180
                    .add_state_event(EventFactory::new().room(ignored_room_id).member(own_user))
cbb715e11963atagen2026-10-24 23:24 UTC181
                    .add_timeline_event(ignored_event.clone()),
cbb715e11963atagen2026-10-24 23:24 UTC182
            );
cbb715e11963atagen2026-10-24 23:24 UTC183
            builder.add_joined_room(
cbb715e11963atagen2026-10-24 23:24 UTC184
                JoinedRoomBuilder::new(muted_room_id)
cbb715e11963atagen2026-10-24 23:24 UTC185
                    .add_state_event(EventFactory::new().room(muted_room_id).member(own_user))
cbb715e11963atagen2026-10-24 23:24 UTC186
                    .add_timeline_event(muted_event.clone()),
cbb715e11963atagen2026-10-24 23:24 UTC187
            );
cbb715e11963atagen2026-10-24 23:24 UTC188
        })
cbb715e11963atagen2026-10-24 23:24 UTC189
        .await;
cbb715e11963atagen2026-10-24 23:24 UTC190
cbb715e11963atagen2026-10-24 23:24 UTC191
    assert!(client.is_user_ignored(&ignored_sender).await);
cbb715e11963atagen2026-10-24 23:24 UTC192
    let ignored_room = client.get_room(ignored_room_id).unwrap();
cbb715e11963atagen2026-10-24 23:24 UTC193
    let ignored_actions = actions_for(&ignored_room, &ignored_event)
cbb715e11963atagen2026-10-24 23:24 UTC194
        .await
cbb715e11963atagen2026-10-24 23:24 UTC195
        .expect("the ignored sender's push actions could not be computed");
cbb715e11963atagen2026-10-24 23:24 UTC196
    assert_mention_actions(&ignored_actions);
cbb715e11963atagen2026-10-24 23:24 UTC197
cbb715e11963atagen2026-10-24 23:24 UTC198
    let muted_room = client.get_room(muted_room_id).unwrap();
cbb715e11963atagen2026-10-24 23:24 UTC199
    let muted_actions = actions_for(&muted_room, &muted_event)
cbb715e11963atagen2026-10-24 23:24 UTC200
        .await
cbb715e11963atagen2026-10-24 23:24 UTC201
        .expect("the muted room's push actions could not be computed");
cbb715e11963atagen2026-10-24 23:24 UTC202
    assert!(muted_actions.is_empty());
cbb715e11963atagen2026-10-24 23:24 UTC203
}
cbb715e11963atagen2026-10-24 23:24 UTC204
cbb715e11963atagen2026-10-24 23:24 UTC205
#[tokio::test]
cbb715e11963atagen2026-10-24 23:24 UTC206
async fn notifications_v3_request_round_trips_opaque_pagination() {
cbb715e11963atagen2026-10-24 23:24 UTC207
    let server = MatrixMockServer::new().await;
cbb715e11963atagen2026-10-24 23:24 UTC208
    let client = server.client_builder().build().await;
cbb715e11963atagen2026-10-24 23:24 UTC209
    let cursor = "opaque / cursor?x=1&y=2";
cbb715e11963atagen2026-10-24 23:24 UTC210
    let next_cursor = "next / cursor?x=3&y=4";
cbb715e11963atagen2026-10-24 23:24 UTC211
cbb715e11963atagen2026-10-24 23:24 UTC212
    Mock::given(method("GET"))
cbb715e11963atagen2026-10-24 23:24 UTC213
        .and(path("/_matrix/client/v3/notifications"))
cbb715e11963atagen2026-10-24 23:24 UTC214
        .and(query_param("from", cursor))
cbb715e11963atagen2026-10-24 23:24 UTC215
        .and(query_param("limit", "8"))
cbb715e11963atagen2026-10-24 23:24 UTC216
        .and(query_param("only", "highlight"))
cbb715e11963atagen2026-10-24 23:24 UTC217
        .respond_with(ResponseTemplate::new(200).set_body_json(json!({
cbb715e11963atagen2026-10-24 23:24 UTC218
            "next_token": next_cursor,
cbb715e11963atagen2026-10-24 23:24 UTC219
            "notifications": [],
cbb715e11963atagen2026-10-24 23:24 UTC220
        })))
cbb715e11963atagen2026-10-24 23:24 UTC221
        .expect(1)
cbb715e11963atagen2026-10-24 23:24 UTC222
        .mount(server.server())
cbb715e11963atagen2026-10-24 23:24 UTC223
        .await;
cbb715e11963atagen2026-10-24 23:24 UTC224
cbb715e11963atagen2026-10-24 23:24 UTC225
    let mut request = v3::Request::new();
cbb715e11963atagen2026-10-24 23:24 UTC226
    request.from = Some(cursor.to_owned());
cbb715e11963atagen2026-10-24 23:24 UTC227
    request.limit = Some(UInt::new(8).unwrap());
cbb715e11963atagen2026-10-24 23:24 UTC228
    request.only = Some("highlight".to_owned());
cbb715e11963atagen2026-10-24 23:24 UTC229
    let response = client.send(request).await.unwrap();
cbb715e11963atagen2026-10-24 23:24 UTC230
cbb715e11963atagen2026-10-24 23:24 UTC231
    assert_eq!(response.next_token.as_deref(), Some(next_cursor));
cbb715e11963atagen2026-10-24 23:24 UTC232
}