use std::collections::BTreeSet;
use assert_matches2::assert_matches;
use matrix_sdk::{
deserialized_responses::RawSyncOrStrippedState,
test_utils::mocks::{AnyRoomBuilder, MatrixMockServer},
};
use matrix_sdk_base::RoomMemberships;
use matrix_sdk_test::{
InvitedRoomBuilder, JoinedRoomBuilder, KnockedRoomBuilder, async_test,
event_factory::EventFactory,
};
use ruma::{
EventEncryptionAlgorithm, MilliSecondsSinceUnixEpoch, RoomVersionId, event_id,
events::{
AnyStrippedStateEvent, AnySyncStateEvent, SyncStateEvent,
room::{
avatar::RoomAvatarEventContent,
canonical_alias::RoomCanonicalAliasEventContent,
create::RoomCreateEventContent,
encryption::RoomEncryptionEventContent,
guest_access::{GuestAccess, RoomGuestAccessEventContent},
history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent},
join_rules::RoomJoinRulesEventContent,
member::RoomMemberEvent,
name::RoomNameEventContent,
pinned_events::RoomPinnedEventsEventContent,
power_levels::RoomPowerLevelsEventContent,
tombstone::RoomTombstoneEventContent,
topic::RoomTopicEventContent,
},
},
mxc_uri, owned_user_id,
room::JoinRule,
room_alias_id, room_id,
serde::Raw,
user_id,
};
use serde_json::json;
use stream_assert::{assert_pending, assert_ready};
#[async_test]
async fn test_receive_room_encryption_event_via_sync() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let room_id = room_id!("!abc");
let room = server.sync_joined_room(&client, room_id).await;
assert_matches!(room.encryption_settings(), None);
assert_matches!(room.get_state_event_static::<RoomEncryptionEventContent>().await, Ok(None));
let raw_event_observer =
client.observe_room_events::<Raw<SyncStateEvent<RoomEncryptionEventContent>>, ()>(room_id);
let mut raw_event_subscriber = raw_event_observer.subscribe();
let event_observer =
client.observe_room_events::<SyncStateEvent<RoomEncryptionEventContent>, ()>(room_id);
let mut event_subscriber = event_observer.subscribe();
let valid_raw_event = Raw::new(&json!({
"content": {
"algorithm": "m.megolm.v1.aes-sha2",
},
"type": "m.room.encryption",
"state_key": "",
"sender": user_id,
"event_id": "$validevent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id).add_state_bulk(vec![valid_raw_event.clone()]),
)
.await;
assert_eq!(
room.encryption_settings().unwrap().algorithm,
Some(EventEncryptionAlgorithm::MegolmV1AesSha2)
);
assert_matches!(
room.get_state_event_static::<RoomEncryptionEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
assert_matches!(raw_event.deserialize(), Ok(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
let (event, _) = assert_ready!(event_subscriber);
assert_eq!(
event.as_original().unwrap().content.algorithm,
EventEncryptionAlgorithm::MegolmV1AesSha2
);
let raw_event_with_invalid_content = Raw::new(&json!({
"content": {
"algorithm": true,
},
"type": "m.room.encryption",
"state_key": "",
"sender": user_id,
"event_id": "$eventwithinvalidcontent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_content.clone()]),
)
.await;
assert_eq!(
room.encryption_settings().unwrap().algorithm,
Some(EventEncryptionAlgorithm::MegolmV1AesSha2)
);
assert_matches!(
room.get_state_event_static::<RoomEncryptionEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_pending!(event_subscriber);
let raw_event_with_invalid_state_key = Raw::new(&json!({
"content": {
"algorithm": "m.megolm.v1.aes-sha2",
},
"type": "m.room.encryption",
"state_key": 1,
"sender": user_id,
"event_id": "$eventwithinvalidstatekey",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_state_key.clone()]),
)
.await;
assert_eq!(
room.encryption_settings().unwrap().algorithm,
Some(EventEncryptionAlgorithm::MegolmV1AesSha2)
);
assert_matches!(
room.get_state_event_static::<RoomEncryptionEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_state_key.json().get());
assert_pending!(event_subscriber);
}
#[async_test]
async fn test_receive_room_avatar_event_via_sync() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let room_id = room_id!("!abc");
let room = server.sync_joined_room(&client, room_id).await;
assert_eq!(room.avatar_url(), None);
assert_matches!(room.get_state_event_static::<RoomAvatarEventContent>().await, Ok(None));
let raw_event_observer =
client.observe_room_events::<Raw<SyncStateEvent<RoomAvatarEventContent>>, ()>(room_id);
let mut raw_event_subscriber = raw_event_observer.subscribe();
let event_observer =
client.observe_room_events::<SyncStateEvent<RoomAvatarEventContent>, ()>(room_id);
let mut event_subscriber = event_observer.subscribe();
let avatar_url = mxc_uri!("mxc://localhost/1234");
let valid_raw_event = Raw::new(&json!({
"content": {
"url": avatar_url,
},
"type": "m.room.avatar",
"state_key": "",
"sender": user_id,
"event_id": "$validevent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id).add_state_bulk(vec![valid_raw_event.clone()]),
)
.await;
assert_eq!(room.avatar_url().as_deref(), Some(avatar_url));
assert_matches!(
room.get_state_event_static::<RoomAvatarEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
assert_matches!(raw_event.deserialize(), Ok(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
let (event, _) = assert_ready!(event_subscriber);
assert_eq!(event.as_original().unwrap().content.url.as_deref(), Some(avatar_url));
let raw_event_with_invalid_content = Raw::new(&json!({
"content": {
"url": true,
},
"type": "m.room.avatar",
"state_key": "",
"sender": user_id,
"event_id": "$eventwithinvalidcontent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_content.clone()]),
)
.await;
assert_eq!(room.avatar_url(), None);
assert_matches!(
room.get_state_event_static::<RoomAvatarEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_pending!(event_subscriber);
let raw_event_with_invalid_state_key = Raw::new(&json!({
"content": {
"url": "mxc://localhost/zyxw",
},
"type": "m.room.avatar",
"state_key": 1,
"sender": user_id,
"event_id": "$eventwithinvalidstatekey",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_state_key.clone()]),
)
.await;
assert_eq!(room.avatar_url(), None);
assert_matches!(
room.get_state_event_static::<RoomAvatarEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_state_key.json().get());
assert_pending!(event_subscriber);
}
#[async_test]
async fn test_receive_room_name_event_via_sync() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let room_id = room_id!("!abc");
let room = server.sync_joined_room(&client, room_id).await;
assert_eq!(room.name(), None);
assert_matches!(room.get_state_event_static::<RoomNameEventContent>().await, Ok(None));
let raw_event_observer =
client.observe_room_events::<Raw<SyncStateEvent<RoomNameEventContent>>, ()>(room_id);
let mut raw_event_subscriber = raw_event_observer.subscribe();
let event_observer =
client.observe_room_events::<SyncStateEvent<RoomNameEventContent>, ()>(room_id);
let mut event_subscriber = event_observer.subscribe();
let room_name = "My room";
let valid_raw_event = Raw::new(&json!({
"content": {
"name": room_name,
},
"type": "m.room.name",
"state_key": "",
"sender": user_id,
"event_id": "$validevent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id).add_state_bulk(vec![valid_raw_event.clone()]),
)
.await;
assert_eq!(room.name().as_deref(), Some(room_name));
assert_matches!(
room.get_state_event_static::<RoomNameEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
assert_matches!(raw_event.deserialize(), Ok(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
let (event, _) = assert_ready!(event_subscriber);
assert_eq!(event.as_original().unwrap().content.name, "My room");
let raw_event_with_invalid_content = Raw::new(&json!({
"content": {
"name": true,
},
"type": "m.room.name",
"state_key": "",
"sender": user_id,
"event_id": "$eventwithinvalidcontent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_content.clone()]),
)
.await;
assert_eq!(room.name(), None);
assert_matches!(
room.get_state_event_static::<RoomNameEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_pending!(event_subscriber);
let raw_event_with_invalid_state_key = Raw::new(&json!({
"content": {
"name": room_name,
},
"type": "m.room.name",
"state_key": 1,
"sender": user_id,
"event_id": "$eventwithinvalidstatekey",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_state_key.clone()]),
)
.await;
assert_eq!(room.name(), None);
assert_matches!(
room.get_state_event_static::<RoomNameEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_state_key.json().get());
assert_pending!(event_subscriber);
}
#[async_test]
async fn test_receive_room_create_event_via_sync() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let room_id = room_id!("!abc");
let room = server.sync_joined_room(&client, room_id).await;
assert_matches!(room.create_content(), None);
assert_matches!(room.get_state_event_static::<RoomCreateEventContent>().await, Ok(None));
let raw_event_observer =
client.observe_room_events::<Raw<SyncStateEvent<RoomCreateEventContent>>, ()>(room_id);
let mut raw_event_subscriber = raw_event_observer.subscribe();
let event_observer =
client.observe_room_events::<SyncStateEvent<RoomCreateEventContent>, ()>(room_id);
let mut event_subscriber = event_observer.subscribe();
let valid_raw_event = Raw::new(&json!({
"content": {
"room_version": "12",
},
"type": "m.room.create",
"state_key": "",
"sender": user_id,
"event_id": "$validevent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id).add_state_bulk(vec![valid_raw_event.clone()]),
)
.await;
assert_eq!(room.create_content().unwrap().room_version, RoomVersionId::V12);
assert_matches!(
room.get_state_event_static::<RoomCreateEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
assert_matches!(raw_event.deserialize(), Ok(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
let (event, _) = assert_ready!(event_subscriber);
assert_eq!(event.as_original().unwrap().content.room_version, RoomVersionId::V12);
let raw_event_with_invalid_content = Raw::new(&json!({
"content": {
"room_version": true,
},
"type": "m.room.create",
"state_key": "",
"sender": user_id,
"event_id": "$eventwithinvalidcontent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_content.clone()]),
)
.await;
assert_eq!(room.create_content().unwrap().room_version, RoomVersionId::V12);
assert_matches!(
room.get_state_event_static::<RoomCreateEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_pending!(event_subscriber);
let room_id = room_id!("!def");
let room = server.sync_joined_room(&client, room_id).await;
assert_matches!(room.create_content(), None);
assert_matches!(room.get_state_event_static::<RoomCreateEventContent>().await, Ok(None));
let raw_event_observer =
client.observe_room_events::<Raw<SyncStateEvent<RoomCreateEventContent>>, ()>(room_id);
let mut raw_event_subscriber = raw_event_observer.subscribe();
let event_observer =
client.observe_room_events::<SyncStateEvent<RoomCreateEventContent>, ()>(room_id);
let mut event_subscriber = event_observer.subscribe();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_content.clone()]),
)
.await;
assert_matches!(room.create_content(), None);
assert_matches!(
room.get_state_event_static::<RoomCreateEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_pending!(event_subscriber);
let raw_event_with_invalid_state_key = Raw::new(&json!({
"content": {
"room_version": "12",
},
"type": "m.room.create",
"state_key": 1,
"sender": user_id,
"event_id": "$eventwithinvalidstatekey",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_state_key.clone()]),
)
.await;
assert_matches!(room.create_content(), None);
assert_matches!(
room.get_state_event_static::<RoomCreateEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_state_key.json().get());
assert_pending!(event_subscriber);
}
#[async_test]
async fn test_receive_room_history_visibility_event_via_sync() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let room_id = room_id!("!abc");
let room = server.sync_joined_room(&client, room_id).await;
assert_eq!(room.history_visibility(), None);
assert_matches!(
room.get_state_event_static::<RoomHistoryVisibilityEventContent>().await,
Ok(None)
);
let raw_event_observer = client
.observe_room_events::<Raw<SyncStateEvent<RoomHistoryVisibilityEventContent>>, ()>(room_id);
let mut raw_event_subscriber = raw_event_observer.subscribe();
let event_observer = client
.observe_room_events::<SyncStateEvent<RoomHistoryVisibilityEventContent>, ()>(room_id);
let mut event_subscriber = event_observer.subscribe();
let valid_raw_event = Raw::new(&json!({
"content": {
"history_visibility": "shared",
},
"type": "m.room.history_visibility",
"state_key": "",
"sender": user_id,
"event_id": "$validevent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id).add_state_bulk(vec![valid_raw_event.clone()]),
)
.await;
assert_eq!(room.history_visibility(), Some(HistoryVisibility::Shared));
assert_matches!(
room.get_state_event_static::<RoomHistoryVisibilityEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
assert_matches!(raw_event.deserialize(), Ok(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
let (event, _) = assert_ready!(event_subscriber);
assert_eq!(event.as_original().unwrap().content.history_visibility, HistoryVisibility::Shared);
let raw_event_with_invalid_content = Raw::new(&json!({
"content": {
"history_visibility": true,
},
"type": "m.room.history_visibility",
"state_key": "",
"sender": user_id,
"event_id": "$eventwithinvalidcontent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_content.clone()]),
)
.await;
assert_eq!(room.history_visibility(), None);
assert_matches!(
room.get_state_event_static::<RoomHistoryVisibilityEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_pending!(event_subscriber);
let raw_event_with_invalid_state_key = Raw::new(&json!({
"content": {
"history_visibility": "shared",
},
"type": "m.room.history_visibility",
"state_key": 1,
"sender": user_id,
"event_id": "$eventwithinvalidstatekey",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_state_key.clone()]),
)
.await;
assert_eq!(room.name(), None);
assert_matches!(
room.get_state_event_static::<RoomHistoryVisibilityEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_state_key.json().get());
assert_pending!(event_subscriber);
}
#[async_test]
async fn test_receive_room_guest_access_event_via_sync() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let room_id = room_id!("!abc");
let room = server.sync_joined_room(&client, room_id).await;
assert_eq!(room.guest_access(), GuestAccess::Forbidden);
assert_matches!(room.get_state_event_static::<RoomGuestAccessEventContent>().await, Ok(None));
let raw_event_observer =
client.observe_room_events::<Raw<SyncStateEvent<RoomGuestAccessEventContent>>, ()>(room_id);
let mut raw_event_subscriber = raw_event_observer.subscribe();
let event_observer =
client.observe_room_events::<SyncStateEvent<RoomGuestAccessEventContent>, ()>(room_id);
let mut event_subscriber = event_observer.subscribe();
let valid_raw_event = Raw::new(&json!({
"content": {
"guest_access": "can_join",
},
"type": "m.room.guest_access",
"state_key": "",
"sender": user_id,
"event_id": "$validevent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id).add_state_bulk(vec![valid_raw_event.clone()]),
)
.await;
assert_eq!(room.guest_access(), GuestAccess::CanJoin);
assert_matches!(
room.get_state_event_static::<RoomGuestAccessEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
assert_matches!(raw_event.deserialize(), Ok(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
let (event, _) = assert_ready!(event_subscriber);
assert_eq!(event.as_original().unwrap().content.guest_access, GuestAccess::CanJoin);
let raw_event_with_invalid_content = Raw::new(&json!({
"content": {
"guest_access": true,
},
"type": "m.room.guest_access",
"state_key": "",
"sender": user_id,
"event_id": "$eventwithinvalidcontent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_content.clone()]),
)
.await;
assert_eq!(room.guest_access(), GuestAccess::Forbidden);
assert_matches!(
room.get_state_event_static::<RoomGuestAccessEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_pending!(event_subscriber);
let raw_event_with_invalid_state_key = Raw::new(&json!({
"content": {
"guest_access": "can_join",
},
"type": "m.room.guest_access",
"state_key": 1,
"sender": user_id,
"event_id": "$eventwithinvalidstatekey",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_state_key.clone()]),
)
.await;
assert_eq!(room.guest_access(), GuestAccess::Forbidden);
assert_matches!(
room.get_state_event_static::<RoomGuestAccessEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_state_key.json().get());
assert_pending!(event_subscriber);
}
#[async_test]
async fn test_receive_room_join_rules_event_via_sync() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let room_id = room_id!("!abc");
let room = server.sync_joined_room(&client, room_id).await;
assert_eq!(room.join_rule(), None);
assert_matches!(room.get_state_event_static::<RoomJoinRulesEventContent>().await, Ok(None));
let raw_event_observer =
client.observe_room_events::<Raw<SyncStateEvent<RoomJoinRulesEventContent>>, ()>(room_id);
let mut raw_event_subscriber = raw_event_observer.subscribe();
let event_observer =
client.observe_room_events::<SyncStateEvent<RoomJoinRulesEventContent>, ()>(room_id);
let mut event_subscriber = event_observer.subscribe();
let valid_raw_event = Raw::new(&json!({
"content": {
"join_rule": "public",
},
"type": "m.room.join_rules",
"state_key": "",
"sender": user_id,
"event_id": "$validevent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id).add_state_bulk(vec![valid_raw_event.clone()]),
)
.await;
assert_eq!(room.join_rule(), Some(JoinRule::Public));
assert_matches!(
room.get_state_event_static::<RoomJoinRulesEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
assert_matches!(raw_event.deserialize(), Ok(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
let (event, _) = assert_ready!(event_subscriber);
assert_eq!(event.as_original().unwrap().content.join_rule, JoinRule::Public);
let raw_event_with_invalid_content = Raw::new(&json!({
"content": {
"join_rule": true,
},
"type": "m.room.join_rules",
"state_key": "",
"sender": user_id,
"event_id": "$eventwithinvalidcontent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_content.clone()]),
)
.await;
assert_eq!(room.join_rule(), None);
assert_matches!(
room.get_state_event_static::<RoomJoinRulesEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_pending!(event_subscriber);
let raw_event_with_invalid_state_key = Raw::new(&json!({
"content": {
"join_rule": "public",
},
"type": "m.room.join_rules",
"state_key": 1,
"sender": user_id,
"event_id": "$eventwithinvalidstatekey",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_state_key.clone()]),
)
.await;
assert_eq!(room.join_rule(), None);
assert_matches!(
room.get_state_event_static::<RoomJoinRulesEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_state_key.json().get());
assert_pending!(event_subscriber);
}
#[async_test]
async fn test_receive_room_canonical_alias_event_via_sync() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let room_id = room_id!("!abc");
let room = server.sync_joined_room(&client, room_id).await;
assert_eq!(room.canonical_alias(), None);
assert_matches!(
room.get_state_event_static::<RoomCanonicalAliasEventContent>().await,
Ok(None)
);
let raw_event_observer = client
.observe_room_events::<Raw<SyncStateEvent<RoomCanonicalAliasEventContent>>, ()>(room_id);
let mut raw_event_subscriber = raw_event_observer.subscribe();
let event_observer =
client.observe_room_events::<SyncStateEvent<RoomCanonicalAliasEventContent>, ()>(room_id);
let mut event_subscriber = event_observer.subscribe();
let room_alias = room_alias_id!("#myroom:localhost");
let valid_raw_event = Raw::new(&json!({
"content": {
"alias": room_alias,
},
"type": "m.room.canonical_alias",
"state_key": "",
"sender": user_id,
"event_id": "$validevent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id).add_state_bulk(vec![valid_raw_event.clone()]),
)
.await;
assert_eq!(room.canonical_alias().as_deref(), Some(room_alias));
assert_matches!(
room.get_state_event_static::<RoomCanonicalAliasEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
assert_matches!(raw_event.deserialize(), Ok(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
let (event, _) = assert_ready!(event_subscriber);
assert_eq!(event.as_original().unwrap().content.alias.as_deref(), Some(room_alias));
let raw_event_with_invalid_content = Raw::new(&json!({
"content": {
"alias": true,
},
"type": "m.room.canonical_alias",
"state_key": "",
"sender": user_id,
"event_id": "$eventwithinvalidcontent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_content.clone()]),
)
.await;
assert_eq!(room.canonical_alias(), None);
assert_matches!(
room.get_state_event_static::<RoomCanonicalAliasEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_pending!(event_subscriber);
let raw_event_with_invalid_state_key = Raw::new(&json!({
"content": {
"alias": room_alias,
},
"type": "m.room.canonical_alias",
"state_key": 1,
"sender": user_id,
"event_id": "$eventwithinvalidstatekey",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_state_key.clone()]),
)
.await;
assert_eq!(room.canonical_alias(), None);
assert_matches!(
room.get_state_event_static::<RoomCanonicalAliasEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_state_key.json().get());
assert_pending!(event_subscriber);
}
#[async_test]
async fn test_receive_room_topic_event_via_sync() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let room_id = room_id!("!abc");
let room = server.sync_joined_room(&client, room_id).await;
assert_eq!(room.topic(), None);
assert_matches!(room.get_state_event_static::<RoomTopicEventContent>().await, Ok(None));
let raw_event_observer =
client.observe_room_events::<Raw<SyncStateEvent<RoomTopicEventContent>>, ()>(room_id);
let mut raw_event_subscriber = raw_event_observer.subscribe();
let event_observer =
client.observe_room_events::<SyncStateEvent<RoomTopicEventContent>, ()>(room_id);
let mut event_subscriber = event_observer.subscribe();
let room_topic = "A room about me, myself, and I!";
let valid_raw_event = Raw::new(&json!({
"content": {
"topic": room_topic,
},
"type": "m.room.topic",
"state_key": "",
"sender": user_id,
"event_id": "$validevent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id).add_state_bulk(vec![valid_raw_event.clone()]),
)
.await;
assert_eq!(room.topic().as_deref(), Some(room_topic));
assert_matches!(
room.get_state_event_static::<RoomTopicEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
assert_matches!(raw_event.deserialize(), Ok(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
let (event, _) = assert_ready!(event_subscriber);
assert_eq!(event.as_original().unwrap().content.topic, room_topic);
let raw_event_with_invalid_content = Raw::new(&json!({
"content": {
"topic": true,
},
"type": "m.room.topic",
"state_key": "",
"sender": user_id,
"event_id": "$eventwithinvalidcontent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_content.clone()]),
)
.await;
assert_eq!(room.topic(), None);
assert_matches!(
room.get_state_event_static::<RoomTopicEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_pending!(event_subscriber);
let raw_event_with_invalid_state_key = Raw::new(&json!({
"content": {
"topic": room_topic,
},
"type": "m.room.topic",
"state_key": 1,
"sender": user_id,
"event_id": "$eventwithinvalidstatekey",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_state_key.clone()]),
)
.await;
assert_eq!(room.topic(), None);
assert_matches!(
room.get_state_event_static::<RoomTopicEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_state_key.json().get());
assert_pending!(event_subscriber);
}
#[async_test]
async fn test_receive_room_tombstone_event_via_sync() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let room_id = room_id!("!abc");
let room = server.sync_joined_room(&client, room_id).await;
assert_matches!(room.tombstone_content(), None);
assert_matches!(room.get_state_event_static::<RoomTombstoneEventContent>().await, Ok(None));
let raw_event_observer =
client.observe_room_events::<Raw<SyncStateEvent<RoomTombstoneEventContent>>, ()>(room_id);
let mut raw_event_subscriber = raw_event_observer.subscribe();
let event_observer =
client.observe_room_events::<SyncStateEvent<RoomTombstoneEventContent>, ()>(room_id);
let mut event_subscriber = event_observer.subscribe();
let tombstone_replacement = room_id!("!replacement");
let valid_raw_event = Raw::new(&json!({
"content": {
"body": "!",
"replacement_room": tombstone_replacement,
},
"type": "m.room.tombstone",
"state_key": "",
"sender": user_id,
"event_id": "$validevent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id).add_state_bulk(vec![valid_raw_event.clone()]),
)
.await;
assert_eq!(
room.tombstone_content().unwrap().replacement_room.as_deref(),
Some(tombstone_replacement)
);
assert_matches!(
room.get_state_event_static::<RoomTombstoneEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
assert_matches!(raw_event.deserialize(), Ok(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
let (event, _) = assert_ready!(event_subscriber);
assert_eq!(event.as_original().unwrap().content.replacement_room, tombstone_replacement);
let raw_event_with_invalid_content = Raw::new(&json!({
"content": {
"body": "!",
"replacement_room": true,
},
"type": "m.room.tombstone",
"state_key": "",
"sender": user_id,
"event_id": "$eventwithinvalidcontent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_content.clone()]),
)
.await;
assert_matches!(room.tombstone_content(), None);
assert_matches!(
room.get_state_event_static::<RoomTombstoneEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_pending!(event_subscriber);
let raw_event_with_invalid_state_key = Raw::new(&json!({
"content": {
"body": "!",
"replacement_room": tombstone_replacement,
},
"type": "m.room.tombstone",
"state_key": 1,
"sender": user_id,
"event_id": "$eventwithinvalidstatekey",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_state_key.clone()]),
)
.await;
assert_matches!(room.tombstone_content(), None);
assert_matches!(
room.get_state_event_static::<RoomTombstoneEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_state_key.json().get());
assert_pending!(event_subscriber);
}
#[async_test]
async fn test_receive_room_power_levels_event_via_sync() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let room_id = room_id!("!abc");
let room = server.sync_joined_room(&client, room_id).await;
assert_matches!(room.max_power_level(), 100);
assert_matches!(room.get_state_event_static::<RoomPowerLevelsEventContent>().await, Ok(None));
let raw_event_observer =
client.observe_room_events::<Raw<SyncStateEvent<RoomPowerLevelsEventContent>>, ()>(room_id);
let mut raw_event_subscriber = raw_event_observer.subscribe();
let event_observer =
client.observe_room_events::<SyncStateEvent<RoomPowerLevelsEventContent>, ()>(room_id);
let mut event_subscriber = event_observer.subscribe();
let valid_raw_event = Raw::new(&json!({
"content": {
"users_default": -10,
},
"type": "m.room.power_levels",
"state_key": "",
"sender": user_id,
"event_id": "$validevent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id).add_state_bulk(vec![valid_raw_event.clone()]),
)
.await;
assert_eq!(room.max_power_level(), -10);
assert_matches!(
room.get_state_event_static::<RoomPowerLevelsEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
assert_matches!(raw_event.deserialize(), Ok(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
let (event, _) = assert_ready!(event_subscriber);
assert_eq!(i64::from(event.as_original().unwrap().content.users_default), -10);
let raw_event_with_invalid_content = Raw::new(&json!({
"content": {
"users_default": true,
},
"type": "m.room.power_levels",
"state_key": "",
"sender": user_id,
"event_id": "$eventwithinvalidcontent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_content.clone()]),
)
.await;
assert_eq!(room.max_power_level(), 100);
assert_matches!(
room.get_state_event_static::<RoomPowerLevelsEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_pending!(event_subscriber);
let raw_event_with_invalid_state_key = Raw::new(&json!({
"content": {
"users_default": -10,
},
"type": "m.room.power_levels",
"state_key": 1,
"sender": user_id,
"event_id": "$eventwithinvalidstatekey",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_state_key.clone()]),
)
.await;
assert_eq!(room.max_power_level(), 100);
assert_matches!(
room.get_state_event_static::<RoomPowerLevelsEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_state_key.json().get());
assert_pending!(event_subscriber);
}
#[async_test]
async fn test_receive_room_pinned_events_event_via_sync() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let room_id = room_id!("!abc");
let room = server.sync_joined_room(&client, room_id).await;
assert_eq!(room.pinned_event_ids(), None);
assert_matches!(room.get_state_event_static::<RoomPinnedEventsEventContent>().await, Ok(None));
let raw_event_observer = client
.observe_room_events::<Raw<SyncStateEvent<RoomPinnedEventsEventContent>>, ()>(room_id);
let mut raw_event_subscriber = raw_event_observer.subscribe();
let event_observer =
client.observe_room_events::<SyncStateEvent<RoomPinnedEventsEventContent>, ()>(room_id);
let mut event_subscriber = event_observer.subscribe();
let pinned_event = event_id!("$pinned");
let valid_raw_event = Raw::new(&json!({
"content": {
"pinned": [pinned_event],
},
"type": "m.room.pinned_events",
"state_key": "",
"sender": user_id,
"event_id": "$validevent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id).add_state_bulk(vec![valid_raw_event.clone()]),
)
.await;
assert_eq!(room.pinned_event_ids().unwrap(), &[pinned_event]);
assert_matches!(
room.get_state_event_static::<RoomPinnedEventsEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
assert_matches!(raw_event.deserialize(), Ok(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
let (event, _) = assert_ready!(event_subscriber);
assert_eq!(event.as_original().unwrap().content.pinned, &[pinned_event]);
let raw_event_with_invalid_content = Raw::new(&json!({
"content": {
"pinned": true,
},
"type": "m.room.pinned_events",
"state_key": "",
"sender": user_id,
"event_id": "$eventwithinvalidcontent",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_content.clone()]),
)
.await;
assert_eq!(room.pinned_event_ids(), None);
assert_matches!(
room.get_state_event_static::<RoomPinnedEventsEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_pending!(event_subscriber);
let raw_event_with_invalid_state_key = Raw::new(&json!({
"content": {
"pinned": [pinned_event],
},
"type": "m.room.pinned_events",
"state_key": 1,
"sender": user_id,
"event_id": "$eventwithinvalidstatekey",
"origin_server_ts": MilliSecondsSinceUnixEpoch::now(),
}))
.unwrap()
.cast_unchecked::<AnySyncStateEvent>();
server
.sync_room(
&client,
JoinedRoomBuilder::new(room_id)
.add_state_bulk(vec![raw_event_with_invalid_state_key.clone()]),
)
.await;
assert_eq!(room.pinned_event_ids(), None);
assert_matches!(
room.get_state_event_static::<RoomPinnedEventsEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Sync(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let (raw_event, _) = assert_ready!(raw_event_subscriber);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_state_key.json().get());
assert_pending!(event_subscriber);
}
#[async_test]
async fn test_receive_stripped_room_encryption_event_via_sync() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let valid_raw_event = Raw::new(&json!({
"content": {
"algorithm": "m.megolm.v1.aes-sha2",
},
"type": "m.room.encryption",
"state_key": "",
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
InvitedRoomBuilder::new(room_id!("!roomwithvalidencryption"))
.add_state_bulk(vec![valid_raw_event.clone()]),
)
.await;
assert_eq!(
room.encryption_settings().unwrap().algorithm,
Some(EventEncryptionAlgorithm::MegolmV1AesSha2)
);
assert_matches!(
room.get_state_event_static::<RoomEncryptionEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Stripped(raw_event)))
);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
assert_matches!(raw_event.deserialize(), Ok(_));
let redacted_raw_event = Raw::new(&json!({
"content": {},
"type": "m.room.encryption",
"state_key": "",
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
InvitedRoomBuilder::new(room_id!("!roomwithredactedencryption"))
.add_state_bulk(vec![redacted_raw_event.clone()]),
)
.await;
assert_matches!(room.encryption_settings(), None);
assert_matches!(
room.get_state_event_static::<RoomEncryptionEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Stripped(raw_event)))
);
assert_eq!(raw_event.json().get(), redacted_raw_event.json().get());
assert_matches!(raw_event.deserialize(), Ok(_));
let raw_event_with_invalid_content = Raw::new(&json!({
"content": {
"algorithm": true,
},
"type": "m.room.encryption",
"state_key": "",
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
InvitedRoomBuilder::new(room_id!("!roomwithinvalidencryptioncontent"))
.add_state_bulk(vec![raw_event_with_invalid_content.clone()]),
)
.await;
assert_matches!(room.encryption_settings(), None);
assert_matches!(
room.get_state_event_static::<RoomEncryptionEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Stripped(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let raw_event_with_invalid_state_key = Raw::new(&json!({
"content": {
"algorithm": "m.megolm.v1.aes-sha2",
},
"type": "m.room.encryption",
"state_key": 1,
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
InvitedRoomBuilder::new(room_id!("!roomwithinvalidencryptionstatekey"))
.add_state_bulk(vec![raw_event_with_invalid_state_key.clone()]),
)
.await;
assert_matches!(room.encryption_settings(), None);
assert_matches!(room.get_state_event_static::<RoomEncryptionEventContent>().await, Ok(None));
}
#[async_test]
async fn test_receive_stripped_room_avatar_event_via_sync() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let avatar_url = mxc_uri!("mxc://localhost/1234");
let valid_raw_event = Raw::new(&json!({
"content": {
"url": avatar_url,
},
"type": "m.room.avatar",
"state_key": "",
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
InvitedRoomBuilder::new(room_id!("!roomwithvalidname"))
.add_state_bulk(vec![valid_raw_event.clone()]),
)
.await;
assert_eq!(room.avatar_url().as_deref(), Some(avatar_url));
assert_matches!(
room.get_state_event_static::<RoomAvatarEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Stripped(raw_event)))
);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
assert_matches!(raw_event.deserialize(), Ok(_));
let raw_event_with_invalid_content = Raw::new(&json!({
"content": {
"url": true,
},
"type": "m.room.avatar",
"state_key": "",
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
InvitedRoomBuilder::new(room_id!("!roomwithinvalidavatarcontent"))
.add_state_bulk(vec![raw_event_with_invalid_content.clone()]),
)
.await;
assert_eq!(room.avatar_url(), None);
assert_matches!(
room.get_state_event_static::<RoomAvatarEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Stripped(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let raw_event_with_invalid_state_key = Raw::new(&json!({
"content": {
"url": "mxc://localhost/zyxw",
},
"type": "m.room.avatar",
"state_key": 1,
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
InvitedRoomBuilder::new(room_id!("!roomwithinvalidavatarstatekey"))
.add_state_bulk(vec![raw_event_with_invalid_state_key.clone()]),
)
.await;
assert_eq!(room.avatar_url(), None);
assert_matches!(room.get_state_event_static::<RoomAvatarEventContent>().await, Ok(None));
}
#[async_test]
async fn test_receive_stripped_room_name_event_via_sync() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let room_name = "My room";
let valid_raw_event = Raw::new(&json!({
"content": {
"name": room_name,
},
"type": "m.room.name",
"state_key": "",
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
KnockedRoomBuilder::new(room_id!("!roomwithvalidname"))
.add_state_bulk(vec![valid_raw_event.clone()]),
)
.await;
assert_eq!(room.name().as_deref(), Some(room_name));
assert_matches!(
room.get_state_event_static::<RoomNameEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Stripped(raw_event)))
);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
assert_matches!(raw_event.deserialize(), Ok(_));
let raw_event_with_invalid_content = Raw::new(&json!({
"content": {
"name": true,
},
"type": "m.room.name",
"state_key": "",
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
KnockedRoomBuilder::new(room_id!("!roomwithinvalidnamecontent"))
.add_state_bulk(vec![raw_event_with_invalid_content.clone()]),
)
.await;
assert_eq!(room.name(), None);
assert_matches!(
room.get_state_event_static::<RoomNameEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Stripped(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let raw_event_with_invalid_state_key = Raw::new(&json!({
"content": {
"name": room_name,
},
"type": "m.room.name",
"state_key": 1,
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
KnockedRoomBuilder::new(room_id!("!roomwithinvalidnamestatekey"))
.add_state_bulk(vec![raw_event_with_invalid_state_key.clone()]),
)
.await;
assert_eq!(room.name(), None);
assert_matches!(room.get_state_event_static::<RoomNameEventContent>().await, Ok(None));
}
#[async_test]
async fn test_receive_stripped_room_create_event_via_sync() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let valid_raw_event = Raw::new(&json!({
"content": {
"room_version": "12",
},
"type": "m.room.create",
"state_key": "",
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
KnockedRoomBuilder::new(room_id!("!roomwithvalidcreate"))
.add_state_bulk(vec![valid_raw_event.clone()]),
)
.await;
assert_eq!(room.create_content().unwrap().room_version, RoomVersionId::V12);
assert_matches!(
room.get_state_event_static::<RoomCreateEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Stripped(raw_event)))
);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
assert_matches!(raw_event.deserialize(), Ok(_));
let raw_event_with_invalid_content = Raw::new(&json!({
"content": {
"room_version": true,
},
"type": "m.room.create",
"state_key": "",
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
KnockedRoomBuilder::new(room_id!("!roomwithinvalidcreatecontent"))
.add_state_bulk(vec![raw_event_with_invalid_content.clone()]),
)
.await;
assert_matches!(room.create_content(), None);
assert_matches!(
room.get_state_event_static::<RoomCreateEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Stripped(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let raw_event_with_invalid_state_key = Raw::new(&json!({
"content": {
"room_version": "12",
},
"type": "m.room.create",
"state_key": 1,
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
KnockedRoomBuilder::new(room_id!("!roomwithinvalidcreatestatekey"))
.add_state_bulk(vec![raw_event_with_invalid_state_key.clone()]),
)
.await;
assert_matches!(room.create_content(), None);
assert_matches!(room.get_state_event_static::<RoomCreateEventContent>().await, Ok(None));
}
#[async_test]
async fn test_receive_stripped_room_join_rules_event_via_sync() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let valid_raw_event = Raw::new(&json!({
"content": {
"join_rule": "public",
},
"type": "m.room.join_rules",
"state_key": "",
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
InvitedRoomBuilder::new(room_id!("!roomwithvalidjoinrules"))
.add_state_bulk(vec![valid_raw_event.clone()]),
)
.await;
assert_eq!(room.join_rule(), Some(JoinRule::Public));
assert_matches!(
room.get_state_event_static::<RoomJoinRulesEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Stripped(raw_event)))
);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
assert_matches!(raw_event.deserialize(), Ok(_));
let raw_event_with_invalid_content = Raw::new(&json!({
"content": {
"join_rule": true,
},
"type": "m.room.join_rules",
"state_key": "",
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
InvitedRoomBuilder::new(room_id!("!roomwithinvalidjoinrulescontent"))
.add_state_bulk(vec![raw_event_with_invalid_content.clone()]),
)
.await;
assert_eq!(room.join_rule(), None);
assert_matches!(
room.get_state_event_static::<RoomJoinRulesEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Stripped(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let raw_event_with_invalid_state_key = Raw::new(&json!({
"content": {
"join_rule": "public",
},
"type": "m.room.join_rules",
"state_key": 1,
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
InvitedRoomBuilder::new(room_id!("!roomwithinvalidjoinrulesstatekey"))
.add_state_bulk(vec![raw_event_with_invalid_state_key.clone()]),
)
.await;
assert_eq!(room.join_rule(), None);
assert_matches!(room.get_state_event_static::<RoomJoinRulesEventContent>().await, Ok(None));
}
#[async_test]
async fn test_receive_stripped_room_canonical_alias_event_via_sync() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let room_alias = room_alias_id!("#myroom:localhost");
let valid_raw_event = Raw::new(&json!({
"content": {
"alias": room_alias,
},
"type": "m.room.canonical_alias",
"state_key": "",
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
InvitedRoomBuilder::new(room_id!("!roomwithvalidcanonicalalias"))
.add_state_bulk(vec![valid_raw_event.clone()]),
)
.await;
assert_eq!(room.canonical_alias().as_deref(), Some(room_alias));
assert_matches!(
room.get_state_event_static::<RoomCanonicalAliasEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Stripped(raw_event)))
);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
assert_matches!(raw_event.deserialize(), Ok(_));
let raw_event_with_invalid_content = Raw::new(&json!({
"content": {
"alias": true,
},
"type": "m.room.canonical_alias",
"state_key": "",
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
InvitedRoomBuilder::new(room_id!("!roomwithinvalidcanonicalaliascontent"))
.add_state_bulk(vec![raw_event_with_invalid_content.clone()]),
)
.await;
assert_eq!(room.canonical_alias(), None);
assert_matches!(
room.get_state_event_static::<RoomCanonicalAliasEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Stripped(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let raw_event_with_invalid_state_key = Raw::new(&json!({
"content": {
"alias": room_alias,
},
"type": "m.room.canonical_alias",
"state_key": 1,
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
InvitedRoomBuilder::new(room_id!("!roomwithinvalidcanonicalaliasstatekey"))
.add_state_bulk(vec![raw_event_with_invalid_state_key.clone()]),
)
.await;
assert_eq!(room.canonical_alias(), None);
assert_matches!(
room.get_state_event_static::<RoomCanonicalAliasEventContent>().await,
Ok(None)
);
}
#[async_test]
async fn test_receive_stripped_room_topic_event_via_sync() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let room_topic = "A room about me, myself, and I!";
let valid_raw_event = Raw::new(&json!({
"content": {
"topic": room_topic,
},
"type": "m.room.topic",
"state_key": "",
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
KnockedRoomBuilder::new(room_id!("!roomwithvalidtopic"))
.add_state_bulk(vec![valid_raw_event.clone()]),
)
.await;
assert_eq!(room.topic().as_deref(), Some(room_topic));
assert_matches!(
room.get_state_event_static::<RoomTopicEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Stripped(raw_event)))
);
assert_eq!(raw_event.json().get(), valid_raw_event.json().get());
assert_matches!(raw_event.deserialize(), Ok(_));
let raw_event_with_invalid_content = Raw::new(&json!({
"content": {
"topic": true,
},
"type": "m.room.topic",
"state_key": "",
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
KnockedRoomBuilder::new(room_id!("!roomwithinvalidtopiccontent"))
.add_state_bulk(vec![raw_event_with_invalid_content.clone()]),
)
.await;
assert_eq!(room.topic(), None);
assert_matches!(
room.get_state_event_static::<RoomTopicEventContent>().await,
Ok(Some(RawSyncOrStrippedState::Stripped(raw_event)))
);
assert_eq!(raw_event.json().get(), raw_event_with_invalid_content.json().get());
assert_matches!(raw_event.deserialize(), Err(_));
let raw_event_with_invalid_state_key = Raw::new(&json!({
"content": {
"topic": room_topic,
},
"type": "m.room.topic",
"state_key": 1,
"sender": user_id,
}))
.unwrap()
.cast_unchecked::<AnyStrippedStateEvent>();
let room = server
.sync_room(
&client,
KnockedRoomBuilder::new(room_id!("!roomwithinvalidtopicstatekey"))
.add_state_bulk(vec![raw_event_with_invalid_state_key.clone()]),
)
.await;
assert_eq!(room.topic(), None);
assert_matches!(room.get_state_event_static::<RoomTopicEventContent>().await, Ok(None));
}
#[async_test]
async fn test_update_active_service_members() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let service_member_id_1 = owned_user_id!("@service_1:localhost");
let service_member_id_2 = owned_user_id!("@service_2:localhost");
let room_id = room_id!("!room:localhost");
let service_members_event = EventFactory::new()
.room(room_id)
.sender(user_id)
.member_hints(BTreeSet::from_iter(vec![
service_member_id_1.clone(),
service_member_id_2.clone(),
]))
.into_raw_sync_state();
let own_member_event =
EventFactory::new().room(room_id).member(user_id).display_name("Me").into_raw_sync_state();
let room = server
.sync_room(
&client,
AnyRoomBuilder::Joined(
JoinedRoomBuilder::new(room_id)
.add_state_event(own_member_event)
.add_state_event(service_members_event),
),
)
.await;
let active_members = room.members_no_sync(RoomMemberships::ACTIVE).await.unwrap();
assert_eq!(active_members.len(), 1);
assert_eq!(room.service_members().unwrap().len(), 2);
assert!(room.update_active_service_members().await.unwrap().unwrap().is_empty());
assert!(room.active_service_members_count().is_none());
let human_user = EventFactory::new()
.room(room_id)
.member(user_id!("@human:localhost"))
.display_name("Human")
.into_raw_sync_state();
let room = server
.sync_room(
&client,
AnyRoomBuilder::Joined(JoinedRoomBuilder::new(room_id).add_state_event(human_user)),
)
.await;
let active_members = room.members_no_sync(RoomMemberships::ACTIVE).await.unwrap();
assert_eq!(active_members.len(), 2);
assert_eq!(room.service_members().unwrap().len(), 2);
assert!(room.update_active_service_members().await.unwrap().unwrap().is_empty());
assert!(room.active_service_members_count().is_none());
let service_member_1 =
EventFactory::new().room(room_id).member(&service_member_id_1).into_raw_sync_state();
let room = server
.sync_room(
&client,
AnyRoomBuilder::Joined(
JoinedRoomBuilder::new(room_id).add_state_event(service_member_1),
),
)
.await;
let active_members = room.members_no_sync(RoomMemberships::ACTIVE).await.unwrap();
assert_eq!(active_members.len(), 3);
assert_eq!(room.service_members().unwrap().len(), 2);
assert_eq!(room.update_active_service_members().await.unwrap().unwrap().len(), 1);
assert_eq!(room.active_service_members_count().unwrap_or_default(), 1);
let service_member_2 =
EventFactory::new().room(room_id).member(&service_member_id_2).into_raw_sync_state();
let room = server
.sync_room(
&client,
AnyRoomBuilder::Joined(
JoinedRoomBuilder::new(room_id).add_state_event(service_member_2),
),
)
.await;
let active_members = room.members_no_sync(RoomMemberships::ACTIVE).await.unwrap();
assert_eq!(active_members.len(), 4);
assert_eq!(room.service_members().unwrap().len(), 2);
assert_eq!(room.update_active_service_members().await.unwrap().unwrap().len(), 2);
assert_eq!(room.active_service_members_count().unwrap_or_default(), 2);
let service_member_2_left = EventFactory::new()
.room(room_id)
.member(&service_member_id_2)
.leave()
.into_raw_sync_state();
let room = server
.sync_room(
&client,
AnyRoomBuilder::Joined(
JoinedRoomBuilder::new(room_id).add_state_event(service_member_2_left),
),
)
.await;
let active_members = room.members_no_sync(RoomMemberships::ACTIVE).await.unwrap();
assert_eq!(active_members.len(), 3);
assert_eq!(room.service_members().unwrap().len(), 2);
assert_eq!(room.update_active_service_members().await.unwrap().unwrap().len(), 1);
assert_eq!(room.active_service_members_count().unwrap_or_default(), 1);
}
#[async_test]
async fn test_active_service_members_resets_when_member_counts_change() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let service_member_id_1 = owned_user_id!("@service_1:localhost");
let service_member_id_2 = owned_user_id!("@service_2:localhost");
let room_id = room_id!("!room:localhost");
let service_members_event = EventFactory::new()
.room(room_id)
.sender(user_id)
.member_hints(BTreeSet::from_iter(vec![
service_member_id_1.clone(),
service_member_id_2.clone(),
]))
.into_raw_sync_state();
let own_member_event =
EventFactory::new().room(room_id).member(user_id).display_name("Me").into_raw_sync_state();
let service_member_1 =
EventFactory::new().room(room_id).member(&service_member_id_1).into_raw_sync_state();
let service_member_2 =
EventFactory::new().room(room_id).member(&service_member_id_2).into_raw_sync_state();
let room = server
.sync_room(
&client,
AnyRoomBuilder::Joined(
JoinedRoomBuilder::new(room_id)
.add_state_event(own_member_event)
.add_state_event(service_member_1)
.add_state_event(service_member_2)
.add_state_event(service_members_event),
),
)
.await;
let active_members = room.members_no_sync(RoomMemberships::ACTIVE).await.unwrap();
assert_eq!(active_members.len(), 3);
assert_eq!(room.service_members().unwrap().len(), 2);
assert_eq!(room.update_active_service_members().await.unwrap().unwrap().len(), 2);
assert_eq!(room.active_service_members_count().unwrap(), 2);
let room = server
.sync_room(
&client,
AnyRoomBuilder::Joined(JoinedRoomBuilder::new(room_id).set_joined_members_count(32)),
)
.await;
assert!(room.active_service_members_count().is_none());
}
#[async_test]
async fn test_cached_active_service_members_resets_when_member_counts_change() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let service_member_id_1 = owned_user_id!("@service_1:localhost");
let service_member_id_2 = owned_user_id!("@service_2:localhost");
let room_id = room_id!("!room:localhost");
let service_members_event = EventFactory::new()
.room(room_id)
.sender(user_id)
.member_hints(BTreeSet::from_iter(vec![
service_member_id_1.clone(),
service_member_id_2.clone(),
]))
.into_raw_sync_state();
let own_member_event =
EventFactory::new().room(room_id).member(user_id).display_name("Me").into_raw_sync_state();
let service_member_1 =
EventFactory::new().room(room_id).member(&service_member_id_1).into_raw();
let service_member_2 =
EventFactory::new().room(room_id).member(&service_member_id_2).into_raw();
let room = server
.sync_room(
&client,
AnyRoomBuilder::Joined(
JoinedRoomBuilder::new(room_id)
.add_state_event(own_member_event)
.add_state_event(service_member_1)
.add_state_event(service_member_2)
.add_state_event(service_members_event),
),
)
.await;
let active_members = room.members_no_sync(RoomMemberships::ACTIVE).await.unwrap();
assert_eq!(active_members.len(), 3);
assert_eq!(room.service_members().unwrap().len(), 2);
assert_eq!(room.update_active_service_members().await.unwrap().unwrap().len(), 2);
assert_eq!(room.active_service_members_count().unwrap(), 2);
let room = server
.sync_room(
&client,
AnyRoomBuilder::Joined(JoinedRoomBuilder::new(room_id).set_joined_members_count(32)),
)
.await;
assert!(room.active_service_members_count().is_none());
}
#[async_test]
async fn test_cached_active_service_members_updates_on_sync_members() {
let server = MatrixMockServer::new().await;
let client = server.client_builder().build().await;
let user_id = client.user_id().unwrap();
let service_member_id_1 = owned_user_id!("@service_1:localhost");
let service_member_id_2 = owned_user_id!("@service_2:localhost");
let room_id = room_id!("!room:localhost");
let service_members_event = EventFactory::new()
.room(room_id)
.sender(user_id)
.member_hints(BTreeSet::from_iter(vec![
service_member_id_1.clone(),
service_member_id_2.clone(),
]))
.into_raw_sync_state();
let own_member_event =
EventFactory::new().room(room_id).member(user_id).display_name("Me").into_raw_sync_state();
let service_member_1 = EventFactory::new()
.room(room_id)
.member(&service_member_id_1)
.into_raw::<RoomMemberEvent>();
let service_member_2 = EventFactory::new()
.room(room_id)
.member(&service_member_id_2)
.into_raw::<RoomMemberEvent>();
let room = server
.sync_room(
&client,
AnyRoomBuilder::Joined(
JoinedRoomBuilder::new(room_id)
.add_state_event(own_member_event)
.add_state_event(service_members_event),
),
)
.await;
let active_members = room.members_no_sync(RoomMemberships::ACTIVE).await.unwrap();
assert_eq!(active_members.len(), 1);
assert_eq!(room.service_members().unwrap().len(), 2);
assert!(room.active_service_members_count().is_none());
server
.mock_get_members()
.ok(vec![service_member_1, service_member_2])
.mock_once()
.mount()
.await;
room.sync_members().await.expect("sync_members");
assert!(room.active_service_members_count().is_some());
assert_eq!(room.active_service_members_count().unwrap(), 2);
}