test for event service
All checks were successful
Rust/sat-rs/pipeline/pr-main This commit looks good

This commit is contained in:
Robin Müller 2024-02-01 15:34:28 +01:00
parent 6296b1b0ac
commit 80fd8bc13e
Signed by: muellerr
GPG Key ID: A649FB78196E3849
5 changed files with 194 additions and 70 deletions

View File

@ -82,7 +82,7 @@ pub mod heapless_mod {
} }
} }
#[derive(Debug)] #[derive(Debug, PartialEq, Eq)]
pub enum EventRequest<Event: GenericEvent = EventU32> { pub enum EventRequest<Event: GenericEvent = EventU32> {
Enable(Event), Enable(Event),
Disable(Event), Disable(Event),

View File

@ -45,7 +45,7 @@ impl<TcInMemConverter: EcssTcInMemConverter> PusService5EventHandler<TcInMemConv
let handle_enable_disable_request = |enable: bool, stamp: [u8; 7]| { let handle_enable_disable_request = |enable: bool, stamp: [u8; 7]| {
if tc.user_data().len() < 4 { if tc.user_data().len() < 4 {
return Err(PusPacketHandlingError::NotEnoughAppData( return Err(PusPacketHandlingError::NotEnoughAppData(
"At least 4 bytes event ID expected".into(), "at least 4 bytes event ID expected".into(),
)); ));
} }
let user_data = tc.user_data(); let user_data = tc.user_data();
@ -115,18 +115,33 @@ impl<TcInMemConverter: EcssTcInMemConverter> PusService5EventHandler<TcInMemConv
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use delegate::delegate; use delegate::delegate;
use spacepackets::ecss::{tc::PusTcCreator, tm::PusTmReader}; use spacepackets::ecss::event::Subservice;
use std::sync::mpsc::Sender; use spacepackets::util::UnsignedEnum;
use spacepackets::{
ecss::{
tc::{PusTcCreator, PusTcSecondaryHeader},
tm::PusTmReader,
},
SequenceFlags, SpHeader,
};
use std::sync::mpsc::{self, Sender};
use crate::pus::{ use crate::pus::event_man::EventRequest;
event_man::EventRequestWithToken, use crate::pus::verification::RequestId;
tests::{PusServiceHandlerWithStoreCommon, PusTestHarness}, use crate::{
verification::{TcStateAccepted, VerificationToken}, events::EventU32,
EcssTcInStoreConverter, PusPacketHandlerResult, PusPacketHandlingError, pus::{
event_man::EventRequestWithToken,
tests::{PusServiceHandlerWithStoreCommon, PusTestHarness, TEST_APID},
verification::{TcStateAccepted, VerificationToken},
EcssTcInStoreConverter, PusPacketHandlerResult, PusPacketHandlingError,
},
}; };
use super::PusService5EventHandler; use super::PusService5EventHandler;
const TEST_EVENT_0: EventU32 = EventU32::const_new(crate::events::Severity::INFO, 5, 25);
struct Pus5HandlerWithStoreTester { struct Pus5HandlerWithStoreTester {
common: PusServiceHandlerWithStoreCommon, common: PusServiceHandlerWithStoreCommon,
handler: PusService5EventHandler<EcssTcInStoreConverter>, handler: PusService5EventHandler<EcssTcInStoreConverter>,
@ -148,11 +163,8 @@ mod tests {
to self.common { to self.common {
fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted>; fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted>;
fn read_next_tm(&mut self) -> PusTmReader<'_>; fn read_next_tm(&mut self) -> PusTmReader<'_>;
fn check_next_verification_tm<STATE>( fn check_no_tm_available(&self) -> bool;
&self, fn check_next_verification_tm(&self, subservice: u8, expected_request_id: RequestId);
subservice: u8,
token: VerificationToken<STATE>,
);
} }
to self.handler { to self.handler {
@ -160,4 +172,104 @@ mod tests {
} }
} }
} }
fn event_test(
test_harness: &mut impl PusTestHarness,
subservice: Subservice,
expected_event_req: EventRequest,
event_req_receiver: mpsc::Receiver<EventRequestWithToken>,
) {
let mut sp_header = SpHeader::tc(TEST_APID, SequenceFlags::Unsegmented, 0, 0).unwrap();
let sec_header = PusTcSecondaryHeader::new_simple(5, subservice as u8);
let mut app_data = [0; 4];
TEST_EVENT_0
.write_to_be_bytes(&mut app_data)
.expect("writing test event failed");
let ping_tc = PusTcCreator::new(&mut sp_header, sec_header, &app_data, true);
let token = test_harness.send_tc(&ping_tc);
let request_id = token.req_id();
test_harness.handle_one_tc().unwrap();
test_harness.check_next_verification_tm(1, request_id);
test_harness.check_next_verification_tm(3, request_id);
// Completion TM is not generated for us.
assert!(test_harness.check_no_tm_available());
let event_request = event_req_receiver
.try_recv()
.expect("no event request received");
assert_eq!(expected_event_req, event_request.request);
}
#[test]
fn test_enabling_event_reporting() {
let (event_request_tx, event_request_rx) = mpsc::channel();
let mut test_harness = Pus5HandlerWithStoreTester::new(event_request_tx);
event_test(
&mut test_harness,
Subservice::TcEnableEventGeneration,
EventRequest::Enable(TEST_EVENT_0),
event_request_rx,
);
}
#[test]
fn test_disabling_event_reporting() {
let (event_request_tx, event_request_rx) = mpsc::channel();
let mut test_harness = Pus5HandlerWithStoreTester::new(event_request_tx);
event_test(
&mut test_harness,
Subservice::TcDisableEventGeneration,
EventRequest::Disable(TEST_EVENT_0),
event_request_rx,
);
}
#[test]
fn test_empty_tc_queue() {
let (event_request_tx, _) = mpsc::channel();
let mut test_harness = Pus5HandlerWithStoreTester::new(event_request_tx);
let result = test_harness.handle_one_tc();
assert!(result.is_ok());
let result = result.unwrap();
if let PusPacketHandlerResult::Empty = result {
} else {
panic!("unexpected result type {result:?}")
}
}
#[test]
fn test_sending_custom_subservice() {
let (event_request_tx, _) = mpsc::channel();
let mut test_harness = Pus5HandlerWithStoreTester::new(event_request_tx);
let mut sp_header = SpHeader::tc(TEST_APID, SequenceFlags::Unsegmented, 0, 0).unwrap();
let sec_header = PusTcSecondaryHeader::new_simple(5, 200);
let ping_tc = PusTcCreator::new_no_app_data(&mut sp_header, sec_header, true);
test_harness.send_tc(&ping_tc);
let result = test_harness.handle_one_tc();
assert!(result.is_ok());
let result = result.unwrap();
if let PusPacketHandlerResult::CustomSubservice(subservice, _) = result {
assert_eq!(subservice, 200);
} else {
panic!("unexpected result type {result:?}")
}
}
#[test]
fn test_sending_invalid_app_data() {
let (event_request_tx, _) = mpsc::channel();
let mut test_harness = Pus5HandlerWithStoreTester::new(event_request_tx);
let mut sp_header = SpHeader::tc(TEST_APID, SequenceFlags::Unsegmented, 0, 0).unwrap();
let sec_header =
PusTcSecondaryHeader::new_simple(5, Subservice::TcEnableEventGeneration as u8);
let ping_tc = PusTcCreator::new(&mut sp_header, sec_header, &[0, 1, 2], true);
test_harness.send_tc(&ping_tc);
let result = test_harness.handle_one_tc();
assert!(result.is_err());
let result = result.unwrap_err();
if let PusPacketHandlingError::NotEnoughAppData(string) = result {
assert_eq!(string, "at least 4 bytes event ID expected");
} else {
panic!("unexpected result type {result:?}")
}
}
} }

View File

@ -914,6 +914,7 @@ pub(crate) fn source_buffer_large_enough(cap: usize, len: usize) -> Result<(), E
#[cfg(test)] #[cfg(test)]
pub mod tests { pub mod tests {
use std::sync::mpsc::TryRecvError;
use std::sync::{mpsc, RwLock}; use std::sync::{mpsc, RwLock};
use alloc::boxed::Box; use alloc::boxed::Box;
@ -950,12 +951,8 @@ pub mod tests {
pub trait PusTestHarness { pub trait PusTestHarness {
fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted>; fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted>;
fn read_next_tm(&mut self) -> PusTmReader<'_>; fn read_next_tm(&mut self) -> PusTmReader<'_>;
fn check_next_verification_tm<STATE>( fn check_no_tm_available(&self) -> bool;
&self, fn check_next_verification_tm(&self, subservice: u8, expected_request_id: RequestId);
subservice: u8,
token: VerificationToken<STATE>,
);
fn handle_one_tc(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError>; fn handle_one_tc(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError>;
} }
@ -1053,11 +1050,15 @@ pub mod tests {
PusTmReader::new(&self.tm_buf, 7).unwrap().0 PusTmReader::new(&self.tm_buf, 7).unwrap().0
} }
pub fn check_next_verification_tm<STATE>( pub fn check_no_tm_available(&self) -> bool {
&self, let next_msg = self.tm_receiver.try_recv();
subservice: u8, if let TryRecvError::Empty = next_msg.unwrap_err() {
token: VerificationToken<STATE>, return true;
) { }
false
}
pub fn check_next_verification_tm(&self, subservice: u8, expected_request_id: RequestId) {
let next_msg = self.tm_receiver.try_recv(); let next_msg = self.tm_receiver.try_recv();
assert!(next_msg.is_ok()); assert!(next_msg.is_ok());
let tm_addr = next_msg.unwrap(); let tm_addr = next_msg.unwrap();
@ -1069,7 +1070,7 @@ pub mod tests {
assert_eq!(tm.apid(), TEST_APID); assert_eq!(tm.apid(), TEST_APID);
let req_id = let req_id =
RequestId::from_bytes(tm.user_data()).expect("generating request ID failed"); RequestId::from_bytes(tm.user_data()).expect("generating request ID failed");
assert_eq!(req_id, token.req_id()); assert_eq!(req_id, expected_request_id);
} }
} }
@ -1134,11 +1135,15 @@ pub mod tests {
.0 .0
} }
pub fn check_next_verification_tm<STATE>( pub fn check_no_tm_available(&self) -> bool {
&self, let next_msg = self.tm_receiver.try_recv();
subservice: u8, if let TryRecvError::Empty = next_msg.unwrap_err() {
token: VerificationToken<STATE>, return true;
) { }
false
}
pub fn check_next_verification_tm(&self, subservice: u8, expected_request_id: RequestId) {
let next_msg = self.tm_receiver.try_recv(); let next_msg = self.tm_receiver.try_recv();
assert!(next_msg.is_ok()); assert!(next_msg.is_ok());
let next_msg = next_msg.unwrap(); let next_msg = next_msg.unwrap();
@ -1148,7 +1153,7 @@ pub mod tests {
assert_eq!(tm.apid(), TEST_APID); assert_eq!(tm.apid(), TEST_APID);
let req_id = let req_id =
RequestId::from_bytes(tm.user_data()).expect("generating request ID failed"); RequestId::from_bytes(tm.user_data()).expect("generating request ID failed");
assert_eq!(req_id, token.req_id()); assert_eq!(req_id, expected_request_id);
} }
} }
} }

View File

@ -15,9 +15,7 @@ pub struct PusService17TestHandler<TcInMemConverter: EcssTcInMemConverter> {
impl<TcInMemConverter: EcssTcInMemConverter> PusService17TestHandler<TcInMemConverter> { impl<TcInMemConverter: EcssTcInMemConverter> PusService17TestHandler<TcInMemConverter> {
pub fn new(service_helper: PusServiceHelper<TcInMemConverter>) -> Self { pub fn new(service_helper: PusServiceHelper<TcInMemConverter>) -> Self {
Self { Self { service_helper }
service_helper,
}
} }
pub fn handle_one_tc(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError> { pub fn handle_one_tc(&mut self) -> Result<PusPacketHandlerResult, PusPacketHandlingError> {
@ -50,7 +48,8 @@ impl<TcInMemConverter: EcssTcInMemConverter> PusService17TestHandler<TcInMemConv
None None
}; };
// Sequence count will be handled centrally in TM funnel. // Sequence count will be handled centrally in TM funnel.
let mut reply_header = SpHeader::tm_unseg(self.service_helper.common.tm_apid, 0, 0).unwrap(); let mut reply_header =
SpHeader::tm_unseg(self.service_helper.common.tm_apid, 0, 0).unwrap();
let tc_header = PusTmSecondaryHeader::new_simple(17, 2, &time_stamp); let tc_header = PusTmSecondaryHeader::new_simple(17, 2, &time_stamp);
let ping_reply = PusTmCreator::new(&mut reply_header, tc_header, &[], true); let ping_reply = PusTmCreator::new(&mut reply_header, tc_header, &[], true);
let result = self let result = self
@ -95,6 +94,7 @@ mod tests {
use crate::pus::tests::{ use crate::pus::tests::{
PusServiceHandlerWithStoreCommon, PusServiceHandlerWithVecCommon, PusTestHarness, TEST_APID, PusServiceHandlerWithStoreCommon, PusServiceHandlerWithVecCommon, PusTestHarness, TEST_APID,
}; };
use crate::pus::verification::RequestId;
use crate::pus::verification::{TcStateAccepted, VerificationToken}; use crate::pus::verification::{TcStateAccepted, VerificationToken};
use crate::pus::{ use crate::pus::{
EcssTcInStoreConverter, EcssTcInVecConverter, PusPacketHandlerResult, EcssTcInStoreConverter, EcssTcInVecConverter, PusPacketHandlerResult,
@ -129,10 +129,11 @@ mod tests {
to self.common { to self.common {
fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted>; fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted>;
fn read_next_tm(&mut self) -> PusTmReader<'_>; fn read_next_tm(&mut self) -> PusTmReader<'_>;
fn check_next_verification_tm<STATE>( fn check_no_tm_available(&self) -> bool;
fn check_next_verification_tm(
&self, &self,
subservice: u8, subservice: u8,
token: VerificationToken<STATE>, expected_request_id: RequestId
); );
} }
@ -163,10 +164,11 @@ mod tests {
to self.common { to self.common {
fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted>; fn send_tc(&mut self, tc: &PusTcCreator) -> VerificationToken<TcStateAccepted>;
fn read_next_tm(&mut self) -> PusTmReader<'_>; fn read_next_tm(&mut self) -> PusTmReader<'_>;
fn check_next_verification_tm<STATE>( fn check_no_tm_available(&self) -> bool;
fn check_next_verification_tm(
&self, &self,
subservice: u8, subservice: u8,
token: VerificationToken<STATE>, expected_request_id: RequestId,
); );
} }
@ -182,16 +184,17 @@ mod tests {
let sec_header = PusTcSecondaryHeader::new_simple(17, 1); let sec_header = PusTcSecondaryHeader::new_simple(17, 1);
let ping_tc = PusTcCreator::new_no_app_data(&mut sp_header, sec_header, true); let ping_tc = PusTcCreator::new_no_app_data(&mut sp_header, sec_header, true);
let token = test_harness.send_tc(&ping_tc); let token = test_harness.send_tc(&ping_tc);
let request_id = token.req_id();
let result = test_harness.handle_one_tc(); let result = test_harness.handle_one_tc();
assert!(result.is_ok()); assert!(result.is_ok());
// We should see 4 replies in the TM queue now: Acceptance TM, Start TM, ping reply and // We should see 4 replies in the TM queue now: Acceptance TM, Start TM, ping reply and
// Completion TM // Completion TM
// Acceptance TM // Acceptance TM
test_harness.check_next_verification_tm(1, token); test_harness.check_next_verification_tm(1, request_id);
// Start TM // Start TM
test_harness.check_next_verification_tm(3, token); test_harness.check_next_verification_tm(3, request_id);
// Ping reply // Ping reply
let tm = test_harness.read_next_tm(); let tm = test_harness.read_next_tm();
@ -200,7 +203,31 @@ mod tests {
assert!(tm.user_data().is_empty()); assert!(tm.user_data().is_empty());
// TM completion // TM completion
test_harness.check_next_verification_tm(7, token); test_harness.check_next_verification_tm(7, request_id);
}
#[test]
fn test_basic_ping_processing_using_store() {
let mut test_harness = Pus17HandlerWithStoreTester::new();
ping_test(&mut test_harness);
}
#[test]
fn test_basic_ping_processing_using_vec() {
let mut test_harness = Pus17HandlerWithVecTester::new();
ping_test(&mut test_harness);
}
#[test]
fn test_empty_tc_queue() {
let mut test_harness = Pus17HandlerWithStoreTester::new();
let result = test_harness.handle_one_tc();
assert!(result.is_ok());
let result = result.unwrap();
if let PusPacketHandlerResult::Empty = result {
} else {
panic!("unexpected result type {result:?}")
}
} }
#[test] #[test]
@ -236,28 +263,4 @@ mod tests {
panic!("unexpected result type {result:?}") panic!("unexpected result type {result:?}")
} }
} }
#[test]
fn test_basic_ping_processing_using_store() {
let mut test_harness = Pus17HandlerWithStoreTester::new();
ping_test(&mut test_harness);
}
#[test]
fn test_basic_ping_processing_using_vec() {
let mut test_harness = Pus17HandlerWithVecTester::new();
ping_test(&mut test_harness);
}
#[test]
fn test_empty_tc_queue() {
let mut test_harness = Pus17HandlerWithStoreTester::new();
let result = test_harness.handle_one_tc();
assert!(result.is_ok());
let result = result.unwrap();
if let PusPacketHandlerResult::Empty = result {
} else {
panic!("unexpected result type {result:?}")
}
}
} }

View File

@ -38,9 +38,13 @@ impl Service17CustomWrapper {
warn!("PUS17: Subservice {subservice} not implemented") warn!("PUS17: Subservice {subservice} not implemented")
} }
PusPacketHandlerResult::CustomSubservice(subservice, token) => { PusPacketHandlerResult::CustomSubservice(subservice, token) => {
let (tc, _) = let (tc, _) = PusTcReader::new(
PusTcReader::new(self.pus17_handler.service_helper.tc_in_mem_converter.tc_slice_raw()) self.pus17_handler
.unwrap(); .service_helper
.tc_in_mem_converter
.tc_slice_raw(),
)
.unwrap();
let time_stamper = TimeProvider::from_now_with_u16_days().unwrap(); let time_stamper = TimeProvider::from_now_with_u16_days().unwrap();
let mut stamp_buf: [u8; 7] = [0; 7]; let mut stamp_buf: [u8; 7] = [0; 7];
time_stamper.write_to_bytes(&mut stamp_buf).unwrap(); time_stamper.write_to_bytes(&mut stamp_buf).unwrap();