Skip to content

Commit

Permalink
everything becomes more tricky..
Browse files Browse the repository at this point in the history
  • Loading branch information
robamu committed Nov 7, 2023
1 parent a2d2030 commit ec29a63
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 23 deletions.
15 changes: 12 additions & 3 deletions examples/cfdp-cli-udp/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@
TransmissionMode,
ChecksumType,
)
from spacepackets.cfdp.tlv import ProxyMessageType, MessageToUserTlv
from spacepackets.cfdp.tlv import (
ProxyMessageType,
MessageToUserTlv,
OriginatingTransactionId,
)
from spacepackets.util import UnsignedByteField, ByteFieldU16
from tmtccmd.cfdp.user import (
CfdpUserBase,
Expand Down Expand Up @@ -109,7 +113,7 @@ class CfdpUser(CfdpUserBase):
def __init__(self, base_str: str, put_req_queue: Queue):
self.base_str = base_str
self.put_req_queue = put_req_queue
self.active_proxy_put_reqs = {}
self.active_proxy_put_reqs = []
super().__init__()

def transaction_indication(self, transaction_id: TransactionId):
Expand All @@ -131,7 +135,9 @@ def metadata_recv_indication(self, params: MetadataRecvParams):
if params.msgs_to_user is not None:
self._handle_msgs_to_user(params.msgs_to_user)

def _handle_msgs_to_user(self, msgs_to_user: List[MessageToUserTlv]):
def _handle_msgs_to_user(
self, transaction_id: TransactionId, msgs_to_user: List[MessageToUserTlv]
):
for msg_to_user in msgs_to_user:
if msg_to_user.is_reserved_cfdp_message():
# TODO: Add support for all other reserved message types.
Expand All @@ -142,14 +148,17 @@ def _handle_msgs_to_user(self, msgs_to_user: List[MessageToUserTlv]):
== ProxyMessageType.PUT_REQUEST
):
put_req_params = reserved_cfdp_msg.get_proxy_put_request_params()
_LOGGER.info(f"Received Proxy Put Request: {put_req_params}")
assert put_req_params is not None
put_req = PutRequest(
destination_id=put_req_params.dest_entity_id,
source_file=put_req_params.source_file_as_path,
dest_file=put_req_params.dest_file_as_path,
trans_mode=None,
closure_requested=None,
msgs_to_user=[OriginatingTransactionId(transaction_id)],
)
self.active_proxy_put_reqs.append(put_req)
self.put_req_queue.put(put_req)

def file_segment_recv_indication(self, params: FileSegmentRecvdParams):
Expand Down
3 changes: 2 additions & 1 deletion tests/cfdp/cfdp_user_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
FileSegmentRecvdParams,
MetadataRecvParams,
TransactionFinishedParams,
TransactionParams,
)


class CfdpUser(CfdpUserBase):
def __init__(self):
super().__init__()

def transaction_indication(self, transaction_id: TransactionId):
def transaction_indication(self, transaction_params: TransactionParams):
pass

def transaction_finished_indication(self, params: TransactionFinishedParams):
Expand Down
21 changes: 14 additions & 7 deletions tests/cfdp/test_dest_handler.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from threading import Lock
import dataclasses
import os
import tempfile
from pathlib import Path
from threading import Lock
from typing import Optional, Tuple, cast
from unittest import TestCase
from unittest.mock import MagicMock
Expand All @@ -14,8 +14,8 @@
DirectiveType,
PduConfig,
PduType,
TransmissionMode,
TransactionId,
TransmissionMode,
)
from spacepackets.cfdp.pdu import (
DeliveryCode,
Expand All @@ -27,20 +27,24 @@
)
from spacepackets.cfdp.pdu.file_data import FileDataParams
from spacepackets.cfdp.pdu.metadata import MetadataParams
from spacepackets.util import ByteFieldU16, ByteFieldU8
from spacepackets.util import ByteFieldU8, ByteFieldU16

from tmtccmd.cfdp import (
IndicationCfg,
LocalEntityCfg,
RemoteEntityCfgTable,
RemoteEntityCfg,
RemoteEntityCfgTable,
)
from tmtccmd.cfdp.defs import CfdpState
from tmtccmd.cfdp.handler.dest import (
DestHandler,
FsmResult,
TransactionStep,
)
from tmtccmd.cfdp.user import FileSegmentRecvdParams, TransactionFinishedParams
from tmtccmd.cfdp.user import (
FileSegmentRecvdParams,
TransactionFinishedParams,
)

