diff --git a/crates/projection-xmpp/src/iq.rs b/crates/projection-xmpp/src/iq.rs index fdff68d..ded0f77 100644 --- a/crates/projection-xmpp/src/iq.rs +++ b/crates/projection-xmpp/src/iq.rs @@ -233,3 +233,121 @@ impl<'a> XmppConnection<'a> { ItemQuery { item } } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::{launch, Authenticated, RunningServer, ServerConfig}; + use lavina_core::player::PlayerId; + use lavina_core::repo::{Storage, StorageConfig}; + use lavina_core::LavinaCore; + use prometheus::Registry as MetricsRegistry; + use proto_xmpp::bind::{BindRequest, Resource}; + use quick_xml::{Reader, Writer}; + use std::collections::HashMap; + use std::io::Cursor; + + struct TestServer { + metrics: MetricsRegistry, + storage: Storage, + core: LavinaCore, + } + + impl TestServer { + async fn start() -> anyhow::Result { + let _ = tracing_subscriber::fmt::try_init(); + let metrics = MetricsRegistry::new(); + let storage = Storage::open(StorageConfig { + db_path: ":memory:".into(), + }) + .await?; + let core = LavinaCore::new(metrics.clone(), storage.clone()).await?; + Ok(TestServer { metrics, storage, core }) + } + + async fn shutdown(self) -> anyhow::Result<()> { + self.core.shutdown().await?; + self.storage.close().await?; + Ok(()) + } + } + + #[tokio::test] + async fn test_handle_iq_bind() { + let server = TestServer::start().await.unwrap(); + + server.storage.create_user("tester").await.unwrap(); + let mut output = Vec::new(); + let player_id = PlayerId::from("tester").unwrap(); + let mut conn = server.core.players.connect_to_player(&player_id).await; + let user = Authenticated { + player_id, + xmpp_name: Name("tester".into()), + xmpp_resource: Resource("tester".into()), + xmpp_muc_name: Resource("tester".into()), + }; + let conn = XmppConnection { + user: &user, + user_handle: &mut conn, + rooms: &server.core.rooms, + hostname: "localhost".into(), + hostname_rooms: "rooms.localhost".into(), + }; + let iq = Iq { + from: None, + id: "test".into(), + to: None, + r#type: IqType::Result, + body: IqClientBody::Bind(BindRequest(Resource("whatever".into()))), + }; + conn.handle_iq(&mut output, iq).await; + let expected = "tester@localhost/tester"; + let mut reader = Reader::from_str(expected); + let mut result_iter = output.into_iter(); + loop { + let result = result_iter.next(); + let expected = reader.read_event().unwrap(); + match (&result, &expected) { + (None, Event::Eof) => { + break; + } + (Some(result), expected) => match (result, expected) { + (Event::Text(result), Event::Text(expected)) => { + assert_eq!(result.as_ref(), expected.as_ref()); + } + (Event::Start(result), Event::Start(expected)) => { + assert_eq!(result.name(), expected.name()); + let result: HashMap = + HashMap::from_iter(result.attributes().into_iter().map(|attr| attr.unwrap()).map(|attr| { + ( + std::str::from_utf8(attr.key.as_ref()).unwrap().to_owned(), + std::str::from_utf8(attr.value.as_ref()).unwrap().to_owned(), + ) + })); + let expected: HashMap = HashMap::from_iter( + expected.attributes().into_iter().map(|attr| attr.unwrap()).map(|attr| { + ( + std::str::from_utf8(attr.key.as_ref()).unwrap().to_owned(), + std::str::from_utf8(attr.value.as_ref()).unwrap().to_owned(), + ) + }), + ); + assert_eq!(result, expected); + } + (Event::End(result), Event::End(expected)) => { + assert_eq!(result.as_ref(), expected.as_ref()); + } + (Event::Empty(result), Event::Empty(expected)) => {} + _ => { + panic!("Unexpected result: {:?}, expected: {:?}", result, expected); + } + }, + _ => { + panic!("Unexpected result: {:?}, expected: {:?}", result, expected); + } + } + } + + server.shutdown().await.unwrap(); + } +} diff --git a/crates/proto-xmpp/src/bind.rs b/crates/proto-xmpp/src/bind.rs index d546141..929cf96 100644 --- a/crates/proto-xmpp/src/bind.rs +++ b/crates/proto-xmpp/src/bind.rs @@ -132,7 +132,10 @@ pub struct BindResponse(pub Jid); impl ToXml for BindResponse { fn serialize(&self, events: &mut Vec>) { events.extend_from_slice(&[ - Event::Start(BytesStart::new(r#"bind xmlns="urn:ietf:params:xml:ns:xmpp-bind""#)), + Event::Start(BytesStart::from_content( + r#"bind xmlns="urn:ietf:params:xml:ns:xmpp-bind""#, + 4, + )), Event::Start(BytesStart::new(r#"jid"#)), Event::Text(BytesText::new(self.0.to_string().as_str()).into_owned()), Event::End(BytesEnd::new("jid")), diff --git a/crates/proto-xmpp/src/client.rs b/crates/proto-xmpp/src/client.rs index 08d203a..bbe6787 100644 --- a/crates/proto-xmpp/src/client.rs +++ b/crates/proto-xmpp/src/client.rs @@ -430,7 +430,7 @@ impl IqType { impl ToXml for Iq { fn serialize(&self, events: &mut Vec>) { let start = format!(r#"iq xmlns="{}""#, XMLNS); - let mut start = BytesStart::new(start); + let mut start = BytesStart::from_content(start, 2); let mut attrs = vec![]; if let Some(ref from) = self.from { let value = from.to_string().into_bytes();