#include #include #include "fsfw/cfdp.h" #include "fsfw/cfdp/handler/PutRequest.h" #include "fsfw/cfdp/handler/SourceHandler.h" #include "fsfw/cfdp/pdu/EofPduCreator.h" #include "fsfw/cfdp/pdu/EofPduReader.h" #include "fsfw/cfdp/pdu/MetadataPduCreator.h" #include "fsfw/cfdp/pdu/MetadataPduReader.h" #include "fsfw/tmtcservices/TmTcMessage.h" #include "fsfw/util/SeqCountProvider.h" #include "mocks/AcceptsTmMock.h" #include "mocks/EventReportingProxyMock.h" #include "mocks/FilesystemMock.h" #include "mocks/MessageQueueMock.h" #include "mocks/StorageManagerMock.h" #include "mocks/cfdp/FaultHandlerMock.h" #include "mocks/cfdp/RemoteConfigTableMock.h" #include "mocks/cfdp/UserMock.h" TEST_CASE("CFDP Source Handler", "[cfdp]") { using namespace cfdp; using namespace returnvalue; using namespace std::filesystem; MessageQueueId_t destQueueId = 2; AcceptsTmMock tmReceiver(destQueueId); MessageQueueMock mqMock(destQueueId); EntityId localId = EntityId(UnsignedByteField(2)); EntityId remoteId = EntityId(UnsignedByteField(3)); FaultHandlerMock fhMock; LocalEntityCfg localEntityCfg(localId, IndicationCfg(), fhMock); FilesystemMock fsMock; UserMock userMock(fsMock); SeqCountProviderU16 seqCountProvider; SourceHandlerParams dp(localEntityCfg, userMock, seqCountProvider); EventReportingProxyMock eventReporterMock; LocalPool::LocalPoolConfig storeCfg = {{10, 32}, {10, 64}, {10, 128}, {10, 1024}}; StorageManagerMock tcStore(2, storeCfg); StorageManagerMock tmStore(3, storeCfg); FsfwParams fp(tmReceiver, &mqMock, &eventReporterMock); fp.tcStore = &tcStore; fp.tmStore = &tmStore; auto sourceHandler = SourceHandler(dp, fp); RemoteEntityCfg cfg; EntityId id(cfdp::WidthInBytes::TWO_BYTES, 5); cfg.remoteId = id; std::string srcFileName = "/tmp/cfdp-test.txt"; std::string destFileName = "/tmp/cfdp-test2.txt"; FilesystemParams srcFileNameFs(srcFileName.c_str()); fsMock.createFile(srcFileNameFs); cfdp::StringLv srcNameLv(srcFileNameFs.path, std::strlen(srcFileNameFs.path)); FilesystemParams destFileNameFs(destFileName.c_str()); cfdp::StringLv destNameLv(destFileNameFs.path, std::strlen(destFileNameFs.path)); PutRequest putRequest(id, srcNameLv, destNameLv); CHECK(sourceHandler.initialize() == OK); auto genericMetadataCheck = [&](SourceHandler::FsmResult& fsmResult, size_t expectedFileSize) { TmTcMessage tmtcMessage; const uint8_t* pduPtr; CHECK(fsmResult.packetsSent == 1); CHECK(mqMock.numberOfSentMessages() == 1); REQUIRE(mqMock.getNextSentMessage(destQueueId, tmtcMessage) == OK); auto accessor = tmStore.getData(tmtcMessage.getStorageId()); REQUIRE(accessor.first == OK); pduPtr = accessor.second.data(); CHECK(accessor.second.size() == 55); MetadataGenericInfo metadataInfo; MetadataPduReader metadataReader(pduPtr, accessor.second.size(), metadataInfo, nullptr, 0); REQUIRE(metadataReader.parseData() == OK); std::string srcNameRead = metadataReader.getSourceFileName().getString(); CHECK(srcNameRead == srcFileName); std::string destNameRead = metadataReader.getDestFileName().getString(); CHECK(destNameRead == destFileName); if (expectedFileSize == 0) { CHECK(metadataInfo.getChecksumType() == ChecksumType::NULL_CHECKSUM); } else { CHECK(metadataInfo.getChecksumType() == ChecksumType::CRC_32); } CHECK(metadataInfo.getFileSize().value() == expectedFileSize); CHECK(!metadataInfo.isClosureRequested()); mqMock.clearMessages(); }; auto genericEofCheck = [&](SourceHandler::FsmResult& fsmResult, size_t expectedFileSize, uint32_t expectedChecksum) { TmTcMessage tmtcMessage; const uint8_t* pduPtr; CHECK(fsmResult.packetsSent == 1); CHECK(mqMock.numberOfSentMessages() == 1); REQUIRE(mqMock.getNextSentMessage(destQueueId, tmtcMessage) == OK); auto accessor = tmStore.getData(tmtcMessage.getStorageId()); REQUIRE(accessor.first == OK); pduPtr = accessor.second.data(); // 10 byte PDU header, 1 byte directive field, 1 byte condition code, 4 byte checksum, // 4 byte FSS CHECK(accessor.second.size() == 20); EofInfo eofInfo; EofPduReader eofReader(pduPtr, accessor.second.size(), eofInfo); REQUIRE(eofReader.parseData() == OK); CHECK(eofInfo.getChecksum() == expectedChecksum); CHECK(eofInfo.getConditionCode() == ConditionCode::NO_ERROR); CHECK(eofInfo.getFileSize().value() == expectedFileSize); }; SECTION("Test Basic") { CHECK(sourceHandler.getState() == CfdpState::IDLE); CHECK(sourceHandler.getStep() == SourceHandler::TransactionStep::IDLE); } SECTION("Transfer empty file") { CHECK(sourceHandler.transactionStart(putRequest, cfg) == OK); size_t expectedFileSize = 0; SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachine(); // Verify metadata PDU was sent. genericMetadataCheck(fsmResult, expectedFileSize); fsmResult = sourceHandler.stateMachine(); // Verify EOF PDU was sent. No file data PDU is sent for an empty file and the checksum is 0. genericEofCheck(fsmResult, expectedFileSize, 0); CHECK(sourceHandler.getStep() == SourceHandler::TransactionStep::IDLE); CHECK(sourceHandler.getState() == CfdpState::IDLE); } SECTION("Transfer small file") { fsMock.createFile(srcFileNameFs); std::string fileContent = "hello world\n"; size_t expectedFileSize = fileContent.size(); FileOpParams params(srcFileName.c_str(), expectedFileSize); fsMock.writeToFile(params, reinterpret_cast(fileContent.data())); CHECK(sourceHandler.transactionStart(putRequest, cfg) == OK); SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachine(); // Verify metadata PDU was sent. genericMetadataCheck(fsmResult, expectedFileSize); fsmResult = sourceHandler.stateMachine(); // TODO: Verify one file data PDU was sent. CHECK(fsmResult.packetsSent == 1); // TODO: Verify one EOF PDU was sent. } SECTION("Transfer two segment file") {} }