forked from lavina/lavina
1
0
Fork 0

Compare commits

...

2 Commits

Author SHA1 Message Date
Nikita Vilunov 16844f5b85 wip 2023-10-04 17:38:59 +02:00
Nikita Vilunov 1373767d7f xmpp: add muc proto tests 2023-10-04 15:55:34 +02:00
5 changed files with 134 additions and 39 deletions

View File

@ -7,6 +7,7 @@ use nonempty::nonempty;
use nonempty::NonEmpty;
use prometheus::{IntCounter, IntGauge, Registry as MetricsRegistry};
use serde::Deserialize;
use tokio::io::AsyncReadExt;
use tokio::io::{AsyncBufReadExt, AsyncWrite, AsyncWriteExt, BufReader, BufWriter};
use tokio::net::tcp::{ReadHalf, WriteHalf};
use tokio::net::{TcpListener, TcpStream};
@ -96,7 +97,7 @@ async fn handle_registration<'a>(
let mut pass: Option<Str> = None;
let user = loop {
let res = reader.read_until(b'\n', &mut buffer).await;
let res = read_irc_message(reader, &mut buffer).await;
let res = match res {
Ok(len) => {
if len == 0 {
@ -252,7 +253,7 @@ async fn handle_registered_socket<'a>(
loop {
select! {
biased;
len = reader.read_until(b'\n', &mut buffer) => {
len = read_irc_message(reader, &mut buffer) => {
let len = len?;
let len = if len == 0 {
log::info!("EOF, Terminating socket");
@ -291,6 +292,21 @@ async fn handle_registered_socket<'a>(
Ok(())
}
async fn read_irc_message(reader: &mut BufReader<ReadHalf<'_>>, buf: &mut Vec<u8>) -> Result<usize> {
let mut size = 0;
'outer: loop {
let res = reader.read_until(b'\r', buf).await?;
size += res;
let next = reader.read_u8().await?;
buf.push(next);
size += 1;
if next != b'\n' {
continue 'outer;
}
return Ok(size);
}
}
async fn handle_update(
config: &ServerConfig,
user: &RegisteredUser,

View File

@ -1,6 +1,6 @@
use super::*;
use nom::combinator::opt;
use nom::combinator::{all_consuming, opt};
/// Client-to-server command.
#[derive(Clone, Debug, PartialEq, Eq)]
@ -60,8 +60,8 @@ pub enum ClientMessage {
},
}
pub fn client_message(input: &str) -> IResult<&str, ClientMessage> {
alt((
pub fn client_message(input: &str) -> Result<ClientMessage, anyhow::Error> {
let (_, m) = all_consuming(alt((
client_message_capability,
client_message_ping,
client_message_pong,
@ -75,7 +75,8 @@ pub fn client_message(input: &str) -> IResult<&str, ClientMessage> {
client_message_part,
client_message_privmsg,
client_message_quit,
))(input)
)))(input)?;
Ok(m)
}
fn client_message_capability(input: &str) -> IResult<&str, ClientMessage> {
@ -89,24 +90,14 @@ fn client_message_ping(input: &str) -> IResult<&str, ClientMessage> {
let (input, _) = tag("PING ")(input)?;
let (input, token) = token(input)?;
Ok((
input,
ClientMessage::Ping {
token: token.into(),
},
))
Ok((input, ClientMessage::Ping { token: token.into() }))
}
fn client_message_pong(input: &str) -> IResult<&str, ClientMessage> {
let (input, _) = tag("PONG ")(input)?;
let (input, token) = token(input)?;
Ok((
input,
ClientMessage::Pong {
token: token.into(),
},
))
Ok((input, ClientMessage::Pong { token: token.into() }))
}
fn client_message_nick(input: &str) -> IResult<&str, ClientMessage> {
@ -225,12 +216,7 @@ fn client_message_quit(input: &str) -> IResult<&str, ClientMessage> {
let (input, _) = tag("QUIT :")(input)?;
let (input, reason) = token(input)?;
Ok((
input,
ClientMessage::Quit {
reason: reason.into(),
},
))
Ok((input, ClientMessage::Quit { reason: reason.into() }))
}
#[derive(Clone, Debug, PartialEq, Eq)]
@ -292,9 +278,7 @@ mod test {
#[test]
fn test_client_message_ping() {
let input = "PING 1337";
let expected = ClientMessage::Ping {
token: "1337".into(),
};
let expected = ClientMessage::Ping { token: "1337".into() };
let result = client_message(input);
assert_matches!(result, Ok((_, result)) => assert_eq!(expected, result));
@ -302,9 +286,7 @@ mod test {
#[test]
fn test_client_message_pong() {
let input = "PONG 1337";
let expected = ClientMessage::Pong {
token: "1337".into(),
};
let expected = ClientMessage::Pong { token: "1337".into() };
let result = client_message(input);
assert_matches!(result, Ok((_, result)) => assert_eq!(expected, result));

View File

@ -104,7 +104,7 @@ mod test {
use assert_matches::*;
use super::*;
use crate::testkit::*;
use crate::{testkit::*, client::client_message};
#[test]
fn test_chan_global() {
@ -153,4 +153,10 @@ mod test {
assert_eq!(bytes.as_slice(), input.as_bytes());
}
#[test]
fn test_aa() {
dbg!(client_message("PING asd"));
panic!()
}
}

View File

@ -1,8 +1,10 @@
#![allow(unused_variables)]
use quick_xml::events::Event;
use quick_xml::name::ResolveResult;
use anyhow::{anyhow, Result};
use crate::xml::*;
use anyhow::{anyhow, Result};
pub const XMLNS: &'static str = "http://jabber.org/protocol/muc";
@ -20,8 +22,8 @@ impl FromXml for History {
|(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result<Self> {
let mut history = History::default();
let (bytes, end) = match event {
Event::Start(bytes) => (bytes, false),
Event::Empty(bytes) => (bytes, true),
Event::Start(bytes) if bytes.name().0 == Self::NAME.as_bytes() => (bytes, false),
Event::Empty(bytes) if bytes.name().0 == Self::NAME.as_bytes() => (bytes, true),
_ => return Err(anyhow!("Unexpected XML event: {event:?}")),
};
for attr in bytes.attributes() {
@ -72,14 +74,16 @@ impl FromXml for Password {
fn parse() -> Self::P {
|(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result<Self> {
let Event::Start(bytes) = event else {
return Err(anyhow!("Unexpected XML event: {event:?}"));
let bytes = match event {
Event::Start(bytes) if bytes.name().0 == Self::NAME.as_bytes() => bytes,
_ => return Err(anyhow!("Unexpected XML event: {event:?}")),
};
let (namespace, event) = yield;
let Event::Text(bytes) = event else {
return Err(anyhow!("Unexpected XML event: {event:?}"));
};
let s = std::str::from_utf8(bytes)?.to_string();
let (namespace, event) = yield;
let Event::End(bytes) = event else {
return Err(anyhow!("Unexpected XML event: {event:?}"));
};
@ -106,7 +110,7 @@ impl FromXml for X {
fn parse() -> Self::P {
|(namespace, event): (ResolveResult<'static>, &'static Event<'static>)| -> Result<Self> {
let mut res = X::default();
let (bytes, end) = match event {
let (_, end) = match event {
Event::Start(bytes) => (bytes, false),
Event::Empty(bytes) => (bytes, true),
_ => return Err(anyhow!("Unexpected XML event: {event:?}")),
@ -138,3 +142,90 @@ impl FromXml for X {
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_history_success_empty() {
let input = "<history/>";
let res: History = parse(input).unwrap();
let expected = History {
maxchars: None,
maxstanzas: None,
seconds: None,
};
assert_eq!(res, expected);
}
#[test]
fn test_history_success_empty_attrs() {
let input = r#"<history maxchars="1" maxstanzas="2" seconds="4"/>"#;
let res: History = parse(input).unwrap();
let expected = History {
maxchars: Some(1),
maxstanzas: Some(2),
seconds: Some(4),
};
assert_eq!(res, expected);
}
#[test]
fn test_history_success_start_end() {
let input = r#"<history></history>"#;
let res: History = parse(input).unwrap();
let expected = History {
maxchars: None,
maxstanzas: None,
seconds: None,
};
assert_eq!(res, expected);
}
#[test]
fn test_history_incorrect_empty() {
let input = r#"<iq/>"#;
parse::<History>(input).err().unwrap();
}
#[test]
fn test_password_success() {
let input = "<password>olala</password>";
let res: Password = parse(input).unwrap();
let expected = Password("olala".into());
assert_eq!(res, expected);
}
#[test]
fn test_password_incorrect() {
let input = r#"<iq>asdsd</iq>"#;
parse::<Password>(input).err().unwrap();
}
#[test]
fn test_x_success_empty() {
let input = "<x/>";
let res: X = parse(input).unwrap();
let expected = X {
history: None,
password: None,
};
assert_eq!(res, expected);
}
#[test]
fn test_x_success_full() {
let input = r#"<x><password>ololo</password><history maxchars="1"/></x>"#;
let res: X = parse(input).unwrap();
let expected = X {
history: Some(History {
maxchars: Some(1),
maxstanzas: None,
seconds: None,
}),
password: Some(Password("ololo".into())),
};
assert_eq!(res, expected);
}
}

View File

@ -17,7 +17,7 @@ impl Parser for IgnoreParser {
fn consume<'a>(
self: Self,
namespace: ResolveResult,
_: ResolveResult,
event: &Event<'a>,
) -> Continuation<Self, Self::Output> {
match self.0 {
@ -58,5 +58,5 @@ impl FromXml for Ignore {
}
impl ToXml for () {
fn serialize(&self, events: &mut Vec<Event<'static>>) {}
fn serialize(&self, _: &mut Vec<Event<'static>>) {}
}