diff --git a/satrs/src/pus/action.rs b/satrs/src/pus/action.rs index 6eb1302..e5c7e2e 100644 --- a/satrs/src/pus/action.rs +++ b/satrs/src/pus/action.rs @@ -170,11 +170,8 @@ pub mod std_mod { #[cfg(test)] mod tests { - use core::cell::RefCell; use delegate::delegate; - use alloc::{collections::VecDeque, vec::Vec}; - use satrs_shared::res_code::ResultU16; use spacepackets::{ ecss::{ tc::{PusTcCreator, PusTcReader, PusTcSecondaryHeader}, @@ -186,24 +183,18 @@ mod tests { use crate::pus::{ tests::{ - PusServiceHandlerWithVecCommon, PusTestHarness, SimplePusPacketHandler, TEST_APID, + PusServiceHandlerWithVecCommon, PusTestHarness, SimplePusPacketHandler, TestConverter, + TestRouter, TestRoutingErrorHandler, APP_DATA_TOO_SHORT, TEST_APID, }, verification::{ tests::TestVerificationReporter, FailParams, RequestId, VerificationReportingProvider, }, EcssTcInVecConverter, GenericRoutingError, PusPacketHandlerResult, PusPacketHandlingError, - PusRoutingErrorHandler, }; use super::*; - #[derive(Default)] - pub struct TestRouter { - pub routing_requests: RefCell>, - pub injected_routing_failure: RefCell>, - } - - impl PusActionRequestRouter for TestRouter { + impl PusActionRequestRouter for TestRouter { type Error = GenericRoutingError; fn route( @@ -222,43 +213,7 @@ mod tests { } } - impl TestRouter { - pub fn inject_routing_error(&mut self, error: GenericRoutingError) { - *self.injected_routing_failure.borrow_mut() = Some(error); - } - } - - #[derive(Default)] - struct TestRoutingErrorHandler { - pub routing_errors: RefCell>, - } - - impl PusRoutingErrorHandler for TestRoutingErrorHandler { - type Error = GenericRoutingError; - - fn handle_error( - &self, - target_id: TargetId, - _token: VerificationToken, - _tc: &PusTcReader, - error: Self::Error, - _time_stamp: &[u8], - _verif_reporter: &impl VerificationReportingProvider, - ) { - self.routing_errors - .borrow_mut() - .push_back((target_id, error)); - } - } - - #[derive(Default)] - pub struct TestConverter { - pub conversion_request: VecDeque>, - } - - const APP_DATA_TOO_SHORT: ResultU16 = ResultU16::new(1, 1); - - impl PusActionToRequestConverter for TestConverter { + impl PusActionToRequestConverter for TestConverter<8> { type Error = PusPacketHandlingError; fn convert( &mut self, @@ -268,6 +223,7 @@ mod tests { verif_reporter: &impl VerificationReportingProvider, ) -> Result<(TargetId, ActionRequest), Self::Error> { self.conversion_request.push_back(tc.raw_data().to_vec()); + self.check_service(tc)?; let target_id = tc.apid(); if tc.user_data().len() < 4 { verif_reporter @@ -308,8 +264,8 @@ mod tests { handler: PusService8ActionHandler< EcssTcInVecConverter, TestVerificationReporter, - TestConverter, - TestRouter, + TestConverter<8>, + TestRouter, TestRoutingErrorHandler, >, } @@ -328,6 +284,17 @@ mod tests { ), } } + + delegate! { + to self.handler.request_converter { + pub fn check_next_conversion(&mut self, tc: &PusTcCreator); + } + } + delegate! { + to self.handler.request_router { + pub fn retrieve_next_request(&mut self) -> (TargetId, ActionRequest); + } + } } impl PusTestHarness for Pus8HandlerWithVecTester { @@ -363,34 +330,8 @@ mod tests { action_handler.send_tc(&tc); let result = action_handler.handle_one_tc(); assert!(result.is_ok()); - assert_eq!( - action_handler - .handler - .request_converter - .conversion_request - .len(), - 1 - ); - assert_eq!( - action_handler.handler.request_converter.conversion_request[0], - tc.to_vec().unwrap() - ); - assert_eq!( - action_handler - .handler - .request_router - .routing_requests - .borrow() - .len(), - 1 - ); - let (target_id, action_req) = action_handler - .handler - .request_router - .routing_requests - .borrow_mut() - .pop_front() - .unwrap(); + action_handler.check_next_conversion(&tc); + let (target_id, action_req) = action_handler.retrieve_next_request(); assert_eq!(target_id, TEST_APID.into()); if let ActionRequest::UnsignedIdAndVecData { action_id, data } = action_req { assert_eq!(action_id, 1); @@ -427,26 +368,8 @@ mod tests { panic!("unexpected error type"); } - assert_eq!( - action_handler - .handler - .request_converter - .conversion_request - .len(), - 1 - ); - assert_eq!( - action_handler.handler.request_converter.conversion_request[0], - tc.to_vec().unwrap() - ); - - let (target_id, action_req) = action_handler - .handler - .request_router - .routing_requests - .borrow_mut() - .pop_front() - .unwrap(); + action_handler.check_next_conversion(&tc); + let (target_id, action_req) = action_handler.retrieve_next_request(); assert_eq!(target_id, TEST_APID.into()); if let ActionRequest::UnsignedIdAndVecData { action_id, data } = action_req { assert_eq!(action_id, 1); diff --git a/satrs/src/pus/hk.rs b/satrs/src/pus/hk.rs index baf29d6..7b8b2e9 100644 --- a/satrs/src/pus/hk.rs +++ b/satrs/src/pus/hk.rs @@ -93,9 +93,9 @@ pub mod std_mod { RoutingError = GenericRoutingError, > { service_helper: PusServiceHelper, - request_converter: RequestConverter, - request_router: RequestRouter, - routing_error_handler: RoutingErrorHandler, + pub request_converter: RequestConverter, + pub request_router: RequestRouter, + pub routing_error_handler: RoutingErrorHandler, } impl< @@ -167,3 +167,185 @@ pub mod std_mod { } } } + +#[cfg(test)] +mod tests { + use delegate::delegate; + use spacepackets::ecss::hk::Subservice; + + use spacepackets::{ + ecss::{ + tc::{PusTcCreator, PusTcReader, PusTcSecondaryHeader}, + tm::PusTmReader, + PusPacket, + }, + CcsdsPacket, SequenceFlags, SpHeader, + }; + + use crate::{ + hk::HkRequest, + pus::{ + tests::{ + PusServiceHandlerWithVecCommon, PusTestHarness, SimplePusPacketHandler, + TestConverter, TestRouter, TestRoutingErrorHandler, APP_DATA_TOO_SHORT, TEST_APID, + }, + verification::{ + tests::TestVerificationReporter, FailParams, RequestId, TcStateAccepted, + VerificationReportingProvider, VerificationToken, + }, + EcssTcInVecConverter, GenericRoutingError, PusPacketHandlerResult, + PusPacketHandlingError, + }, + TargetId, + }; + + use super::{PusHkRequestRouter, PusHkToRequestConverter, PusService3HkHandler}; + + impl PusHkRequestRouter for TestRouter { + type Error = GenericRoutingError; + + fn route( + &self, + target_id: TargetId, + hk_request: HkRequest, + _token: VerificationToken, + ) -> Result<(), Self::Error> { + self.routing_requests + .borrow_mut() + .push_back((target_id, hk_request)); + if self.injected_routing_failure.borrow().is_some() { + return Err(self.injected_routing_failure.borrow_mut().take().unwrap()); + } + Ok(()) + } + } + + impl PusHkToRequestConverter for TestConverter<3> { + type Error = PusPacketHandlingError; + fn convert( + &mut self, + token: VerificationToken, + tc: &PusTcReader, + time_stamp: &[u8], + verif_reporter: &impl VerificationReportingProvider, + ) -> Result<(TargetId, HkRequest), Self::Error> { + self.conversion_request.push_back(tc.raw_data().to_vec()); + self.check_service(tc)?; + let target_id = tc.apid(); + if tc.user_data().len() < 4 { + verif_reporter + .start_failure( + token, + FailParams::new( + time_stamp, + &APP_DATA_TOO_SHORT, + (tc.user_data().len() as u32).to_be_bytes().as_ref(), + ), + ) + .expect("start success failure"); + return Err(PusPacketHandlingError::NotEnoughAppData { + expected: 4, + found: tc.user_data().len(), + }); + } + if tc.subservice() == Subservice::TcGenerateOneShotHk as u8 { + verif_reporter + .start_success(token, time_stamp) + .expect("start success failure"); + return Ok(( + target_id.into(), + HkRequest::OneShot(u32::from_be_bytes( + tc.user_data()[0..4].try_into().unwrap(), + )), + )); + } + Err(PusPacketHandlingError::InvalidAppData( + "unexpected app data".into(), + )) + } + } + + struct Pus3HandlerWithVecTester { + common: PusServiceHandlerWithVecCommon, + handler: PusService3HkHandler< + EcssTcInVecConverter, + TestVerificationReporter, + TestConverter<3>, + TestRouter, + TestRoutingErrorHandler, + >, + } + + impl Pus3HandlerWithVecTester { + pub fn new() -> Self { + let (common, srv_handler) = + PusServiceHandlerWithVecCommon::new_with_test_verif_sender(); + Self { + common, + handler: PusService3HkHandler::new( + srv_handler, + TestConverter::default(), + TestRouter::default(), + TestRoutingErrorHandler::default(), + ), + } + } + + delegate! { + to self.handler.request_converter { + pub fn check_next_conversion(&mut self, tc: &PusTcCreator); + } + } + delegate! { + to self.handler.request_router { + pub fn retrieve_next_request(&mut self) -> (TargetId, HkRequest); + } + } + } + + impl PusTestHarness for Pus3HandlerWithVecTester { + delegate! { + to self.common { + fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken; + fn read_next_tm(&mut self) -> PusTmReader<'_>; + fn check_no_tm_available(&self) -> bool; + fn check_next_verification_tm( + &self, + subservice: u8, + expected_request_id: RequestId, + ); + } + } + } + impl SimplePusPacketHandler for Pus3HandlerWithVecTester { + delegate! { + to self.handler { + fn handle_one_tc(&mut self) -> Result; + } + } + } + + #[test] + fn basic_test() { + let mut hk_handler = Pus3HandlerWithVecTester::new(); + let mut sp_header = SpHeader::tc(TEST_APID, SequenceFlags::Unsegmented, 0, 0).unwrap(); + let sec_header = PusTcSecondaryHeader::new_simple(3, Subservice::TcGenerateOneShotHk as u8); + let unique_id: u32 = 1; + let unique_id_raw = unique_id.to_be_bytes(); + let tc = PusTcCreator::new(&mut sp_header, sec_header, unique_id_raw.as_ref(), true); + hk_handler.send_tc(&tc); + let result = hk_handler.handle_one_tc(); + assert!(result.is_ok()); + hk_handler.check_next_conversion(&tc); + let (target_id, hk_request) = hk_handler.retrieve_next_request(); + assert_eq!(target_id, TEST_APID.into()); + if let HkRequest::OneShot(id) = hk_request { + assert_eq!(id, unique_id); + } else { + panic!("unexpected request"); + } + } + + #[test] + fn test_routing_error() {} +} diff --git a/satrs/src/pus/mod.rs b/satrs/src/pus/mod.rs index 4afe0e3..264b4fc 100644 --- a/satrs/src/pus/mod.rs +++ b/satrs/src/pus/mod.rs @@ -931,12 +931,15 @@ pub(crate) fn source_buffer_large_enough(cap: usize, len: usize) -> Result<(), E #[cfg(test)] pub mod tests { + use core::cell::RefCell; use std::sync::mpsc::TryRecvError; use std::sync::{mpsc, RwLock}; use alloc::boxed::Box; - use alloc::vec; - use spacepackets::ecss::tc::PusTcCreator; + use alloc::collections::VecDeque; + use alloc::vec::Vec; + use satrs_shared::res_code::ResultU16; + use spacepackets::ecss::tc::{PusTcCreator, PusTcReader}; use spacepackets::ecss::tm::{GenericPusTmSecondaryHeader, PusTmCreator, PusTmReader}; use spacepackets::ecss::{PusPacket, WritablePusPacket}; use spacepackets::CcsdsPacket; @@ -946,6 +949,7 @@ pub mod tests { }; use crate::pus::verification::RequestId; use crate::tmtc::tm_helper::SharedTmPool; + use crate::TargetId; use super::verification::tests::{SharedVerificationMap, TestVerificationReporter}; use super::verification::{ @@ -953,9 +957,9 @@ pub mod tests { VerificationReportingProvider, VerificationToken, }; use super::{ - EcssTcAndToken, EcssTcInSharedStoreConverter, EcssTcInVecConverter, MpscTcReceiver, - MpscTmAsVecSender, MpscTmInSharedPoolSender, PusPacketHandlerResult, - PusPacketHandlingError, PusServiceHelper, TcInMemory, + EcssTcAndToken, EcssTcInSharedStoreConverter, EcssTcInVecConverter, GenericRoutingError, + MpscTcReceiver, MpscTmAsVecSender, MpscTmInSharedPoolSender, PusPacketHandlerResult, + PusPacketHandlingError, PusRoutingErrorHandler, PusServiceHelper, TcInMemory, }; pub const TEST_APID: u16 = 0x101; @@ -1014,7 +1018,7 @@ pub mod tests { Self, PusServiceHelper, ) { - let pool_cfg = StaticPoolConfig::new(vec![(16, 16), (8, 32), (4, 64)], false); + let pool_cfg = StaticPoolConfig::new(alloc::vec![(16, 16), (8, 32), (4, 64)], false); let tc_pool = StaticMemoryPool::new(pool_cfg.clone()); let tm_pool = StaticMemoryPool::new(pool_cfg); let shared_tc_pool = SharedStaticMemoryPool::new(RwLock::new(tc_pool)); @@ -1227,4 +1231,86 @@ pub mod tests { assert_eq!(req_id, expected_request_id); } } + + pub const APP_DATA_TOO_SHORT: ResultU16 = ResultU16::new(1, 1); + + #[derive(Default)] + pub struct TestConverter { + pub conversion_request: VecDeque>, + } + + impl TestConverter { + pub fn check_service(&self, tc: &PusTcReader) -> Result<(), PusPacketHandlingError> { + if tc.service() != SERVICE { + return Err(PusPacketHandlingError::WrongService(tc.service())); + } + Ok(()) + } + + pub fn is_empty(&self) { + self.conversion_request.is_empty(); + } + + pub fn check_next_conversion(&mut self, tc: &PusTcCreator) { + assert!(!self.conversion_request.is_empty()); + assert_eq!( + self.conversion_request.pop_front().unwrap(), + tc.to_vec().unwrap() + ); + } + } + + #[derive(Default)] + pub struct TestRoutingErrorHandler { + pub routing_errors: RefCell>, + } + + impl PusRoutingErrorHandler for TestRoutingErrorHandler { + type Error = GenericRoutingError; + + fn handle_error( + &self, + target_id: TargetId, + _token: VerificationToken, + _tc: &PusTcReader, + error: Self::Error, + _time_stamp: &[u8], + _verif_reporter: &impl VerificationReportingProvider, + ) { + self.routing_errors + .borrow_mut() + .push_back((target_id, error)); + } + } + + pub struct TestRouter { + pub routing_requests: RefCell>, + pub injected_routing_failure: RefCell>, + } + + impl Default for TestRouter { + fn default() -> Self { + Self { + routing_requests: Default::default(), + injected_routing_failure: Default::default(), + } + } + } + + impl TestRouter { + pub fn inject_routing_error(&mut self, error: GenericRoutingError) { + *self.injected_routing_failure.borrow_mut() = Some(error); + } + + pub fn is_empty(&self) -> bool { + self.routing_requests.borrow().is_empty() + } + + pub fn retrieve_next_request(&mut self) -> (TargetId, REQUEST) { + if self.routing_requests.borrow().is_empty() { + panic!("no routing request available"); + } + self.routing_requests.borrow_mut().pop_front().unwrap() + } + } }