from .cfdp_fault_handler_mock import FaultHandler
from .cfdp_user_mock import CfdpUser
Expand Down Expand Up @@ -89,10 +93,11 @@ def common_setup(self, trans_mode: TransmissionMode):
self.expected_mode = trans_mode
self.closure_requested = False
self.cfdp_user = CfdpUser()
self.file_segment_len = 128
self.cfdp_user.transaction_indication = MagicMock()
self.cfdp_user.eof_recv_indication = MagicMock()
self.cfdp_user.file_segment_recv_indication = MagicMock()
self.cfdp_user.transaction_finished_indication = MagicMock()
self.file_segment_len = 128
self.remote_cfg_table = RemoteEntityCfgTable()
self.timeout_nak_procedure_seconds = 0.05
self.timeout_positive_ack_procedure_seconds = 0.05
Expand Down Expand Up @@ -160,6 +165,7 @@ def _generic_transfer_init(
expected_init_packets: int,
expected_init_state: CfdpState,
expected_init_step: TransactionStep,
expected_originating_id: Optional[TransactionId] = None,
) -> FsmResult:
checksum_type = ChecksumType.NULL_CHECKSUM
if file_size > 0:
Expand All @@ -178,7 +184,8 @@ def _generic_transfer_init(
None, expected_init_packets, expected_init_state, expected_init_step
)
self.dest_handler.insert_packet(file_transfer_init)
return self.dest_handler.state_machine()
fsm_res = self.dest_handler.state_machine()
return fsm_res

def _insert_file_segment(
self,
Expand Down
26 changes: 20 additions & 6 deletions tests/cfdp/test_src_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from dataclasses import dataclass
import tempfile
from pathlib import Path
from typing import Optional, Tuple
from typing import Optional, Tuple, cast
from unittest import TestCase
from unittest.mock import MagicMock

Expand All @@ -30,6 +30,7 @@
from tmtccmd.cfdp.handler import SourceHandler, FsmResult
from tmtccmd.cfdp.exceptions import UnretrievedPdusToBeSent
from tmtccmd.cfdp.handler.source import TransactionStep
from tmtccmd.cfdp.user import TransactionParams
from tmtccmd.cfdp.request import PutRequest
from tmtccmd.util import SeqCountProvider
from .cfdp_fault_handler_mock import FaultHandler
Expand Down Expand Up @@ -252,6 +253,7 @@ def _start_source_transaction(
self,
dest_id: UnsignedByteField,
put_request: PutRequest,
expected_originating_id: Optional[TransactionId] = None,
) -> Tuple[MetadataPdu, TransactionId]:
self.source_handler.put_request(put_request)
fsm_res = self.source_handler.state_machine()
Expand All @@ -263,11 +265,7 @@ def _start_source_transaction(
)
transaction_id = self.source_handler.transaction_id
assert transaction_id is not None
self.cfdp_user.transaction_indication.assert_called_once()
self.assertEqual(self.cfdp_user.transaction_indication.call_count, 1)
self.assertEqual(len(self.cfdp_user.transaction_indication.call_args[0]), 1)
call_args = self.cfdp_user.transaction_indication.call_args[0]
self.assertEqual(call_args[0], transaction_id)
self._verify_transaction_indication(expected_originating_id)
next_packet = self.source_handler.get_next_packet()
assert next_packet is not None
self.assertEqual(next_packet.pdu_type, PduType.FILE_DIRECTIVE)
Expand All @@ -284,6 +282,22 @@ def _start_source_transaction(
self.assertEqual(metadata_pdu.dest_entity_id, dest_id)
return metadata_pdu, transaction_id

def _verify_transaction_indication(
self, expected_originating_id: Optional[TransactionId]
):
self.cfdp_user.transaction_indication.assert_called_once()
self.assertEqual(self.cfdp_user.transaction_indication.call_count, 1)
transaction_params = cast(
TransactionParams,
self.cfdp_user.transaction_indication.call_args.args[0],
)
self.assertEqual(
transaction_params.transaction_id, self.source_handler.transaction_id
)
self.assertEqual(
transaction_params.originating_transaction_id, expected_originating_id
)

def _verify_eof_indication(self, expected_transaction_id: TransactionId):
self.source_handler.state_machine()
self.cfdp_user.eof_sent_indication.assert_called_once()
Expand Down
9 changes: 7 additions & 2 deletions tests/cfdp/test_src_handler_nak_no_closure.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from tmtccmd.cfdp.handler import FsmResult
from tmtccmd.cfdp.handler.source import TransactionStep
from tmtccmd.cfdp.request import PutRequest
from tmtccmd.cfdp.user import TransactionFinishedParams
from tmtccmd.cfdp.user import TransactionFinishedParams, TransactionParams
from .test_src_handler import TestCfdpSourceHandler


Expand Down Expand Up @@ -149,7 +149,9 @@ def test_proxy_get_request(self):
expected_id = TransactionId(
metadata_pdu.source_entity_id, metadata_pdu.transaction_seq_num
)
self.cfdp_user.transaction_indication.assert_called_once_with(expected_id)
self.cfdp_user.transaction_indication.assert_called_once_with(
TransactionParams(expected_id)
)
# Now the state machine should be finished.
fsm_res = self.source_handler.state_machine()
finished_params = TransactionFinishedParams(
Expand All @@ -165,6 +167,9 @@ def test_proxy_get_request(self):
)
self._state_checker(fsm_res, 0, CfdpState.IDLE, TransactionStep.IDLE)

def test_put_req_by_proxy_op(self):
pass

def _second_file_segment_handling(self) -> FileDataPdu:
fsm_res = self.source_handler.state_machine()
self.assertEqual(fsm_res.states.state, CfdpState.BUSY)
Expand Down
17 changes: 15 additions & 2 deletions tmtccmd/cfdp/handler/source.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
)
from tmtccmd.cfdp.mib import CheckTimerProvider, EntityType, RemoteEntityCfgTable
from tmtccmd.cfdp.request import PutRequest
from tmtccmd.cfdp.user import TransactionFinishedParams
from tmtccmd.cfdp.user import TransactionFinishedParams, TransactionParams
from tmtccmd.util import ProvidesSeqCount
from tmtccmd.util.countdown import Countdown
from tmtccmd.version import get_version
Expand Down Expand Up @@ -522,6 +522,7 @@ def _fsm_non_idle(self):

def _transaction_start(self):
file_size = 0
originating_transaction_id = self._check_for_originating_id()
self._prepare_file_params()
self._prepare_pdu_conf(file_size)
self._get_next_transfer_seq_num()
Expand All @@ -530,7 +531,19 @@ def _transaction_start(self):
source_entity_id=self.cfg.local_entity_id,
transaction_seq_num=self.transaction_seq_num,
)
self.user.transaction_indication(self._params.transaction_id)
self.user.transaction_indication(
TransactionParams(self._params.transaction_id, originating_transaction_id)
)

