use std::fmt::Debug;
use derive_more::derive::Display;
use thiserror::Error;
use super::RawRequest;
pub mod bound_socket;
pub mod launcher;
pub mod processor;
pub mod receiver;
pub mod request_buffer;
pub mod spawner;
pub mod states;
#[derive(Debug, Error)]
pub enum UdpError {
#[error("Any error to do with the socket")]
FailedToBindSocket(std::io::Error),
#[error("Any error to do with starting or stopping the sever")]
FailedToStartOrStopServer(String),
}
#[allow(clippy::module_name_repetitions)]
#[derive(Debug, Display)]
pub struct Server<S>
where
S: std::fmt::Debug + std::fmt::Display,
{
pub state: S,
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use std::time::Duration;
use torrust_tracker_test_helpers::configuration::ephemeral_public;
use super::spawner::Spawner;
use super::Server;
use crate::bootstrap::app::initialize_with_configuration;
use crate::servers::registar::Registar;
#[tokio::test]
async fn it_should_be_able_to_start_and_stop() {
let cfg = Arc::new(ephemeral_public());
let tracker = initialize_with_configuration(&cfg);
let udp_trackers = cfg.udp_trackers.clone().expect("missing UDP trackers configuration");
let config = &udp_trackers[0];
let bind_to = config.bind_address;
let register = &Registar::default();
let stopped = Server::new(Spawner::new(bind_to));
let started = stopped
.start(tracker, register.give_form())
.await
.expect("it should start the server");
let stopped = started.stop().await.expect("it should stop the server");
tokio::time::sleep(Duration::from_secs(1)).await;
assert_eq!(stopped.state.spawner.bind_to, bind_to);
}
#[tokio::test]
async fn it_should_be_able_to_start_and_stop_with_wait() {
let cfg = Arc::new(ephemeral_public());
let tracker = initialize_with_configuration(&cfg);
let config = &cfg.udp_trackers.as_ref().unwrap().first().unwrap();
let bind_to = config.bind_address;
let register = &Registar::default();
let stopped = Server::new(Spawner::new(bind_to));
let started = stopped
.start(tracker, register.give_form())
.await
.expect("it should start the server");
tokio::time::sleep(Duration::from_secs(1)).await;
let stopped = started.stop().await.expect("it should stop the server");
tokio::time::sleep(Duration::from_secs(1)).await;
assert_eq!(stopped.state.spawner.bind_to, bind_to);
}
}
#[cfg(test)]
mod test_tokio {
use std::sync::Arc;
use std::time::Duration;
use tokio::sync::Barrier;
use tokio::task::JoinSet;
#[tokio::test]
async fn test_barrier_with_aborted_tasks() {
let barrier = Arc::new(Barrier::new(10));
let mut tasks = JoinSet::default();
let mut handles = Vec::default();
for _ in 0..9 {
let c = barrier.clone();
handles.push(tasks.spawn(async move {
c.wait().await;
}));
}
for _ in 0..2 {
if let Some(handle) = handles.pop() {
handle.abort();
}
}
let c = barrier.clone();
handles.push(tasks.spawn(async move {
c.wait().await;
}));
tokio::time::sleep(Duration::from_millis(50)).await;
for h in &handles {
assert!(!h.is_finished());
}
for _ in 0..2 {
let c = barrier.clone();
handles.push(tasks.spawn(async move {
c.wait().await;
}));
}
tokio::time::sleep(Duration::from_millis(50)).await;
for h in &handles {
assert!(h.is_finished());
}
tasks.shutdown().await;
}
}