use assert_matches2::assert_matches;
use matrix_sdk::{
notification_settings::RoomNotificationMode,
room::ThreadSubscription,
test_utils::mocks::{MatrixMockServer, PushRuleIdSpec},
};
use matrix_sdk_test::{ALICE, JoinedRoomBuilder, async_test, event_factory::EventFactory};
use ruma::{event_id, owned_event_id, push::RuleKind, room_id};
#[async_test]
async fn test_subscribe_thread() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let room_id = room_id!("!test:example.org");
let room = server.sync_joined_room(&client, room_id).await;
let root_id = owned_event_id!("$root");
server
.mock_room_put_thread_subscription()
.match_room_id(room_id.to_owned())
.match_thread_id(root_id.clone())
.ok()
.mock_once()
.mount()
.await;
room.subscribe_thread(root_id.clone(), Some(root_id.clone())).await.unwrap();
server
.mock_room_get_thread_subscription()
.match_room_id(room_id.to_owned())
.match_thread_id(root_id.clone())
.ok(true)
.mock_once()
.mount()
.await;
let subscription = room.fetch_thread_subscription(root_id.clone()).await.unwrap().unwrap();
assert_eq!(subscription, ThreadSubscription { automatic: true });
let subscription =
room.fetch_thread_subscription(owned_event_id!("$another_root")).await.unwrap();
assert!(subscription.is_none());
server
.mock_room_delete_thread_subscription()
.match_room_id(room_id.to_owned())
.match_thread_id(root_id.clone())
.ok()
.mock_once()
.mount()
.await;
room.unsubscribe_thread(root_id.clone()).await.unwrap();
let subscription = room.fetch_thread_subscription(root_id.clone()).await.unwrap();
assert_matches!(subscription, None);
server
.mock_room_put_thread_subscription()
.match_room_id(room_id.to_owned())
.match_thread_id(root_id.clone())
.conflicting_unsubscription()
.mock_once()
.mount()
.await;
room.subscribe_thread(root_id.clone(), Some(root_id.clone())).await.unwrap();
let subscription = room.fetch_thread_subscription(root_id).await.unwrap();
assert_matches!(subscription, None);
}
#[async_test]
async fn test_subscribe_thread_if_needed() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let room_id = room_id!("!test:example.org");
let room = server.sync_joined_room(&client, room_id).await;
for (root_id, automatic) in [
(owned_event_id!("$root"), None),
(owned_event_id!("$woot"), Some(owned_event_id!("$woot"))),
] {
server
.mock_room_put_thread_subscription()
.match_room_id(room_id.to_owned())
.match_thread_id(root_id.clone())
.ok()
.mock_once()
.mount()
.await;
room.subscribe_thread_if_needed(&root_id, automatic).await.unwrap();
}
{
let root_id = owned_event_id!("$toot");
server
.mock_room_get_thread_subscription()
.match_room_id(room_id.to_owned())
.match_thread_id(root_id.clone())
.ok(true)
.mock_once()
.mount()
.await;
server
.mock_room_put_thread_subscription()
.match_room_id(room_id.to_owned())
.match_thread_id(root_id.clone())
.ok()
.mock_once()
.mount()
.await;
room.subscribe_thread_if_needed(&root_id, None).await.unwrap();
}
{
let root_id = owned_event_id!("$foot");
server
.mock_room_get_thread_subscription()
.match_room_id(room_id.to_owned())
.match_thread_id(root_id.clone())
.ok(true)
.mock_once()
.mount()
.await;
room.subscribe_thread_if_needed(&root_id, Some(owned_event_id!("$foot"))).await.unwrap();
}
for (root_id, automatic) in [
(owned_event_id!("$root"), None),
(owned_event_id!("$woot"), Some(owned_event_id!("$woot"))),
] {
server
.mock_room_get_thread_subscription()
.match_room_id(room_id.to_owned())
.match_thread_id(root_id.clone())
.ok(false)
.mock_once()
.mount()
.await;
room.subscribe_thread_if_needed(&root_id, automatic).await.unwrap();
}
}
#[async_test]
async fn test_thread_push_rule_is_triggered_for_subscribed_threads() {
let server = MatrixMockServer::new().await;
let client = server
.client_builder()
.on_builder(|builder| {
builder.with_threading_support(matrix_sdk::ThreadingSupport::Enabled {
with_subscriptions: true,
})
})
.build()
.await;
let room_id = room_id!("!test:example.org");
let room = server.sync_joined_room(&client, room_id).await;
let thread_root_id = owned_event_id!("$root");
let f = EventFactory::new().room(room_id).sender(*ALICE);
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id).add_state_event(f.member(client.user_id().unwrap())),
)
.await;
let push_context = room
.push_context()
.await
.expect("getting a push context works")
.expect("the push context should exist");
server
.mock_room_get_thread_subscription()
.match_room_id(room_id.to_owned())
.match_thread_id(thread_root_id.clone())
.ok(true)
.mock_once()
.mount()
.await;
let event =
f.text_msg("hello to you too!").in_thread(&thread_root_id, &thread_root_id).into_raw_sync();
let actions = push_context.for_event(&event).await;
assert!(actions.iter().any(|action| action.should_notify()));
let another_thread_root_id = event_id!("$another_root");
let event = f
.text_msg("bonjour à vous également !")
.in_thread(another_thread_root_id, another_thread_root_id)
.into_raw_sync();
let actions = push_context.for_event(&event).await;
assert!(actions.is_empty());
}
#[async_test]
async fn test_thread_push_rules_and_notification_modes() {
let server = MatrixMockServer::new().await;
let client = server
.client_builder()
.on_builder(|builder| {
builder.with_threading_support(matrix_sdk::ThreadingSupport::Enabled {
with_subscriptions: true,
})
})
.build()
.await;
let room_id = room_id!("!test:example.org");
let f = EventFactory::new().room(room_id).sender(*ALICE);
let room = server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id).add_state_event(f.member(client.user_id().unwrap())),
)
.await;
room.push_context()
.await
.expect("getting a push context works")
.expect("the push context should exist");
server.mock_set_push_rules_actions(RuleKind::Underride, PushRuleIdSpec::Any).ok().mount().await;
server.mock_set_push_rules_actions(RuleKind::Room, PushRuleIdSpec::Any).ok().mount().await;
server.mock_set_push_rules(RuleKind::Underride, PushRuleIdSpec::Any).ok().mount().await;
server.mock_set_push_rules(RuleKind::Room, PushRuleIdSpec::Any).ok().mount().await;
server.mock_set_push_rules(RuleKind::Override, PushRuleIdSpec::Any).ok().mount().await;
server.mock_delete_push_rules(RuleKind::Room, PushRuleIdSpec::Any).ok().mount().await;
server.mock_delete_push_rules(RuleKind::Override, PushRuleIdSpec::Any).ok().mount().await;
let thread_root_id = owned_event_id!("$root");
server
.mock_room_get_thread_subscription()
.match_room_id(room_id.to_owned())
.match_thread_id(thread_root_id.clone())
.ok(true)
.mount()
.await;
let event =
f.text_msg("hello to you too!").in_thread(&thread_root_id, &thread_root_id).into_raw_sync();
let settings = client.notification_settings().await;
let is_encrypted = false;
let is_one_to_one = false;
settings
.set_default_room_notification_mode(
is_encrypted.into(),
is_one_to_one.into(),
RoomNotificationMode::AllMessages,
)
.await
.unwrap();
settings.set_room_notification_mode(room_id, RoomNotificationMode::AllMessages).await.unwrap();
let ruleset = settings.ruleset().await;
server
.mock_sync()
.ok_and_run(&client, |builder| {
builder.add_global_account_data(f.push_rules(ruleset));
})
.await;
let actions = room.push_context().await.unwrap().unwrap().traced_for_event(&event).await;
assert!(actions.iter().any(|action| action.should_notify()));
settings
.set_room_notification_mode(room_id, RoomNotificationMode::MentionsAndKeywordsOnly)
.await
.unwrap();
let ruleset = settings.ruleset().await;
server
.mock_sync()
.ok_and_run(&client, |builder| {
builder.add_global_account_data(f.push_rules(ruleset));
})
.await;
let actions = room.push_context().await.unwrap().unwrap().traced_for_event(&event).await;
assert!(actions.iter().any(|action| action.should_notify()));
settings.set_room_notification_mode(room_id, RoomNotificationMode::Mute).await.unwrap();
let ruleset = settings.ruleset().await;
server
.mock_sync()
.ok_and_run(&client, |builder| {
builder.add_global_account_data(f.push_rules(ruleset));
})
.await;
let actions = room.push_context().await.unwrap().unwrap().traced_for_event(&event).await;
assert!(!actions.iter().any(|action| action.should_notify()));
settings
.set_default_room_notification_mode(
is_encrypted.into(),
is_one_to_one.into(),
RoomNotificationMode::MentionsAndKeywordsOnly,
)
.await
.unwrap();
settings.set_room_notification_mode(room_id, RoomNotificationMode::AllMessages).await.unwrap();
let ruleset = settings.ruleset().await;
server
.mock_sync()
.ok_and_run(&client, |builder| {
builder.add_global_account_data(f.push_rules(ruleset));
})
.await;
let actions = room.push_context().await.unwrap().unwrap().traced_for_event(&event).await;
assert!(actions.iter().any(|action| action.should_notify()));
settings
.set_room_notification_mode(room_id, RoomNotificationMode::MentionsAndKeywordsOnly)
.await
.unwrap();
let ruleset = settings.ruleset().await;
server
.mock_sync()
.ok_and_run(&client, |builder| {
builder.add_global_account_data(f.push_rules(ruleset));
})
.await;
let actions = room.push_context().await.unwrap().unwrap().traced_for_event(&event).await;
assert!(actions.iter().any(|action| action.should_notify()));
settings.set_room_notification_mode(room_id, RoomNotificationMode::Mute).await.unwrap();
let ruleset = settings.ruleset().await;
server
.mock_sync()
.ok_and_run(&client, |builder| {
builder.add_global_account_data(f.push_rules(ruleset));
})
.await;
let actions = room.push_context().await.unwrap().unwrap().traced_for_event(&event).await;
assert!(!actions.iter().any(|action| action.should_notify()));
}