add unittest for whole TCP server
Some checks failed
Rust/sat-rs/pipeline/pr-main There was a failure building this commit
Some checks failed
Rust/sat-rs/pipeline/pr-main There was a failure building this commit
This commit is contained in:
parent
eb5c755dd3
commit
0e6d903942
@ -4,7 +4,6 @@ use std::net::SocketAddr;
|
|||||||
use std::net::{TcpListener, ToSocketAddrs};
|
use std::net::{TcpListener, ToSocketAddrs};
|
||||||
|
|
||||||
use crate::tmtc::{ReceivesTc, TmPacketSource};
|
use crate::tmtc::{ReceivesTc, TmPacketSource};
|
||||||
use core::fmt::Display;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
// Re-export the TMTC in COBS server.
|
// Re-export the TMTC in COBS server.
|
||||||
@ -13,7 +12,7 @@ pub use crate::hal::host::tcp_with_cobs_server::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum TcpTmtcError<TmError: Display, TcError: Display> {
|
pub enum TcpTmtcError<TmError, TcError> {
|
||||||
#[error("TM retrieval error: {0}")]
|
#[error("TM retrieval error: {0}")]
|
||||||
TmError(TmError),
|
TmError(TmError),
|
||||||
#[error("TC retrieval error: {0}")]
|
#[error("TC retrieval error: {0}")]
|
||||||
@ -33,9 +32,9 @@ pub struct ConnectionResult {
|
|||||||
|
|
||||||
pub(crate) struct TcpTmtcServerBase<TcError, TmError> {
|
pub(crate) struct TcpTmtcServerBase<TcError, TmError> {
|
||||||
pub(crate) listener: TcpListener,
|
pub(crate) listener: TcpListener,
|
||||||
pub(crate) tm_source: Box<dyn TmPacketSource<Error = TmError>>,
|
pub(crate) tm_source: Box<dyn TmPacketSource<Error = TmError> + Send>,
|
||||||
pub(crate) tm_buffer: Vec<u8>,
|
pub(crate) tm_buffer: Vec<u8>,
|
||||||
pub(crate) tc_receiver: Box<dyn ReceivesTc<Error = TcError>>,
|
pub(crate) tc_receiver: Box<dyn ReceivesTc<Error = TcError> + Send>,
|
||||||
pub(crate) tc_buffer: Vec<u8>,
|
pub(crate) tc_buffer: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,9 +42,9 @@ impl<TcError, TmError> TcpTmtcServerBase<TcError, TmError> {
|
|||||||
pub(crate) fn new<A: ToSocketAddrs>(
|
pub(crate) fn new<A: ToSocketAddrs>(
|
||||||
addr: A,
|
addr: A,
|
||||||
tm_buffer_size: usize,
|
tm_buffer_size: usize,
|
||||||
tm_source: Box<dyn TmPacketSource<Error = TmError>>,
|
tm_source: Box<dyn TmPacketSource<Error = TmError> + Send>,
|
||||||
tc_buffer_size: usize,
|
tc_buffer_size: usize,
|
||||||
tc_receiver: Box<dyn ReceivesTc<Error = TcError>>,
|
tc_receiver: Box<dyn ReceivesTc<Error = TcError> + Send>,
|
||||||
) -> Result<Self, std::io::Error> {
|
) -> Result<Self, std::io::Error> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
listener: TcpListener::bind(addr)?,
|
listener: TcpListener::bind(addr)?,
|
||||||
|
@ -3,7 +3,6 @@ use alloc::vec;
|
|||||||
use cobs::decode_in_place;
|
use cobs::decode_in_place;
|
||||||
use cobs::encode;
|
use cobs::encode;
|
||||||
use cobs::max_encoding_length;
|
use cobs::max_encoding_length;
|
||||||
use core::fmt::Display;
|
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::net::ToSocketAddrs;
|
use std::net::ToSocketAddrs;
|
||||||
@ -25,19 +24,18 @@ use super::tcp_server::TcpTmtcError;
|
|||||||
///
|
///
|
||||||
/// The server wil use the [parse_buffer_for_cobs_encoded_packets] function to parse for packets
|
/// The server wil use the [parse_buffer_for_cobs_encoded_packets] function to parse for packets
|
||||||
/// and pass them to a generic TC receiver.
|
/// and pass them to a generic TC receiver.
|
||||||
///
|
|
||||||
pub struct TcpTmtcInCobsServer<TcError, TmError> {
|
pub struct TcpTmtcInCobsServer<TcError, TmError> {
|
||||||
base: TcpTmtcServerBase<TcError, TmError>,
|
base: TcpTmtcServerBase<TcError, TmError>,
|
||||||
tm_encoding_buffer: Vec<u8>,
|
tm_encoding_buffer: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<TcError: 'static + Display, TmError: 'static + Display> TcpTmtcInCobsServer<TcError, TmError> {
|
impl<TcError: 'static, TmError: 'static> TcpTmtcInCobsServer<TcError, TmError> {
|
||||||
pub fn new<A: ToSocketAddrs>(
|
pub fn new<A: ToSocketAddrs>(
|
||||||
addr: A,
|
addr: A,
|
||||||
tm_buffer_size: usize,
|
tm_buffer_size: usize,
|
||||||
tm_source: Box<dyn TmPacketSource<Error = TmError>>,
|
tm_source: Box<dyn TmPacketSource<Error = TmError> + Send>,
|
||||||
tc_buffer_size: usize,
|
tc_buffer_size: usize,
|
||||||
tc_receiver: Box<dyn ReceivesTc<Error = TcError>>,
|
tc_receiver: Box<dyn ReceivesTc<Error = TcError> + Send>,
|
||||||
) -> Result<Self, std::io::Error> {
|
) -> Result<Self, std::io::Error> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
base: TcpTmtcServerBase::new(
|
base: TcpTmtcServerBase::new(
|
||||||
@ -170,20 +168,31 @@ pub fn parse_buffer_for_cobs_encoded_packets<E>(
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::tmtc::ReceivesTcCore;
|
use core::{
|
||||||
use alloc::vec::Vec;
|
sync::atomic::{AtomicBool, Ordering},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
io::Write,
|
||||||
|
net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream},
|
||||||
|
sync::Mutex,
|
||||||
|
thread,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::tmtc::{ReceivesTcCore, TmPacketSource};
|
||||||
|
use alloc::{boxed::Box, collections::VecDeque, sync::Arc, vec::Vec};
|
||||||
use cobs::encode;
|
use cobs::encode;
|
||||||
|
|
||||||
use super::parse_buffer_for_cobs_encoded_packets;
|
use super::{parse_buffer_for_cobs_encoded_packets, TcpTmtcInCobsServer};
|
||||||
|
|
||||||
const SIMPLE_PACKET: [u8; 5] = [1, 2, 3, 4, 5];
|
const SIMPLE_PACKET: [u8; 5] = [1, 2, 3, 4, 5];
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct TestSender {
|
struct TestTcSender {
|
||||||
received_tcs: Vec<Vec<u8>>,
|
received_tcs: Vec<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReceivesTcCore for TestSender {
|
impl ReceivesTcCore for TestTcSender {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
fn pass_tc(&mut self, tc_raw: &[u8]) -> Result<(), Self::Error> {
|
fn pass_tc(&mut self, tc_raw: &[u8]) -> Result<(), Self::Error> {
|
||||||
@ -192,6 +201,32 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
struct TmSource {
|
||||||
|
shared_tm_source: Arc<Mutex<VecDeque<Vec<u8>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TmSource {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
shared_tm_source: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_tm(&mut self, tm: &[u8]) {
|
||||||
|
let mut shared_tm_source = self.shared_tm_source.lock().unwrap();
|
||||||
|
shared_tm_source.push_back(tm.to_vec());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TmPacketSource for TmSource {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn retrieve_packet(&mut self, buffer: &mut [u8]) -> Result<usize, Self::Error> {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn encode_simple_packet(encoded_buf: &mut [u8], current_idx: &mut usize) {
|
fn encode_simple_packet(encoded_buf: &mut [u8], current_idx: &mut usize) {
|
||||||
encoded_buf[*current_idx] = 0;
|
encoded_buf[*current_idx] = 0;
|
||||||
*current_idx += 1;
|
*current_idx += 1;
|
||||||
@ -202,7 +237,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parsing_simple_packet() {
|
fn test_parsing_simple_packet() {
|
||||||
let mut test_sender = TestSender::default();
|
let mut test_sender = TestTcSender::default();
|
||||||
let mut encoded_buf: [u8; 16] = [0; 16];
|
let mut encoded_buf: [u8; 16] = [0; 16];
|
||||||
let mut current_idx = 0;
|
let mut current_idx = 0;
|
||||||
encode_simple_packet(&mut encoded_buf, &mut current_idx);
|
encode_simple_packet(&mut encoded_buf, &mut current_idx);
|
||||||
@ -221,7 +256,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parsing_consecutive_packets() {
|
fn test_parsing_consecutive_packets() {
|
||||||
let mut test_sender = TestSender::default();
|
let mut test_sender = TestTcSender::default();
|
||||||
let mut encoded_buf: [u8; 16] = [0; 16];
|
let mut encoded_buf: [u8; 16] = [0; 16];
|
||||||
let mut current_idx = 0;
|
let mut current_idx = 0;
|
||||||
encode_simple_packet(&mut encoded_buf, &mut current_idx);
|
encode_simple_packet(&mut encoded_buf, &mut current_idx);
|
||||||
@ -250,7 +285,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_split_tail_packet_only() {
|
fn test_split_tail_packet_only() {
|
||||||
let mut test_sender = TestSender::default();
|
let mut test_sender = TestTcSender::default();
|
||||||
let mut encoded_buf: [u8; 16] = [0; 16];
|
let mut encoded_buf: [u8; 16] = [0; 16];
|
||||||
let mut current_idx = 0;
|
let mut current_idx = 0;
|
||||||
encode_simple_packet(&mut encoded_buf, &mut current_idx);
|
encode_simple_packet(&mut encoded_buf, &mut current_idx);
|
||||||
@ -268,7 +303,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn generic_test_split_packet(cut_off: usize) {
|
fn generic_test_split_packet(cut_off: usize) {
|
||||||
let mut test_sender = TestSender::default();
|
let mut test_sender = TestTcSender::default();
|
||||||
let mut encoded_buf: [u8; 16] = [0; 16];
|
let mut encoded_buf: [u8; 16] = [0; 16];
|
||||||
let inverted_packet: [u8; 5] = [5, 4, 3, 2, 1];
|
let inverted_packet: [u8; 5] = [5, 4, 3, 2, 1];
|
||||||
assert!(cut_off < inverted_packet.len() + 1);
|
assert!(cut_off < inverted_packet.len() + 1);
|
||||||
@ -319,7 +354,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_zero_at_end() {
|
fn test_zero_at_end() {
|
||||||
let mut test_sender = TestSender::default();
|
let mut test_sender = TestTcSender::default();
|
||||||
let mut encoded_buf: [u8; 16] = [0; 16];
|
let mut encoded_buf: [u8; 16] = [0; 16];
|
||||||
let mut next_write_idx = 0;
|
let mut next_write_idx = 0;
|
||||||
let mut current_idx = 0;
|
let mut current_idx = 0;
|
||||||
@ -344,7 +379,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_all_zeroes() {
|
fn test_all_zeroes() {
|
||||||
let mut test_sender = TestSender::default();
|
let mut test_sender = TestTcSender::default();
|
||||||
let mut all_zeroes: [u8; 5] = [0; 5];
|
let mut all_zeroes: [u8; 5] = [0; 5];
|
||||||
let mut next_write_idx = 0;
|
let mut next_write_idx = 0;
|
||||||
let packets = parse_buffer_for_cobs_encoded_packets(
|
let packets = parse_buffer_for_cobs_encoded_packets(
|
||||||
@ -358,4 +393,46 @@ mod tests {
|
|||||||
assert!(test_sender.received_tcs.is_empty());
|
assert!(test_sender.received_tcs.is_empty());
|
||||||
assert_eq!(next_write_idx, 0);
|
assert_eq!(next_write_idx, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_server_basic() {
|
||||||
|
let dest_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 7777);
|
||||||
|
let tc_receiver = TestTcSender::default();
|
||||||
|
let tm_source = TmSource::default();
|
||||||
|
let mut tcp_server = TcpTmtcInCobsServer::new(
|
||||||
|
dest_addr,
|
||||||
|
1024,
|
||||||
|
Box::new(tm_source),
|
||||||
|
1024,
|
||||||
|
Box::new(tc_receiver),
|
||||||
|
)
|
||||||
|
.expect("TCP server generation failed");
|
||||||
|
let conn_handled: Arc<AtomicBool> = Default::default();
|
||||||
|
let set_if_done = conn_handled.clone();
|
||||||
|
// Call the connection handler in separate thread, does block.
|
||||||
|
thread::spawn(move || {
|
||||||
|
let result = tcp_server.handle_next_connection();
|
||||||
|
if result.is_err() {
|
||||||
|
panic!("handling connection failed: {:?}", result.unwrap_err());
|
||||||
|
}
|
||||||
|
set_if_done.store(true, Ordering::Relaxed);
|
||||||
|
});
|
||||||
|
// Send TC to server now.
|
||||||
|
let mut encoded_buf: [u8; 16] = [0; 16];
|
||||||
|
let mut current_idx = 0;
|
||||||
|
encode_simple_packet(&mut encoded_buf, &mut current_idx);
|
||||||
|
let mut stream = TcpStream::connect(dest_addr).expect("connecting to TCP server failed");
|
||||||
|
stream
|
||||||
|
.write_all(&encoded_buf)
|
||||||
|
.expect("writing to TCP server failed");
|
||||||
|
// A certain amount of time is allowed for the transaction to complete.
|
||||||
|
for _ in 0..3 {
|
||||||
|
if !conn_handled.load(Ordering::Relaxed) {
|
||||||
|
thread::sleep(Duration::from_millis(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !conn_handled.load(Ordering::Relaxed) {
|
||||||
|
panic!("connection was not handled properly");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user