add test for reached check limit
All checks were successful
Rust/sat-rs/pipeline/pr-main This commit looks good

This commit is contained in:
Robin Müller 2023-12-18 15:28:15 +01:00
parent 7f301a0771
commit 620ffbb131
Signed by: muellerr
GPG Key ID: A649FB78196E3849
2 changed files with 136 additions and 41 deletions

View File

@ -52,6 +52,12 @@ struct FileProperties {
dest_path_buf: PathBuf, dest_path_buf: PathBuf,
} }
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
enum CompletionDisposition {
Completed = 0,
Cancelled = 1,
}
#[derive(Debug)] #[derive(Debug)]
struct TransferState { struct TransferState {
transaction_id: Option<TransactionId>, transaction_id: Option<TransactionId>,
@ -60,6 +66,7 @@ struct TransferState {
condition_code: ConditionCode, condition_code: ConditionCode,
delivery_code: DeliveryCode, delivery_code: DeliveryCode,
file_status: FileStatus, file_status: FileStatus,
completion_disposition: CompletionDisposition,
checksum: u32, checksum: u32,
current_check_count: u32, current_check_count: u32,
current_check_timer: Option<Box<dyn CheckTimer>>, current_check_timer: Option<Box<dyn CheckTimer>>,
@ -74,6 +81,7 @@ impl Default for TransferState {
condition_code: ConditionCode::NoError, condition_code: ConditionCode::NoError,
delivery_code: DeliveryCode::Incomplete, delivery_code: DeliveryCode::Incomplete,
file_status: FileStatus::Unreported, file_status: FileStatus::Unreported,
completion_disposition: CompletionDisposition::Completed,
checksum: 0, checksum: 0,
current_check_count: 0, current_check_count: 0,
current_check_timer: None, current_check_timer: None,
@ -206,31 +214,13 @@ impl DestinationHandler {
} }
} }
fn insert_packet( /// Returns [None] if the state machine is IDLE, and the transmission mode of the current
&mut self, /// request otherwise.
cfdp_user: &mut impl CfdpUser, pub fn current_transmission_mode(&self) -> Option<TransmissionMode> {
packet_info: &PacketInfo, if self.state == State::Idle {
) -> Result<(), DestError> { return None;
if packet_info.target() != PacketTarget::DestEntity {
// Unwrap is okay here, a PacketInfo for a file data PDU should always have the
// destination as the target.
return Err(DestError::CantProcessPacketType(
packet_info.pdu_directive().unwrap(),
));
}
match packet_info.pdu_type {
PduType::FileDirective => {
if packet_info.pdu_directive.is_none() {
return Err(DestError::DirectiveExpected);
}
self.handle_file_directive(
cfdp_user,
packet_info.pdu_directive.unwrap(),
packet_info.raw_packet,
)
}
PduType::FileData => self.handle_file_data(cfdp_user, packet_info.raw_packet),
} }
Some(self.tparams.transmission_mode())
} }
pub fn packet_to_send_ready(&self) -> bool { pub fn packet_to_send_ready(&self) -> bool {
@ -281,7 +271,34 @@ impl DestinationHandler {
Ok(Some((directive, written_size))) Ok(Some((directive, written_size)))
} }
pub fn handle_file_directive( fn insert_packet(
&mut self,
cfdp_user: &mut impl CfdpUser,
packet_info: &PacketInfo,
) -> Result<(), DestError> {
if packet_info.target() != PacketTarget::DestEntity {
// Unwrap is okay here, a PacketInfo for a file data PDU should always have the
// destination as the target.
return Err(DestError::CantProcessPacketType(
packet_info.pdu_directive().unwrap(),
));
}
match packet_info.pdu_type {
PduType::FileDirective => {
if packet_info.pdu_directive.is_none() {
return Err(DestError::DirectiveExpected);
}
self.handle_file_directive(
cfdp_user,
packet_info.pdu_directive.unwrap(),
packet_info.raw_packet,
)
}
PduType::FileData => self.handle_file_data(cfdp_user, packet_info.raw_packet),
}
}
fn handle_file_directive(
&mut self, &mut self,
cfdp_user: &mut impl CfdpUser, cfdp_user: &mut impl CfdpUser,
pdu_directive: FileDirectiveType, pdu_directive: FileDirectiveType,
@ -305,7 +322,7 @@ impl DestinationHandler {
Ok(()) Ok(())
} }
pub fn handle_metadata_pdu(&mut self, raw_packet: &[u8]) -> Result<(), DestError> { fn handle_metadata_pdu(&mut self, raw_packet: &[u8]) -> Result<(), DestError> {
if self.state != State::Idle { if self.state != State::Idle {
return Err(DestError::RecvdMetadataButIsBusy); return Err(DestError::RecvdMetadataButIsBusy);
} }
@ -354,7 +371,7 @@ impl DestinationHandler {
Ok(()) Ok(())
} }
pub fn handle_file_data( fn handle_file_data(
&mut self, &mut self,
user: &mut impl CfdpUser, user: &mut impl CfdpUser,
raw_packet: &[u8], raw_packet: &[u8],
@ -385,7 +402,7 @@ impl DestinationHandler {
Ok(()) Ok(())
} }
pub fn handle_eof_pdu( fn handle_eof_pdu(
&mut self, &mut self,
cfdp_user: &mut impl CfdpUser, cfdp_user: &mut impl CfdpUser,
raw_packet: &[u8], raw_packet: &[u8],
@ -616,6 +633,33 @@ impl DestinationHandler {
} }
fn transfer_completion(&mut self, cfdp_user: &mut impl CfdpUser) -> Result<(), DestError> { fn transfer_completion(&mut self, cfdp_user: &mut impl CfdpUser) -> Result<(), DestError> {
self.notice_of_completion(cfdp_user)?;
if self.tparams.transmission_mode() == TransmissionMode::Acknowledged
|| self.tparams.metadata_params().closure_requested
{
self.prepare_finished_pdu()?;
self.step = TransactionStep::SendingFinishedPdu;
} else {
self.reset();
}
Ok(())
}
fn notice_of_completion(&mut self, cfdp_user: &mut impl CfdpUser) -> Result<(), DestError> {
if self.tstate().completion_disposition == CompletionDisposition::Completed {
// TODO: Execute any filestore requests
} else if self
.tparams
.remote_cfg
.as_ref()
.unwrap()
.disposition_on_cancellation
&& self.tstate().delivery_code == DeliveryCode::Incomplete
{
self.vfs
.remove_file(self.tparams.file_properties.dest_path_buf.to_str().unwrap())?;
self.tstate_mut().file_status = FileStatus::DiscardDeliberately;
}
let tstate = self.tstate(); let tstate = self.tstate();
let transaction_finished_params = TransactionFinishedParams { let transaction_finished_params = TransactionFinishedParams {
id: tstate.transaction_id.unwrap(), id: tstate.transaction_id.unwrap(),
@ -624,15 +668,6 @@ impl DestinationHandler {
file_status: tstate.file_status, file_status: tstate.file_status,
}; };
cfdp_user.transaction_finished_indication(&transaction_finished_params); cfdp_user.transaction_finished_indication(&transaction_finished_params);
// This function should never be called with metadata parameters not set
if self.tparams.metadata_params().closure_requested {
self.prepare_finished_pdu()?;
self.step = TransactionStep::SendingFinishedPdu;
} else {
self.reset();
self.state = State::Idle;
self.step = TransactionStep::Idle;
}
Ok(()) Ok(())
} }
@ -646,7 +681,7 @@ impl DestinationHandler {
.get_fault_handler(condition_code); .get_fault_handler(condition_code);
match fh_code { match fh_code {
FaultHandlerCode::NoticeOfCancellation => { FaultHandlerCode::NoticeOfCancellation => {
self.notice_of_cancellation(); self.notice_of_cancellation(condition_code);
} }
FaultHandlerCode::NoticeOfSuspension => self.notice_of_suspension(), FaultHandlerCode::NoticeOfSuspension => self.notice_of_suspension(),
FaultHandlerCode::IgnoreError => (), FaultHandlerCode::IgnoreError => (),
@ -657,7 +692,12 @@ impl DestinationHandler {
.report_fault(transaction_id, condition_code, progress) .report_fault(transaction_id, condition_code, progress)
} }
fn notice_of_cancellation(&mut self) {} fn notice_of_cancellation(&mut self, condition_code: ConditionCode) {
self.step = TransactionStep::TransferCompletion;
self.tstate_mut().condition_code = condition_code;
self.tstate_mut().completion_disposition = CompletionDisposition::Cancelled;
}
fn notice_of_suspension(&mut self) {} fn notice_of_suspension(&mut self) {}
fn abandon_transaction(&mut self) { fn abandon_transaction(&mut self) {
self.reset(); self.reset();
@ -680,6 +720,10 @@ impl DestinationHandler {
fn tstate(&self) -> &TransferState { fn tstate(&self) -> &TransferState {
&self.tparams.tstate &self.tparams.tstate
} }
fn tstate_mut(&mut self) -> &mut TransferState {
&mut self.tparams.tstate
}
} }
#[cfg(test)] #[cfg(test)]
@ -967,6 +1011,7 @@ mod tests {
handler handler
} }
#[allow(dead_code)]
fn indication_cfg_mut(&mut self) -> &mut IndicationConfig { fn indication_cfg_mut(&mut self) -> &mut IndicationConfig {
&mut self.handler.local_cfg.indication_cfg &mut self.handler.local_cfg.indication_cfg
} }
@ -1004,6 +1049,10 @@ mod tests {
let packet_info = create_packet_info(&metadata_pdu, &mut self.buf); let packet_info = create_packet_info(&metadata_pdu, &mut self.buf);
let result = self.handler.state_machine(user, Some(&packet_info)); let result = self.handler.state_machine(user, Some(&packet_info));
assert_eq!(user.metadata_recv_queue.len(), 1); assert_eq!(user.metadata_recv_queue.len(), 1);
assert_eq!(
self.handler.current_transmission_mode().unwrap(),
TransmissionMode::Unacknowledged
);
result result
} }
@ -1159,7 +1208,8 @@ mod tests {
#[test] #[test]
fn test_basic() { fn test_basic() {
default_dest_handler(Arc::default()); let dest_handler = default_dest_handler(Arc::default());
assert!(dest_handler.current_transmission_mode().is_none());
} }
#[test] #[test]
@ -1225,7 +1275,7 @@ mod tests {
} }
#[test] #[test]
fn test_check_limit_handling() { fn test_check_limit_handling_transfer_success() {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let mut random_data = [0u8; 512]; let mut random_data = [0u8; 512];
rng.fill(&mut random_data); rng.fill(&mut random_data);
@ -1262,4 +1312,47 @@ mod tests {
.state_machine(&mut test_user, None) .state_machine(&mut test_user, None)
.expect("fsm failure"); .expect("fsm failure");
} }
#[test]
fn test_check_limit_handling_limit_reached() {
let mut rng = rand::thread_rng();
let mut random_data = [0u8; 512];
rng.fill(&mut random_data);
let file_size = random_data.len() as u64;
let segment_len = 256;
let mut test_obj = TestClass::new();
let mut test_user = test_obj.test_user_from_cached_paths(file_size);
test_obj
.generic_transfer_init(&mut test_user, file_size)
.expect("transfer init failed");
test_obj.state_check(State::Busy, TransactionStep::ReceivingFileDataPdus);
test_obj
.generic_file_data_insert(&mut test_user, 0, &random_data[0..segment_len])
.expect("file data insertion 0 failed");
test_obj
.generic_eof_no_error(&mut test_user, random_data.to_vec())
.expect("EOF no error insertion failed");
test_obj.state_check(
State::Busy,
TransactionStep::ReceivingFileDataPdusWithCheckLimitHandling,
);
test_obj.set_check_timer_expired();
test_obj
.handler
.state_machine(&mut test_user, None)
.expect("fsm error");
test_obj.state_check(
State::Busy,
TransactionStep::ReceivingFileDataPdusWithCheckLimitHandling,
);
test_obj.set_check_timer_expired();
test_obj
.handler
.state_machine(&mut test_user, None)
.expect("fsm error");
test_obj.state_check(State::Idle, TransactionStep::Idle);
test_obj.check_dest_file = false;
}
} }

View File

@ -107,6 +107,7 @@ pub struct RemoteEntityConfig {
pub default_transmission_mode: TransmissionMode, pub default_transmission_mode: TransmissionMode,
pub default_crc_type: ChecksumType, pub default_crc_type: ChecksumType,
pub check_limit: u32, pub check_limit: u32,
pub disposition_on_cancellation: bool,
} }
impl RemoteEntityConfig { impl RemoteEntityConfig {
@ -128,6 +129,7 @@ impl RemoteEntityConfig {
default_transmission_mode, default_transmission_mode,
default_crc_type, default_crc_type,
check_limit: 2, check_limit: 2,
disposition_on_cancellation: false,
} }
} }
} }