use std::{
pin::Pin,
sync::{
Arc, Mutex,
atomic::{AtomicU32, Ordering},
},
task::{Context, Poll},
time::Duration,
};
use futures::StreamExt;
use rusmpp::{Command, CommandId, CommandStatus, Pdu, pdus::SubmitSm};
use crate::{
ConnectionBuilder,
error::Error,
mock::{delay::MockDelay, framed::MockFramed},
tests::init_tracing,
};
pin_project_lite::pin_project! {
struct PollTraceFuture<F> {
#[pin]
future: F,
}
}
impl<F> PollTraceFuture<F> {
fn new(future: F) -> Self {
Self { future }
}
}
impl<F: Future> Future for PollTraceFuture<F> {
type Output = F::Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
tracing::info!("Polling future");
match self.project().future.poll(cx) {
Poll::Ready(output) => {
tracing::info!("Future ready");
Poll::Ready(output)
}
Poll::Pending => {
tracing::info!("Future pending");
Poll::Pending
}
}
}
}
#[tokio::test]
async fn server_ddos_client_should_still_send_requests_and_connection_should_still_manage_timeouts()
{
init_tracing();
let mut framed = MockFramed::new().sink_always_ready_ok();
framed.expect_poll_next_pin().returning(|_ctx| {
Poll::Ready(Some(Ok(Command::builder()
.status(CommandStatus::EsmeRok)
.sequence_number(0)
.pdu(Pdu::AlertNotification(Default::default())))))
});
let enquire_link_timer_delay = MockDelay::new().delay_after_seconds();
let enquire_link_response_timer_delay = MockDelay::new().delay_after_seconds();
let (client, events, future) = ConnectionBuilder::new()
.enquire_link_interval(Duration::from_secs(50))
.enquire_link_response_timeout(Duration::from_secs(5))
.no_spawn()
.raw(
framed,
enquire_link_timer_delay,
enquire_link_response_timer_delay,
);
tokio::spawn(future);
for _ in 0..1000 {
match client
.no_wait() .submit_sm(SubmitSm::default())
.await
{
Ok(_) => {}
Err(Error::ConnectionClosed) => {}
Err(err) => {
panic!("Failed to submit SM: {:?}", err);
}
}
}
let _ = events.count().await;
}
#[tokio::test]
async fn client_ddos_and_server_ddos_connection_should_still_respond_to_enquire_link_spawned() {
init_tracing();
let sequence_number = Arc::new(AtomicU32::new(0));
let sent_enquire_link_sequence_numbers = Arc::new(Mutex::new(Vec::new()));
let received_enquire_link_response_sequence_number = Arc::new(Mutex::new(Vec::new()));
let mock_sent_enquire_link_sequence_numbers = sent_enquire_link_sequence_numbers.clone();
let mock_received_enquire_link_response_sequence_number =
received_enquire_link_response_sequence_number.clone();
let mut framed = MockFramed::new()
.poll_ready_always_ready_ok()
.poll_flush_always_ready_ok()
.poll_close_always_ready_ok();
framed.expect_poll_next_pin().returning(move |_ctx| {
let seq_number = sequence_number.fetch_add(1, Ordering::SeqCst);
let command = Command::builder()
.status(CommandStatus::EsmeRok)
.sequence_number(seq_number)
.pdu(Pdu::EnquireLink);
mock_sent_enquire_link_sequence_numbers
.lock()
.unwrap()
.push(seq_number);
Poll::Ready(Some(Ok(command)))
});
framed.expect_start_send_pin().returning(move |command| {
if let CommandId::EnquireLinkResp = command.id() {
mock_received_enquire_link_response_sequence_number
.lock()
.unwrap()
.push(command.sequence_number());
}
Ok(())
});
let enquire_link_timer_delay = MockDelay::new().delay_after_seconds();
let enquire_link_response_timer_delay = MockDelay::new().delay_after_seconds();
let (client, events, future) = ConnectionBuilder::new()
.no_enquire_link_interval()
.no_spawn()
.raw(
framed,
enquire_link_timer_delay,
enquire_link_response_timer_delay,
);
tokio::spawn(PollTraceFuture::new(future));
let mut handles = Vec::new();
for _ in 0..1000 {
let client_clone = client.clone();
let handle = tokio::spawn(async move {
client_clone
.no_wait() .submit_sm(SubmitSm::default())
.await
.expect("Failed to submit SM");
});
handles.push(handle);
}
for handle in handles {
handle.await.expect("Task panicked");
}
client.close().await.expect("Failed to close connection");
let _ = events.count().await;
assert_eq!(
*sent_enquire_link_sequence_numbers.lock().unwrap(),
*received_enquire_link_response_sequence_number
.lock()
.unwrap()
);
}
#[tokio::test]
async fn client_ddos_and_server_ddos_connection_should_still_respond_to_enquire_link_not_spawned() {
init_tracing();
let sequence_number = Arc::new(AtomicU32::new(0));
let sent_enquire_link_sequence_numbers = Arc::new(Mutex::new(Vec::new()));
let received_enquire_link_response_sequence_number = Arc::new(Mutex::new(Vec::new()));
let mock_sent_enquire_link_sequence_numbers = sent_enquire_link_sequence_numbers.clone();
let mock_received_enquire_link_response_sequence_number =
received_enquire_link_response_sequence_number.clone();
let mut framed = MockFramed::new()
.poll_ready_always_ready_ok()
.poll_flush_always_ready_ok()
.poll_close_always_ready_ok();
framed.expect_poll_next_pin().returning(move |_ctx| {
let seq_number = sequence_number.fetch_add(1, Ordering::SeqCst);
let command = Command::builder()
.status(CommandStatus::EsmeRok)
.sequence_number(seq_number)
.pdu(Pdu::EnquireLink);
mock_sent_enquire_link_sequence_numbers
.lock()
.unwrap()
.push(seq_number);
Poll::Ready(Some(Ok(command)))
});
framed.expect_start_send_pin().returning(move |command| {
if let CommandId::EnquireLinkResp = command.id() {
mock_received_enquire_link_response_sequence_number
.lock()
.unwrap()
.push(command.sequence_number());
}
Ok(())
});
let enquire_link_timer_delay = MockDelay::new().delay_after_seconds();
let enquire_link_response_timer_delay = MockDelay::new().delay_after_seconds();
let (client, events, future) = ConnectionBuilder::new()
.no_enquire_link_interval()
.no_spawn()
.raw(
framed,
enquire_link_timer_delay,
enquire_link_response_timer_delay,
);
tokio::spawn(PollTraceFuture::new(future));
for _ in 0..1000 {
client
.no_wait() .submit_sm(SubmitSm::default())
.await
.expect("Failed to submit SM");
}
client.close().await.expect("Failed to close connection");
let _ = events.count().await;
assert_eq!(
*sent_enquire_link_sequence_numbers.lock().unwrap(),
*received_enquire_link_response_sequence_number
.lock()
.unwrap()
);
}
#[tokio::test]
async fn sink_first_poll_ready_pending_pending_request_should_be_sent() {
init_tracing();
let mut framed = MockFramed::new()
.poll_next_always_pending()
.poll_flush_always_ready_ok()
.poll_close_always_ready_ok();
framed.expect_poll_ready_pin().times(1).returning(|cx| {
cx.waker().wake_by_ref();
Poll::Pending
});
framed
.expect_poll_ready_pin()
.times(1)
.returning(|_cx| Poll::Ready(Ok(())));
framed
.expect_start_send_pin()
.times(1)
.returning(|command| {
assert!(matches!(command.pdu(), Some(Pdu::SubmitSm(_))));
assert_eq!(command.sequence_number(), 1);
Ok(())
});
let enquire_link_timer_delay = MockDelay::new().delay_after_seconds();
let enquire_link_response_timer_delay = MockDelay::new().delay_after_seconds();
let (client, events, future) = ConnectionBuilder::new()
.no_enquire_link_interval()
.no_spawn()
.raw(
framed,
enquire_link_timer_delay,
enquire_link_response_timer_delay,
);
tokio::spawn(PollTraceFuture::new(future));
client
.no_wait()
.submit_sm(SubmitSm::default())
.await
.expect("Failed to submit SM");
client.close().await.expect("Failed to close connection");
let _ = events.count().await;
}
#[tokio::test]
async fn sink_first_poll_flush_pending_pending_request_should_be_sent() {
init_tracing();
let submit_count = 10;
let mut framed = MockFramed::new()
.poll_next_always_pending()
.poll_ready_always_ready_ok()
.poll_close_always_ready_ok();
framed.expect_poll_flush_pin().times(1).returning(|cx| {
cx.waker().wake_by_ref();
Poll::Pending
});
framed
.expect_poll_flush_pin()
.returning(|_cx| Poll::Ready(Ok(())));
for n in 0..submit_count {
let i = 1 + n * 2;
framed
.expect_start_send_pin()
.times(1)
.returning(move |command| {
assert!(matches!(command.pdu(), Some(Pdu::SubmitSm(_))));
assert_eq!(command.sequence_number(), i);
Ok(())
});
}
let enquire_link_timer_delay = MockDelay::new().delay_after_seconds();
let enquire_link_response_timer_delay = MockDelay::new().delay_after_seconds();
let (client, events, future) = ConnectionBuilder::new()
.no_enquire_link_interval()
.no_spawn()
.raw(
framed,
enquire_link_timer_delay,
enquire_link_response_timer_delay,
);
tokio::spawn(PollTraceFuture::new(future));
for _ in 0..submit_count {
client
.no_wait()
.submit_sm(SubmitSm::default())
.await
.expect("Failed to submit SM");
}
client.close().await.expect("Failed to close connection");
let _ = events.count().await;
}