add test_0045_join_presence_empty_room

Remove static ROOMS, pass it down to handlers

Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
This commit is contained in:
Maxime “pep” Buquet 2022-09-10 12:35:27 +02:00
parent 88828da67e
commit b29ac6b274
Signed by: pep
GPG key ID: DEDA74AEECA9D0F2
5 changed files with 99 additions and 34 deletions

View file

@ -68,12 +68,7 @@ impl DerefMut for Component {
}
impl Component {
pub async fn new(
jid: &str,
password: &str,
server: &str,
port: u16,
) -> Result<Self, Error> {
pub async fn new(jid: &str, password: &str, server: &str, port: u16) -> Result<Self, Error> {
Ok(Component(
TokioXMPPComponent::new(jid, password, server, port).await?,
))
@ -109,7 +104,9 @@ impl TestComponent {
match (out, expected) {
(None, None) => break,
(Some(out), Some(expected)) => assert_eq!(String::from(&expected), String::from(&out)),
(Some(out), Some(expected)) => {
assert_eq!(String::from(&expected), String::from(&out))
}
(Some(out), None) => assert_eq!(format!(""), String::from(&out)),
(None, Some(expected)) => assert_eq!(String::from(&expected), format!("")),
}

View file

@ -15,8 +15,9 @@
use crate::component::ComponentTrait;
use crate::error::Error;
use crate::types::{Nick, Room, ROOMS};
use crate::types::{Nick, Room};
use std::collections::HashMap;
use std::ops::ControlFlow;
use futures::stream::StreamExt;
@ -103,6 +104,7 @@ async fn handle_iq<C: ComponentTrait>(component: &mut C, iq: Iq) -> Result<(), E
async fn handle_presence<C: ComponentTrait>(
component: &mut C,
presence: Presence,
rooms: &mut HashMap<BareJid, Room>,
) -> Result<(), Error> {
let muc = presence
.payloads
@ -124,14 +126,14 @@ async fn handle_presence<C: ComponentTrait>(
let nick: Nick = participant.resource.clone();
// Room already exists
if let Some(room) = unsafe { ROOMS.lock().unwrap().get_mut(&roomjid) } {
if let Some(room) = rooms.get_mut(&roomjid) {
debug!("Presence received to existing room: {}", &roomjid);
room.add_session(component, realjid, nick).await.unwrap();
} else {
debug!("Presence received to new room: {}", &roomjid);
let mut room = Room::new(roomjid.clone());
room.add_session(component, realjid, nick).await.unwrap();
let _ = unsafe { ROOMS.lock().unwrap().insert(roomjid, room) };
let _ = rooms.insert(roomjid, room);
}
}
@ -145,7 +147,10 @@ async fn handle_message<C: ComponentTrait>(
Ok(())
}
pub(crate) async fn handle_stanza<C: ComponentTrait>(component: &mut C) -> Result<(), Error> {
pub(crate) async fn handle_stanza<C: ComponentTrait>(
component: &mut C,
rooms: &mut HashMap<BareJid, Room>,
) -> Result<(), Error> {
while let Some(elem) = component.next().await {
debug!("RECV {}", String::from(&elem));
if elem.is("iq", ns::COMPONENT_ACCEPT) {
@ -156,7 +161,7 @@ pub(crate) async fn handle_stanza<C: ComponentTrait>(component: &mut C) -> Resul
handle_message(component, message).await?;
} else if elem.is("presence", ns::COMPONENT_ACCEPT) {
let presence = Presence::try_from(elem).unwrap();
handle_presence(component, presence).await?;
handle_presence(component, presence, rooms).await?;
}
}

View file

@ -13,7 +13,6 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#![feature(once_cell)]
#![feature(let_chains)]
mod component;
@ -27,12 +26,15 @@ mod tests;
use crate::component::Component;
use crate::error::Error;
use crate::handlers::handle_stanza;
use crate::types::Room;
use std::collections::HashMap;
use std::env::args;
use std::process::exit;
use env_logger;
use log::info;
use xmpp_parsers::BareJid;
#[tokio::main]
async fn main() -> Result<(), Error> {
@ -52,7 +54,9 @@ async fn main() -> Result<(), Error> {
let mut component = Component::new(jid, passwd, server, port).await.unwrap();
info!("Online as {}!", component.jid);
handle_stanza(&mut component).await?;
let mut rooms: HashMap<BareJid, Room> = HashMap::new();
handle_stanza(&mut component, &mut rooms).await?;
Ok(())
}

View file

@ -13,16 +13,24 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
use std::str::FromStr;
use crate::component::TestComponent;
use crate::handlers::handle_stanza;
use crate::types::Room;
use std::collections::{BTreeMap, HashMap};
use std::str::FromStr;
use lazy_static::lazy_static;
use xmpp_parsers::{
iq::{Iq, IqType},
BareJid, Element, FullJid, Jid,
message::{Message, MessageType, Subject as MessageSubject},
muc::{
user::{Affiliation, Item as MucItem, Role, Status as MucStatus},
Muc, MucUser,
},
presence::{Presence, Type as PresenceType},
stanza_error::{DefinedCondition, ErrorType, StanzaError},
BareJid, Element, FullJid, Jid,
};
lazy_static! {
@ -39,22 +47,77 @@ async fn test_iq_unimplemented() {
to: Some(to.clone()),
id: String::from("disco"),
payload: IqType::Get(Element::builder("x", "urn:example:unimplemented").build()),
}.into();
}
.into();
let reply: Element = Iq::from_error("disco", StanzaError::new(
ErrorType::Cancel,
DefinedCondition::ServiceUnavailable,
"en",
"No handler defined for this kind of iq.",
))
let reply: Element = Iq::from_error(
"disco",
StanzaError::new(
ErrorType::Cancel,
DefinedCondition::ServiceUnavailable,
"en",
"No handler defined for this kind of iq.",
),
)
.with_from(to)
.with_to(from)
.into();
let mut component = TestComponent::new(vec![disco]);
let mut rooms: HashMap<BareJid, Room> = HashMap::new();
component.expect(reply);
handle_stanza(&mut component).await.unwrap();
handle_stanza(&mut component, &mut rooms).await.unwrap();
component.assert();
}
#[tokio::test]
async fn test_0045_join_presence_empty_room() {
let from = FullJid::from_str("foo@bar/qxx").unwrap();
let to = COMPONENT_JID
.clone()
.with_node("room")
.with_resource("nick");
// <x xmlns='http://jabber.org/protocol/muc'/>
let join: Element = Presence::new(PresenceType::None)
.with_from(Jid::Full(from.clone()))
.with_to(Jid::Full(to.clone()))
.with_payloads(vec![Muc::new().into()])
.into();
let mut component = TestComponent::new(vec![join]);
let mut rooms: HashMap<BareJid, Room> = HashMap::new();
// Room is empty so there should be:
// - No presence sent except for self-presence
// - No message history
// - Empty subject.
component.expect(
Presence::new(PresenceType::None)
.with_from(Jid::Full(to.clone()))
.with_to(Jid::Full(from.clone()))
.with_payloads(vec![MucUser {
status: vec![MucStatus::SelfPresence, MucStatus::AssignedNick],
items: vec![MucItem::new(Affiliation::Owner, Role::Moderator)],
}
.into()]),
);
let mut subjects = BTreeMap::new();
subjects.insert(String::from("en"), MessageSubject::from_str("").unwrap());
component.expect(Message {
// Set by the first participant
from: Some(Jid::Full(to)),
to: Some(Jid::Full(from)),
id: None,
type_: MessageType::Groupchat,
bodies: BTreeMap::new(),
subjects,
thread: None,
payloads: Vec::new(),
});
handle_stanza(&mut component, &mut rooms).await.unwrap();
component.assert();
}

View file

@ -18,7 +18,6 @@ use crate::error::Error;
use std::collections::HashMap;
use std::iter::IntoIterator;
use std::sync::{LazyLock, Mutex};
use log::debug;
use xmpp_parsers::{
@ -89,7 +88,7 @@ impl Room {
let status = vec![MucStatus::SelfPresence, MucStatus::AssignedNick];
let items = vec![MucItem::new(Affiliation::Owner, Role::Moderator)];
let self_presence = Presence::new(PresenceType::None)
.with_from(participant)
.with_from(participant.clone())
.with_to(realjid.clone())
.with_payloads(vec![MucUser { status, items }.into()]);
component.send_stanza(self_presence).await?;
@ -97,10 +96,10 @@ impl Room {
// Send subject
debug!("Sending subject!");
let mut subject = Message::new(Some(Jid::Full(realjid)));
subject.from = Some(Jid::Bare(self.jid.clone()));
subject.from = Some(Jid::Full(participant));
subject
.subjects
.insert(String::from("en"), Subject(String::from("Hanabi")));
.insert(String::from("en"), Subject(String::from("")));
subject.type_ = MessageType::Groupchat;
component.send_stanza(subject).await?;
}
@ -149,9 +148,6 @@ impl Occupant {
}
}
pub(crate) static mut ROOMS: LazyLock<Mutex<HashMap<BareJid, Room>>> =
LazyLock::new(|| Mutex::new(HashMap::new()));
#[cfg(test)]
mod tests {
use super::*;