diff --git a/src/component/test.rs b/src/component/test.rs index baa6e0c..b5697c7 100644 --- a/src/component/test.rs +++ b/src/component/test.rs @@ -16,7 +16,7 @@ use crate::component::ComponentTrait; use crate::error::Error; -use std::collections::VecDeque; +use std::collections::{HashMap, VecDeque}; use std::fmt; use std::marker::Send; use std::ops::Deref; @@ -26,7 +26,7 @@ use std::thread; use async_trait::async_trait; use futures::{task::Poll, Stream}; -use xmpp_parsers::{iq::Iq, message::Message, presence::Presence, Element}; +use xmpp_parsers::{iq::Iq, message::Message, presence::Presence, Element, Jid}; enum Expect { /// Simple Element @@ -113,7 +113,7 @@ impl From for TestElement { #[derive(Debug)] pub struct Component { in_buffer: VecDeque, - expect_buffer: VecDeque, + expect_buffer: HashMap>, } impl Component { @@ -125,82 +125,115 @@ impl Component { .map(|el| TestElement(el)) .collect::>(), ), - expect_buffer: VecDeque::new(), + expect_buffer: HashMap::new(), + } + } + + fn add_expect(&mut self, stream: Jid, expect: Expect) { + match self.expect_buffer.get_mut(&stream) { + Some(buf) => buf.push_back(expect), + None => { + let mut buf = VecDeque::new(); + buf.push_back(expect); + self.expect_buffer.insert(stream, buf); + } } } /// Adds elements to be expected, in the order they're being added pub fn expect>(&mut self, el: E) { - self.expect_buffer.push_back(Expect::Element(el.into())) + let element: TestElement = el.into(); + let dest: Jid = match element.attr("to") { + Some(to) => to.parse().unwrap(), + None => panic!("A destination Jid is needed on expected stanzas"), + }; + + self.add_expect(dest, Expect::Element(element.into())) } pub fn expect_iq>( &mut self, + stream: Jid, callback: F, desc: S, ) { - self.expect_buffer - .push_back(Expect::Iq(Box::new(callback), desc.into())) + self.add_expect(stream, Expect::Iq(Box::new(callback), desc.into())) } pub fn expect_message>( &mut self, + stream: Jid, callback: F, desc: S, ) { - self.expect_buffer - .push_back(Expect::Message(Box::new(callback), desc.into())) + self.add_expect(stream, Expect::Message(Box::new(callback), desc.into())) } pub fn expect_presence>( &mut self, + stream: Jid, callback: F, desc: S, ) { - self.expect_buffer - .push_back(Expect::Presence(Box::new(callback), desc.into())) + self.add_expect(stream, Expect::Presence(Box::new(callback), desc.into())) } fn send_stanza_inner + Send>(&mut self, el: E) -> Result<(), Error> { let out: TestElement = el.into(); - let expected = self.expect_buffer.pop_front(); + let dest: Jid = match out.attr("to") { + Some(to) => to.parse().unwrap(), + None => panic!("A destination Jid is needed on outgoing stanzas"), + }; - match expected { - Some(expected) => match expected { - Expect::Element(el) => { - let (expected, actual) = (String::from(&el), String::from(&out)); - if expected != actual { - panic!( - r#"assertion failed: `(actual == expected)` - actual: `{}`, - expected: `{}`"#, - actual, expected - ) - } - } - Expect::Iq(cb, _) => match Iq::try_from(out.0.clone()) { - Ok(iq) => cb(iq), - _ => panic!( - "Mismatch stanza type. Expected iq, got: {}", - String::from(&out) - ), - }, - Expect::Message(cb, _) => match Message::try_from(out.0.clone()) { - Ok(message) => cb(message), - _ => panic!( - "Mismatch stanza type. Expected message, got: {}", - String::from(&out) - ), - }, - Expect::Presence(cb, _) => match Presence::try_from(out.0.clone()) { - Ok(presence) => cb(presence), - _ => panic!( - "Mismatch stanza type. Expected presence, got: {}", - String::from(&out) - ), - }, - }, + let empty_buf = match self.expect_buffer.get_mut(&dest) { + Some(buf) => { + let expected = buf.pop_front(); + + match expected { + Some(expected) => match expected { + Expect::Element(el) => { + let (expected, actual) = (String::from(&el), String::from(&out)); + if expected != actual { + panic!( + r#"assertion failed: `(actual == expected)` + actual: `{}`, +expected: `{}`"#, + actual, expected + ) + } + } + Expect::Iq(cb, _) => match Iq::try_from(out.0.clone()) { + Ok(iq) => cb(iq), + _ => panic!( + "Mismatch stanza type. Expected iq, got: {}", + String::from(&out) + ), + }, + Expect::Message(cb, _) => match Message::try_from(out.0.clone()) { + Ok(message) => cb(message), + _ => panic!( + "Mismatch stanza type. Expected message, got: {}", + String::from(&out) + ), + }, + Expect::Presence(cb, _) => match Presence::try_from(out.0.clone()) { + Ok(presence) => cb(presence), + _ => panic!( + "Mismatch stanza type. Expected presence, got: {}", + String::from(&out) + ), + }, + }, + None => panic!("Missing matching expected element: {:?}", out), + }; + // Do we need to remove the empty VecDeque from the HashMap? + buf.is_empty() + } None => panic!("Missing matching expected element: {:?}", out), + }; + + if empty_buf { + self.expect_buffer.remove(&dest); } Ok(()) diff --git a/src/handlers.rs b/src/handlers.rs index 319112f..e94ea7c 100644 --- a/src/handlers.rs +++ b/src/handlers.rs @@ -86,9 +86,10 @@ async fn handle_iq_ping( ) -> Result<(), Error> { match Ping::try_from(payload) { Ok(_) => { - let success = Iq::empty_result(iq.from.as_ref().unwrap().clone(), iq.id.clone()); - let from = iq.from.unwrap(); + let from = iq.from.clone().unwrap(); let to = iq.to.unwrap(); + let success = Iq::empty_result(iq.from.as_ref().unwrap().clone(), iq.id.clone()) + .with_to(from.clone()); // Pinging a participant if let Jid::Full(participant) = to.clone() { @@ -132,11 +133,13 @@ async fn handle_iq_ping( StanzaError { type_: ErrorType::Modify, defined_condition: DefinedCondition::NotAcceptable, - by: Some(Jid::Bare(BareJid::from(to))), + by: Some(Jid::Bare(BareJid::from(to.clone()))), texts: BTreeMap::new(), other: None, }, - ); + ) + .with_to(from.clone()) + .with_from(to); component.send_stanza(error).await?; Ok(()) diff --git a/src/tests/iq.rs b/src/tests/iq.rs index eefcfca..96fbe12 100644 --- a/src/tests/iq.rs +++ b/src/tests/iq.rs @@ -87,10 +87,11 @@ async fn test_self_ping_answer() { let mut component = TestComponent::new(vec![join, disco, ping]); let mut rooms: HashMap = HashMap::new(); - component.expect_presence(|_| (), "Self-presence"); - component.expect_message(|_| (), "Subject"); + component.expect_presence(Jid::Full(LOUISE_FULL1.clone()), |_| (), "Self-presence"); + component.expect_message(Jid::Full(LOUISE_FULL1.clone()), |_| (), "Subject"); component.expect_iq( + Jid::Full(LOUISE_FULL1.clone()), |iq| { if let IqType::Result(Some(el)) = iq.payload { if let Ok(result) = DiscoInfoResult::try_from(el) { @@ -132,16 +133,20 @@ async fn test_self_ping_participant_non_existing() { let mut component = TestComponent::new(vec![ping]); let mut rooms: HashMap = HashMap::new(); - component.expect(Into::::into(Iq::from_error( - "ping", - StanzaError { - type_: ErrorType::Modify, - defined_condition: DefinedCondition::NotAcceptable, - by: Some(Jid::Bare(roomjid)), - texts: BTreeMap::new(), - other: None, - }, - ))); + component.expect(Into::::into( + Iq::from_error( + "ping", + StanzaError { + type_: ErrorType::Modify, + defined_condition: DefinedCondition::NotAcceptable, + by: Some(Jid::Bare(roomjid)), + texts: BTreeMap::new(), + other: None, + }, + ) + .with_to(realjid1.clone()) + .with_from(Jid::Full(participant1.clone())), + )); handle_stanza(&mut component, &mut rooms).await.unwrap(); } diff --git a/src/tests/presence.rs b/src/tests/presence.rs index eafdf5a..3ace761 100644 --- a/src/tests/presence.rs +++ b/src/tests/presence.rs @@ -68,6 +68,7 @@ async fn test_join_presence_empty_room() { ); component.expect_message( + Jid::Full(LOUISE_FULL1.clone()), move |mut out| { let roomjid = ROOM1_BARE.clone(); @@ -127,8 +128,16 @@ async fn test_join_presence_nick_already_assigned() { let mut component = TestComponent::new(vec![join1, join2]); let mut rooms: HashMap = HashMap::new(); - component.expect_presence(|_| (), "Self-presence for first participant"); - component.expect_message(|_| (), "Subject for first participant"); + component.expect_presence( + Jid::Full(LOUISE_FULL1.clone()), + |_| (), + "Self-presence for first participant", + ); + component.expect_message( + Jid::Full(LOUISE_FULL1.clone()), + |_| (), + "Subject for first participant", + ); component.expect( Presence::new(PresenceType::Error) @@ -168,8 +177,16 @@ async fn test_join_presence_existing_room() { let mut component = TestComponent::new(vec![join1, join2]); let mut rooms: HashMap = HashMap::new(); - component.expect_presence(|_| (), "Self-presence for participant1"); - component.expect_message(|_| (), "Subject for participant1"); + component.expect_presence( + Jid::Full(LOUISE_FULL1.clone()), + |_| (), + "Self-presence for participant1", + ); + component.expect_message( + Jid::Full(LOUISE_FULL1.clone()), + |_| (), + "Subject for participant1", + ); // Participant1 presence for participant2 component.expect( @@ -212,6 +229,7 @@ async fn test_join_presence_existing_room() { ); component.expect_message( + Jid::Full(SUGAKO_FULL1.clone()), |el| { let mut subjects = BTreeMap::new(); subjects.insert(String::from("en"), MessageSubject::from_str("").unwrap()); @@ -267,12 +285,36 @@ async fn test_presence_resync() { let mut component = TestComponent::new(vec![join1.clone(), join2, join1]); let mut rooms: HashMap = HashMap::new(); - component.expect_presence(|_| (), "Self-presence for participant1"); - component.expect_message(|_| (), "Subject for participant1"); - component.expect_presence(|_| (), "Participant1 presence for participant2"); - component.expect_presence(|_| (), "Participant2 presence for participant1"); - component.expect_presence(|_| (), "Self-presence for participant2"); - component.expect_message(|_| (), "Subject for participant2"); + component.expect_presence( + Jid::Full(LOUISE_FULL1.clone()), + |_| (), + "Self-presence for participant1", + ); + component.expect_message( + Jid::Full(LOUISE_FULL1.clone()), + |_| (), + "Subject for participant1", + ); + component.expect_presence( + Jid::Full(SUGAKO_FULL1.clone()), + |_| (), + "Participant1 presence for participant2", + ); + component.expect_presence( + Jid::Full(LOUISE_FULL1.clone()), + |_| (), + "Participant2 presence for participant1", + ); + component.expect_presence( + Jid::Full(SUGAKO_FULL1.clone()), + |_| (), + "Self-presence for participant2", + ); + component.expect_message( + Jid::Full(SUGAKO_FULL1.clone()), + |_| (), + "Subject for participant2", + ); // Resync: Participant2 presence for participant1 component.expect( @@ -341,8 +383,16 @@ async fn test_leave_last_participant() { let mut component = TestComponent::new(vec![join1, leave1]); let mut rooms: HashMap = HashMap::new(); - component.expect_presence(|_| (), "Self-presence for participant1"); - component.expect_message(|_| (), "Subject for participant1"); + component.expect_presence( + Jid::Full(LOUISE_FULL1.clone()), + |_| (), + "Self-presence for participant1", + ); + component.expect_message( + Jid::Full(LOUISE_FULL1.clone()), + |_| (), + "Subject for participant1", + ); component.expect( Presence::new(PresenceType::Unavailable) @@ -387,12 +437,36 @@ async fn test_leave_room_not_last() { let mut component = TestComponent::new(vec![join1, join2, leave2]); let mut rooms: HashMap = HashMap::new(); - component.expect_presence(|_| (), "Self-presence for participant1"); - component.expect_message(|_| (), "Subject message for participant1"); - component.expect_presence(|_| (), "Participant1 presence for participant2"); - component.expect_presence(|_| (), "Self-presence for participant2"); - component.expect_presence(|_| (), "Participant2 presence for participant1"); - component.expect_message(|_| (), "Subject message for participant2"); + component.expect_presence( + Jid::Full(LOUISE_FULL1.clone()), + |_| (), + "Self-presence for participant1", + ); + component.expect_message( + Jid::Full(LOUISE_FULL1.clone()), + |_| (), + "Subject message for participant1", + ); + component.expect_presence( + Jid::Full(SUGAKO_FULL1.clone()), + |_| (), + "Participant1 presence for participant2", + ); + component.expect_presence( + Jid::Full(SUGAKO_FULL1.clone()), + |_| (), + "Self-presence for participant2", + ); + component.expect_presence( + Jid::Full(LOUISE_FULL1.clone()), + |_| (), + "Participant2 presence for participant1", + ); + component.expect_message( + Jid::Full(SUGAKO_FULL1.clone()), + |_| (), + "Subject message for participant2", + ); component.expect( Presence::new(PresenceType::Unavailable) @@ -460,7 +534,11 @@ async fn test_join_msn() { .into()]), ); - component.expect_message(|_| (), "Subject message for session1"); + component.expect_message( + Jid::Full(LOUISE_FULL1.clone()), + |_| (), + "Subject message for session1", + ); // New session joins // Participant1 presence for session2 @@ -501,7 +579,11 @@ async fn test_join_msn() { .into()]), ); - component.expect_message(|_| (), "Subject message for session2"); + component.expect_message( + Jid::Full(LOUISE_FULL2.clone()), + |_| (), + "Subject message for session2", + ); handle_stanza(&mut component, &mut rooms).await.unwrap();