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 room_version; | ||||
| mod state_event; | ||||
| #[doc(hidden)] | ||||
| pub mod test_utils; | ||||
| #[cfg(test)] | ||||
| mod test_utils; | ||||
| 
 | ||||
| pub use error::{Error, Result}; | ||||
| 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, | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[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