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:
Maxime “pep” Buquet 2022-12-04 17:44:09 +01:00
parent 2b6a151f7e
commit 1463a55d3f
Signed by: pep
GPG key ID: DEDA74AEECA9D0F2
4 changed files with 206 additions and 83 deletions

View file

@ -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,45 +125,69 @@ 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"),
};
let empty_buf = match self.expect_buffer.get_mut(&dest) {
Some(buf) => {
let expected = buf.pop_front();
match expected {
Some(expected) => match expected {
@ -173,7 +197,7 @@ impl Component {
panic!(
r#"assertion failed: `(actual == expected)`
actual: `{}`,
expected: `{}`"#,
expected: `{}`"#,
actual, expected
)
}
@ -201,6 +225,15 @@ impl Component {
},
},
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(())

View file

@ -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(())

View file

@ -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,7 +133,8 @@ 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(
component.expect(Into::<Element>::into(
Iq::from_error(
"ping",
StanzaError {
type_: ErrorType::Modify,
@ -141,7 +143,10 @@ async fn test_self_ping_participant_non_existing() {
texts: BTreeMap::new(),
other: None,
},
)));
)
.with_to(realjid1.clone())
.with_from(Jid::Full(participant1.clone())),
));
handle_stanza(&mut component, &mut rooms).await.unwrap();
}

View file

@ -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();