use core::mem;
use core::sync::atomic::{AtomicU16, Ordering};
use core::time::Duration;
use std::collections::HashMap;
use std::env;
use std::path::PathBuf;
use std::process::Command;
use std::sync::{Arc, Mutex, RwLock};
use libstrophe::*;
use names::Generator;
#[test]
fn default_context() {
Context::new_with_default_logger();
}
#[test]
fn default_context_null() {
Context::new_with_null_logger();
}
#[test]
fn default_logger() {
Logger::default();
}
#[test]
fn null_logger() {
Logger::new_null();
}
#[test]
fn custom_logger() {
let i: AtomicU16 = AtomicU16::new(0);
{
let ctx = Context::new(Logger::new(|_, _, _| {
i.fetch_add(1, Ordering::Relaxed);
}));
let mut conn = Connection::new(ctx);
conn.set_jid("test-JID@127.50.60.70");
let mut ctx = conn.connect_client(None, Some(1234), |_, _, _| {}).unwrap();
ctx.run_once(Duration::from_secs(1));
}
assert_eq!(i.load(Ordering::Relaxed), 5);
}
#[test]
fn conn_client_wo_jid() {
let conn = Connection::new(Context::new_with_null_logger());
assert!(matches!(
conn.connect_client(None, None, |_, _, _| {}),
Err(ConnectClientError {
error: Error::InvalidOperation,
..
})
));
}
#[test]
fn conn_client() {
let conn_handler = |ctx: &Context, _: &mut Connection, event: ConnectionEvent| {
assert!(matches!(event, ConnectionEvent::Disconnect(_)));
ctx.stop();
};
{
let mut conn = Connection::new(Context::new_with_null_logger());
conn.set_jid("test-JID@127.50.60.70");
let mut ctx = conn.connect_client(None, None, conn_handler).unwrap();
ctx.run();
}
{
let mut conn = Connection::new(Context::new_with_null_logger());
conn.set_jid("test-JID@127.50.60.70");
let mut ctx = conn.connect_client(None, None, conn_handler).unwrap();
ctx.run();
}
}
#[test]
fn conn_raw() {
let conn_handler = |ctx: &Context, _: &mut Connection, event: ConnectionEvent| {
assert!(matches!(event, ConnectionEvent::Disconnect(_)));
ctx.stop();
};
{
let mut conn = Connection::new(Context::new_with_null_logger());
conn.set_jid("test-JID@127.50.60.70");
let mut ctx = conn.connect_raw(None, Some(1234), conn_handler).unwrap();
ctx.run();
}
{
let mut conn = Connection::new(Context::new_with_null_logger());
conn.set_jid("test-JID@127.50.60.70");
let mut ctx = conn.connect_raw(None, Some(1234), conn_handler).unwrap();
ctx.run();
}
}
#[test]
fn timed_handler() {
let timed_handler = |_: &Context, _: &mut Connection| HandlerResult::RemoveHandler;
let ctx = Context::new_with_null_logger();
let mut conn = Connection::new(ctx);
let handle = conn
.timed_handler_add(timed_handler, Duration::from_secs(1))
.expect("Can't add timed handler");
assert!(conn.timed_handler_add(timed_handler, Duration::from_secs(1)).is_none());
let removed_count = conn.timed_handler_delete(handle);
assert_eq!(1, removed_count);
}
#[test]
fn stanza_handler() {
let stanza_handler = |_: &Context, _: &mut Connection, _: &Stanza| HandlerResult::RemoveHandler;
let ctx = Context::new_with_null_logger();
let mut conn = Connection::new(ctx);
let handle = conn
.handler_add(stanza_handler, Some("ns"), None, None)
.expect("Can't add handler");
assert!(conn.handler_add(stanza_handler, Some("ns"), None, None).is_none());
let removed_count = conn.handler_delete(handle);
assert_eq!(1, removed_count);
let handle = conn
.handler_add(stanza_handler, None, Some("name"), None)
.expect("Can't add handler");
let removed_count = conn.handler_delete(handle);
assert_eq!(1, removed_count);
}
#[test]
fn id_handler() {
let id_handler = |_: &Context, _: &mut Connection, _: &Stanza| HandlerResult::RemoveHandler;
let ctx = Context::new_with_null_logger();
let mut conn = Connection::new(ctx);
let h = conn.id_handler_add(id_handler, "test").expect("Can't add id handler");
assert!(conn.id_handler_add(id_handler, "test").is_none());
let removed_count = conn.id_handler_delete(h);
assert_eq!(1, removed_count);
}
#[test]
fn stanza_handler_in_con() {
let stanza_handler = |_: &Context, _: &mut Connection, _: &Stanza| HandlerResult::RemoveHandler;
let con_handler = move |_: &Context, conn: &mut Connection, _: ConnectionEvent| {
conn.handler_add(stanza_handler, None, None, None).expect("Can't add handler");
};
let ctx = Context::new_with_null_logger();
let mut conn = Connection::new(ctx);
conn.set_jid("test-JID@127.50.60.70");
conn.connect_client(None, None, con_handler).unwrap();
}
#[test]
fn jid_test() {
assert_eq!(
Some("node@domain.com/test".to_string()),
jid::jid_new(Some("node"), "domain.com", Some("test"))
);
assert_eq!(
Some("domain.com/test".to_string()),
jid::jid_new(None, "domain.com", Some("test"))
);
assert_eq!(Some("domain.com".to_string()), jid::jid_new(None, "domain.com", None));
let jid = jid::jid_new(Some("node"), "domain.com", Some("test")).unwrap();
let jid_domain = jid::jid_new(None, "domain.com", None).unwrap();
assert_eq!(Some("node@domain.com".to_string()), jid::jid_bare(&jid));
assert_eq!(Some("node".to_string()), jid::jid_node(&jid));
assert_eq!(None, jid::jid_node(&jid_domain));
assert_eq!(Some("domain.com".to_string()), jid::jid_domain(&jid));
assert_eq!(Some("domain.com".to_string()), jid::jid_domain(&jid_domain));
assert_eq!(Some("test".to_string()), jid::jid_resource(&jid));
assert_eq!(None, jid::jid_resource(&jid_domain));
}
#[test]
fn stanza_err() {
let mut stanza = Stanza::new();
assert!(matches!(
stanza.to_text(),
Err(ToTextError::StropheError(Error::InvalidOperation))
));
stanza.set_name("test").unwrap();
assert!(matches!(stanza.set_body("body"), Err(Error::InvalidOperation)));
}
#[test]
fn stanza_display() {
let mut stanza = Stanza::new();
stanza.set_name("message").unwrap();
stanza.set_id("stanza_id").unwrap();
stanza.add_child(Stanza::new_iq(Some("test"), None)).unwrap();
assert_eq!(stanza.to_string(), stanza.to_text().unwrap());
}
#[test]
fn stanza_hier() {
let mut stanza = Stanza::new();
stanza.set_name("test").unwrap();
stanza.add_child(Stanza::new_presence()).unwrap();
stanza.add_child(Stanza::new_iq(Some("test"), None)).unwrap();
let mut msg = Stanza::new_message(Some("chat"), Some("id"), Some("to"));
msg.set_body("Test body").unwrap();
stanza.add_child(msg).unwrap();
{
let child = stanza.get_first_child().unwrap();
assert_eq!(child.name().unwrap(), "presence");
let child = child.get_next().unwrap();
assert_eq!(child.name().unwrap(), "iq");
}
{
let mut child = stanza.get_first_child_mut().unwrap();
let mut child = child.get_next_mut().unwrap();
let child = child.get_next_mut().unwrap();
assert_eq!(child.name().unwrap(), "message");
assert_eq!(child.body().unwrap(), "Test body");
}
{
for (i, child) in stanza.children().enumerate() {
assert_eq!(stanza.get_first_child().unwrap().name().unwrap(), "presence"); match i {
0 => assert_eq!(child.name().unwrap(), "presence"),
1 => assert_eq!(child.name().unwrap(), "iq"),
2 => {
assert_eq!(child.name().unwrap(), "message");
assert_eq!(child.body().unwrap(), "Test body");
}
_ => panic!("Too many items: {child}"),
}
}
}
{
for (i, mut child) in stanza.children_mut().enumerate() {
match i {
0 => {
assert_eq!(child.name().unwrap(), "presence");
child.set_name("presence1").unwrap();
}
1 => assert_eq!(child.name().unwrap(), "iq"),
2 => {
assert_eq!(child.name().unwrap(), "message");
assert_eq!(child.body().unwrap(), "Test body");
}
_ => panic!("Too many items: {child}"),
}
}
assert_eq!(stanza.get_first_child().unwrap().name().unwrap(), "presence1");
}
}
#[test]
fn stanza_get_child() {
let mut root = Stanza::new();
root.set_name("test").unwrap();
let presence = Stanza::new_presence();
root.add_child(presence.clone()).unwrap();
let mut iq_ns = Stanza::new_iq(Some("test"), None);
iq_ns.set_ns("iq_namespace").unwrap();
root.add_child(iq_ns.clone()).unwrap();
let mut msg = Stanza::new_message(Some("chat"), Some("id"), Some("to"));
msg.set_body("Test body").unwrap();
root.add_child(msg.clone()).unwrap();
assert_eq!(presence.to_string(), root.get_child_by_name("presence").unwrap().to_string());
assert_eq!(iq_ns.to_string(), root.get_child_by_ns("iq_namespace").unwrap().to_string());
#[cfg(feature = "libstrophe-0_10_0")]
{
assert_eq!(
iq_ns.to_string(),
root.get_child_by_name_and_ns("iq", "iq_namespace").unwrap().to_string()
);
assert_eq!(None, root.get_child_by_name_and_ns("presence", "iq_namespace"));
}
#[cfg(feature = "libstrophe-0_12_0")]
{
assert_eq!(root.to_string(), root.get_child_by_path(&["test"]).unwrap().to_string());
assert_eq!(
iq_ns.to_string(),
root
.get_child_by_path(&["test", &XMPP_STANZA_NAME_IN_NS("iq", "iq_namespace")])
.unwrap()
.to_string()
);
assert_eq!(
msg.clone().to_string(), root.get_child_by_path(&["test", "message"]).unwrap().to_string()
);
assert_eq!(
"<body>Test body</body>",
root.get_child_by_path(&["test", "message", "body"]).unwrap().to_string()
);
root
.get_child_by_path_mut(&["test", "message"])
.unwrap()
.set_to("New to")
.unwrap();
assert_eq!("New to", root.get_child_by_name("message").unwrap().to().unwrap());
}
}
#[test]
fn stanza() {
let mut stanza = Stanza::new();
stanza.set_name("message").unwrap();
stanza.set_id("stanza_id").unwrap();
let stanza2 = Stanza::new_message(None, Some("stanza_id"), None);
assert_eq!(stanza.name(), stanza2.name());
assert_eq!(stanza.stanza_type(), stanza2.stanza_type());
assert_eq!(stanza.id(), stanza2.id());
assert_eq!(stanza.to(), stanza2.to());
assert_eq!(stanza.body(), stanza2.body());
stanza.set_name("presence").unwrap();
let stanza2 = Stanza::new_presence();
assert_eq!(stanza.name(), stanza2.name());
let mut stanza3 = stanza.clone();
stanza3.set_id("iq").unwrap();
assert_ne!(stanza.id(), stanza3.id());
}
#[test]
fn stanza_clone() {
let stanza = {
let mut stanza = Stanza::new();
stanza.set_name("message").unwrap();
stanza.set_id("stanza_id").unwrap();
#[allow(clippy::redundant_clone)]
stanza.clone()
};
assert_eq!("<message id=\"stanza_id\"/>", stanza.to_text().unwrap());
}
#[test]
fn stanza_attributes() {
let mut stanza = Stanza::new();
assert!(matches!(stanza.set_id("stanza_id"), Err(Error::InvalidOperation)));
assert_eq!(stanza.attribute_count(), 0);
stanza.set_name("message").unwrap();
stanza.set_id("stanza_id").unwrap();
stanza.set_stanza_type("type").unwrap();
stanza.set_ns("myns").unwrap();
assert_eq!(stanza.attribute_count(), 3);
assert!(matches!(stanza.get_attribute("type"), Some("type")));
assert!(stanza.get_attribute("non-existent").is_none());
stanza.set_attribute("xmlns", "myotherns").unwrap();
assert!(matches!(stanza.ns(), Some("myotherns")));
let mut compare = HashMap::new();
compare.insert("xmlns", "myotherns");
compare.insert("type", "type");
compare.insert("id", "stanza_id");
assert_eq!(stanza.attributes(), compare);
stanza.del_attribute("type").unwrap();
assert_eq!(stanza.attribute_count(), 2);
assert!(stanza.get_attribute("type").is_none());
compare.remove("type");
assert_eq!(stanza.attributes(), compare);
}
#[test]
#[cfg(feature = "libstrophe-0_10_0")]
fn stanza_from_str() {
let s = Stanza::from_str("<test><child1/><child2/></test>");
let mut children = s.children();
assert_eq!(Some("<child1/>".to_string()), children.next().map(|c| c.to_string()));
assert_eq!(Some("<child2/>".to_string()), children.next().map(|c| c.to_string()));
assert_eq!(None, children.next().as_deref());
}
#[test]
fn zero_sized_handlers() {
let creds = if let Some(creds) = Creds::acquire() {
creds
} else {
eprintln!("Can't acquire creds, skipping test");
return;
};
let i = Arc::new(AtomicU16::new(0));
{
let i_incrementer = {
let i = Arc::clone(&i);
move |_: &Context, _: &mut Connection, _: &Stanza| {
i.fetch_add(1, Ordering::Relaxed);
HandlerResult::RemoveHandler
}
};
assert_ne!(mem::size_of_val(&i_incrementer), 0);
{
let zero_sized = |_: &Context, conn: &mut Connection, _: &Stanza| {
let pres = Stanza::new_presence();
conn.send(&pres);
HandlerResult::RemoveHandler
};
assert_eq!(mem::size_of_val(&zero_sized), 0);
let conn = creds.make_conn();
let mut ctx = conn
.connect_client(None, None, {
let i_incrementer = i_incrementer.clone();
move |ctx, conn, evt| match evt {
ConnectionEvent::Connect => {
conn.handler_add(zero_sized, None, None, None).expect("Can't add handler");
conn.send(&Stanza::new_iq(None, None));
conn
.handler_add(i_incrementer.clone(), None, Some("presence"), None)
.expect("Can't add handler");
conn
.timed_handler_add(
|_, conn| {
conn.disconnect();
HandlerResult::RemoveHandler
},
Duration::from_secs(1),
)
.expect("Can't add timed handler");
}
ConnectionEvent::Disconnect(_) => ctx.stop(),
_ => (),
}
})
.unwrap();
ctx.run();
}
assert_eq!(i.load(Ordering::Relaxed), 1);
i.store(0, Ordering::Relaxed);
{
assert_ne!(mem::size_of_val(&i_incrementer), 0);
let conn = creds.make_conn();
let mut ctx = conn
.connect_client(None, None, {
let i_incrementer = i_incrementer.clone();
move |ctx, conn, evt| match evt {
ConnectionEvent::Connect => {
conn
.handler_add(i_incrementer.clone(), None, Some("presence"), None)
.expect("Can't add handler");
let pres = Stanza::new_presence();
conn.send(&pres);
conn
.timed_handler_add(
|_, conn| {
conn.disconnect();
HandlerResult::RemoveHandler
},
Duration::from_secs(1),
)
.expect("Can't add timed handler");
}
ConnectionEvent::Disconnect(_) => ctx.stop(),
_ => (),
}
})
.unwrap();
ctx.run();
}
assert_eq!(i.load(Ordering::Relaxed), 1);
i.store(0, Ordering::Relaxed);
{
let zero_sized = |_: &Context, conn: &mut Connection, _: &Stanza| {
let pres = Stanza::new_presence();
conn.send(&pres);
HandlerResult::RemoveHandler
};
assert_eq!(mem::size_of_val(&zero_sized), 0);
let conn = creds.make_conn();
let mut ctx = conn
.connect_client(None, None, {
let i_incrementer = i_incrementer.clone();
move |ctx, conn, evt| match evt {
ConnectionEvent::Connect => {
conn.handler_add(zero_sized, None, None, None).expect("Can't add handler");
if conn.handler_add(zero_sized, None, None, None).is_some() {
panic!("Must not be able to add handler");
}
conn
.handler_add(i_incrementer.clone(), None, None, None)
.expect("Can't add handler");
if conn.handler_add(i_incrementer.clone(), None, None, None).is_some() {
panic!("Must not be able to add handler");
}
let removed_count = conn.handlers_clear();
assert_eq!(2, removed_count);
conn
.handler_add(i_incrementer.clone(), None, Some("presence"), None)
.expect("Can't add handler");
conn
.timed_handler_add(
|_, conn| {
conn.disconnect();
HandlerResult::RemoveHandler
},
Duration::from_secs(1),
)
.expect("Can't add timed handler");
}
ConnectionEvent::Disconnect(_) => ctx.stop(),
_ => (),
}
})
.unwrap();
ctx.run();
}
assert_eq!(i.load(Ordering::Relaxed), 0);
}
assert_eq!(
Arc::try_unwrap(i)
.expect("There are hanging references to rc value")
.into_inner(),
0
);
}
#[test]
fn connection_handler() {
let creds = if let Some(creds) = Creds::acquire() {
creds
} else {
eprintln!("Can't acquire creds, skipping test");
return;
};
let flags = Arc::new(RwLock::new((0, 0, 0)));
{
let conn = creds.make_conn();
let mut ctx = conn
.connect_client(None, None, {
let flags = Arc::clone(&flags);
move |ctx, conn, evt| match evt {
ConnectionEvent::Connect => {
flags.write().unwrap().0 += 1;
conn.disconnect();
}
ConnectionEvent::RawConnect => {
flags.write().unwrap().1 += 1;
}
ConnectionEvent::Disconnect(_) => {
flags.write().unwrap().2 += 1;
ctx.stop();
}
}
})
.unwrap();
ctx.run();
}
assert_eq!(
Arc::try_unwrap(flags)
.expect("There are hanging references to rc value")
.into_inner()
.unwrap(),
(1, 0, 1)
);
}
#[test]
fn timed_handler_creds() {
let creds = if let Some(creds) = Creds::acquire() {
creds
} else {
eprintln!("Can't acquire creds, skipping test");
return;
};
let i = Arc::new(AtomicU16::new(0));
let do_common_stuff = |conn: &mut Connection| {
conn
.timed_handler_add(
|_, conn| {
conn.disconnect();
HandlerResult::RemoveHandler
},
Duration::from_secs(1),
)
.expect("Can't add timed handler");
};
{
let i_incrementer = {
let i = Arc::clone(&i);
move |_: &Context, _: &mut Connection| {
i.fetch_add(1, Ordering::Relaxed);
HandlerResult::KeepHandler
}
};
{
let conn = creds.make_conn();
let mut ctx = conn
.connect_client(None, None, {
let i_incrementer = i_incrementer.clone();
move |ctx, conn, evt| match evt {
ConnectionEvent::Connect => {
conn
.timed_handler_add(i_incrementer.clone(), Duration::from_millis(1))
.expect("Can't add timed handler");
do_common_stuff(conn);
}
ConnectionEvent::Disconnect(_) => ctx.stop(),
_ => {}
}
})
.unwrap();
ctx.run();
assert!(i.load(Ordering::Relaxed) > 0);
assert!(i.load(Ordering::Relaxed) < 1000);
}
i.store(0, Ordering::Relaxed);
{
let mut conn = creds.make_conn();
conn
.timed_handler_add(i_incrementer.clone(), Duration::from_millis(1))
.expect("Can't add timed handler");
let mut ctx = conn
.connect_client(None, None, {
move |ctx, conn, evt| match evt {
ConnectionEvent::Connect => {
do_common_stuff(conn);
}
ConnectionEvent::Disconnect(_) => ctx.stop(),
_ => {}
}
})
.unwrap();
ctx.run();
assert!(i.load(Ordering::Relaxed) > 0);
assert!(i.load(Ordering::Relaxed) < 1000);
}
i.store(0, Ordering::Relaxed);
{
let conn = creds.make_conn();
let mut ctx = conn
.connect_client(None, None, {
let i_incrementer = i_incrementer.clone();
move |ctx, conn, evt| match evt {
ConnectionEvent::Connect => {
let handler = conn
.timed_handler_add(i_incrementer.clone(), Duration::from_millis(1))
.expect("Can't add timed handler");
let removed_count = conn.timed_handler_delete(handler);
assert_eq!(1, removed_count);
do_common_stuff(conn);
}
ConnectionEvent::Disconnect(_) => ctx.stop(),
_ => {}
}
})
.unwrap();
ctx.run();
assert_eq!(i.load(Ordering::Relaxed), 0);
}
i.store(0, Ordering::Relaxed);
{
let conn = creds.make_conn();
let mut ctx = conn
.connect_client(None, None, {
let i_incrementer = i_incrementer.clone();
move |ctx, conn, evt| match evt {
ConnectionEvent::Connect => {
conn
.timed_handler_add(i_incrementer.clone(), Duration::from_millis(1))
.expect("Can't add timed handler");
let removed_count = conn.timed_handlers_clear();
assert_eq!(1, removed_count);
do_common_stuff(conn);
}
ConnectionEvent::Disconnect(_) => ctx.stop(),
_ => {}
}
})
.unwrap();
ctx.run();
assert_eq!(i.load(Ordering::Relaxed), 0);
}
}
assert_eq!(
Arc::try_unwrap(i)
.expect("There are hanging references to rc value")
.into_inner(),
0
);
}
#[test]
fn id_handler_creds() {
let creds = if let Some(creds) = Creds::acquire() {
creds
} else {
eprintln!("Can't acquire creds, skipping test");
return;
};
let i = Arc::new(AtomicU16::new(0));
let do_common_stuff = |_: &Context, conn: &mut Connection| {
let mut iq = Stanza::new_iq(Some("get"), Some("get_roster"));
let mut query = Stanza::new();
query.set_name("query").unwrap();
query.set_ns("jabber:iq:roster").unwrap();
iq.add_child(query).unwrap();
conn.send(&iq);
conn
.timed_handler_add(
|_, conn| {
conn.disconnect();
HandlerResult::RemoveHandler
},
Duration::from_secs(1),
)
.expect("Can't add id handler");
};
{
let i_incrementer = {
let i = Arc::clone(&i);
move |_: &Context, _: &mut Connection, _: &Stanza| {
i.fetch_add(1, Ordering::Relaxed);
HandlerResult::KeepHandler
}
};
{
let conn = creds.make_conn();
let mut ctx = conn
.connect_client(None, None, {
let i_incrementer = i_incrementer.clone();
move |ctx, conn, evt| match evt {
ConnectionEvent::Connect => {
conn
.id_handler_add(i_incrementer.clone(), "get_roster")
.expect("Can't add id handler");
let mut iq = Stanza::new_iq(Some("get"), Some("get_roster1"));
let mut query = Stanza::new();
query.set_name("query").unwrap();
query.set_ns("jabber:iq:roster").unwrap();
iq.add_child(query).unwrap();
conn.send(&iq);
do_common_stuff(ctx, conn);
}
ConnectionEvent::Disconnect(_) => ctx.stop(),
_ => {}
}
})
.unwrap();
ctx.run();
assert_eq!(i.load(Ordering::Relaxed), 1);
}
i.store(0, Ordering::Relaxed);
{
let mut conn = creds.make_conn();
conn
.id_handler_add(i_incrementer.clone(), "get_roster")
.expect("Can't add id handler");
let mut ctx = conn
.connect_client(None, None, {
move |ctx, conn, evt| match evt {
ConnectionEvent::Connect => {
let mut iq = Stanza::new_iq(Some("get"), Some("get_roster1"));
let mut query = Stanza::new();
query.set_name("query").unwrap();
query.set_ns("jabber:iq:roster").unwrap();
iq.add_child(query).unwrap();
conn.send(&iq);
do_common_stuff(ctx, conn);
}
ConnectionEvent::Disconnect(_) => ctx.stop(),
_ => {}
}
})
.unwrap();
ctx.run();
assert_eq!(i.load(Ordering::Relaxed), 1);
}
i.store(0, Ordering::Relaxed);
{
let conn = creds.make_conn();
let mut ctx = conn
.connect_client(None, None, {
let i_incrementer = i_incrementer.clone();
move |ctx, conn, evt| match evt {
ConnectionEvent::Connect => {
let handler = conn
.id_handler_add(i_incrementer.clone(), "get_roster")
.expect("Can't id timed handler");
let removed_count = conn.id_handler_delete(handler);
assert_eq!(1, removed_count);
do_common_stuff(ctx, conn);
}
ConnectionEvent::Disconnect(_) => ctx.stop(),
_ => {}
}
})
.unwrap();
ctx.run();
assert_eq!(i.load(Ordering::Relaxed), 0);
}
i.store(0, Ordering::Relaxed);
{
let conn = creds.make_conn();
let mut ctx = conn
.connect_client(None, None, {
let i_incrementer = i_incrementer.clone();
move |ctx, conn, evt| match evt {
ConnectionEvent::Connect => {
conn
.id_handler_add(i_incrementer.clone(), "get_roster")
.expect("Can't add id handler");
let removed_count = conn.id_handlers_clear();
assert_eq!(1, removed_count);
do_common_stuff(ctx, conn);
}
ConnectionEvent::Disconnect(_) => ctx.stop(),
_ => {}
}
})
.unwrap();
ctx.run();
assert_eq!(i.load(Ordering::Relaxed), 0);
}
}
assert_eq!(
Arc::try_unwrap(i)
.expect("There are hanging references to rc value")
.into_inner(),
0
);
}
#[test]
fn handler() {
let creds = if let Some(creds) = Creds::acquire() {
creds
} else {
eprintln!("Can't acquire creds, skipping test");
return;
};
let i = Arc::new(AtomicU16::new(0));
let default_con_handler = |ctx: &Context, conn: &mut Connection, evt: ConnectionEvent| match evt {
ConnectionEvent::Connect => {
conn.send(&Stanza::new_iq(None, None));
conn.timed_handler_add(
|_, conn| {
conn.disconnect();
HandlerResult::RemoveHandler
},
Duration::from_secs(1),
);
}
ConnectionEvent::Disconnect(_) => ctx.stop(),
_ => {}
};
let i_incrementer = {
let i = Arc::clone(&i);
move |_: &Context, _: &mut Connection, _: &Stanza| {
i.fetch_add(1, Ordering::Relaxed);
HandlerResult::RemoveHandler
}
};
{
let mut conn = creds.make_conn();
conn
.handler_add(i_incrementer.clone(), None, Some("iq"), None)
.expect("Can't add handler");
let mut ctx = conn.connect_client(None, None, default_con_handler).unwrap();
ctx.run();
assert_eq!(i.load(Ordering::Relaxed), 1);
}
i.store(0, Ordering::Relaxed);
{
let mut conn = creds.make_conn();
conn
.handler_add(i_incrementer.clone(), None, Some("non-existent"), None)
.expect("Can't add handler");
let mut ctx = conn.connect_client(None, None, default_con_handler).unwrap();
ctx.run();
assert_eq!(i.load(Ordering::Relaxed), 0);
}
i.store(0, Ordering::Relaxed);
{
let mut conn = creds.make_conn();
let handler = conn
.handler_add(i_incrementer.clone(), None, None, None)
.expect("Can't add handler");
let removed_count = conn.handler_delete(handler);
assert_eq!(1, removed_count);
let mut ctx = conn.connect_client(None, None, default_con_handler).unwrap();
ctx.run();
assert_eq!(i.load(Ordering::Relaxed), 0);
}
i.store(0, Ordering::Relaxed);
{
let mut conn = creds.make_conn();
conn
.handler_add(i_incrementer.clone(), None, None, None)
.expect("Can't add handler");
conn
.handler_add(
|_, _, _| {
println!("This handler should be removed, 1");
HandlerResult::KeepHandler
},
None,
None,
None,
)
.expect("Can't add handler");
conn
.handler_add(
|_, _, _| {
println!("This handler should be removed, 2");
HandlerResult::KeepHandler
},
None,
None,
None,
)
.expect("Can't add handler");
let removed_count = conn.handlers_clear();
assert_eq!(3, removed_count);
let mut ctx = conn.connect_client(None, None, default_con_handler).unwrap();
ctx.run();
assert_eq!(i.load(Ordering::Relaxed), 0);
}
i.store(0, Ordering::Relaxed);
{
let mut conn = creds.make_conn();
assert!(conn.handler_add(&i_incrementer, None, Some("iq"), None,).is_some());
assert!(conn.handler_add(&i_incrementer, None, Some("iq"), None).is_none());
let mut ctx = conn.connect_client(None, None, default_con_handler).unwrap();
ctx.run();
assert_eq!(i.load(Ordering::Relaxed), 1);
}
i.store(0, Ordering::Relaxed);
{
let mut conn = creds.make_conn();
assert!(conn.handler_add(i_incrementer.clone(), None, Some("iq"), None,).is_some());
assert!(conn.handler_add(i_incrementer.clone(), None, Some("iq"), None).is_none());
let mut ctx = conn.connect_client(None, None, default_con_handler).unwrap();
ctx.run();
assert_eq!(i.load(Ordering::Relaxed), 1);
}
}
#[test]
fn stanza_global_context() {
let creds = if let Some(creds) = Creds::acquire() {
creds
} else {
eprintln!("Can't acquire creds, skipping test");
return;
};
let stz = Arc::new(Mutex::new(None));
{
let mut conn = creds.make_conn();
conn
.handler_add(
{
let stz = stz.clone();
move |_, _, stanza| {
*stz.lock().unwrap() = Some(stanza.clone());
HandlerResult::RemoveHandler
}
},
None,
Some("iq"),
None,
)
.expect("Can't add handler");
let mut ctx = conn
.connect_client(None, None, |ctx, conn, evt| match evt {
ConnectionEvent::Connect => {
conn.send(&Stanza::new_iq(None, None));
conn.timed_handler_add(
|_, conn| {
conn.disconnect();
HandlerResult::RemoveHandler
},
Duration::from_secs(1),
);
}
ConnectionEvent::Disconnect(_) => ctx.stop(),
_ => (),
})
.unwrap();
ctx.run();
}
let stanza = Arc::try_unwrap(stz).unwrap().into_inner().unwrap().unwrap();
assert_eq!(stanza.to_text().unwrap(), stanza.to_string());
}
#[test]
#[cfg(feature = "libstrophe-0_11_0")]
fn connection_handler_tls() {
let creds = if let Some(creds) = Creds::acquire() {
creds
} else {
eprintln!("Can't acquire creds, skipping test");
return;
};
{
let flags = Arc::new(RwLock::new((0, 0, 0, 0)));
{
let mut conn = creds.make_tls_conn();
conn.set_certfail_handler({
let flags = Arc::clone(&flags);
move |_cert, _err| {
flags.write().unwrap().0 += 2;
CertFailResult::TerminateConnection
}
});
conn.set_certfail_handler({
let flags = Arc::clone(&flags);
move |_cert, _err| {
flags.write().unwrap().0 += 1;
CertFailResult::TerminateConnection
}
});
let mut ctx = conn
.connect_client(None, None, {
let flags = Arc::clone(&flags);
move |ctx, conn, evt| match evt {
ConnectionEvent::Connect => {
flags.write().unwrap().1 += 1;
conn.disconnect();
}
ConnectionEvent::RawConnect => {
flags.write().unwrap().2 += 1;
}
ConnectionEvent::Disconnect(_) => {
flags.write().unwrap().3 += 1;
ctx.stop();
}
}
})
.unwrap();
ctx.run();
}
assert_eq!(
Arc::try_unwrap(flags)
.expect("There are hanging references to rc value")
.into_inner()
.unwrap(),
(1, 0, 0, 1)
);
}
{
let flags = Arc::new(RwLock::new((0, 0, 0, 0)));
{
let mut conn = creds.make_tls_conn();
conn.set_certfail_handler({
let flags = Arc::clone(&flags);
move |_cert, _err| {
flags.write().unwrap().0 += 1;
CertFailResult::EstablishConnection
}
});
let mut ctx = conn
.connect_client(None, None, {
let flags = Arc::clone(&flags);
move |ctx, conn, evt| match evt {
ConnectionEvent::Connect => {
flags.write().unwrap().1 += 1;
if conn.peer_cert().is_some() {
flags.write().unwrap().1 += 1;
}
conn.disconnect();
}
ConnectionEvent::RawConnect => {
flags.write().unwrap().2 += 1;
}
ConnectionEvent::Disconnect(_) => {
flags.write().unwrap().3 += 1;
ctx.stop();
}
}
})
.unwrap();
ctx.run();
}
let call_counts = Arc::try_unwrap(flags)
.expect("There are hanging references to rc value")
.into_inner()
.unwrap();
assert!((2, 2, 0, 1) == call_counts || (3, 2, 0, 1) == call_counts);
}
}
#[test]
#[cfg(feature = "libstrophe-0_12_0")]
fn sockopt() {
let creds = if let Some(creds) = Creds::acquire() {
creds
} else {
eprintln!("Can't acquire creds, skipping test");
return;
};
let mut conn = creds.make_conn();
conn.set_sockopt_callback(|_sock| SockoptResult::Ok);
conn
.connect_client(None, None, |ctx, conn, evt| match evt {
ConnectionEvent::Connect => conn.disconnect(),
ConnectionEvent::Disconnect(_) => ctx.stop(),
_ => (),
})
.unwrap()
.run();
}
#[test]
#[cfg(feature = "libstrophe-0_14")]
fn sm_state() {
let creds = if let Some(creds) = Creds::acquire() {
creds
} else {
eprintln!("Can't acquire creds, skipping test");
return;
};
let sm_state = Arc::new(Mutex::new(None));
let mut conn = creds.make_conn();
conn.set_sm_callback({
let sm_state = Arc::clone(&sm_state);
move |_conn, state| {
if !state.as_slice().is_empty() {
sm_state.lock().unwrap().replace(state.to_owned());
}
}
});
conn
.connect_client(None, None, |ctx, conn, evt| match evt {
ConnectionEvent::Connect => conn.disconnect(),
ConnectionEvent::Disconnect(_) => ctx.stop(),
_ => (),
})
.unwrap()
.run();
let sm_state = Arc::into_inner(sm_state).unwrap().into_inner().unwrap().unwrap();
assert!(!sm_state.as_slice().is_empty());
}
#[test]
fn fail() {
let t = trybuild::TestCases::new();
t.compile_fail("src/tests/fail/*.rs");
}
#[derive(Debug)]
struct Creds {
jid: String,
name: String,
pass: String,
}
impl Creds {
pub fn acquire() -> Option<Self> {
let mut generator = Generator::default();
let name = generator.next()?;
let jid = format!("{name}@localhost");
let pass = generator.next()?;
let creds_acquire_script = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR")?).join("creds-acquire.sh");
let result = Command::new(creds_acquire_script).arg(&name).arg(&pass).output().unwrap();
if !result.status.success() {
return None;
}
Some(Self { jid, name, pass })
}
pub fn make_conn(&self) -> Connection<'_, 'static> {
let mut conn = Connection::new(Context::new_with_default_logger());
conn.set_jid(&self.jid);
conn.set_pass(&self.pass);
conn
.set_flags(ConnectionFlags::DISABLE_TLS)
.expect("Cannot set connection flags");
conn
}
#[cfg(feature = "libstrophe-0_11_0")]
pub fn make_tls_conn(&self) -> Connection<'_, 'static> {
let mut conn = Connection::new(Context::new_with_default_logger());
conn.set_jid(&self.jid);
conn.set_pass(&self.pass);
conn
.set_flags(ConnectionFlags::MANDATORY_TLS)
.expect("Cannot set connection flags");
conn
}
}
impl Drop for Creds {
fn drop(&mut self) {
if let Some(cargo_manifest_dir) = env::var_os("CARGO_MANIFEST_DIR") {
let creds_release_script = PathBuf::from(cargo_manifest_dir).join("creds-release.sh");
if let Err(e) = Command::new(creds_release_script).arg(&self.name).output() {
eprintln!("Failure releasing credentials: {e}");
}
}
}
}