Add test for joining an existing room
- Send affiliation/role in occupant presence. Always the same for now. - Send one presence per occupant (might changer again later on) - Store subject in Room. Store participant/date alongside subject Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
This commit is contained in:
parent
d1d7aea45b
commit
b7ee30c3f7
2 changed files with 134 additions and 24 deletions
71
src/room.rs
71
src/room.rs
|
@ -39,6 +39,9 @@ pub type Nick = String;
|
|||
pub struct Room {
|
||||
pub jid: BareJid,
|
||||
pub occupants: HashMap<BareJid, Occupant>,
|
||||
// TODO: Subject struct.
|
||||
// TODO: Store subject lang
|
||||
pub subject: Option<(String, Occupant, DateTime)>,
|
||||
}
|
||||
|
||||
impl Room {
|
||||
|
@ -46,6 +49,7 @@ impl Room {
|
|||
Room {
|
||||
jid,
|
||||
occupants: HashMap::new(),
|
||||
subject: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,6 +65,8 @@ impl Room {
|
|||
} else {
|
||||
debug!("{} is joining {}", realjid, self.jid);
|
||||
|
||||
let new_occupant = Occupant::new(&self, realjid.clone(), nick.clone());
|
||||
|
||||
// Ensure nick isn't already assigned
|
||||
let _ = self.occupants.iter().try_for_each(|(_, occupant)| {
|
||||
let nick = nick.clone();
|
||||
|
@ -72,18 +78,21 @@ impl Room {
|
|||
|
||||
// Send occupants
|
||||
debug!("Sending occupants for {}", realjid);
|
||||
let presence = Presence::new(PresenceType::None).with_to(realjid.clone());
|
||||
let presence = Presence::new(PresenceType::None)
|
||||
// New occupant with a single session
|
||||
.with_to(new_occupant.sessions[0].clone())
|
||||
.with_payloads(vec![MucUser {
|
||||
status: Vec::new(),
|
||||
items: vec![MucItem::new(Affiliation::Owner, Role::Moderator)],
|
||||
}.into()]);
|
||||
for (_, occupant) in self.occupants.iter() {
|
||||
for session in occupant.iter() {
|
||||
let presence = presence.clone().with_from(session.clone());
|
||||
component.send_stanza(presence).await?;
|
||||
}
|
||||
let presence = presence.clone()
|
||||
.with_from(occupant.participant.clone());
|
||||
component.send_stanza(presence).await?;
|
||||
}
|
||||
|
||||
// Add into occupants
|
||||
let _ = self
|
||||
.occupants
|
||||
.insert(bare.clone(), Occupant::new(realjid.clone(), nick.clone()));
|
||||
let _ = self.occupants.insert(bare.clone(), new_occupant.clone());
|
||||
|
||||
// Self-presence
|
||||
debug!("Sending self-presence for {}", realjid);
|
||||
|
@ -98,15 +107,25 @@ impl Room {
|
|||
|
||||
// Send subject
|
||||
debug!("Sending subject!");
|
||||
if self.subject.is_none() {
|
||||
let subject = String::from("");
|
||||
let setter = new_occupant;
|
||||
let stamp = DateTime::from_utc(chrono::Utc::now());
|
||||
self.subject = Some((subject, setter, stamp));
|
||||
}
|
||||
|
||||
let mut subject = Message::new(Some(Jid::Full(realjid)));
|
||||
subject.from = Some(Jid::Full(participant));
|
||||
subject
|
||||
.subjects
|
||||
.insert(String::from("en"), Subject(String::from("")));
|
||||
subject.from = Some(Jid::Full(
|
||||
self.subject.as_ref().unwrap().1.participant.clone(),
|
||||
));
|
||||
subject.subjects.insert(
|
||||
String::from("en"),
|
||||
Subject(self.subject.as_ref().unwrap().0.clone()),
|
||||
);
|
||||
subject.type_ = MessageType::Groupchat;
|
||||
subject.payloads = vec![Delay {
|
||||
from: Some(Jid::Bare(self.jid.clone())),
|
||||
stamp: DateTime::from_utc(chrono::Utc::now()),
|
||||
stamp: self.subject.as_ref().unwrap().2.clone(),
|
||||
data: None,
|
||||
}
|
||||
.into()];
|
||||
|
@ -119,23 +138,26 @@ impl Room {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Occupant {
|
||||
jid: BareJid,
|
||||
/// Public Jid for the Occupant
|
||||
real: BareJid,
|
||||
participant: FullJid,
|
||||
nick: Nick,
|
||||
sessions: Vec<FullJid>,
|
||||
}
|
||||
|
||||
impl Occupant {
|
||||
fn new(fulljid: FullJid, nick: Nick) -> Occupant {
|
||||
fn new(room: &Room, real: FullJid, nick: Nick) -> Occupant {
|
||||
Occupant {
|
||||
jid: BareJid::from(fulljid.clone()),
|
||||
real: BareJid::from(real.clone()),
|
||||
participant: room.jid.clone().with_resource(nick.clone()),
|
||||
nick,
|
||||
sessions: vec![fulljid],
|
||||
sessions: vec![real],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_session(&mut self, fulljid: FullJid) -> Result<(), Error> {
|
||||
if BareJid::from(fulljid.clone()) != self.jid {
|
||||
return Err(Error::MismatchJids(Jid::from(fulljid.clone())));
|
||||
pub fn add_session(&mut self, real: FullJid) -> Result<(), Error> {
|
||||
if BareJid::from(real.clone()) != self.real {
|
||||
return Err(Error::MismatchJids(Jid::from(real.clone())));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -161,13 +183,14 @@ impl Occupant {
|
|||
mod tests {
|
||||
use super::*;
|
||||
use std::str::FromStr;
|
||||
use xmpp_parsers::FullJid;
|
||||
use xmpp_parsers::{BareJid, FullJid};
|
||||
|
||||
#[test]
|
||||
fn occupant_ignore_dup_session() {
|
||||
let fulljid = FullJid::from_str("foo@bar/meh").unwrap();
|
||||
let mut occupant = Occupant::new(fulljid.clone(), String::from("nick"));
|
||||
occupant.add_session(fulljid.clone()).unwrap();
|
||||
let room = Room::new(BareJid::from_str("room@muc").unwrap());
|
||||
let real = FullJid::from_str("foo@bar/meh").unwrap();
|
||||
let mut occupant = Occupant::new(&room, real.clone(), String::from("nick"));
|
||||
occupant.add_session(real.clone()).unwrap();
|
||||
assert_eq!(occupant.iter().count(), 1);
|
||||
}
|
||||
}
|
||||
|
|
87
src/tests.rs
87
src/tests.rs
|
@ -201,3 +201,90 @@ async fn test_join_presence_nick_already_assigned() {
|
|||
None => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_join_presence_existing_room() {
|
||||
let realjid1 = FullJid::from_str("foo@bar/qxx").unwrap();
|
||||
let realjid2 = FullJid::from_str("qxx@bar/foo").unwrap();
|
||||
let roomjid = COMPONENT_JID.clone().with_node("room");
|
||||
let participant1 = roomjid.clone().with_resource("nick1");
|
||||
let participant2 = roomjid.clone().with_resource("nick2");
|
||||
|
||||
let join1: Element = Presence::new(PresenceType::None)
|
||||
.with_from(Jid::Full(realjid1.clone()))
|
||||
.with_to(Jid::Full(participant1.clone()))
|
||||
.with_payloads(vec![Muc::new().into()])
|
||||
.into();
|
||||
|
||||
let join2: Element = Presence::new(PresenceType::None)
|
||||
.with_from(Jid::Full(realjid2.clone()))
|
||||
.with_to(Jid::Full(participant2.clone()))
|
||||
.with_payloads(vec![Muc::new().into()])
|
||||
.into();
|
||||
|
||||
let mut component = TestComponent::new(vec![join1, join2]);
|
||||
let mut rooms: HashMap<BareJid, Room> = HashMap::new();
|
||||
|
||||
// Ignore self-presence for first participant
|
||||
component.expect_with(|_| ());
|
||||
// Ignore message subject for first participant
|
||||
component.expect_with(|_| ());
|
||||
|
||||
// Occupant presences for participant2
|
||||
component.expect(
|
||||
Presence::new(PresenceType::None)
|
||||
.with_from(Jid::Full(participant1.clone()))
|
||||
.with_to(Jid::Full(realjid2.clone()))
|
||||
.with_payloads(vec![MucUser {
|
||||
status: Vec::new(),
|
||||
items: vec![MucItem::new(Affiliation::Owner, Role::Moderator)],
|
||||
}.into()])
|
||||
);
|
||||
|
||||
// self-presence for participant2
|
||||
component.expect(
|
||||
Presence::new(PresenceType::None)
|
||||
.with_from(Jid::Full(participant2))
|
||||
.with_to(Jid::Full(realjid2.clone()))
|
||||
.with_payloads(vec![MucUser {
|
||||
status: vec![MucStatus::SelfPresence, MucStatus::AssignedNick],
|
||||
items: vec![MucItem::new(Affiliation::Owner, Role::Moderator)],
|
||||
}.into()])
|
||||
);
|
||||
|
||||
// Subject for participant2
|
||||
component.expect_with(|el| {
|
||||
let mut subjects = BTreeMap::new();
|
||||
subjects.insert(String::from("en"), MessageSubject::from_str("").unwrap());
|
||||
let expected: Element = Message {
|
||||
// Set by the first participant
|
||||
from: Some(Jid::Full(participant1)),
|
||||
to: Some(Jid::Full(realjid2)),
|
||||
id: None,
|
||||
type_: MessageType::Groupchat,
|
||||
bodies: BTreeMap::new(),
|
||||
subjects,
|
||||
thread: None,
|
||||
payloads: Vec::new(),
|
||||
}.into();
|
||||
|
||||
let mut out = Message::try_from(el).unwrap();
|
||||
// Check that <delay/> is present. Don't check content as it's checked in a test earlier
|
||||
assert_eq!(out.payloads.len(), 1);
|
||||
let _delay = Delay::try_from(out.payloads[0].clone()).unwrap();
|
||||
|
||||
out.payloads = vec![];
|
||||
assert_eq!(
|
||||
String::from(&expected),
|
||||
String::from(&Into::<Element>::into(out))
|
||||
);
|
||||
});
|
||||
|
||||
handle_stanza(&mut component, &mut rooms).await.unwrap();
|
||||
component.assert();
|
||||
|
||||
match rooms.get(&roomjid) {
|
||||
Some(room) => assert_eq!(room.occupants.len(), 2),
|
||||
None => panic!(),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue