add test for reached check limit
All checks were successful
Rust/sat-rs/pipeline/pr-main This commit looks good
All checks were successful
Rust/sat-rs/pipeline/pr-main This commit looks good
This commit is contained in:
parent
7f301a0771
commit
620ffbb131
@ -52,6 +52,12 @@ struct FileProperties {
|
||||
dest_path_buf: PathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||
enum CompletionDisposition {
|
||||
Completed = 0,
|
||||
Cancelled = 1,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TransferState {
|
||||
transaction_id: Option<TransactionId>,
|
||||
@ -60,6 +66,7 @@ struct TransferState {
|
||||
condition_code: ConditionCode,
|
||||
delivery_code: DeliveryCode,
|
||||
file_status: FileStatus,
|
||||
completion_disposition: CompletionDisposition,
|
||||
checksum: u32,
|
||||
current_check_count: u32,
|
||||
current_check_timer: Option<Box<dyn CheckTimer>>,
|
||||
@ -74,6 +81,7 @@ impl Default for TransferState {
|
||||
condition_code: ConditionCode::NoError,
|
||||
delivery_code: DeliveryCode::Incomplete,
|
||||
file_status: FileStatus::Unreported,
|
||||
completion_disposition: CompletionDisposition::Completed,
|
||||
checksum: 0,
|
||||
current_check_count: 0,
|
||||
current_check_timer: None,
|
||||
@ -206,31 +214,13 @@ impl DestinationHandler {
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
/// Returns [None] if the state machine is IDLE, and the transmission mode of the current
|
||||
/// request otherwise.
|
||||
pub fn current_transmission_mode(&self) -> Option<TransmissionMode> {
|
||||
if self.state == State::Idle {
|
||||
return None;
|
||||
}
|
||||
Some(self.tparams.transmission_mode())
|
||||
}
|
||||
|
||||
pub fn packet_to_send_ready(&self) -> bool {
|
||||
@ -281,7 +271,34 @@ impl DestinationHandler {
|
||||
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,
|
||||
cfdp_user: &mut impl CfdpUser,
|
||||
pdu_directive: FileDirectiveType,
|
||||
@ -305,7 +322,7 @@ impl DestinationHandler {
|
||||
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 {
|
||||
return Err(DestError::RecvdMetadataButIsBusy);
|
||||
}
|
||||
@ -354,7 +371,7 @@ impl DestinationHandler {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn handle_file_data(
|
||||
fn handle_file_data(
|
||||
&mut self,
|
||||
user: &mut impl CfdpUser,
|
||||
raw_packet: &[u8],
|
||||
@ -385,7 +402,7 @@ impl DestinationHandler {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn handle_eof_pdu(
|
||||
fn handle_eof_pdu(
|
||||
&mut self,
|
||||
cfdp_user: &mut impl CfdpUser,
|
||||
raw_packet: &[u8],
|
||||
@ -616,6 +633,33 @@ impl DestinationHandler {
|
||||
}
|
||||
|
||||
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 transaction_finished_params = TransactionFinishedParams {
|
||||
id: tstate.transaction_id.unwrap(),
|
||||
@ -624,15 +668,6 @@ impl DestinationHandler {
|
||||
file_status: tstate.file_status,
|
||||
};
|
||||
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(())
|
||||
}
|
||||
|
||||
@ -646,7 +681,7 @@ impl DestinationHandler {
|
||||
.get_fault_handler(condition_code);
|
||||
match fh_code {
|
||||
FaultHandlerCode::NoticeOfCancellation => {
|
||||
self.notice_of_cancellation();
|
||||
self.notice_of_cancellation(condition_code);
|
||||
}
|
||||
FaultHandlerCode::NoticeOfSuspension => self.notice_of_suspension(),
|
||||
FaultHandlerCode::IgnoreError => (),
|
||||
@ -657,7 +692,12 @@ impl DestinationHandler {
|
||||
.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 abandon_transaction(&mut self) {
|
||||
self.reset();
|
||||
@ -680,6 +720,10 @@ impl DestinationHandler {
|
||||
fn tstate(&self) -> &TransferState {
|
||||
&self.tparams.tstate
|
||||
}
|
||||
|
||||
fn tstate_mut(&mut self) -> &mut TransferState {
|
||||
&mut self.tparams.tstate
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -967,6 +1011,7 @@ mod tests {
|
||||
handler
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn indication_cfg_mut(&mut self) -> &mut IndicationConfig {
|
||||
&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 result = self.handler.state_machine(user, Some(&packet_info));
|
||||
assert_eq!(user.metadata_recv_queue.len(), 1);
|
||||
assert_eq!(
|
||||
self.handler.current_transmission_mode().unwrap(),
|
||||
TransmissionMode::Unacknowledged
|
||||
);
|
||||
result
|
||||
}
|
||||
|
||||
@ -1159,7 +1208,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
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]
|
||||
@ -1225,7 +1275,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check_limit_handling() {
|
||||
fn test_check_limit_handling_transfer_success() {
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut random_data = [0u8; 512];
|
||||
rng.fill(&mut random_data);
|
||||
@ -1262,4 +1312,47 @@ mod tests {
|
||||
.state_machine(&mut test_user, None)
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
@ -107,6 +107,7 @@ pub struct RemoteEntityConfig {
|
||||
pub default_transmission_mode: TransmissionMode,
|
||||
pub default_crc_type: ChecksumType,
|
||||
pub check_limit: u32,
|
||||
pub disposition_on_cancellation: bool,
|
||||
}
|
||||
|
||||
impl RemoteEntityConfig {
|
||||
@ -128,6 +129,7 @@ impl RemoteEntityConfig {
|
||||
default_transmission_mode,
|
||||
default_crc_type,
|
||||
check_limit: 2,
|
||||
disposition_on_cancellation: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user