def _check_for_originating_id(self) -> Optional[TransactionId]:
if self._put_req.msgs_to_user is None:
return None
for msgs_to_user in self._put_req.msgs_to_user:
if msgs_to_user.is_reserved_cfdp_message():
reserved_cfdp_msg = msgs_to_user.to_reserved_msg_tlv()
if reserved_cfdp_msg.is_originating_transaction_id():
return reserved_cfdp_msg.get_originating_transaction_id()
return None

def _prepare_file_params(self):
assert self._put_req is not None
Expand Down
18 changes: 16 additions & 2 deletions tmtccmd/cfdp/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@
_LOGGER = logging.getLogger(__name__)


@dataclass
class TransactionParams:
"""Not wholly standard conformant here, but supplying the originating transaction ID
makes the implementation of handling with proxy put requests easier."""

transaction_id: TransactionId
originating_transaction_id: Optional[TransactionId] = None


@dataclass
class MetadataRecvParams:
transaction_id: TransactionId
Expand Down Expand Up @@ -59,9 +68,14 @@ def __init__(self, vfs: Optional[VirtualFilestore] = None):
self.vfs = vfs

@abstractmethod
def transaction_indication(self, transaction_id: TransactionId):
def transaction_indication(
self,
transaction_indication_params: TransactionParams,
):
"""This indication is used to report the transaction ID to the CFDP user"""
_LOGGER.info(f"Transaction.indication for {transaction_id}")
_LOGGER.info(
f"Transaction.indication for {transaction_indication_params.transaction_id}"
)

@abstractmethod
def eof_sent_indication(self, transaction_id: TransactionId):
Expand Down

0 comments on commit ec29a63

Please sign in to comment.