state-res: Move tests into the crate and make test_utils private
This commit is contained in:
parent
3b9bd1fc76
commit
3c0493bddf
@ -20,8 +20,8 @@ mod error;
|
|||||||
pub mod event_auth;
|
pub mod event_auth;
|
||||||
pub mod room_version;
|
pub mod room_version;
|
||||||
mod state_event;
|
mod state_event;
|
||||||
#[doc(hidden)]
|
#[cfg(test)]
|
||||||
pub mod test_utils;
|
mod test_utils;
|
||||||
|
|
||||||
pub use error::{Error, Result};
|
pub use error::{Error, Result};
|
||||||
pub use event_auth::{auth_check, auth_types_for_event};
|
pub use event_auth::{auth_check, auth_types_for_event};
|
||||||
@ -628,3 +628,582 @@ pub fn is_power_event<E: Event>(event: &E) -> bool {
|
|||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::{
|
||||||
|
collections::{HashMap, HashSet},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
|
use js_int::uint;
|
||||||
|
use maplit::{hashmap, hashset};
|
||||||
|
use rand::seq::SliceRandom;
|
||||||
|
use ruma_common::MilliSecondsSinceUnixEpoch;
|
||||||
|
use ruma_events::{room::join_rules::JoinRule, EventType};
|
||||||
|
use ruma_identifiers::{EventId, RoomVersionId};
|
||||||
|
use serde_json::json;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
is_power_event,
|
||||||
|
room_version::RoomVersion,
|
||||||
|
test_utils::{
|
||||||
|
alice, bob, charlie, do_check, ella, event_id, member_content_ban, member_content_join,
|
||||||
|
room_id, to_init_pdu_event, to_pdu_event, zara, StateEvent, TestStore, INITIAL_EVENTS,
|
||||||
|
},
|
||||||
|
EventMap, StateMap,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn test_event_sort() {
|
||||||
|
let _ =
|
||||||
|
tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
||||||
|
let events = INITIAL_EVENTS();
|
||||||
|
|
||||||
|
let event_map = events
|
||||||
|
.values()
|
||||||
|
.map(|ev| ((ev.event_type().to_owned(), ev.state_key().to_owned()), ev.clone()))
|
||||||
|
.collect::<StateMap<_>>();
|
||||||
|
|
||||||
|
let auth_chain = HashSet::new();
|
||||||
|
|
||||||
|
let power_events = event_map
|
||||||
|
.values()
|
||||||
|
.filter(|&pdu| is_power_event(&**pdu))
|
||||||
|
.map(|pdu| pdu.event_id().clone())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let sorted_power_events =
|
||||||
|
crate::reverse_topological_power_sort(power_events, &auth_chain, |id| {
|
||||||
|
events.get(id).map(Arc::clone)
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let resolved_power = crate::iterative_auth_check(
|
||||||
|
&RoomVersion::version_6(),
|
||||||
|
&sorted_power_events,
|
||||||
|
HashMap::new(), // unconflicted events
|
||||||
|
|id| events.get(id).map(Arc::clone),
|
||||||
|
)
|
||||||
|
.expect("iterative auth check failed on resolved events");
|
||||||
|
|
||||||
|
// don't remove any events so we know it sorts them all correctly
|
||||||
|
let mut events_to_sort = events.keys().cloned().collect::<Vec<_>>();
|
||||||
|
|
||||||
|
events_to_sort.shuffle(&mut rand::thread_rng());
|
||||||
|
|
||||||
|
let power_level = resolved_power.get(&(EventType::RoomPowerLevels, "".to_owned()));
|
||||||
|
|
||||||
|
let sorted_event_ids =
|
||||||
|
crate::mainline_sort(&events_to_sort, power_level, |id| events.get(id).map(Arc::clone))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
vec![
|
||||||
|
"$CREATE:foo",
|
||||||
|
"$IMA:foo",
|
||||||
|
"$IPOWER:foo",
|
||||||
|
"$IJR:foo",
|
||||||
|
"$IMB:foo",
|
||||||
|
"$IMC:foo",
|
||||||
|
"$START:foo",
|
||||||
|
"$END:foo"
|
||||||
|
],
|
||||||
|
sorted_event_ids.iter().map(|id| id.to_string()).collect::<Vec<_>>()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_sort() {
|
||||||
|
for _ in 0..20 {
|
||||||
|
// since we shuffle the eventIds before we sort them introducing randomness
|
||||||
|
// seems like we should test this a few times
|
||||||
|
test_event_sort()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ban_vs_power_level() {
|
||||||
|
let _ =
|
||||||
|
tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
||||||
|
|
||||||
|
let events = &[
|
||||||
|
to_init_pdu_event(
|
||||||
|
"PA",
|
||||||
|
alice(),
|
||||||
|
EventType::RoomPowerLevels,
|
||||||
|
Some(""),
|
||||||
|
json!({ "users": { alice(): 100, bob(): 50 } }),
|
||||||
|
),
|
||||||
|
to_init_pdu_event(
|
||||||
|
"MA",
|
||||||
|
alice(),
|
||||||
|
EventType::RoomMember,
|
||||||
|
Some(alice().to_string().as_str()),
|
||||||
|
member_content_join(),
|
||||||
|
),
|
||||||
|
to_init_pdu_event(
|
||||||
|
"MB",
|
||||||
|
alice(),
|
||||||
|
EventType::RoomMember,
|
||||||
|
Some(bob().to_string().as_str()),
|
||||||
|
member_content_ban(),
|
||||||
|
),
|
||||||
|
to_init_pdu_event(
|
||||||
|
"PB",
|
||||||
|
bob(),
|
||||||
|
EventType::RoomPowerLevels,
|
||||||
|
Some(""),
|
||||||
|
json!({ "users": { alice(): 100, bob(): 50 } }),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
let edges = vec![vec!["END", "MB", "MA", "PA", "START"], vec!["END", "PA", "PB"]]
|
||||||
|
.into_iter()
|
||||||
|
.map(|list| list.into_iter().map(event_id).collect::<Vec<_>>())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let expected_state_ids =
|
||||||
|
vec!["PA", "MA", "MB"].into_iter().map(event_id).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
do_check(events, edges, expected_state_ids)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn topic_basic() {
|
||||||
|
let _ =
|
||||||
|
tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
||||||
|
|
||||||
|
let events = &[
|
||||||
|
to_init_pdu_event("T1", alice(), EventType::RoomTopic, Some(""), json!({})),
|
||||||
|
to_init_pdu_event(
|
||||||
|
"PA1",
|
||||||
|
alice(),
|
||||||
|
EventType::RoomPowerLevels,
|
||||||
|
Some(""),
|
||||||
|
json!({ "users": { alice(): 100, bob(): 50 } }),
|
||||||
|
),
|
||||||
|
to_init_pdu_event("T2", alice(), EventType::RoomTopic, Some(""), json!({})),
|
||||||
|
to_init_pdu_event(
|
||||||
|
"PA2",
|
||||||
|
alice(),
|
||||||
|
EventType::RoomPowerLevels,
|
||||||
|
Some(""),
|
||||||
|
json!({ "users": { alice(): 100, bob(): 0 } }),
|
||||||
|
),
|
||||||
|
to_init_pdu_event(
|
||||||
|
"PB",
|
||||||
|
bob(),
|
||||||
|
EventType::RoomPowerLevels,
|
||||||
|
Some(""),
|
||||||
|
json!({ "users": { alice(): 100, bob(): 50 } }),
|
||||||
|
),
|
||||||
|
to_init_pdu_event("T3", bob(), EventType::RoomTopic, Some(""), json!({})),
|
||||||
|
];
|
||||||
|
|
||||||
|
let edges =
|
||||||
|
vec![vec!["END", "PA2", "T2", "PA1", "T1", "START"], vec!["END", "T3", "PB", "PA1"]]
|
||||||
|
.into_iter()
|
||||||
|
.map(|list| list.into_iter().map(event_id).collect::<Vec<_>>())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let expected_state_ids = vec!["PA2", "T2"].into_iter().map(event_id).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
do_check(events, edges, expected_state_ids)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn topic_reset() {
|
||||||
|
let _ =
|
||||||
|
tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
||||||
|
|
||||||
|
let events = &[
|
||||||
|
to_init_pdu_event("T1", alice(), EventType::RoomTopic, Some(""), json!({})),
|
||||||
|
to_init_pdu_event(
|
||||||
|
"PA",
|
||||||
|
alice(),
|
||||||
|
EventType::RoomPowerLevels,
|
||||||
|
Some(""),
|
||||||
|
json!({ "users": { alice(): 100, bob(): 50 } }),
|
||||||
|
),
|
||||||
|
to_init_pdu_event("T2", bob(), EventType::RoomTopic, Some(""), json!({})),
|
||||||
|
to_init_pdu_event(
|
||||||
|
"MB",
|
||||||
|
alice(),
|
||||||
|
EventType::RoomMember,
|
||||||
|
Some(bob().to_string().as_str()),
|
||||||
|
member_content_ban(),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
let edges = vec![vec!["END", "MB", "T2", "PA", "T1", "START"], vec!["END", "T1"]]
|
||||||
|
.into_iter()
|
||||||
|
.map(|list| list.into_iter().map(event_id).collect::<Vec<_>>())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let expected_state_ids =
|
||||||
|
vec!["T1", "MB", "PA"].into_iter().map(event_id).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
do_check(events, edges, expected_state_ids)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn join_rule_evasion() {
|
||||||
|
let _ =
|
||||||
|
tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
||||||
|
|
||||||
|
let events = &[
|
||||||
|
to_init_pdu_event(
|
||||||
|
"JR",
|
||||||
|
alice(),
|
||||||
|
EventType::RoomJoinRules,
|
||||||
|
Some(""),
|
||||||
|
json!({ "join_rule": JoinRule::Private }),
|
||||||
|
),
|
||||||
|
to_init_pdu_event(
|
||||||
|
"ME",
|
||||||
|
ella(),
|
||||||
|
EventType::RoomMember,
|
||||||
|
Some(ella().to_string().as_str()),
|
||||||
|
member_content_join(),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
let edges = vec![vec!["END", "JR", "START"], vec!["END", "ME", "START"]]
|
||||||
|
.into_iter()
|
||||||
|
.map(|list| list.into_iter().map(event_id).collect::<Vec<_>>())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let expected_state_ids = vec![event_id("JR")];
|
||||||
|
|
||||||
|
do_check(events, edges, expected_state_ids)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn offtopic_power_level() {
|
||||||
|
let _ =
|
||||||
|
tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
||||||
|
|
||||||
|
let events = &[
|
||||||
|
to_init_pdu_event(
|
||||||
|
"PA",
|
||||||
|
alice(),
|
||||||
|
EventType::RoomPowerLevels,
|
||||||
|
Some(""),
|
||||||
|
json!({ "users": { alice(): 100, bob(): 50 } }),
|
||||||
|
),
|
||||||
|
to_init_pdu_event(
|
||||||
|
"PB",
|
||||||
|
bob(),
|
||||||
|
EventType::RoomPowerLevels,
|
||||||
|
Some(""),
|
||||||
|
json!({ "users": { alice(): 100, bob(): 50, charlie(): 50 } }),
|
||||||
|
),
|
||||||
|
to_init_pdu_event(
|
||||||
|
"PC",
|
||||||
|
charlie(),
|
||||||
|
EventType::RoomPowerLevels,
|
||||||
|
Some(""),
|
||||||
|
json!({ "users": { alice(): 100, bob(): 50, charlie(): 0 } }),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
let edges = vec![vec!["END", "PC", "PB", "PA", "START"], vec!["END", "PA"]]
|
||||||
|
.into_iter()
|
||||||
|
.map(|list| list.into_iter().map(event_id).collect::<Vec<_>>())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let expected_state_ids = vec!["PC"].into_iter().map(event_id).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
do_check(events, edges, expected_state_ids)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn topic_setting() {
|
||||||
|
let _ =
|
||||||
|
tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
||||||
|
|
||||||
|
let events = &[
|
||||||
|
to_init_pdu_event("T1", alice(), EventType::RoomTopic, Some(""), json!({})),
|
||||||
|
to_init_pdu_event(
|
||||||
|
"PA1",
|
||||||
|
alice(),
|
||||||
|
EventType::RoomPowerLevels,
|
||||||
|
Some(""),
|
||||||
|
json!({ "users": { alice(): 100, bob(): 50 } }),
|
||||||
|
),
|
||||||
|
to_init_pdu_event("T2", alice(), EventType::RoomTopic, Some(""), json!({})),
|
||||||
|
to_init_pdu_event(
|
||||||
|
"PA2",
|
||||||
|
alice(),
|
||||||
|
EventType::RoomPowerLevels,
|
||||||
|
Some(""),
|
||||||
|
json!({ "users": { alice(): 100, bob(): 0 } }),
|
||||||
|
),
|
||||||
|
to_init_pdu_event(
|
||||||
|
"PB",
|
||||||
|
bob(),
|
||||||
|
EventType::RoomPowerLevels,
|
||||||
|
Some(""),
|
||||||
|
json!({ "users": { alice(): 100, bob(): 50 } }),
|
||||||
|
),
|
||||||
|
to_init_pdu_event("T3", bob(), EventType::RoomTopic, Some(""), json!({})),
|
||||||
|
to_init_pdu_event("MZ1", zara(), EventType::RoomTopic, Some(""), json!({})),
|
||||||
|
to_init_pdu_event("T4", alice(), EventType::RoomTopic, Some(""), json!({})),
|
||||||
|
];
|
||||||
|
|
||||||
|
let edges = vec![
|
||||||
|
vec!["END", "T4", "MZ1", "PA2", "T2", "PA1", "T1", "START"],
|
||||||
|
vec!["END", "MZ1", "T3", "PB", "PA1"],
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.map(|list| list.into_iter().map(event_id).collect::<Vec<_>>())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let expected_state_ids = vec!["T4", "PA2"].into_iter().map(event_id).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
do_check(events, edges, expected_state_ids)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_event_map_none() {
|
||||||
|
let _ =
|
||||||
|
tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
||||||
|
|
||||||
|
let mut store = TestStore::<StateEvent>(hashmap! {});
|
||||||
|
|
||||||
|
// build up the DAG
|
||||||
|
let (state_at_bob, state_at_charlie, expected) = store.set_up();
|
||||||
|
|
||||||
|
let ev_map: EventMap<Arc<StateEvent>> = store.0.clone();
|
||||||
|
let state_sets = vec![state_at_bob, state_at_charlie];
|
||||||
|
let resolved = match crate::resolve::<StateEvent, _>(
|
||||||
|
&RoomVersionId::Version2,
|
||||||
|
&state_sets,
|
||||||
|
state_sets
|
||||||
|
.iter()
|
||||||
|
.map(|map| {
|
||||||
|
store
|
||||||
|
.auth_event_ids(&room_id(), &map.values().cloned().collect::<Vec<_>>())
|
||||||
|
.unwrap()
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
|id| ev_map.get(id).map(Arc::clone),
|
||||||
|
) {
|
||||||
|
Ok(state) => state,
|
||||||
|
Err(e) => panic!("{}", e),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(expected, resolved)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_lexicographical_sort() {
|
||||||
|
let _ =
|
||||||
|
tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
||||||
|
|
||||||
|
let graph = hashmap! {
|
||||||
|
event_id("l") => hashset![event_id("o")],
|
||||||
|
event_id("m") => hashset![event_id("n"), event_id("o")],
|
||||||
|
event_id("n") => hashset![event_id("o")],
|
||||||
|
event_id("o") => hashset![], // "o" has zero outgoing edges but 4 incoming edges
|
||||||
|
event_id("p") => hashset![event_id("o")],
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = crate::lexicographical_topological_sort(&graph, |id| {
|
||||||
|
Ok((0, MilliSecondsSinceUnixEpoch(uint!(0)), id.clone()))
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
vec!["o", "l", "n", "m", "p"],
|
||||||
|
res.iter()
|
||||||
|
.map(ToString::to_string)
|
||||||
|
.map(|s| s.replace("$", "").replace(":foo", ""))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ban_with_auth_chains() {
|
||||||
|
let _ =
|
||||||
|
tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
||||||
|
let ban = BAN_STATE_SET();
|
||||||
|
|
||||||
|
let edges = vec![vec!["END", "MB", "PA", "START"], vec!["END", "IME", "MB"]]
|
||||||
|
.into_iter()
|
||||||
|
.map(|list| list.into_iter().map(event_id).collect::<Vec<_>>())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let expected_state_ids = vec!["PA", "MB"].into_iter().map(event_id).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
do_check(&ban.values().cloned().collect::<Vec<_>>(), edges, expected_state_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ban_with_auth_chains2() {
|
||||||
|
let _ =
|
||||||
|
tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
||||||
|
let init = INITIAL_EVENTS();
|
||||||
|
let ban = BAN_STATE_SET();
|
||||||
|
|
||||||
|
let mut inner = init.clone();
|
||||||
|
inner.extend(ban);
|
||||||
|
let store = TestStore(inner.clone());
|
||||||
|
|
||||||
|
let state_set_a = [
|
||||||
|
inner.get(&event_id("CREATE")).unwrap(),
|
||||||
|
inner.get(&event_id("IJR")).unwrap(),
|
||||||
|
inner.get(&event_id("IMA")).unwrap(),
|
||||||
|
inner.get(&event_id("IMB")).unwrap(),
|
||||||
|
inner.get(&event_id("IMC")).unwrap(),
|
||||||
|
inner.get(&event_id("MB")).unwrap(),
|
||||||
|
inner.get(&event_id("PA")).unwrap(),
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.map(|ev| ((ev.event_type().to_owned(), ev.state_key().to_owned()), ev.event_id().clone()))
|
||||||
|
.collect::<StateMap<_>>();
|
||||||
|
|
||||||
|
let state_set_b = [
|
||||||
|
inner.get(&event_id("CREATE")).unwrap(),
|
||||||
|
inner.get(&event_id("IJR")).unwrap(),
|
||||||
|
inner.get(&event_id("IMA")).unwrap(),
|
||||||
|
inner.get(&event_id("IMB")).unwrap(),
|
||||||
|
inner.get(&event_id("IMC")).unwrap(),
|
||||||
|
inner.get(&event_id("IME")).unwrap(),
|
||||||
|
inner.get(&event_id("PA")).unwrap(),
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.map(|ev| ((ev.event_type().to_owned(), ev.state_key().to_owned()), ev.event_id().clone()))
|
||||||
|
.collect::<StateMap<_>>();
|
||||||
|
|
||||||
|
let ev_map: EventMap<Arc<StateEvent>> = store.0.clone();
|
||||||
|
let state_sets = vec![state_set_a, state_set_b];
|
||||||
|
let resolved = match crate::resolve::<StateEvent, _>(
|
||||||
|
&RoomVersionId::Version6,
|
||||||
|
&state_sets,
|
||||||
|
state_sets
|
||||||
|
.iter()
|
||||||
|
.map(|map| {
|
||||||
|
store
|
||||||
|
.auth_event_ids(&room_id(), &map.values().cloned().collect::<Vec<_>>())
|
||||||
|
.unwrap()
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
|id| ev_map.get(id).map(Arc::clone),
|
||||||
|
) {
|
||||||
|
Ok(state) => state,
|
||||||
|
Err(e) => panic!("{}", e),
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"{:#?}",
|
||||||
|
resolved
|
||||||
|
.iter()
|
||||||
|
.map(|((ty, key), id)| format!("(({}{:?}), {})", ty, key, id))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
);
|
||||||
|
|
||||||
|
let expected = vec![
|
||||||
|
"$CREATE:foo",
|
||||||
|
"$IJR:foo",
|
||||||
|
"$PA:foo",
|
||||||
|
"$IMA:foo",
|
||||||
|
"$IMB:foo",
|
||||||
|
"$IMC:foo",
|
||||||
|
"$MB:foo",
|
||||||
|
];
|
||||||
|
|
||||||
|
for id in expected.iter().map(|i| event_id(i)) {
|
||||||
|
// make sure our resolved events are equal to the expected list
|
||||||
|
assert!(resolved.values().any(|eid| eid == &id) || init.contains_key(&id), "{}", id)
|
||||||
|
}
|
||||||
|
assert_eq!(expected.len(), resolved.len())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn join_rule_with_auth_chain() {
|
||||||
|
let join_rule = JOIN_RULE();
|
||||||
|
|
||||||
|
let edges = vec![vec!["END", "JR", "START"], vec!["END", "IMZ", "START"]]
|
||||||
|
.into_iter()
|
||||||
|
.map(|list| list.into_iter().map(event_id).collect::<Vec<_>>())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let expected_state_ids = vec!["JR"].into_iter().map(event_id).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
do_check(&join_rule.values().cloned().collect::<Vec<_>>(), edges, expected_state_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn BAN_STATE_SET() -> HashMap<EventId, Arc<StateEvent>> {
|
||||||
|
vec![
|
||||||
|
to_pdu_event(
|
||||||
|
"PA",
|
||||||
|
alice(),
|
||||||
|
EventType::RoomPowerLevels,
|
||||||
|
Some(""),
|
||||||
|
json!({ "users": { alice(): 100, bob(): 50 } }),
|
||||||
|
&["CREATE", "IMA", "IPOWER"], // auth_events
|
||||||
|
&["START"], // prev_events
|
||||||
|
),
|
||||||
|
to_pdu_event(
|
||||||
|
"PB",
|
||||||
|
alice(),
|
||||||
|
EventType::RoomPowerLevels,
|
||||||
|
Some(""),
|
||||||
|
json!({ "users": { alice(): 100, bob(): 50 } }),
|
||||||
|
&["CREATE", "IMA", "IPOWER"],
|
||||||
|
&["END"],
|
||||||
|
),
|
||||||
|
to_pdu_event(
|
||||||
|
"MB",
|
||||||
|
alice(),
|
||||||
|
EventType::RoomMember,
|
||||||
|
Some(ella().as_str()),
|
||||||
|
member_content_ban(),
|
||||||
|
&["CREATE", "IMA", "PB"],
|
||||||
|
&["PA"],
|
||||||
|
),
|
||||||
|
to_pdu_event(
|
||||||
|
"IME",
|
||||||
|
ella(),
|
||||||
|
EventType::RoomMember,
|
||||||
|
Some(ella().as_str()),
|
||||||
|
member_content_join(),
|
||||||
|
&["CREATE", "IJR", "PA"],
|
||||||
|
&["MB"],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.map(|ev| (ev.event_id().clone(), ev))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn JOIN_RULE() -> HashMap<EventId, Arc<StateEvent>> {
|
||||||
|
vec![
|
||||||
|
to_pdu_event(
|
||||||
|
"JR",
|
||||||
|
alice(),
|
||||||
|
EventType::RoomJoinRules,
|
||||||
|
Some(""),
|
||||||
|
json!({ "join_rule": "invite" }),
|
||||||
|
&["CREATE", "IMA", "IPOWER"],
|
||||||
|
&["START"],
|
||||||
|
),
|
||||||
|
to_pdu_event(
|
||||||
|
"IMZ",
|
||||||
|
zara(),
|
||||||
|
EventType::RoomPowerLevels,
|
||||||
|
Some(zara().as_str()),
|
||||||
|
member_content_join(),
|
||||||
|
&["CREATE", "JR", "IPOWER"],
|
||||||
|
&["START"],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.map(|ev| (ev.event_id().clone(), ev))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,77 +0,0 @@
|
|||||||
use std::{
|
|
||||||
collections::{HashMap, HashSet},
|
|
||||||
sync::Arc,
|
|
||||||
};
|
|
||||||
|
|
||||||
use rand::seq::SliceRandom;
|
|
||||||
use ruma_events::EventType;
|
|
||||||
use ruma_state_res::{
|
|
||||||
self as state_res, is_power_event, room_version::RoomVersion, test_utils::INITIAL_EVENTS,
|
|
||||||
StateMap,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn test_event_sort() {
|
|
||||||
let _ = tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
|
||||||
let events = INITIAL_EVENTS();
|
|
||||||
|
|
||||||
let event_map = events
|
|
||||||
.values()
|
|
||||||
.map(|ev| ((ev.event_type().to_owned(), ev.state_key().to_owned()), ev.clone()))
|
|
||||||
.collect::<StateMap<_>>();
|
|
||||||
|
|
||||||
let auth_chain = HashSet::new();
|
|
||||||
|
|
||||||
let power_events = event_map
|
|
||||||
.values()
|
|
||||||
.filter(|&pdu| is_power_event(&**pdu))
|
|
||||||
.map(|pdu| pdu.event_id().clone())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let sorted_power_events =
|
|
||||||
state_res::reverse_topological_power_sort(power_events, &auth_chain, |id| {
|
|
||||||
events.get(id).map(Arc::clone)
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let resolved_power = state_res::iterative_auth_check(
|
|
||||||
&RoomVersion::version_6(),
|
|
||||||
&sorted_power_events,
|
|
||||||
HashMap::new(), // unconflicted events
|
|
||||||
|id| events.get(id).map(Arc::clone),
|
|
||||||
)
|
|
||||||
.expect("iterative auth check failed on resolved events");
|
|
||||||
|
|
||||||
// don't remove any events so we know it sorts them all correctly
|
|
||||||
let mut events_to_sort = events.keys().cloned().collect::<Vec<_>>();
|
|
||||||
|
|
||||||
events_to_sort.shuffle(&mut rand::thread_rng());
|
|
||||||
|
|
||||||
let power_level = resolved_power.get(&(EventType::RoomPowerLevels, "".to_owned()));
|
|
||||||
|
|
||||||
let sorted_event_ids =
|
|
||||||
state_res::mainline_sort(&events_to_sort, power_level, |id| events.get(id).map(Arc::clone))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
vec![
|
|
||||||
"$CREATE:foo",
|
|
||||||
"$IMA:foo",
|
|
||||||
"$IPOWER:foo",
|
|
||||||
"$IJR:foo",
|
|
||||||
"$IMB:foo",
|
|
||||||
"$IMC:foo",
|
|
||||||
"$START:foo",
|
|
||||||
"$END:foo"
|
|
||||||
],
|
|
||||||
sorted_event_ids.iter().map(|id| id.to_string()).collect::<Vec<_>>()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_sort() {
|
|
||||||
for _ in 0..20 {
|
|
||||||
// since we shuffle the eventIds before we sort them introducing randomness
|
|
||||||
// seems like we should test this a few times
|
|
||||||
test_event_sort()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,190 +0,0 @@
|
|||||||
#![allow(clippy::or_fun_call, clippy::expect_fun_call)]
|
|
||||||
|
|
||||||
use std::{collections::HashMap, sync::Arc};
|
|
||||||
|
|
||||||
use ruma_events::EventType;
|
|
||||||
use ruma_identifiers::{EventId, RoomVersionId};
|
|
||||||
use ruma_state_res::{
|
|
||||||
self as state_res,
|
|
||||||
test_utils::{
|
|
||||||
alice, bob, do_check, ella, event_id, member_content_ban, member_content_join, room_id,
|
|
||||||
to_pdu_event, zara, StateEvent, TestStore, INITIAL_EVENTS,
|
|
||||||
},
|
|
||||||
EventMap, StateMap,
|
|
||||||
};
|
|
||||||
use serde_json::json;
|
|
||||||
use tracing::debug;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn ban_with_auth_chains() {
|
|
||||||
let _ = tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
|
||||||
let ban = BAN_STATE_SET();
|
|
||||||
|
|
||||||
let edges = vec![vec!["END", "MB", "PA", "START"], vec!["END", "IME", "MB"]]
|
|
||||||
.into_iter()
|
|
||||||
.map(|list| list.into_iter().map(event_id).collect::<Vec<_>>())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let expected_state_ids = vec!["PA", "MB"].into_iter().map(event_id).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
do_check(&ban.values().cloned().collect::<Vec<_>>(), edges, expected_state_ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn ban_with_auth_chains2() {
|
|
||||||
let _ = tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
|
||||||
let init = INITIAL_EVENTS();
|
|
||||||
let ban = BAN_STATE_SET();
|
|
||||||
|
|
||||||
let mut inner = init.clone();
|
|
||||||
inner.extend(ban);
|
|
||||||
let store = TestStore(inner.clone());
|
|
||||||
|
|
||||||
let state_set_a = [
|
|
||||||
inner.get(&event_id("CREATE")).unwrap(),
|
|
||||||
inner.get(&event_id("IJR")).unwrap(),
|
|
||||||
inner.get(&event_id("IMA")).unwrap(),
|
|
||||||
inner.get(&event_id("IMB")).unwrap(),
|
|
||||||
inner.get(&event_id("IMC")).unwrap(),
|
|
||||||
inner.get(&event_id("MB")).unwrap(),
|
|
||||||
inner.get(&event_id("PA")).unwrap(),
|
|
||||||
]
|
|
||||||
.iter()
|
|
||||||
.map(|ev| ((ev.event_type().to_owned(), ev.state_key().to_owned()), ev.event_id().clone()))
|
|
||||||
.collect::<StateMap<_>>();
|
|
||||||
|
|
||||||
let state_set_b = [
|
|
||||||
inner.get(&event_id("CREATE")).unwrap(),
|
|
||||||
inner.get(&event_id("IJR")).unwrap(),
|
|
||||||
inner.get(&event_id("IMA")).unwrap(),
|
|
||||||
inner.get(&event_id("IMB")).unwrap(),
|
|
||||||
inner.get(&event_id("IMC")).unwrap(),
|
|
||||||
inner.get(&event_id("IME")).unwrap(),
|
|
||||||
inner.get(&event_id("PA")).unwrap(),
|
|
||||||
]
|
|
||||||
.iter()
|
|
||||||
.map(|ev| ((ev.event_type().to_owned(), ev.state_key().to_owned()), ev.event_id().clone()))
|
|
||||||
.collect::<StateMap<_>>();
|
|
||||||
|
|
||||||
let ev_map: EventMap<Arc<StateEvent>> = store.0.clone();
|
|
||||||
let state_sets = vec![state_set_a, state_set_b];
|
|
||||||
let resolved = match state_res::resolve::<StateEvent, _>(
|
|
||||||
&RoomVersionId::Version6,
|
|
||||||
&state_sets,
|
|
||||||
state_sets
|
|
||||||
.iter()
|
|
||||||
.map(|map| {
|
|
||||||
store
|
|
||||||
.auth_event_ids(&room_id(), &map.values().cloned().collect::<Vec<_>>())
|
|
||||||
.unwrap()
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
|id| ev_map.get(id).map(Arc::clone),
|
|
||||||
) {
|
|
||||||
Ok(state) => state,
|
|
||||||
Err(e) => panic!("{}", e),
|
|
||||||
};
|
|
||||||
|
|
||||||
debug!(
|
|
||||||
"{:#?}",
|
|
||||||
resolved
|
|
||||||
.iter()
|
|
||||||
.map(|((ty, key), id)| format!("(({}{:?}), {})", ty, key, id))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
);
|
|
||||||
|
|
||||||
let expected =
|
|
||||||
vec!["$CREATE:foo", "$IJR:foo", "$PA:foo", "$IMA:foo", "$IMB:foo", "$IMC:foo", "$MB:foo"];
|
|
||||||
|
|
||||||
for id in expected.iter().map(|i| event_id(i)) {
|
|
||||||
// make sure our resolved events are equal to the expected list
|
|
||||||
assert!(resolved.values().any(|eid| eid == &id) || init.contains_key(&id), "{}", id)
|
|
||||||
}
|
|
||||||
assert_eq!(expected.len(), resolved.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn join_rule_with_auth_chain() {
|
|
||||||
let join_rule = JOIN_RULE();
|
|
||||||
|
|
||||||
let edges = vec![vec!["END", "JR", "START"], vec!["END", "IMZ", "START"]]
|
|
||||||
.into_iter()
|
|
||||||
.map(|list| list.into_iter().map(event_id).collect::<Vec<_>>())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let expected_state_ids = vec!["JR"].into_iter().map(event_id).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
do_check(&join_rule.values().cloned().collect::<Vec<_>>(), edges, expected_state_ids);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
fn BAN_STATE_SET() -> HashMap<EventId, Arc<StateEvent>> {
|
|
||||||
vec![
|
|
||||||
to_pdu_event(
|
|
||||||
"PA",
|
|
||||||
alice(),
|
|
||||||
EventType::RoomPowerLevels,
|
|
||||||
Some(""),
|
|
||||||
json!({ "users": { alice(): 100, bob(): 50 } }),
|
|
||||||
&["CREATE", "IMA", "IPOWER"], // auth_events
|
|
||||||
&["START"], // prev_events
|
|
||||||
),
|
|
||||||
to_pdu_event(
|
|
||||||
"PB",
|
|
||||||
alice(),
|
|
||||||
EventType::RoomPowerLevels,
|
|
||||||
Some(""),
|
|
||||||
json!({ "users": { alice(): 100, bob(): 50 } }),
|
|
||||||
&["CREATE", "IMA", "IPOWER"],
|
|
||||||
&["END"],
|
|
||||||
),
|
|
||||||
to_pdu_event(
|
|
||||||
"MB",
|
|
||||||
alice(),
|
|
||||||
EventType::RoomMember,
|
|
||||||
Some(ella().as_str()),
|
|
||||||
member_content_ban(),
|
|
||||||
&["CREATE", "IMA", "PB"],
|
|
||||||
&["PA"],
|
|
||||||
),
|
|
||||||
to_pdu_event(
|
|
||||||
"IME",
|
|
||||||
ella(),
|
|
||||||
EventType::RoomMember,
|
|
||||||
Some(ella().as_str()),
|
|
||||||
member_content_join(),
|
|
||||||
&["CREATE", "IJR", "PA"],
|
|
||||||
&["MB"],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.map(|ev| (ev.event_id().clone(), ev))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
|
||||||
fn JOIN_RULE() -> HashMap<EventId, Arc<StateEvent>> {
|
|
||||||
vec![
|
|
||||||
to_pdu_event(
|
|
||||||
"JR",
|
|
||||||
alice(),
|
|
||||||
EventType::RoomJoinRules,
|
|
||||||
Some(""),
|
|
||||||
json!({ "join_rule": "invite" }),
|
|
||||||
&["CREATE", "IMA", "IPOWER"],
|
|
||||||
&["START"],
|
|
||||||
),
|
|
||||||
to_pdu_event(
|
|
||||||
"IMZ",
|
|
||||||
zara(),
|
|
||||||
EventType::RoomPowerLevels,
|
|
||||||
Some(zara().as_str()),
|
|
||||||
member_content_join(),
|
|
||||||
&["CREATE", "JR", "IPOWER"],
|
|
||||||
&["START"],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.map(|ev| (ev.event_id().clone(), ev))
|
|
||||||
.collect()
|
|
||||||
}
|
|
@ -1,308 +0,0 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use js_int::uint;
|
|
||||||
use maplit::{hashmap, hashset};
|
|
||||||
use ruma_common::MilliSecondsSinceUnixEpoch;
|
|
||||||
use ruma_events::{room::join_rules::JoinRule, EventType};
|
|
||||||
use ruma_identifiers::RoomVersionId;
|
|
||||||
use ruma_state_res::{
|
|
||||||
self as state_res,
|
|
||||||
test_utils::{
|
|
||||||
alice, bob, charlie, do_check, ella, event_id, member_content_ban, member_content_join,
|
|
||||||
room_id, to_init_pdu_event, zara, StateEvent, TestStore,
|
|
||||||
},
|
|
||||||
EventMap,
|
|
||||||
};
|
|
||||||
use serde_json::json;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn ban_vs_power_level() {
|
|
||||||
let _ = tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
|
||||||
|
|
||||||
let events = &[
|
|
||||||
to_init_pdu_event(
|
|
||||||
"PA",
|
|
||||||
alice(),
|
|
||||||
EventType::RoomPowerLevels,
|
|
||||||
Some(""),
|
|
||||||
json!({ "users": { alice(): 100, bob(): 50 } }),
|
|
||||||
),
|
|
||||||
to_init_pdu_event(
|
|
||||||
"MA",
|
|
||||||
alice(),
|
|
||||||
EventType::RoomMember,
|
|
||||||
Some(alice().to_string().as_str()),
|
|
||||||
member_content_join(),
|
|
||||||
),
|
|
||||||
to_init_pdu_event(
|
|
||||||
"MB",
|
|
||||||
alice(),
|
|
||||||
EventType::RoomMember,
|
|
||||||
Some(bob().to_string().as_str()),
|
|
||||||
member_content_ban(),
|
|
||||||
),
|
|
||||||
to_init_pdu_event(
|
|
||||||
"PB",
|
|
||||||
bob(),
|
|
||||||
EventType::RoomPowerLevels,
|
|
||||||
Some(""),
|
|
||||||
json!({ "users": { alice(): 100, bob(): 50 } }),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
let edges = vec![vec!["END", "MB", "MA", "PA", "START"], vec!["END", "PA", "PB"]]
|
|
||||||
.into_iter()
|
|
||||||
.map(|list| list.into_iter().map(event_id).collect::<Vec<_>>())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let expected_state_ids = vec!["PA", "MA", "MB"].into_iter().map(event_id).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
do_check(events, edges, expected_state_ids)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn topic_basic() {
|
|
||||||
let _ = tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
|
||||||
|
|
||||||
let events = &[
|
|
||||||
to_init_pdu_event("T1", alice(), EventType::RoomTopic, Some(""), json!({})),
|
|
||||||
to_init_pdu_event(
|
|
||||||
"PA1",
|
|
||||||
alice(),
|
|
||||||
EventType::RoomPowerLevels,
|
|
||||||
Some(""),
|
|
||||||
json!({ "users": { alice(): 100, bob(): 50 } }),
|
|
||||||
),
|
|
||||||
to_init_pdu_event("T2", alice(), EventType::RoomTopic, Some(""), json!({})),
|
|
||||||
to_init_pdu_event(
|
|
||||||
"PA2",
|
|
||||||
alice(),
|
|
||||||
EventType::RoomPowerLevels,
|
|
||||||
Some(""),
|
|
||||||
json!({ "users": { alice(): 100, bob(): 0 } }),
|
|
||||||
),
|
|
||||||
to_init_pdu_event(
|
|
||||||
"PB",
|
|
||||||
bob(),
|
|
||||||
EventType::RoomPowerLevels,
|
|
||||||
Some(""),
|
|
||||||
json!({ "users": { alice(): 100, bob(): 50 } }),
|
|
||||||
),
|
|
||||||
to_init_pdu_event("T3", bob(), EventType::RoomTopic, Some(""), json!({})),
|
|
||||||
];
|
|
||||||
|
|
||||||
let edges =
|
|
||||||
vec![vec!["END", "PA2", "T2", "PA1", "T1", "START"], vec!["END", "T3", "PB", "PA1"]]
|
|
||||||
.into_iter()
|
|
||||||
.map(|list| list.into_iter().map(event_id).collect::<Vec<_>>())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let expected_state_ids = vec!["PA2", "T2"].into_iter().map(event_id).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
do_check(events, edges, expected_state_ids)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn topic_reset() {
|
|
||||||
let _ = tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
|
||||||
|
|
||||||
let events = &[
|
|
||||||
to_init_pdu_event("T1", alice(), EventType::RoomTopic, Some(""), json!({})),
|
|
||||||
to_init_pdu_event(
|
|
||||||
"PA",
|
|
||||||
alice(),
|
|
||||||
EventType::RoomPowerLevels,
|
|
||||||
Some(""),
|
|
||||||
json!({ "users": { alice(): 100, bob(): 50 } }),
|
|
||||||
),
|
|
||||||
to_init_pdu_event("T2", bob(), EventType::RoomTopic, Some(""), json!({})),
|
|
||||||
to_init_pdu_event(
|
|
||||||
"MB",
|
|
||||||
alice(),
|
|
||||||
EventType::RoomMember,
|
|
||||||
Some(bob().to_string().as_str()),
|
|
||||||
member_content_ban(),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
let edges = vec![vec!["END", "MB", "T2", "PA", "T1", "START"], vec!["END", "T1"]]
|
|
||||||
.into_iter()
|
|
||||||
.map(|list| list.into_iter().map(event_id).collect::<Vec<_>>())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let expected_state_ids = vec!["T1", "MB", "PA"].into_iter().map(event_id).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
do_check(events, edges, expected_state_ids)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn join_rule_evasion() {
|
|
||||||
let _ = tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
|
||||||
|
|
||||||
let events = &[
|
|
||||||
to_init_pdu_event(
|
|
||||||
"JR",
|
|
||||||
alice(),
|
|
||||||
EventType::RoomJoinRules,
|
|
||||||
Some(""),
|
|
||||||
json!({ "join_rule": JoinRule::Private }),
|
|
||||||
),
|
|
||||||
to_init_pdu_event(
|
|
||||||
"ME",
|
|
||||||
ella(),
|
|
||||||
EventType::RoomMember,
|
|
||||||
Some(ella().to_string().as_str()),
|
|
||||||
member_content_join(),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
let edges = vec![vec!["END", "JR", "START"], vec!["END", "ME", "START"]]
|
|
||||||
.into_iter()
|
|
||||||
.map(|list| list.into_iter().map(event_id).collect::<Vec<_>>())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let expected_state_ids = vec![event_id("JR")];
|
|
||||||
|
|
||||||
do_check(events, edges, expected_state_ids)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn offtopic_power_level() {
|
|
||||||
let _ = tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
|
||||||
|
|
||||||
let events = &[
|
|
||||||
to_init_pdu_event(
|
|
||||||
"PA",
|
|
||||||
alice(),
|
|
||||||
EventType::RoomPowerLevels,
|
|
||||||
Some(""),
|
|
||||||
json!({ "users": { alice(): 100, bob(): 50 } }),
|
|
||||||
),
|
|
||||||
to_init_pdu_event(
|
|
||||||
"PB",
|
|
||||||
bob(),
|
|
||||||
EventType::RoomPowerLevels,
|
|
||||||
Some(""),
|
|
||||||
json!({ "users": { alice(): 100, bob(): 50, charlie(): 50 } }),
|
|
||||||
),
|
|
||||||
to_init_pdu_event(
|
|
||||||
"PC",
|
|
||||||
charlie(),
|
|
||||||
EventType::RoomPowerLevels,
|
|
||||||
Some(""),
|
|
||||||
json!({ "users": { alice(): 100, bob(): 50, charlie(): 0 } }),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
let edges = vec![vec!["END", "PC", "PB", "PA", "START"], vec!["END", "PA"]]
|
|
||||||
.into_iter()
|
|
||||||
.map(|list| list.into_iter().map(event_id).collect::<Vec<_>>())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let expected_state_ids = vec!["PC"].into_iter().map(event_id).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
do_check(events, edges, expected_state_ids)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn topic_setting() {
|
|
||||||
let _ = tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
|
||||||
|
|
||||||
let events = &[
|
|
||||||
to_init_pdu_event("T1", alice(), EventType::RoomTopic, Some(""), json!({})),
|
|
||||||
to_init_pdu_event(
|
|
||||||
"PA1",
|
|
||||||
alice(),
|
|
||||||
EventType::RoomPowerLevels,
|
|
||||||
Some(""),
|
|
||||||
json!({ "users": { alice(): 100, bob(): 50 } }),
|
|
||||||
),
|
|
||||||
to_init_pdu_event("T2", alice(), EventType::RoomTopic, Some(""), json!({})),
|
|
||||||
to_init_pdu_event(
|
|
||||||
"PA2",
|
|
||||||
alice(),
|
|
||||||
EventType::RoomPowerLevels,
|
|
||||||
Some(""),
|
|
||||||
json!({ "users": { alice(): 100, bob(): 0 } }),
|
|
||||||
),
|
|
||||||
to_init_pdu_event(
|
|
||||||
"PB",
|
|
||||||
bob(),
|
|
||||||
EventType::RoomPowerLevels,
|
|
||||||
Some(""),
|
|
||||||
json!({ "users": { alice(): 100, bob(): 50 } }),
|
|
||||||
),
|
|
||||||
to_init_pdu_event("T3", bob(), EventType::RoomTopic, Some(""), json!({})),
|
|
||||||
to_init_pdu_event("MZ1", zara(), EventType::RoomTopic, Some(""), json!({})),
|
|
||||||
to_init_pdu_event("T4", alice(), EventType::RoomTopic, Some(""), json!({})),
|
|
||||||
];
|
|
||||||
|
|
||||||
let edges = vec![
|
|
||||||
vec!["END", "T4", "MZ1", "PA2", "T2", "PA1", "T1", "START"],
|
|
||||||
vec!["END", "MZ1", "T3", "PB", "PA1"],
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.map(|list| list.into_iter().map(event_id).collect::<Vec<_>>())
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let expected_state_ids = vec!["T4", "PA2"].into_iter().map(event_id).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
do_check(events, edges, expected_state_ids)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_event_map_none() {
|
|
||||||
let _ = tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
|
||||||
|
|
||||||
let mut store = TestStore::<StateEvent>(hashmap! {});
|
|
||||||
|
|
||||||
// build up the DAG
|
|
||||||
let (state_at_bob, state_at_charlie, expected) = store.set_up();
|
|
||||||
|
|
||||||
let ev_map: EventMap<Arc<StateEvent>> = store.0.clone();
|
|
||||||
let state_sets = vec![state_at_bob, state_at_charlie];
|
|
||||||
let resolved = match state_res::resolve::<StateEvent, _>(
|
|
||||||
&RoomVersionId::Version2,
|
|
||||||
&state_sets,
|
|
||||||
state_sets
|
|
||||||
.iter()
|
|
||||||
.map(|map| {
|
|
||||||
store
|
|
||||||
.auth_event_ids(&room_id(), &map.values().cloned().collect::<Vec<_>>())
|
|
||||||
.unwrap()
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
|id| ev_map.get(id).map(Arc::clone),
|
|
||||||
) {
|
|
||||||
Ok(state) => state,
|
|
||||||
Err(e) => panic!("{}", e),
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(expected, resolved)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_lexicographical_sort() {
|
|
||||||
let _ = tracing::subscriber::set_default(tracing_subscriber::fmt().with_test_writer().finish());
|
|
||||||
|
|
||||||
let graph = hashmap! {
|
|
||||||
event_id("l") => hashset![event_id("o")],
|
|
||||||
event_id("m") => hashset![event_id("n"), event_id("o")],
|
|
||||||
event_id("n") => hashset![event_id("o")],
|
|
||||||
event_id("o") => hashset![], // "o" has zero outgoing edges but 4 incoming edges
|
|
||||||
event_id("p") => hashset![event_id("o")],
|
|
||||||
};
|
|
||||||
|
|
||||||
let res = state_res::lexicographical_topological_sort(&graph, |id| {
|
|
||||||
Ok((0, MilliSecondsSinceUnixEpoch(uint!(0)), id.clone()))
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
vec!["o", "l", "n", "m", "p"],
|
|
||||||
res.iter()
|
|
||||||
.map(ToString::to_string)
|
|
||||||
.map(|s| s.replace("$", "").replace(":foo", ""))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
)
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user