add individual events for tests, working TestRunner
parent
854948fc6d
commit
78f92130fa
|
@ -65,3 +65,4 @@ tracing-subscriber = "0.2.3"
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
mockito = "0.23.3"
|
mockito = "0.23.3"
|
||||||
serde = "1.0.105"
|
serde = "1.0.105"
|
||||||
|
ansi_term = "0.12.1"
|
||||||
|
|
|
@ -7,8 +7,12 @@ mod test_it {
|
||||||
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::panic;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::identifiers::UserId;
|
use crate::identifiers::{RoomId, UserId};
|
||||||
use crate::events::{
|
use crate::events::{
|
||||||
collections::all::RoomEvent,
|
collections::all::RoomEvent,
|
||||||
room::{
|
room::{
|
||||||
|
@ -18,15 +22,13 @@ mod test_it {
|
||||||
};
|
};
|
||||||
use crate::{AsyncClient, Session, SyncSettings};
|
use crate::{AsyncClient, Session, SyncSettings};
|
||||||
|
|
||||||
|
use ansi_term::Colour;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use mockito::{mock, Matcher};
|
use mockito::{mock, Matcher};
|
||||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use std::convert::TryFrom;
|
use crate::models::Room;
|
||||||
use std::str::FromStr;
|
|
||||||
use std::time::Duration;
|
|
||||||
use std::panic;
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct ResponseBuilder {
|
pub struct ResponseBuilder {
|
||||||
|
@ -34,19 +36,28 @@ mod test_it {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TestRunner {
|
pub struct TestRunner {
|
||||||
|
/// Used when testing the whole client
|
||||||
client: Option<AsyncClient>,
|
client: Option<AsyncClient>,
|
||||||
|
/// Used To test the models
|
||||||
|
room: Option<Room>,
|
||||||
|
/// When testing the models a vec of RoomEvents is needed.
|
||||||
|
events: Vec<RoomEvent>,
|
||||||
/// A `Vec` of callbacks that should assert something about the client.
|
/// A `Vec` of callbacks that should assert something about the client.
|
||||||
///
|
///
|
||||||
/// The callback should panic if the state is unexpected (use `assert_*!` macro)
|
/// The callback should panic if the state is unexpected (use `assert_*!` macro)
|
||||||
assertions: Vec<fn(&AsyncClient)>,
|
client_assertions: Vec<fn(&AsyncClient)>,
|
||||||
|
/// A `Vec` of callbacks that should assert something about the room.
|
||||||
|
///
|
||||||
|
/// The callback should panic if the state is unexpected (use `assert_*!` macro)
|
||||||
|
room_assertions: Vec<fn(&Room)>,
|
||||||
/// `mokito::Mock`
|
/// `mokito::Mock`
|
||||||
mock: mockito::Mock,
|
mock: Option<mockito::Mock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ResponseBuilder {
|
impl ResponseBuilder {
|
||||||
|
|
||||||
/// Creates an `IncomingResponse` to hold events for a sync.
|
/// Creates an `IncomingResponse` to hold events for a sync.
|
||||||
pub fn create_sync_response(mut self) -> &mut Self {
|
pub fn create_sync_response(mut self) -> Self {
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -57,11 +68,10 @@ mod test_it {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an event either to the event stream or the appropriate `IncomingResponse` field.
|
/// Add an event to the events `Vec`.
|
||||||
pub fn add_event_from_file<Ev: TryFromRaw, P: AsRef<Path>>(mut self, path: P, variant: fn(Ev) -> RoomEvent) -> Self {
|
pub fn add_event_from_file<Ev: TryFromRaw, P: AsRef<Path>>(mut self, path: P, variant: fn(Ev) -> RoomEvent) -> Self {
|
||||||
let val = fs::read_to_string(path.as_ref()).expect(&format!("file not found {:?}", path.as_ref()));
|
let val = fs::read_to_string(path.as_ref()).expect(&format!("file not found {:?}", path.as_ref()));
|
||||||
let json = serde_json::value::Value::from_str(&val).expect(&format!("not valid json {}", val));
|
let event = serde_json::from_str::<ruma_events::EventResult<Ev>>(&val).unwrap().into_result().unwrap();
|
||||||
let event = serde_json::from_value::<ruma_events::EventResult<Ev>>(json).unwrap().into_result().unwrap();
|
|
||||||
self.add_event(variant(event));
|
self.add_event(variant(event));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -74,38 +84,127 @@ mod test_it {
|
||||||
///
|
///
|
||||||
/// The `TestRunner` streams the events to the client and enables methods to set assertions
|
/// The `TestRunner` streams the events to the client and enables methods to set assertions
|
||||||
/// about the state of the client.
|
/// about the state of the client.
|
||||||
pub fn build(mut self) -> TestRunner {
|
pub fn build_responses(mut self, method: &str, path: &str) -> TestRunner {
|
||||||
let mock = mock("POST", "/_matrix/client/r0/login")
|
let body = serde_json::to_string(&self.events).unwrap();
|
||||||
|
let mock = Some(mock(method, path)
|
||||||
.with_status(200)
|
.with_status(200)
|
||||||
.with_body_from_file("tests/data/login_response.json")
|
.with_body(body)
|
||||||
.create();
|
.create());
|
||||||
|
|
||||||
TestRunner {
|
TestRunner {
|
||||||
client: None,
|
client: None,
|
||||||
assertions: Vec::new(),
|
room: None,
|
||||||
|
events: Vec::new(),
|
||||||
|
client_assertions: Vec::new(),
|
||||||
|
room_assertions: Vec::new(),
|
||||||
mock,
|
mock,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Consumes `ResponseBuilder and returns a `TestRunner`.
|
||||||
|
///
|
||||||
|
/// The `TestRunner` streams the events to the client and enables methods to set assertions
|
||||||
|
/// about the state of the client.
|
||||||
|
pub fn build_room_events(mut self, room_id: &RoomId, user_id: &UserId) -> TestRunner {
|
||||||
|
TestRunner {
|
||||||
|
client: None,
|
||||||
|
room: Some(Room::new(room_id, user_id)),
|
||||||
|
events: self.events,
|
||||||
|
client_assertions: Vec::new(),
|
||||||
|
room_assertions: Vec::new(),
|
||||||
|
mock: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestRunner {
|
impl TestRunner {
|
||||||
pub fn set_client(&mut self, client: AsyncClient) -> &mut Self {
|
pub fn set_client(mut self, client: AsyncClient) -> Self {
|
||||||
self.client = Some(client);
|
self.client = Some(client);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
pub fn run_test(self) -> Result<(), Vec<String>> {
|
|
||||||
|
|
||||||
|
pub fn add_client_assert(mut self, assert: fn(&AsyncClient)) -> Self {
|
||||||
|
self.client_assertions.push(assert);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_room_assert(mut self, assert: fn(&Room)) -> Self {
|
||||||
|
self.room_assertions.push(assert);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_client_tests(mut self) -> Result<(), Vec<String>> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn run_room_tests(mut self) -> Result<(), Vec<String>> {
|
||||||
|
let mut errs = Vec::new();
|
||||||
|
let mut room = self.room.unwrap();
|
||||||
|
for event in &self.events {
|
||||||
|
match event {
|
||||||
|
RoomEvent::RoomMember(m) => room.handle_membership(m),
|
||||||
|
RoomEvent::RoomName(n) => room.handle_room_name(n),
|
||||||
|
RoomEvent::RoomCanonicalAlias(ca) => room.handle_canonical(ca),
|
||||||
|
RoomEvent::RoomAliases(a) => room.handle_room_aliases(a),
|
||||||
|
RoomEvent::RoomPowerLevels(p) => room.handle_power_level(p),
|
||||||
|
// RoomEvent::RoomEncryption(e) => room.handle_encryption_event(e),
|
||||||
|
_ => todo!("implement more RoomEvent variants"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
for assert in self.room_assertions {
|
||||||
|
if let Err(e) = panic::catch_unwind(|| assert(&room)) {
|
||||||
|
errs.push(stringify!(e).to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if errs.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(errs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_test(mut self) {
|
||||||
|
let errs = if let Some(room) = &self.room {
|
||||||
|
self.run_room_tests()
|
||||||
|
} else if let Some(cli) = &self.client {
|
||||||
|
self.run_client_tests()
|
||||||
|
} else {
|
||||||
|
panic!("must have either AsyncClient or Room")
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(errs) = errs {
|
||||||
|
let err_str = errs.join(&format!("{}\n", Colour::Red.paint("Error: ")));
|
||||||
|
if !errs.is_empty() {
|
||||||
|
panic!("{}", Colour::Red.paint("some tests failed"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_room_users(room: &Room) {
|
||||||
|
assert_eq!(room.members.len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_room_power(room: &Room) {
|
||||||
|
assert!(room.power_levels.is_some());
|
||||||
|
assert_eq!(room.power_levels.as_ref().unwrap().kick, js_int::Int::new(50).unwrap());
|
||||||
|
let admin = room.members.get(&UserId::try_from("@example:localhost").unwrap()).unwrap();
|
||||||
|
assert_eq!(admin.power_level.unwrap(), js_int::Int::new(100).unwrap());
|
||||||
|
println!("{:#?}", room);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test() {
|
fn room_events() {
|
||||||
|
let rid = RoomId::try_from("!roomid:room.com").unwrap();
|
||||||
|
let uid = UserId::try_from("@example:localhost").unwrap();
|
||||||
let mut bld = ResponseBuilder::default();
|
let mut bld = ResponseBuilder::default();
|
||||||
let runner = bld.add_event_from_file("./tests/data/events/power_levels.json", RoomEvent::RoomPowerLevels)
|
let runner = bld.add_event_from_file("./tests/data/events/member.json", RoomEvent::RoomMember)
|
||||||
.build();
|
.add_event_from_file("./tests/data/events/power_levels.json", RoomEvent::RoomPowerLevels)
|
||||||
|
.build_room_events(&rid, &uid)
|
||||||
|
.add_room_assert(test_room_power)
|
||||||
|
.add_room_assert(test_room_users);
|
||||||
|
|
||||||
|
runner.run_test();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"alias": "#tutorial:localhost"
|
||||||
|
},
|
||||||
|
"event_id": "$15139375513VdeRF:localhost",
|
||||||
|
"origin_server_ts": 1513937551461,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.canonical_alias",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 7034220433
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"creator": "@example:localhost",
|
||||||
|
"m.federate": true,
|
||||||
|
"room_version": "1"
|
||||||
|
},
|
||||||
|
"event_id": "$151957878228ekrDs:localhost",
|
||||||
|
"origin_server_ts": 1519578782185,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.create",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1392989709
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"event_id": "$someplace:example.org"
|
||||||
|
},
|
||||||
|
"room_id": "!somewhere:example.org",
|
||||||
|
"type": "m.fully_read"
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"history_visibility": "world_readable"
|
||||||
|
},
|
||||||
|
"event_id": "$151957878235ricnD:localhost",
|
||||||
|
"origin_server_ts": 1519578782195,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.history_visibility",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1392989715
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"join_rule": "public"
|
||||||
|
},
|
||||||
|
"event_id": "$151957878231iejdB:localhost",
|
||||||
|
"origin_server_ts": 1519578782192,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.join_rules",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1392989713
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"avatar_url": null,
|
||||||
|
"displayname": "example",
|
||||||
|
"membership": "join"
|
||||||
|
},
|
||||||
|
"event_id": "$151800140517rfvjc:localhost",
|
||||||
|
"membership": "join",
|
||||||
|
"origin_server_ts": 1518001405556,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"state_key": "@example:localhost",
|
||||||
|
"type": "m.room.member",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 2970366338,
|
||||||
|
"replaces_state": "$151800111315tsynI:localhost"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "is dancing", "format": "org.matrix.custom.html",
|
||||||
|
"formatted_body": "<strong>is dancing</strong>",
|
||||||
|
"msgtype": "m.emote"
|
||||||
|
},
|
||||||
|
"event_id": "$152037280074GZeOm:localhost",
|
||||||
|
"origin_server_ts": 1520372800469,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 598971425
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"origin_server_ts": 1533565163841,
|
||||||
|
"sender": "@_neb_github:matrix.org",
|
||||||
|
"event_id": "$153356516319138IHRIC:matrix.org",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 743
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"body": "https://github.com/matrix-org/matrix-python-sdk/issues/266 : Consider allowing MatrixClient.__init__ to take sync_token kwarg",
|
||||||
|
"format": "org.matrix.custom.html",
|
||||||
|
"formatted_body": "<a href='https://github.com/matrix-org/matrix-python-sdk/pull/313'>313: nio wins!</a>",
|
||||||
|
"msgtype": "m.notice"
|
||||||
|
},
|
||||||
|
"type": "m.room.message",
|
||||||
|
"room_id": "!YHhmBTmGBHGQOlGpaZ:matrix.org"
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"body": "is dancing", "format": "org.matrix.custom.html",
|
||||||
|
"formatted_body": "<strong>is dancing</strong>",
|
||||||
|
"msgtype": "m.text"
|
||||||
|
},
|
||||||
|
"event_id": "$152037280074GZeOm:localhost",
|
||||||
|
"origin_server_ts": 1520372800469,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 598971425
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"name": "#tutorial:localhost"
|
||||||
|
},
|
||||||
|
"event_id": "$15139375513VdeRF:localhost",
|
||||||
|
"origin_server_ts": 1513937551461,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.name",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 7034220433
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"content": {},
|
||||||
|
"event_id": "$15275046980maRLj:localhost",
|
||||||
|
"origin_server_ts": 1527504698685,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"type": "m.room.message",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 19334,
|
||||||
|
"redacted_because": {
|
||||||
|
"content": {},
|
||||||
|
"event_id": "$15275047031IXQRi:localhost",
|
||||||
|
"origin_server_ts": 1527504703496,
|
||||||
|
"redacts": "$15275046980maRLj:localhost",
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"type": "m.room.redaction",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 14523
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"redacted_by": "$15275047031IXQRi:localhost"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"content": {},
|
||||||
|
"event_id": "$15275046980maRLj:localhost",
|
||||||
|
"origin_server_ts": 1527504698685,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"type": "m.room.message"
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"content": {},
|
||||||
|
"event_id": "$example_id:example.org",
|
||||||
|
"origin_server_ts": 1532324933640,
|
||||||
|
"sender": "@example:example.org",
|
||||||
|
"state_key": "test_state_key",
|
||||||
|
"type": "m.some.state",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 30693154231,
|
||||||
|
"redacted_because": {
|
||||||
|
"content": {},
|
||||||
|
"event_id": "$redaction_example_id:example.org",
|
||||||
|
"origin_server_ts": 1532324940702,
|
||||||
|
"redacts": "$example_id:example.org",
|
||||||
|
"sender": "@example:example:org",
|
||||||
|
"type": "m.room.redaction",
|
||||||
|
"unsigned": {"age": 30693147169}
|
||||||
|
},
|
||||||
|
"redacted_by": "$redaction_example_id:example.org"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"reason": "😀"
|
||||||
|
},
|
||||||
|
"event_id": "$151957878228ssqrJ:localhost",
|
||||||
|
"origin_server_ts": 1519578782185,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"type": "m.room.redaction",
|
||||||
|
"redacts": "$151957878228ssqrj:localhost"
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"info": {
|
||||||
|
"h": 398,
|
||||||
|
"mimetype": "image/jpeg",
|
||||||
|
"size": 31037,
|
||||||
|
"w": 394
|
||||||
|
},
|
||||||
|
"url": "mxc://domain.com/JWEIFJgwEIhweiWJE"
|
||||||
|
},
|
||||||
|
"event_id": "$143273582443PhrSn:domain.com",
|
||||||
|
"origin_server_ts": 1432735824653,
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:domain.com",
|
||||||
|
"sender": "@example:domain.com",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.avatar",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1234
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"tags": {
|
||||||
|
"u.work": {
|
||||||
|
"order": 0.9
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "m.tag"
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"topic": "😀"
|
||||||
|
},
|
||||||
|
"event_id": "$151957878228ssqrJ:localhost",
|
||||||
|
"origin_server_ts": 1519578782185,
|
||||||
|
"sender": "@example:localhost",
|
||||||
|
"state_key": "",
|
||||||
|
"type": "m.room.topic",
|
||||||
|
"unsigned": {
|
||||||
|
"age": 1392989709,
|
||||||
|
"prev_content": {
|
||||||
|
"topic": "test"
|
||||||
|
},
|
||||||
|
"prev_sender": "@example:localhost",
|
||||||
|
"replaces_state": "$151957069225EVYKm:localhost"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"user_ids": [
|
||||||
|
"@alice:matrix.org",
|
||||||
|
"@bob:example.com"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"room_id": "!jEsUZKDJdhlrceRyVU:example.org",
|
||||||
|
"type": "m.typing"
|
||||||
|
}
|
Loading…
Reference in New Issue