Add missing tests changes.

main
Laurent Pelecq 2 years ago
parent 883e491a7f
commit ea75e00edc

@ -8,6 +8,9 @@
#[cfg(feature = "async-mio")]
use mio::{Events, Poll, Token};
#[cfg(feature = "async-mio")]
use std::{slice::Iter, time::Duration};
#[cfg(feature = "async-mio")]
use ssip_client::*;
@ -18,86 +21,143 @@ mod server;
use server::Server;
#[cfg(feature = "async-mio")]
mod utils {
enum Answer {
Str(&'static str),
Int(i8),
}
#[cfg(feature = "async-mio")]
struct State<'a, 'b> {
pub done: bool,
pub countdown: usize,
pub writable: bool,
pub start_get: bool,
pub iter_requests: Iter<'a, Request>,
pub iter_answers: Iter<'b, Answer>,
}
use ssip_client::*;
#[cfg(feature = "async-mio")]
impl<'a, 'b> State<'a, 'b> {
fn new(iter_requests: Iter<'a, Request>, iter_answers: Iter<'b, Answer>) -> Self {
State {
done: false,
countdown: 50,
writable: false,
start_get: false,
iter_requests,
iter_answers,
}
}
const MAX_RETRIES: u16 = 10;
fn terminated(&self) -> bool {
self.done || self.countdown == 0
}
pub struct Controler {
step: u16,
retry: u16,
fn must_send(&self) -> bool {
self.writable && self.countdown > 0
}
impl Controler {
pub fn new() -> Controler {
Controler {
step: 0,
retry: MAX_RETRIES,
}
fn next_request(&mut self) -> Option<&Request> {
if self.start_get {
self.iter_requests.next()
} else {
None
}
}
pub fn step(&self) -> u16 {
self.step
fn assert_string(&mut self, val: &str) {
match self.iter_answers.next() {
Some(Answer::Str(expected_val)) => assert_eq!(expected_val, &val),
Some(Answer::Int(expected_val)) => panic!(
"expecting integer {} instead of string '{}'",
expected_val, val
),
None => panic!("no more answers"),
}
}
pub fn check_result<V>(&mut self, result: ClientResult<V>) -> Option<V> {
match result {
Ok(value) => {
self.step += 1;
self.retry = MAX_RETRIES;
Some(value)
}
Err(ClientError::NotReady) if self.retry > 0 => {
self.retry -= 1;
None
}
Err(err) => panic!("{:?}", err),
}
fn assert_integer(&mut self, val: i8) {
match self.iter_answers.next() {
Some(Answer::Int(expected_val)) => assert_eq!(expected_val, &val),
Some(Answer::Str(expected_val)) => panic!(
"expecting string '{}' instead of integer {}",
expected_val, val
),
None => panic!("no more answers"),
}
}
}
#[cfg(feature = "async-mio")]
use utils::Controler;
#[test]
#[cfg(feature = "async-mio")]
fn basic_async_communication() -> std::io::Result<()> {
const COMMUNICATION: [(&str, &str); 1] = [(
"SET self CLIENT_NAME test:test:main\r\n",
"208 OK CLIENT NAME SET\r\n",
)];
fn basic_async_communication() -> ClientResult<()> {
const COMMUNICATION: [(&str, &str); 5] = [
(
"SET self CLIENT_NAME test:test:main\r\n",
"208 OK CLIENT NAME SET\r\n",
),
("SET self LANGUAGE en\r\n", "201 OK LANGUAGE SET\r\n"),
("STOP self\r\n", "210 OK STOPPED\r\n"),
(
"GET OUTPUT_MODULE\r\n",
"251-espeak\r\n251 OK GET RETURNED\r\n",
),
("GET RATE\r\n", "251-10\r\n251 OK GET RETURNED\r\n"),
];
let socket_path = Server::temporary_path();
let get_requests = vec![Request::GetOutputModule, Request::GetRate];
let get_answers = vec![Answer::Str("espeak"), Answer::Int(10)];
let mut state = State::new(get_requests.iter(), get_answers.iter());
let socket_dir = tempfile::tempdir()?;
let socket_path = socket_dir.path().join("basic_async_communication.socket");
assert!(!socket_path.exists());
let server_path = socket_path.clone();
let result = std::panic::catch_unwind(move || -> std::io::Result<u16> {
let handle = Server::run(&server_path, &COMMUNICATION);
let mut poll = Poll::new()?;
let mut events = Events::with_capacity(128);
let mut client = fifo::Builder::new().path(&server_path).build().unwrap();
let input_token = Token(0);
let output_token = Token(1);
client.register(&poll, input_token, output_token).unwrap();
let mut controler = Controler::new();
while controler.step() < 2 {
poll.poll(&mut events, None)?;
for event in &events {
if event.token() == output_token && event.is_writable() && controler.step() == 0 {
controler.check_result(client.set_client_name(ClientName::new("test", "test")));
} else if event.token() == input_token
&& event.is_readable()
&& controler.step() == 1
{
controler.check_result(client.check_client_name_set());
let handle = Server::run(&socket_path, &COMMUNICATION);
let mut poll = Poll::new()?;
let mut events = Events::with_capacity(128);
let mut client = AsyncClient::new(fifo::Builder::new().path(&socket_path).build()?);
let input_token = Token(0);
let output_token = Token(1);
let timeout = Duration::new(0, 500 * 1000 * 1000 /* 500 ms */);
client.register(&poll, input_token, output_token).unwrap();
client.push(Request::SetName(ClientName::new("test", "test")));
while !state.terminated() {
if !state.writable || !client.has_next() {
poll.poll(&mut events, Some(timeout))?;
}
state.countdown -= 1;
for event in &events {
let token = event.token();
if token == input_token {
match dbg!(client.receive_next()?) {
Response::ClientNameSet => {
client.push(Request::SetLanguage(ClientScope::Current, "en".to_string()))
}
Response::LanguageSet => client.push(Request::Stop(MessageScope::Last)),
Response::Stopped => state.start_get = true,
Response::GetString(val) => state.assert_string(&val),
Response::GetInteger(val) => state.assert_integer(val),
result => panic!("Unexpected response: {:?}", result),
}
if let Some(request) = state.next_request() {
client.push(request.clone());
} else if state.start_get {
state.done = true; // No more get request
}
} else if token == output_token {
state.writable = true;
}
}
handle.join().unwrap().unwrap();
Ok(controler.step())
});
std::fs::remove_file(socket_path)?;
assert_eq!(2, result.unwrap().unwrap());
if state.must_send() {
match client.send_next() {
Ok(()) => (),
Err(ClientError::NotReady) => state.writable = false,
err => return err,
}
}
}
handle.join().unwrap().unwrap();
assert!(state.countdown > 0);
socket_dir.close()?;
Ok(())
}

@ -24,30 +24,25 @@ use server::Server;
fn test_client<F>(
communication: &'static [(&'static str, &'static str)],
process: F,
) -> io::Result<()>
) -> ClientResult<()>
where
F: FnMut(&mut Client<UnixStream>) -> io::Result<()>,
{
let socket_path = Server::temporary_path();
let socket_dir = tempfile::tempdir()?;
let socket_path = socket_dir.path().join("test_client.socket");
assert!(!socket_path.exists());
let server_path = socket_path.clone();
let mut process_wrapper = std::panic::AssertUnwindSafe(process);
let result = std::panic::catch_unwind(move || {
let handle = Server::run(&server_path, communication);
let mut client = ssip_client::fifo::Builder::new()
.path(&server_path)
.build()
.unwrap();
client
.set_client_name(ClientName::new("test", "test"))
.unwrap()
.check_client_name_set()
.unwrap();
process_wrapper(&mut client).unwrap();
handle.join().unwrap()
});
std::fs::remove_file(socket_path)?;
result.unwrap().unwrap();
let handle = Server::run(&server_path, communication);
let mut client = ssip_client::fifo::Builder::new()
.path(&server_path)
.build()?;
client
.set_client_name(ClientName::new("test", "test"))?
.check_client_name_set()?;
process_wrapper(&mut client)?;
handle.join().unwrap().unwrap();
socket_dir.close()?;
Ok(())
}
@ -59,7 +54,7 @@ const SET_CLIENT_COMMUNICATION: (&str, &str) = (
#[test]
#[cfg(not(feature = "async-mio"))]
fn connect_and_quit() -> io::Result<()> {
fn connect_and_quit() -> ClientResult<()> {
test_client(
&[
SET_CLIENT_COMMUNICATION,
@ -74,7 +69,7 @@ fn connect_and_quit() -> io::Result<()> {
#[test]
#[cfg(not(feature = "async-mio"))]
fn say_one_line() -> io::Result<()> {
fn say_one_line() -> ClientResult<()> {
test_client(
&[
SET_CLIENT_COMMUNICATION,
@ -106,7 +101,7 @@ macro_rules! test_setter {
($setter:ident, $question:expr, $answer:expr, $code:expr, $($arg:tt)*) => {
#[test]
#[cfg(not(feature = "async-mio"))]
fn $setter() -> io::Result<()> {
fn $setter() -> ClientResult<()> {
test_client(
&[SET_CLIENT_COMMUNICATION, ($question, $answer)],
|client| {
@ -122,7 +117,7 @@ macro_rules! test_getter {
($getter:ident, $receive:ident, $arg:tt, $question:expr, $answer:expr, $value:expr) => {
#[test]
#[cfg(not(feature = "async-mio"))]
fn $getter() -> io::Result<()> {
fn $getter() -> ClientResult<()> {
test_client(
&[SET_CLIENT_COMMUNICATION, ($question, $answer)],
|client| {
@ -142,7 +137,7 @@ macro_rules! test_list {
($getter:ident, $question:expr, $answer:expr, $code:expr, $values:expr) => {
#[test]
#[cfg(not(feature = "async-mio"))]
fn $getter() -> io::Result<()> {
fn $getter() -> ClientResult<()> {
test_client(
&[SET_CLIENT_COMMUNICATION, ($question, $answer)],
|client| {
@ -165,7 +160,7 @@ test_setter!(
#[test]
#[cfg(not(feature = "async-mio"))]
fn set_debug() -> io::Result<()> {
fn set_debug() -> ClientResult<()> {
test_client(
&[
SET_CLIENT_COMMUNICATION,
@ -341,7 +336,7 @@ test_list!(
#[test]
#[cfg(not(feature = "async-mio"))]
fn list_synthesis_voices() -> io::Result<()> {
fn list_synthesis_voices() -> ClientResult<()> {
test_client(
&[
SET_CLIENT_COMMUNICATION,
@ -367,7 +362,7 @@ fn list_synthesis_voices() -> io::Result<()> {
#[test]
#[cfg(not(feature = "async-mio"))]
fn receive_notification() -> io::Result<()> {
fn receive_notification() -> ClientResult<()> {
test_client(
&[
SET_CLIENT_COMMUNICATION,

@ -7,7 +7,7 @@
// modified, or distributed except according to those terms.
use std::io::{self, BufRead, BufReader, BufWriter, Write};
use std::path::{Path, PathBuf};
use std::path::Path;
use std::thread;
use std::os::unix::net::UnixListener;
@ -24,13 +24,13 @@ impl Server {
/// Argument `communication` is an array of pairs. The first item is a list of strings
/// the server will receive and the second item is the answer.
pub fn new<P>(
socket_path: &P,
socket_path: P,
communication: &[(&'static str, &'static str)],
) -> io::Result<Self>
where
P: AsRef<Path>,
{
let listener = UnixListener::bind(socket_path)?;
let listener = UnixListener::bind(socket_path.as_ref())?;
Ok(Server {
listener,
communication: communication.to_vec(),
@ -56,7 +56,7 @@ impl Server {
if line != *question {
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("read <{}> instead of <{}>", dbg!(line), *question),
format!("read <{}> instead of <{}>", line, *question),
));
}
}
@ -66,11 +66,6 @@ impl Server {
Ok(())
}
pub fn temporary_path() -> PathBuf {
let tid = unsafe { libc::pthread_self() } as u64;
std::env::temp_dir().join(format!("ssip-client-test-{}-{}", std::process::id(), tid))
}
pub fn run<P>(
socket_path: P,
communication: &'static [(&'static str, &'static str)],

Loading…
Cancel
Save