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:
parent
88828da67e
commit
b29ac6b274
5 changed files with 99 additions and 34 deletions
|
@ -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!("")),
|
||||
}
|
||||
|
|
|
@ -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?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
89
src/tests.rs
89
src/tests.rs
|
@ -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();
|
||||
}
|
||||
|
|
10
src/types.rs
10
src/types.rs
|
@ -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::*;
|
||||
|
|
Loading…
Reference in a new issue