TestComponent: Make order of stanza unimportant across different resources
Split expected stanza by resource thus rendering order of stanza across different resource unimportant. Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
This commit is contained in:
parent
2b6a151f7e
commit
1463a55d3f
4 changed files with 206 additions and 83 deletions
|
@ -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<Message> for TestElement {
|
|||
#[derive(Debug)]
|
||||
pub struct Component {
|
||||
in_buffer: VecDeque<TestElement>,
|
||||
expect_buffer: VecDeque<Expect>,
|
||||
expect_buffer: HashMap<Jid, VecDeque<Expect>>,
|
||||
}
|
||||
|
||||
impl Component {
|
||||
|
@ -125,82 +125,115 @@ impl Component {
|
|||
.map(|el| TestElement(el))
|
||||
.collect::<Vec<_>>(),
|
||||
),
|
||||
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<E: Into<TestElement>>(&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<F: FnOnce(Iq) + Send + 'static, S: Into<String>>(
|
||||
&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<F: FnOnce(Message) + Send + 'static, S: Into<String>>(
|
||||
&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<F: FnOnce(Presence) + Send + 'static, S: Into<String>>(
|
||||
&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<E: Into<TestElement> + 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(())
|
||||
|
|
|
@ -86,9 +86,10 @@ async fn handle_iq_ping<C: ComponentTrait>(
|
|||
) -> 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<C: ComponentTrait>(
|
|||
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(())
|
||||
|
|
|
@ -87,10 +87,11 @@ async fn test_self_ping_answer() {
|
|||
let mut component = TestComponent::new(vec![join, disco, ping]);
|
||||
let mut rooms: HashMap<BareJid, Room> = 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<BareJid, Room> = HashMap::new();
|
||||
|
||||
component.expect(Into::<Element>::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::<Element>::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();
|
||||
}
|
||||
|
|
|
@ -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<BareJid, Room> = 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<BareJid, Room> = 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<BareJid, Room> = 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<BareJid, Room> = 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<BareJid, Room> = 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();
|
||||
|
||||
|
|
Loading…
Reference in a new issue