2020-05-13 13:57:09 +00:00
|
|
|
use std::collections::HashMap;
|
2020-05-08 07:49:55 +00:00
|
|
|
use std::convert::TryFrom;
|
2020-04-07 00:59:44 +00:00
|
|
|
use std::panic;
|
2020-04-06 11:12:02 +00:00
|
|
|
|
2020-05-08 07:49:55 +00:00
|
|
|
use http::Response;
|
|
|
|
|
|
|
|
use matrix_sdk_common::api::r0::sync::sync_events::Response as SyncResponse;
|
|
|
|
use matrix_sdk_common::events::{
|
2020-04-07 12:55:42 +00:00
|
|
|
collections::{
|
|
|
|
all::{RoomEvent, StateEvent},
|
|
|
|
only::Event,
|
|
|
|
},
|
2020-04-07 00:59:44 +00:00
|
|
|
presence::PresenceEvent,
|
2020-05-13 13:57:09 +00:00
|
|
|
stripped::AnyStrippedStateEvent,
|
2020-04-23 08:52:47 +00:00
|
|
|
EventJson, TryFromRaw,
|
2020-04-07 00:59:44 +00:00
|
|
|
};
|
2020-05-13 13:57:09 +00:00
|
|
|
use matrix_sdk_common::identifiers::RoomId;
|
2020-04-07 00:59:44 +00:00
|
|
|
|
2020-05-08 14:12:21 +00:00
|
|
|
pub use matrix_sdk_test_macros::async_test;
|
|
|
|
|
|
|
|
/// Embedded event files
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum EventsFile {
|
|
|
|
Alias,
|
|
|
|
Aliases,
|
|
|
|
Create,
|
|
|
|
FullyRead,
|
|
|
|
HistoryVisibility,
|
|
|
|
JoinRules,
|
|
|
|
Member,
|
|
|
|
MessageEmote,
|
|
|
|
MessageNotice,
|
|
|
|
MessageText,
|
|
|
|
Name,
|
|
|
|
PowerLevels,
|
|
|
|
Presence,
|
|
|
|
RedactedInvalid,
|
|
|
|
RedactedState,
|
|
|
|
Redacted,
|
|
|
|
Redaction,
|
|
|
|
RoomAvatar,
|
|
|
|
Tag,
|
|
|
|
Topic,
|
|
|
|
Typing,
|
|
|
|
}
|
|
|
|
|
2020-04-07 20:11:35 +00:00
|
|
|
/// Easily create events to stream into either a Client or a `Room` for testing.
|
2020-04-07 00:59:44 +00:00
|
|
|
#[derive(Default)]
|
|
|
|
pub struct EventBuilder {
|
|
|
|
/// The events that determine the state of a `Room`.
|
2020-05-13 13:57:09 +00:00
|
|
|
joined_room_events: HashMap<RoomId, Vec<RoomEvent>>,
|
|
|
|
/// The events that determine the state of a `Room`.
|
2020-05-13 14:25:42 +00:00
|
|
|
invited_room_events: HashMap<RoomId, Vec<AnyStrippedStateEvent>>,
|
2020-05-13 13:57:09 +00:00
|
|
|
/// The events that determine the state of a `Room`.
|
2020-05-13 14:25:42 +00:00
|
|
|
left_room_events: HashMap<RoomId, Vec<RoomEvent>>,
|
2020-04-07 00:59:44 +00:00
|
|
|
/// The presence events that determine the presence state of a `RoomMember`.
|
|
|
|
presence_events: Vec<PresenceEvent>,
|
|
|
|
/// The state events that determine the state of a `Room`.
|
|
|
|
state_events: Vec<StateEvent>,
|
2020-04-07 12:55:42 +00:00
|
|
|
/// The ephemeral room events that determine the state of a `Room`.
|
|
|
|
ephemeral: Vec<Event>,
|
|
|
|
/// The account data events that determine the state of a `Room`.
|
|
|
|
account_data: Vec<Event>,
|
|
|
|
}
|
|
|
|
|
2020-04-07 00:59:44 +00:00
|
|
|
impl EventBuilder {
|
2020-04-07 12:55:42 +00:00
|
|
|
/// Add an event to the room events `Vec`.
|
2020-05-08 14:12:21 +00:00
|
|
|
pub fn add_ephemeral<Ev: TryFromRaw>(
|
2020-04-07 12:55:42 +00:00
|
|
|
mut self,
|
2020-05-08 14:12:21 +00:00
|
|
|
file: EventsFile,
|
2020-04-07 12:55:42 +00:00
|
|
|
variant: fn(Ev) -> Event,
|
|
|
|
) -> Self {
|
2020-05-08 14:12:21 +00:00
|
|
|
let val: &str = match file {
|
2020-05-26 19:30:15 +00:00
|
|
|
EventsFile::Typing => include_str!("../test_data/events/typing.json"),
|
2020-05-08 14:12:21 +00:00
|
|
|
_ => panic!("unknown ephemeral event file {:?}", file),
|
|
|
|
};
|
|
|
|
|
2020-04-23 08:52:47 +00:00
|
|
|
let event = serde_json::from_str::<EventJson<Ev>>(&val)
|
2020-04-07 12:55:42 +00:00
|
|
|
.unwrap()
|
2020-04-23 08:52:47 +00:00
|
|
|
.deserialize()
|
2020-04-07 12:55:42 +00:00
|
|
|
.unwrap();
|
|
|
|
self.ephemeral.push(variant(event));
|
2020-04-07 00:59:44 +00:00
|
|
|
self
|
2020-04-06 11:12:02 +00:00
|
|
|
}
|
|
|
|
|
2020-04-07 00:59:44 +00:00
|
|
|
/// Add an event to the room events `Vec`.
|
2020-05-08 14:12:21 +00:00
|
|
|
#[allow(clippy::match_single_binding, unused)]
|
|
|
|
pub fn add_account<Ev: TryFromRaw>(
|
2020-04-07 12:55:42 +00:00
|
|
|
mut self,
|
2020-05-08 14:12:21 +00:00
|
|
|
file: EventsFile,
|
2020-04-07 12:55:42 +00:00
|
|
|
variant: fn(Ev) -> Event,
|
|
|
|
) -> Self {
|
2020-05-08 14:12:21 +00:00
|
|
|
let val: &str = match file {
|
|
|
|
_ => panic!("unknown account event file {:?}", file),
|
|
|
|
};
|
|
|
|
|
2020-04-23 08:52:47 +00:00
|
|
|
let event = serde_json::from_str::<EventJson<Ev>>(&val)
|
2020-04-07 12:55:42 +00:00
|
|
|
.unwrap()
|
2020-04-23 08:52:47 +00:00
|
|
|
.deserialize()
|
2020-04-07 12:55:42 +00:00
|
|
|
.unwrap();
|
|
|
|
self.account_data.push(variant(event));
|
2020-04-07 00:59:44 +00:00
|
|
|
self
|
|
|
|
}
|
2020-04-06 11:12:02 +00:00
|
|
|
|
2020-04-07 00:59:44 +00:00
|
|
|
/// Add an event to the room events `Vec`.
|
2020-05-08 14:12:21 +00:00
|
|
|
pub fn add_room_event<Ev: TryFromRaw>(
|
2020-04-07 12:55:42 +00:00
|
|
|
mut self,
|
2020-05-08 14:12:21 +00:00
|
|
|
file: EventsFile,
|
2020-04-07 12:55:42 +00:00
|
|
|
variant: fn(Ev) -> RoomEvent,
|
|
|
|
) -> Self {
|
2020-05-08 14:12:21 +00:00
|
|
|
let val = match file {
|
2020-05-26 19:30:15 +00:00
|
|
|
EventsFile::Member => include_str!("../test_data/events/member.json"),
|
|
|
|
EventsFile::PowerLevels => include_str!("../test_data/events/power_levels.json"),
|
2020-05-08 14:12:21 +00:00
|
|
|
_ => panic!("unknown room event file {:?}", file),
|
|
|
|
};
|
|
|
|
|
2020-04-23 08:52:47 +00:00
|
|
|
let event = serde_json::from_str::<EventJson<Ev>>(&val)
|
2020-04-07 12:55:42 +00:00
|
|
|
.unwrap()
|
2020-04-23 08:52:47 +00:00
|
|
|
.deserialize()
|
2020-04-07 12:55:42 +00:00
|
|
|
.unwrap();
|
2020-05-13 13:57:09 +00:00
|
|
|
self.add_joined_event(
|
|
|
|
&RoomId::try_from("!SVkFJHzfwvuaIEawgC:localhost").unwrap(),
|
|
|
|
variant(event),
|
|
|
|
);
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add_custom_joined_event<Ev: TryFromRaw>(
|
|
|
|
mut self,
|
2020-05-14 08:57:21 +00:00
|
|
|
room_id: &RoomId,
|
2020-05-13 13:57:09 +00:00
|
|
|
event: serde_json::Value,
|
|
|
|
variant: fn(Ev) -> RoomEvent,
|
|
|
|
) -> Self {
|
|
|
|
let event = serde_json::from_value::<EventJson<Ev>>(event)
|
|
|
|
.unwrap()
|
|
|
|
.deserialize()
|
|
|
|
.unwrap();
|
2020-05-14 08:57:21 +00:00
|
|
|
self.add_joined_event(room_id, variant(event));
|
2020-05-13 13:57:09 +00:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
fn add_joined_event(&mut self, room_id: &RoomId, event: RoomEvent) {
|
|
|
|
self.joined_room_events
|
|
|
|
.entry(room_id.clone())
|
|
|
|
.or_insert_with(Vec::new)
|
|
|
|
.push(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add_custom_invited_event<Ev: TryFromRaw>(
|
|
|
|
mut self,
|
2020-05-13 14:25:42 +00:00
|
|
|
room_id: &RoomId,
|
2020-05-13 13:57:09 +00:00
|
|
|
event: serde_json::Value,
|
|
|
|
variant: fn(Ev) -> AnyStrippedStateEvent,
|
|
|
|
) -> Self {
|
|
|
|
let event = serde_json::from_value::<EventJson<Ev>>(event)
|
|
|
|
.unwrap()
|
|
|
|
.deserialize()
|
|
|
|
.unwrap();
|
2020-05-13 14:25:42 +00:00
|
|
|
self.invited_room_events
|
|
|
|
.entry(room_id.clone())
|
|
|
|
.or_insert_with(Vec::new)
|
|
|
|
.push(variant(event));
|
2020-05-13 13:57:09 +00:00
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn add_custom_left_event<Ev: TryFromRaw>(
|
|
|
|
mut self,
|
2020-05-13 14:25:42 +00:00
|
|
|
room_id: &RoomId,
|
2020-05-13 13:57:09 +00:00
|
|
|
event: serde_json::Value,
|
|
|
|
variant: fn(Ev) -> RoomEvent,
|
|
|
|
) -> Self {
|
|
|
|
let event = serde_json::from_value::<EventJson<Ev>>(event)
|
|
|
|
.unwrap()
|
|
|
|
.deserialize()
|
|
|
|
.unwrap();
|
2020-05-13 14:25:42 +00:00
|
|
|
self.left_room_events
|
|
|
|
.entry(room_id.clone())
|
|
|
|
.or_insert_with(Vec::new)
|
|
|
|
.push(variant(event));
|
2020-04-07 00:59:44 +00:00
|
|
|
self
|
|
|
|
}
|
2020-04-06 11:12:02 +00:00
|
|
|
|
2020-04-07 00:59:44 +00:00
|
|
|
/// Add a state event to the state events `Vec`.
|
2020-05-08 14:12:21 +00:00
|
|
|
pub fn add_state_event<Ev: TryFromRaw>(
|
2020-04-07 12:55:42 +00:00
|
|
|
mut self,
|
2020-05-08 14:12:21 +00:00
|
|
|
file: EventsFile,
|
2020-04-07 12:55:42 +00:00
|
|
|
variant: fn(Ev) -> StateEvent,
|
|
|
|
) -> Self {
|
2020-05-08 14:12:21 +00:00
|
|
|
let val = match file {
|
2020-05-26 19:30:15 +00:00
|
|
|
EventsFile::Alias => include_str!("../test_data/events/alias.json"),
|
|
|
|
EventsFile::Aliases => include_str!("../test_data/events/aliases.json"),
|
|
|
|
EventsFile::Name => include_str!("../test_data/events/name.json"),
|
2020-05-08 14:12:21 +00:00
|
|
|
_ => panic!("unknown state event file {:?}", file),
|
|
|
|
};
|
|
|
|
|
2020-04-23 08:52:47 +00:00
|
|
|
let event = serde_json::from_str::<EventJson<Ev>>(&val)
|
2020-04-07 12:55:42 +00:00
|
|
|
.unwrap()
|
2020-04-23 08:52:47 +00:00
|
|
|
.deserialize()
|
2020-04-07 12:55:42 +00:00
|
|
|
.unwrap();
|
2020-04-07 00:59:44 +00:00
|
|
|
self.state_events.push(variant(event));
|
|
|
|
self
|
|
|
|
}
|
2020-04-06 11:12:02 +00:00
|
|
|
|
2020-05-08 14:12:21 +00:00
|
|
|
/// Add an presence event to the presence events `Vec`.
|
|
|
|
pub fn add_presence_event(mut self, file: EventsFile) -> Self {
|
|
|
|
let val = match file {
|
2020-05-26 19:30:15 +00:00
|
|
|
EventsFile::Presence => include_str!("../test_data/events/presence.json"),
|
2020-05-08 14:12:21 +00:00
|
|
|
_ => panic!("unknown presence event file {:?}", file),
|
|
|
|
};
|
|
|
|
|
2020-04-23 08:52:47 +00:00
|
|
|
let event = serde_json::from_str::<EventJson<PresenceEvent>>(&val)
|
2020-04-07 12:55:42 +00:00
|
|
|
.unwrap()
|
2020-04-23 08:52:47 +00:00
|
|
|
.deserialize()
|
2020-04-07 12:55:42 +00:00
|
|
|
.unwrap();
|
2020-04-07 00:59:44 +00:00
|
|
|
self.presence_events.push(event);
|
|
|
|
self
|
|
|
|
}
|
2020-04-06 11:12:02 +00:00
|
|
|
|
2020-05-07 14:22:18 +00:00
|
|
|
/// Consumes `ResponseBuilder and returns SyncResponse.
|
2020-05-13 13:57:09 +00:00
|
|
|
pub fn build_sync_response(mut self) -> SyncResponse {
|
|
|
|
let main_room_id = RoomId::try_from("!SVkFJHzfwvuaIEawgC:localhost").unwrap();
|
|
|
|
|
|
|
|
// TODO generalize this.
|
|
|
|
let joined_room = serde_json::json!({
|
|
|
|
"summary": {},
|
|
|
|
"account_data": {
|
|
|
|
"events": self.account_data
|
|
|
|
},
|
|
|
|
"ephemeral": {
|
|
|
|
"events": self.ephemeral
|
|
|
|
},
|
|
|
|
"state": {
|
|
|
|
"events": self.state_events
|
|
|
|
},
|
|
|
|
"timeline": {
|
|
|
|
"events": self.joined_room_events.remove(&main_room_id).unwrap_or_default(),
|
|
|
|
"limited": true,
|
|
|
|
"prev_batch": "t392-516_47314_0_7_1_1_1_11444_1"
|
|
|
|
},
|
|
|
|
"unread_notifications": {
|
|
|
|
"highlight_count": 0,
|
|
|
|
"notification_count": 11
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-05-13 14:25:42 +00:00
|
|
|
let mut joined_rooms: HashMap<RoomId, serde_json::Value> = HashMap::new();
|
2020-05-13 13:57:09 +00:00
|
|
|
|
2020-05-13 14:25:42 +00:00
|
|
|
joined_rooms.insert(main_room_id, joined_room);
|
2020-05-13 13:57:09 +00:00
|
|
|
|
|
|
|
for (room_id, events) in self.joined_room_events.drain() {
|
|
|
|
let joined_room = serde_json::json!({
|
|
|
|
"summary": {},
|
|
|
|
"account_data": {
|
|
|
|
"events": [],
|
|
|
|
},
|
|
|
|
"ephemeral": {
|
|
|
|
"events": [],
|
|
|
|
},
|
|
|
|
"state": {
|
|
|
|
"events": [],
|
|
|
|
},
|
|
|
|
"timeline": {
|
|
|
|
"events": events,
|
|
|
|
"limited": true,
|
|
|
|
"prev_batch": "t392-516_47314_0_7_1_1_1_11444_1"
|
|
|
|
},
|
|
|
|
"unread_notifications": {
|
|
|
|
"highlight_count": 0,
|
|
|
|
"notification_count": 11
|
|
|
|
}
|
|
|
|
});
|
2020-05-13 14:25:42 +00:00
|
|
|
joined_rooms.insert(room_id, joined_room);
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut left_rooms: HashMap<RoomId, serde_json::Value> = HashMap::new();
|
|
|
|
|
|
|
|
for (room_id, events) in self.left_room_events.drain() {
|
|
|
|
let room = serde_json::json!({
|
|
|
|
"state": {
|
|
|
|
"events": [],
|
|
|
|
},
|
|
|
|
"timeline": {
|
|
|
|
"events": events,
|
|
|
|
"limited": false,
|
|
|
|
"prev_batch": "t392-516_47314_0_7_1_1_1_11444_1"
|
|
|
|
},
|
|
|
|
});
|
|
|
|
left_rooms.insert(room_id, room);
|
2020-05-13 13:57:09 +00:00
|
|
|
}
|
|
|
|
|
2020-05-14 08:57:21 +00:00
|
|
|
let mut invited_rooms: HashMap<RoomId, serde_json::Value> = HashMap::new();
|
|
|
|
|
|
|
|
for (room_id, events) in self.invited_room_events.drain() {
|
|
|
|
let room = serde_json::json!({
|
|
|
|
"invite_state": {
|
|
|
|
"events": events,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
invited_rooms.insert(room_id, room);
|
|
|
|
}
|
|
|
|
|
2020-04-07 12:55:42 +00:00
|
|
|
let body = serde_json::json! {
|
|
|
|
{
|
|
|
|
"device_one_time_keys_count": {},
|
|
|
|
"next_batch": "s526_47314_0_7_1_1_1_11444_1",
|
|
|
|
"device_lists": {
|
|
|
|
"changed": [],
|
|
|
|
"left": []
|
|
|
|
},
|
|
|
|
"rooms": {
|
2020-05-14 08:57:21 +00:00
|
|
|
"invite": invited_rooms,
|
2020-05-13 14:25:42 +00:00
|
|
|
"join": joined_rooms,
|
|
|
|
"leave": left_rooms,
|
2020-04-07 12:55:42 +00:00
|
|
|
},
|
|
|
|
"to_device": {
|
|
|
|
"events": []
|
|
|
|
},
|
|
|
|
"presence": {
|
|
|
|
"events": []
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2020-05-07 14:22:18 +00:00
|
|
|
let response = Response::builder()
|
|
|
|
.body(serde_json::to_vec(&body).unwrap())
|
|
|
|
.unwrap();
|
|
|
|
SyncResponse::try_from(response).unwrap()
|
2020-04-06 13:11:38 +00:00
|
|
|
}
|
2020-04-06 11:12:02 +00:00
|
|
|
}
|
2020-05-08 14:12:21 +00:00
|
|
|
|
|
|
|
/// Embedded sync reponse files
|
|
|
|
pub enum SyncResponseFile {
|
|
|
|
Default,
|
|
|
|
DefaultWithSummary,
|
|
|
|
Invite,
|
|
|
|
Leave,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get specific API responses for testing
|
|
|
|
pub fn sync_response(kind: SyncResponseFile) -> SyncResponse {
|
|
|
|
let data = match kind {
|
2020-05-26 19:30:15 +00:00
|
|
|
SyncResponseFile::Default => include_bytes!("../test_data/sync.json").to_vec(),
|
2020-05-08 14:12:21 +00:00
|
|
|
SyncResponseFile::DefaultWithSummary => {
|
2020-05-26 19:30:15 +00:00
|
|
|
include_bytes!("../test_data/sync_with_summary.json").to_vec()
|
2020-05-08 14:12:21 +00:00
|
|
|
}
|
2020-05-26 19:30:15 +00:00
|
|
|
SyncResponseFile::Invite => include_bytes!("../test_data/invite_sync.json").to_vec(),
|
|
|
|
SyncResponseFile::Leave => include_bytes!("../test_data/leave_sync.json").to_vec(),
|
2020-05-08 14:12:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
let response = Response::builder().body(data.to_vec()).unwrap();
|
|
|
|
SyncResponse::try_from(response).unwrap()
|
|
|
|
}
|