Merge remote-tracking branch 'eive/develop' into bump-fsfw
This commit is contained in:
@ -32,7 +32,7 @@ void Factory::produceFrameworkObjects(void* args) {
|
||||
setStaticFrameworkObjectIds();
|
||||
new EventManager(objects::EVENT_MANAGER, 80);
|
||||
new HealthTable(objects::HEALTH_TABLE);
|
||||
new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER, 20, false, 1.0);
|
||||
new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER, 20, false, 5.0);
|
||||
|
||||
{
|
||||
PoolManager::LocalPoolConfig poolCfg = {{100, 16}, {50, 32}, {25, 64}, {15, 128}, {5, 1024}};
|
||||
|
@ -57,7 +57,7 @@ TEST_CASE("Action Helper", "[action]") {
|
||||
step += 1;
|
||||
CHECK(testMqMock.wasMessageSent());
|
||||
CommandMessage testMessage;
|
||||
REQUIRE(testMqMock.getNextSentMessage(testMessage) == returnvalue::OK);
|
||||
REQUIRE(testMqMock.getNextSentMessageToDefaultDest(testMessage) == returnvalue::OK);
|
||||
REQUIRE(testMessage.getCommand() == static_cast<uint32_t>(ActionMessage::STEP_FAILED));
|
||||
REQUIRE(testMessage.getParameter() == static_cast<uint32_t>(testActionId));
|
||||
uint32_t parameter2 = ((uint32_t)step << 16) | (uint32_t)status;
|
||||
@ -71,7 +71,7 @@ TEST_CASE("Action Helper", "[action]") {
|
||||
actionHelper.finish(false, testMqMock.getId(), testActionId, status);
|
||||
CHECK(testMqMock.wasMessageSent());
|
||||
CommandMessage testMessage;
|
||||
REQUIRE(testMqMock.getNextSentMessage(testMessage) == returnvalue::OK);
|
||||
REQUIRE(testMqMock.getNextSentMessageToDefaultDest(testMessage) == returnvalue::OK);
|
||||
REQUIRE(testMessage.getCommand() == static_cast<uint32_t>(ActionMessage::COMPLETION_FAILED));
|
||||
REQUIRE(ActionMessage::getActionId(&testMessage) == testActionId);
|
||||
REQUIRE(ActionMessage::getReturnCode(&testMessage) == static_cast<uint32_t>(status));
|
||||
@ -87,7 +87,7 @@ TEST_CASE("Action Helper", "[action]") {
|
||||
REQUIRE(ipcStore->getData(toLongParamAddress).first ==
|
||||
static_cast<uint32_t>(StorageManagerIF::DATA_DOES_NOT_EXIST));
|
||||
CommandMessage testMessage;
|
||||
REQUIRE(testMqMock.getNextSentMessage(testMessage) == returnvalue::OK);
|
||||
REQUIRE(testMqMock.getNextSentMessageToDefaultDest(testMessage) == returnvalue::OK);
|
||||
REQUIRE(testMessage.getCommand() == static_cast<uint32_t>(ActionMessage::STEP_FAILED));
|
||||
REQUIRE(ActionMessage::getReturnCode(&testMessage) == 0xAFFE);
|
||||
REQUIRE(ActionMessage::getStep(&testMessage) == 0);
|
||||
|
@ -1,5 +1,6 @@
|
||||
target_sources(${FSFW_TEST_TGT} PRIVATE testCfdp.cpp testOtherTlvs.cpp
|
||||
testTlv.cpp testLvs.cpp)
|
||||
target_sources(
|
||||
${FSFW_TEST_TGT} PRIVATE testCfdp.cpp testOtherTlvs.cpp
|
||||
testReservedMsgCreator.cpp testTlv.cpp testLvs.cpp)
|
||||
|
||||
add_subdirectory(handler)
|
||||
add_subdirectory(pdu)
|
||||
|
@ -1,3 +1,4 @@
|
||||
target_sources(
|
||||
${FSFW_TEST_TGT} PRIVATE testDistributor.cpp testDestHandler.cpp
|
||||
testSourceHandler.cpp testFaultHandler.cpp)
|
||||
${FSFW_TEST_TGT}
|
||||
PRIVATE testDistributor.cpp testDestHandler.cpp testReservedMsgParser.cpp
|
||||
testPutRequest.cpp testSourceHandler.cpp testFaultHandler.cpp)
|
||||
|
@ -50,18 +50,18 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
|
||||
auto destHandler = DestHandler(dp, fp);
|
||||
CHECK(destHandler.initialize() == OK);
|
||||
|
||||
auto metadataPreparation = [&](FileSize cfdpFileSize, ChecksumType checksumType) {
|
||||
auto metadataPreparation = [&](Fss cfdpFileSize, ChecksumType checksumType) {
|
||||
std::string srcNameString = "hello.txt";
|
||||
std::string destNameString = "hello-cpy.txt";
|
||||
StringLv srcName(srcNameString);
|
||||
StringLv destName(destNameString);
|
||||
MetadataInfo info(false, checksumType, cfdpFileSize, srcName, destName);
|
||||
MetadataGenericInfo info(false, checksumType, std::move(cfdpFileSize));
|
||||
TransactionSeqNum seqNum(UnsignedByteField<uint16_t>(1));
|
||||
conf.sourceId = remoteId;
|
||||
conf.destId = localId;
|
||||
conf.mode = TransmissionMode::UNACKNOWLEDGED;
|
||||
conf.seqNum = seqNum;
|
||||
MetadataPduCreator metadataCreator(conf, info);
|
||||
MetadataPduCreator metadataCreator(conf, info, srcName, destName, nullptr, 0);
|
||||
REQUIRE(tcStore.getFreeElement(&storeId, metadataCreator.getSerializedSize(), &buf) == OK);
|
||||
REQUIRE(metadataCreator.serialize(buf, serLen, metadataCreator.getSerializedSize()) == OK);
|
||||
PacketInfo packetInfo(metadataCreator.getPduType(), storeId,
|
||||
@ -81,17 +81,17 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
|
||||
auto& idMetadataPair = userMock.metadataRecvd.back();
|
||||
REQUIRE(idMetadataPair.first == destHandler.getTransactionId());
|
||||
REQUIRE(idMetadataPair.second.sourceId.getValue() == 3);
|
||||
REQUIRE(idMetadataPair.second.fileSize == fileLen);
|
||||
REQUIRE(idMetadataPair.second.fileSize.getSize(nullptr) == fileLen);
|
||||
REQUIRE(strcmp(idMetadataPair.second.destFileName, destName) == 0);
|
||||
REQUIRE(strcmp(idMetadataPair.second.sourceFileName, sourceName) == 0);
|
||||
userMock.metadataRecvd.pop();
|
||||
REQUIRE(fsMock.fileMap.find(destName) != fsMock.fileMap.end());
|
||||
REQUIRE(res.result == OK);
|
||||
REQUIRE(res.state == CfdpStates::BUSY_CLASS_1_NACKED);
|
||||
REQUIRE(res.state == CfdpState::BUSY_CLASS_1_NACKED);
|
||||
REQUIRE(res.step == DestHandler::TransactionStep::RECEIVING_FILE_DATA_PDUS);
|
||||
};
|
||||
|
||||
auto eofPreparation = [&](FileSize cfdpFileSize, uint32_t crc) {
|
||||
auto eofPreparation = [&](Fss cfdpFileSize, uint32_t crc) {
|
||||
EofInfo eofInfo(cfdp::ConditionCode::NO_ERROR, crc, std::move(cfdpFileSize));
|
||||
EofPduCreator eofCreator(conf, eofInfo);
|
||||
REQUIRE(tcStore.getFreeElement(&storeId, eofCreator.getSerializedSize(), &buf) == OK);
|
||||
@ -102,14 +102,14 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
|
||||
|
||||
auto eofCheck = [&](const cfdp::DestHandler::FsmResult& res, const TransactionId& id) {
|
||||
REQUIRE(res.result == OK);
|
||||
REQUIRE(res.state == CfdpStates::IDLE);
|
||||
REQUIRE(res.state == CfdpState::IDLE);
|
||||
REQUIRE(res.errors == 0);
|
||||
REQUIRE(res.step == DestHandler::TransactionStep::IDLE);
|
||||
// Assert that the packet was deleted after handling
|
||||
REQUIRE(not tcStore.hasDataAtId(storeId));
|
||||
REQUIRE(packetInfoList.empty());
|
||||
REQUIRE(userMock.eofsRevd.size() == 1);
|
||||
auto& eofId = userMock.eofsRevd.back();
|
||||
REQUIRE(userMock.eofRecvdRecvd.size() == 1);
|
||||
auto& eofId = userMock.eofRecvdRecvd.back();
|
||||
CHECK(eofId == id);
|
||||
REQUIRE(userMock.finishedRecvd.size() == 1);
|
||||
auto& idParamPair = userMock.finishedRecvd.back();
|
||||
@ -120,7 +120,7 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
|
||||
auto fileDataPduCheck = [&](const cfdp::DestHandler::FsmResult& res,
|
||||
const std::vector<store_address_t>& idsToCheck) {
|
||||
REQUIRE(res.result == OK);
|
||||
REQUIRE(res.state == CfdpStates::BUSY_CLASS_1_NACKED);
|
||||
REQUIRE(res.state == CfdpState::BUSY_CLASS_1_NACKED);
|
||||
REQUIRE(res.step == DestHandler::TransactionStep::RECEIVING_FILE_DATA_PDUS);
|
||||
for (const auto id : idsToCheck) {
|
||||
REQUIRE(not tcStore.hasDataAtId(id));
|
||||
@ -129,50 +129,50 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
|
||||
};
|
||||
|
||||
SECTION("State") {
|
||||
CHECK(destHandler.getCfdpState() == CfdpStates::IDLE);
|
||||
CHECK(destHandler.getCfdpState() == CfdpState::IDLE);
|
||||
CHECK(destHandler.getTransactionStep() == DestHandler::TransactionStep::IDLE);
|
||||
}
|
||||
|
||||
SECTION("Idle State Machine Iteration") {
|
||||
auto res = destHandler.performStateMachine();
|
||||
auto res = destHandler.stateMachine();
|
||||
CHECK(res.result == OK);
|
||||
CHECK(res.callStatus == CallStatus::CALL_AFTER_DELAY);
|
||||
CHECK(res.errors == 0);
|
||||
CHECK(destHandler.getCfdpState() == CfdpStates::IDLE);
|
||||
CHECK(destHandler.getCfdpState() == CfdpState::IDLE);
|
||||
CHECK(destHandler.getTransactionStep() == DestHandler::TransactionStep::IDLE);
|
||||
}
|
||||
|
||||
SECTION("Empty File Transfer") {
|
||||
const DestHandler::FsmResult& res = destHandler.performStateMachine();
|
||||
const DestHandler::FsmResult& res = destHandler.stateMachine();
|
||||
CHECK(res.result == OK);
|
||||
FileSize cfdpFileSize(0);
|
||||
Fss cfdpFileSize(0);
|
||||
metadataPreparation(cfdpFileSize, ChecksumType::NULL_CHECKSUM);
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
metadataCheck(res, "hello.txt", "hello-cpy.txt", 0);
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY);
|
||||
auto transactionId = destHandler.getTransactionId();
|
||||
eofPreparation(cfdpFileSize, 0);
|
||||
// After EOF, operation is done because no closure was requested
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
eofCheck(res, transactionId);
|
||||
}
|
||||
|
||||
SECTION("Small File Transfer") {
|
||||
const DestHandler::FsmResult& res = destHandler.performStateMachine();
|
||||
const DestHandler::FsmResult& res = destHandler.stateMachine();
|
||||
CHECK(res.result == OK);
|
||||
std::string fileData = "hello test data";
|
||||
etl::crc32 crcCalc;
|
||||
crcCalc.add(fileData.begin(), fileData.end());
|
||||
uint32_t crc32 = crcCalc.value();
|
||||
FileSize cfdpFileSize(fileData.size());
|
||||
Fss cfdpFileSize(fileData.size());
|
||||
metadataPreparation(cfdpFileSize, ChecksumType::CRC_32);
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
metadataCheck(res, "hello.txt", "hello-cpy.txt", fileData.size());
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY);
|
||||
auto transactionId = destHandler.getTransactionId();
|
||||
FileSize offset(0);
|
||||
Fss offset(0);
|
||||
FileDataInfo fdPduInfo(offset, reinterpret_cast<const uint8_t*>(fileData.data()),
|
||||
fileData.size());
|
||||
FileDataCreator fdPduCreator(conf, fdPduInfo);
|
||||
@ -180,16 +180,16 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
|
||||
REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK);
|
||||
PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt);
|
||||
packetInfoList.push_back(packetInfo);
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
fileDataPduCheck(res, {storeId});
|
||||
eofPreparation(cfdpFileSize, crc32);
|
||||
// After EOF, operation is done because no closure was requested
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
eofCheck(res, transactionId);
|
||||
}
|
||||
|
||||
SECTION("Segmented File Transfer") {
|
||||
const DestHandler::FsmResult& res = destHandler.performStateMachine();
|
||||
const DestHandler::FsmResult& res = destHandler.stateMachine();
|
||||
CHECK(res.result == OK);
|
||||
std::random_device dev;
|
||||
std::mt19937 rng(dev());
|
||||
@ -201,17 +201,17 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
|
||||
etl::crc32 crcCalc;
|
||||
crcCalc.add(largerFileData.begin(), largerFileData.end());
|
||||
uint32_t crc32 = crcCalc.value();
|
||||
FileSize cfdpFileSize(largerFileData.size());
|
||||
Fss cfdpFileSize(largerFileData.size());
|
||||
metadataPreparation(cfdpFileSize, ChecksumType::CRC_32);
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
metadataCheck(res, "hello.txt", "hello-cpy.txt", largerFileData.size());
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY);
|
||||
auto transactionId = destHandler.getTransactionId();
|
||||
|
||||
std::vector<store_address_t> idsToCheck;
|
||||
{
|
||||
FileSize offset(0);
|
||||
Fss offset(0);
|
||||
FileDataInfo fdPduInfo(offset, reinterpret_cast<const uint8_t*>(largerFileData.data()),
|
||||
largerFileData.size() / 2);
|
||||
FileDataCreator fdPduCreator(conf, fdPduInfo);
|
||||
@ -223,7 +223,7 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
|
||||
}
|
||||
|
||||
{
|
||||
FileSize offset(512);
|
||||
Fss offset(512);
|
||||
FileDataInfo fdPduInfo(offset, reinterpret_cast<const uint8_t*>(largerFileData.data() + 512),
|
||||
largerFileData.size() / 2);
|
||||
FileDataCreator fdPduCreator(conf, fdPduInfo);
|
||||
@ -234,11 +234,11 @@ TEST_CASE("CFDP Dest Handler", "[cfdp]") {
|
||||
packetInfoList.push_back(packetInfo);
|
||||
}
|
||||
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
fileDataPduCheck(res, idsToCheck);
|
||||
eofPreparation(cfdpFileSize, crc32);
|
||||
// After EOF, operation is done because no closure was requested
|
||||
destHandler.performStateMachine();
|
||||
destHandler.stateMachine();
|
||||
eofCheck(res, transactionId);
|
||||
}
|
||||
}
|
@ -21,7 +21,7 @@ TEST_CASE("CFDP Distributor", "[cfdp][distributor]") {
|
||||
auto tcAcceptor = AcceptsTcMock("CFDP Receiver", 0, receiverQueueId);
|
||||
|
||||
// Set up Metadata PDU for generate test data.
|
||||
cfdp::FileSize fileSize(12);
|
||||
cfdp::Fss fileSize(12);
|
||||
const cfdp::EntityId& sourceId(groundEntityId);
|
||||
const cfdp::EntityId& destId(obswEntityId);
|
||||
cfdp::TransactionSeqNum seqNum(UnsignedByteField<uint16_t>(12));
|
||||
@ -30,9 +30,8 @@ TEST_CASE("CFDP Distributor", "[cfdp][distributor]") {
|
||||
cfdp::StringLv sourceFileName(sourceFileString);
|
||||
std::string destFileString = "hello2.txt";
|
||||
cfdp::StringLv destFileName(destFileString);
|
||||
MetadataInfo metadataInfo(false, cfdp::ChecksumType::CRC_32, fileSize, sourceFileName,
|
||||
destFileName);
|
||||
MetadataPduCreator creator(pduConf, metadataInfo);
|
||||
MetadataGenericInfo metadataInfo(false, cfdp::ChecksumType::CRC_32, fileSize);
|
||||
MetadataPduCreator creator(pduConf, metadataInfo, sourceFileName, destFileName, nullptr, 0);
|
||||
uint8_t* dataPtr = nullptr;
|
||||
|
||||
SECTION("State") {
|
||||
|
59
unittests/cfdp/handler/testPutRequest.cpp
Normal file
59
unittests/cfdp/handler/testPutRequest.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
#include <array>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "fsfw/cfdp/handler/PutRequest.h"
|
||||
#include "fsfw/cfdp/tlv/ReservedMessageCreator.h"
|
||||
|
||||
TEST_CASE("Put Request", "[cfdp]") {
|
||||
using namespace cfdp;
|
||||
using namespace returnvalue;
|
||||
|
||||
std::array<uint8_t, 32> reservedMsgCustomData{};
|
||||
std::array<uint8_t, 128> reservedMsgBuf{};
|
||||
std::array<uint8_t, 128> buffer{};
|
||||
EntityId destId(WidthInBytes::ONE_BYTE, 5);
|
||||
std::string srcFileName = "hello.txt";
|
||||
std::string destFileName = "hello2.txt";
|
||||
uint8_t* msgBufPtr = reservedMsgCustomData.data();
|
||||
size_t msgSize = 0;
|
||||
cfdp::StringLv srcName(srcFileName);
|
||||
cfdp::StringLv destName(destFileName);
|
||||
CHECK(destId.serializeAsLv(&msgBufPtr, &msgSize, reservedMsgCustomData.size()) == OK);
|
||||
CHECK(srcName.serialize(&msgBufPtr, &msgSize, reservedMsgCustomData.size(),
|
||||
SerializeIF::Endianness::NETWORK) == OK);
|
||||
CHECK(destName.serialize(&msgBufPtr, &msgSize, reservedMsgCustomData.size(),
|
||||
SerializeIF::Endianness::NETWORK) == OK);
|
||||
ReservedMessageCreator creator(static_cast<uint8_t>(ProxyOpMessageType::PUT_REQUEST),
|
||||
reservedMsgCustomData.data(), msgSize);
|
||||
msgSize = 0;
|
||||
ReturnValue_t result = creator.serializeBe(reservedMsgBuf.data(), msgSize, buffer.size());
|
||||
CHECK(result == returnvalue::OK);
|
||||
|
||||
SECTION("Put Request with reserved message") {
|
||||
PutRequest putRequest(destId, reservedMsgBuf.data(), msgSize, nullptr, 0);
|
||||
uint8_t* bufPtr = buffer.data();
|
||||
size_t serLen = 0;
|
||||
REQUIRE(putRequest.serialize(&bufPtr, &serLen, buffer.size(),
|
||||
SerializeIF::Endianness::NETWORK) == OK);
|
||||
|
||||
CHECK(putRequest.getSerializedSize() == serLen);
|
||||
PutRequest requestDeserialized;
|
||||
size_t deserLen = putRequest.getSerializedSize();
|
||||
const uint8_t* deserPtr = buffer.data();
|
||||
REQUIRE(requestDeserialized.deSerialize(&deserPtr, &deserLen,
|
||||
SerializeIF::Endianness::NETWORK) == OK);
|
||||
CHECK(requestDeserialized.getDestId().getWidth() == destId.getWidth());
|
||||
CHECK(requestDeserialized.getDestId().getValue() == destId.getValue());
|
||||
size_t totalMsgsSize = 0;
|
||||
const uint8_t* msgsToUserStart = requestDeserialized.getMessagesToUser(totalMsgsSize);
|
||||
CHECK(totalMsgsSize == msgSize);
|
||||
cfdp::Tlv genericTlv;
|
||||
genericTlv.deSerialize(&msgsToUserStart, &totalMsgsSize, SerializeIF::Endianness::NETWORK);
|
||||
CHECK(genericTlv.getType() == TlvType::MSG_TO_USER);
|
||||
CHECK(genericTlv.getLengthField() == genericTlv.getSerializedSize() - 2);
|
||||
CHECK(genericTlv.getValue()[0] == 'c');
|
||||
CHECK(genericTlv.getValue()[1] == 'f');
|
||||
CHECK(genericTlv.getValue()[2] == 'd');
|
||||
CHECK(genericTlv.getValue()[3] == 'p');
|
||||
}
|
||||
}
|
67
unittests/cfdp/handler/testReservedMsgParser.cpp
Normal file
67
unittests/cfdp/handler/testReservedMsgParser.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "fsfw/cfdp/CfdpMessage.h"
|
||||
#include "fsfw/cfdp/VarLenFields.h"
|
||||
#include "fsfw/cfdp/handler/PutRequest.h"
|
||||
#include "fsfw/cfdp/handler/ReservedMessageParser.h"
|
||||
#include "fsfw/cfdp/tlv/Lv.h"
|
||||
#include "fsfw/cfdp/tlv/ReservedMessageCreator.h"
|
||||
#include "fsfw/cfdp/tlv/StringLv.h"
|
||||
#include "fsfw/globalfunctions/arrayprinter.h"
|
||||
#include "fsfw/serialize.h"
|
||||
#include "mocks/MessageQueueMock.h"
|
||||
#include "mocks/StorageManagerMock.h"
|
||||
|
||||
TEST_CASE("Reserved Message Parser", "[cfdp]") {
|
||||
using namespace cfdp;
|
||||
using namespace returnvalue;
|
||||
|
||||
std::string srcFileName = "hello.txt";
|
||||
std::string destFileName = "hello2.txt";
|
||||
MessageQueueId_t destQueueId = 2;
|
||||
MessageQueueMock msgQueue(1);
|
||||
LocalPool::LocalPoolConfig storeCfg = {{10, 32}, {10, 64}, {10, 128}, {10, 1024}};
|
||||
StorageManagerMock ipcStore(0, storeCfg);
|
||||
std::array<uint8_t, 128> buffer{};
|
||||
uint8_t msgBuf[32]{};
|
||||
|
||||
EntityId entityId(cfdp::WidthInBytes::ONE_BYTE, 5);
|
||||
uint8_t* msgBufPtr = msgBuf;
|
||||
size_t serLen = 0;
|
||||
cfdp::StringLv srcName(srcFileName);
|
||||
cfdp::StringLv destName(destFileName);
|
||||
CHECK(entityId.serializeAsLv(&msgBufPtr, &serLen, sizeof(msgBuf)) == OK);
|
||||
CHECK(srcName.serialize(&msgBufPtr, &serLen, sizeof(msgBuf), SerializeIF::Endianness::NETWORK) ==
|
||||
OK);
|
||||
CHECK(destName.serialize(&msgBufPtr, &serLen, sizeof(msgBuf), SerializeIF::Endianness::NETWORK) ==
|
||||
OK);
|
||||
ReservedMessageCreator creator(static_cast<uint8_t>(ProxyOpMessageType::PUT_REQUEST), msgBuf,
|
||||
serLen);
|
||||
serLen = 0;
|
||||
ReturnValue_t result = creator.serializeBe(buffer.data(), serLen, buffer.size());
|
||||
CHECK(result == returnvalue::OK);
|
||||
MessageToUserTlv msgToUser;
|
||||
CHECK(msgToUser.deSerializeBe(buffer.data(), serLen, buffer.size()) == OK);
|
||||
ReservedMessageParser parser(ipcStore, msgQueue, destQueueId);
|
||||
REQUIRE(parser.parse(&msgToUser, 1) == OK);
|
||||
CommandMessage msg;
|
||||
CHECK(msgQueue.wasMessageSent());
|
||||
CHECK(msgQueue.numberOfSentMessages() == 1);
|
||||
CHECK(msgQueue.getNextSentMessage(destQueueId, msg) == OK);
|
||||
store_address_t storeId = CfdpMessage::getStoreId(&msg);
|
||||
const uint8_t* data;
|
||||
size_t packetLen;
|
||||
CHECK(ipcStore.getData(storeId, &data, &packetLen) == OK);
|
||||
CHECK(packetLen > 0);
|
||||
PutRequest putRequest;
|
||||
size_t dummy = packetLen;
|
||||
REQUIRE(putRequest.deSerialize(&data, &dummy, SerializeIF::Endianness::MACHINE) == OK);
|
||||
CHECK(putRequest.getDestId().getValue() == entityId.getValue());
|
||||
CHECK(putRequest.getDestId().getWidth() == entityId.getWidth());
|
||||
auto& sourceNameLv = putRequest.getSourceName();
|
||||
std::string srcNameRead = sourceNameLv.getString();
|
||||
CHECK(srcNameRead == srcFileName);
|
||||
auto& destNameLv = putRequest.getDestName();
|
||||
std::string destNameRead = destNameLv.getString();
|
||||
CHECK(destNameRead == destFileName);
|
||||
}
|
@ -1,3 +1,286 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <etl/crc32.h>
|
||||
|
||||
TEST_CASE("CFDP Source Handler", "[cfdp]") {}
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <filesystem>
|
||||
#include <random>
|
||||
|
||||
#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/FileDataReader.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;
|
||||
const size_t MAX_FILE_SEGMENT_SIZE = 255;
|
||||
|
||||
MessageQueueId_t destQueueId = 2;
|
||||
AcceptsTmMock tmReceiver(destQueueId);
|
||||
MessageQueueMock mqMock(destQueueId);
|
||||
EntityId localId = EntityId(UnsignedByteField<uint16_t>(2));
|
||||
EntityId remoteId = EntityId(UnsignedByteField<uint16_t>(5));
|
||||
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;
|
||||
cfg.maxFileSegmentLen = MAX_FILE_SEGMENT_SIZE;
|
||||
cfg.remoteId = remoteId;
|
||||
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(remoteId, srcNameLv, destNameLv);
|
||||
CHECK(sourceHandler.initialize() == OK);
|
||||
|
||||
auto onePduSentCheck = [&](const SourceHandler::FsmResult& fsmResult, TmTcMessage& tmtcMessage,
|
||||
const uint8_t** pduPtr) {
|
||||
CHECK(fsmResult.errors == 0);
|
||||
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();
|
||||
return std::move(accessor);
|
||||
};
|
||||
auto genericMetadataCheck = [&](const SourceHandler::FsmResult& fsmResult,
|
||||
size_t expectedFileSize, uint16_t expectedSeqNum) {
|
||||
CHECK(fsmResult.errors == 0);
|
||||
CHECK(fsmResult.callStatus == CallStatus::CALL_AGAIN);
|
||||
TmTcMessage tmtcMessage;
|
||||
const uint8_t* pduPtr;
|
||||
auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr);
|
||||
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);
|
||||
TransactionSeqNum seqNum;
|
||||
metadataReader.getTransactionSeqNum(seqNum);
|
||||
CHECK(seqNum.getValue() == expectedSeqNum);
|
||||
CHECK(userMock.transactionIndicRecvd.size() == 1);
|
||||
CHECK(userMock.transactionIndicRecvd.back() == TransactionId(localId, seqNum));
|
||||
EntityId srcId;
|
||||
metadataReader.getSourceId(srcId);
|
||||
EntityId destId;
|
||||
metadataReader.getDestId(destId);
|
||||
CHECK(srcId.getValue() == localId.getValue());
|
||||
CHECK(destId.getValue() == remoteId.getValue());
|
||||
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 = [&](const SourceHandler::FsmResult& fsmResult, size_t expectedFileSize,
|
||||
uint32_t expectedChecksum, uint16_t expectedSeqNum) {
|
||||
CHECK(fsmResult.errors == 0);
|
||||
CHECK(fsmResult.callStatus == CallStatus::CALL_AGAIN);
|
||||
TmTcMessage tmtcMessage;
|
||||
const uint8_t* pduPtr;
|
||||
auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr);
|
||||
// 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);
|
||||
TransactionSeqNum seqNum;
|
||||
eofReader.getTransactionSeqNum(seqNum);
|
||||
CHECK(seqNum.getValue() == expectedSeqNum);
|
||||
auto transactionId = TransactionId(localId, seqNum);
|
||||
CHECK(userMock.eofSentRecvd.size() == 1);
|
||||
CHECK(userMock.eofSentRecvd.back() == transactionId);
|
||||
CHECK(eofInfo.getChecksum() == expectedChecksum);
|
||||
CHECK(eofInfo.getConditionCode() == ConditionCode::NO_ERROR);
|
||||
CHECK(eofInfo.getFileSize().value() == expectedFileSize);
|
||||
};
|
||||
auto genericNoticeOfCompletionCheck = [&](const SourceHandler::FsmResult& fsmResult,
|
||||
uint16_t expectedSeqNum) {
|
||||
CHECK(fsmResult.callStatus == CallStatus::DONE);
|
||||
CHECK(userMock.finishedRecvd.size() == 1);
|
||||
CHECK(userMock.finishedRecvd.back().first ==
|
||||
TransactionId(localId, TransactionSeqNum(cfdp::WidthInBytes::TWO_BYTES, expectedSeqNum)));
|
||||
CHECK(sourceHandler.getStep() == SourceHandler::TransactionStep::IDLE);
|
||||
CHECK(sourceHandler.getState() == CfdpState::IDLE);
|
||||
};
|
||||
|
||||
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;
|
||||
const SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachine();
|
||||
// Verify metadata PDU was sent.
|
||||
genericMetadataCheck(fsmResult, expectedFileSize, 0);
|
||||
|
||||
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, 0);
|
||||
|
||||
// Verify notice of completion.
|
||||
sourceHandler.stateMachine();
|
||||
genericNoticeOfCompletionCheck(fsmResult, 0);
|
||||
}
|
||||
|
||||
SECTION("Transfer small file") {
|
||||
uint16_t expectedSeqNum = 0;
|
||||
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<const uint8_t*>(fileContent.data()));
|
||||
CHECK(sourceHandler.transactionStart(putRequest, cfg) == OK);
|
||||
const SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachine();
|
||||
|
||||
// Verify metadata PDU was sent.
|
||||
genericMetadataCheck(fsmResult, expectedFileSize, expectedSeqNum);
|
||||
|
||||
// Verify that a small file data PDU was sent.
|
||||
sourceHandler.stateMachine();
|
||||
TmTcMessage tmtcMessage;
|
||||
const uint8_t* pduPtr;
|
||||
auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr);
|
||||
FileDataInfo fdInfo;
|
||||
FileDataReader fdReader(pduPtr, accessor.second.size(), fdInfo);
|
||||
// 10 byte PDU header, 4 byte offset, 12 bytes file data.
|
||||
CHECK(accessor.second.size() == 26);
|
||||
CHECK(fdReader.parseData() == OK);
|
||||
CHECK(fdInfo.getOffset().value() == 0);
|
||||
size_t fileSize = 0;
|
||||
const uint8_t* fileData = fdInfo.getFileData(&fileSize);
|
||||
REQUIRE(fileSize == fileContent.size());
|
||||
CHECK(fileData != nullptr);
|
||||
std::string dataReadBack(reinterpret_cast<const char*>(fileData), fileSize);
|
||||
CHECK(dataReadBack == fileContent);
|
||||
mqMock.clearMessages();
|
||||
|
||||
sourceHandler.stateMachine();
|
||||
|
||||
etl::crc32 crcCalc;
|
||||
crcCalc.add(fileContent.data(), fileContent.data() + fileContent.size());
|
||||
// Verify EOF PDU was sent.
|
||||
genericEofCheck(fsmResult, expectedFileSize, crcCalc.value(), expectedSeqNum);
|
||||
|
||||
// Verify notice of completion.
|
||||
sourceHandler.stateMachine();
|
||||
genericNoticeOfCompletionCheck(fsmResult, expectedSeqNum);
|
||||
}
|
||||
|
||||
SECTION("Transfer two segment file") {
|
||||
uint16_t expectedSeqNum = 0;
|
||||
// Create 400 bytes of random data. This should result in two file segments, with one
|
||||
// having the maximum size.
|
||||
std::random_device dev;
|
||||
std::mt19937 rng(dev());
|
||||
std::uniform_int_distribution<std::mt19937::result_type> distU8(0, 255);
|
||||
std::array<uint8_t, 400> largerFileData{};
|
||||
for (auto& val : largerFileData) {
|
||||
val = distU8(rng);
|
||||
}
|
||||
size_t expectedFileSize = largerFileData.size();
|
||||
fsMock.createFile(srcFileNameFs);
|
||||
FileOpParams params(srcFileName.c_str(), expectedFileSize);
|
||||
fsMock.writeToFile(params, reinterpret_cast<const uint8_t*>(largerFileData.data()));
|
||||
CHECK(sourceHandler.transactionStart(putRequest, cfg) == OK);
|
||||
const SourceHandler::FsmResult& fsmResult = sourceHandler.stateMachine();
|
||||
// Verify metadata PDU was sent.
|
||||
genericMetadataCheck(fsmResult, expectedFileSize, expectedSeqNum);
|
||||
|
||||
// Check first file data PDU. It should have the maximum file segment size.
|
||||
sourceHandler.stateMachine();
|
||||
TmTcMessage tmtcMessage;
|
||||
const uint8_t* pduPtr;
|
||||
FileDataInfo fdInfo;
|
||||
{
|
||||
CHECK(fsmResult.callStatus == CallStatus::CALL_AGAIN);
|
||||
auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr);
|
||||
FileDataReader fdReader(pduPtr, accessor.second.size(), fdInfo);
|
||||
// 10 byte PDU header, 4 byte offset, 255 byte file data
|
||||
CHECK(accessor.second.size() == 269);
|
||||
CHECK(fdReader.parseData() == OK);
|
||||
CHECK(fdInfo.getOffset().value() == 0);
|
||||
size_t fileSize = 0;
|
||||
const uint8_t* fileData = fdInfo.getFileData(&fileSize);
|
||||
// Maximum file segment size.
|
||||
REQUIRE(fileSize == MAX_FILE_SEGMENT_SIZE);
|
||||
for (unsigned i = 0; i < fileSize; i++) {
|
||||
CHECK(fileData[i] == largerFileData[i]);
|
||||
}
|
||||
}
|
||||
mqMock.clearMessages();
|
||||
|
||||
// Check second file data PDU.
|
||||
sourceHandler.stateMachine();
|
||||
{
|
||||
CHECK(fsmResult.callStatus == CallStatus::CALL_AGAIN);
|
||||
auto accessor = onePduSentCheck(fsmResult, tmtcMessage, &pduPtr);
|
||||
FileDataReader fdReader(pduPtr, accessor.second.size(), fdInfo);
|
||||
// 10 byte PDU header, 4 byte offset, remaining file data (400 - 255 == 145).
|
||||
CHECK(accessor.second.size() == 10 + 4 + largerFileData.size() - MAX_FILE_SEGMENT_SIZE);
|
||||
CHECK(fdReader.parseData() == OK);
|
||||
CHECK(fdInfo.getOffset().value() == MAX_FILE_SEGMENT_SIZE);
|
||||
size_t fileDataSize = 0;
|
||||
const uint8_t* fileData = fdInfo.getFileData(&fileDataSize);
|
||||
// Maximum file segment size.
|
||||
REQUIRE(fileDataSize == largerFileData.size() - MAX_FILE_SEGMENT_SIZE);
|
||||
for (unsigned i = 0; i < fileDataSize; i++) {
|
||||
CHECK(fileData[i] == largerFileData[MAX_FILE_SEGMENT_SIZE + i]);
|
||||
}
|
||||
}
|
||||
mqMock.clearMessages();
|
||||
|
||||
// Check EOF and verify checksum.
|
||||
sourceHandler.stateMachine();
|
||||
|
||||
etl::crc32 crcCalc;
|
||||
crcCalc.add(largerFileData.data(), largerFileData.data() + largerFileData.size());
|
||||
// Verify EOF PDU was sent.
|
||||
genericEofCheck(fsmResult, expectedFileSize, crcCalc.value(), expectedSeqNum);
|
||||
|
||||
// Verify notice of completion.
|
||||
sourceHandler.stateMachine();
|
||||
genericNoticeOfCompletionCheck(fsmResult, expectedSeqNum);
|
||||
}
|
||||
}
|
@ -110,9 +110,9 @@ TEST_CASE("CFDP Header", "[cfdp]") {
|
||||
}
|
||||
|
||||
SECTION("Other variable sized fields") {
|
||||
pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff);
|
||||
pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00);
|
||||
pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff);
|
||||
pduConf.seqNum.setValueAndWidth(cfdp::WidthInBytes::TWO_BYTES, 0x0fff);
|
||||
pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00);
|
||||
pduConf.destId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff);
|
||||
REQUIRE(pduConf.sourceId.getSerializedSize() == 4);
|
||||
REQUIRE(creator.getSerializedSize() == 14);
|
||||
REQUIRE(creator.serialize(&serTarget, &serSize, serBuf.size(),
|
||||
@ -146,9 +146,9 @@ TEST_CASE("CFDP Header", "[cfdp]") {
|
||||
}
|
||||
|
||||
SECTION("Buffer Too Short") {
|
||||
pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff);
|
||||
pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00);
|
||||
pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff);
|
||||
pduConf.seqNum.setValueAndWidth(cfdp::WidthInBytes::TWO_BYTES, 0x0fff);
|
||||
pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00);
|
||||
pduConf.destId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff);
|
||||
for (uint8_t idx = 0; idx < 14; idx++) {
|
||||
REQUIRE(creator.serialize(&serTarget, &serSize, idx, SerializeIF::Endianness::BIG) ==
|
||||
SerializeIF::BUFFER_TOO_SHORT);
|
||||
@ -157,11 +157,11 @@ TEST_CASE("CFDP Header", "[cfdp]") {
|
||||
}
|
||||
|
||||
SECTION("Invalid Variable Sized Fields") {
|
||||
result = pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 0xfff);
|
||||
result = pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::ONE_BYTE, 0xfff);
|
||||
REQUIRE(result == returnvalue::FAILED);
|
||||
result = pduConf.sourceId.setValue(cfdp::WidthInBytes::TWO_BYTES, 0xfffff);
|
||||
result = pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::TWO_BYTES, 0xfffff);
|
||||
REQUIRE(result == returnvalue::FAILED);
|
||||
result = pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xfffffffff);
|
||||
result = pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0xfffffffff);
|
||||
REQUIRE(result == returnvalue::FAILED);
|
||||
}
|
||||
|
||||
@ -207,7 +207,7 @@ TEST_CASE("CFDP Header", "[cfdp]") {
|
||||
SerializeIF::Endianness::MACHINE);
|
||||
REQUIRE(pduConf.sourceId.getValue() == 0xf0f0f0f0);
|
||||
|
||||
pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 1);
|
||||
pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::ONE_BYTE, 1);
|
||||
serTarget = serBuf.data();
|
||||
serSize = 1;
|
||||
result = pduConf.sourceId.serialize(&serTarget, &serSize, 1, SerializeIF::Endianness::MACHINE);
|
||||
@ -257,11 +257,11 @@ TEST_CASE("CFDP Header", "[cfdp]") {
|
||||
creator.setSegmentationControl(cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION);
|
||||
creator.setPduType(cfdp::PduType::FILE_DATA);
|
||||
creator.setSegmentMetadataFlag(cfdp::SegmentMetadataFlag::PRESENT);
|
||||
result = pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff);
|
||||
result = pduConf.seqNum.setValueAndWidth(cfdp::WidthInBytes::TWO_BYTES, 0x0fff);
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
result = pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00);
|
||||
result = pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00);
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
result = pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff);
|
||||
result = pduConf.destId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff);
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
serTarget = serBuf.data();
|
||||
serSize = 0;
|
||||
@ -302,8 +302,8 @@ TEST_CASE("CFDP Header", "[cfdp]") {
|
||||
SECTION("Manipulate Source Dest ID") {
|
||||
serTarget = serBuf.data();
|
||||
serSize = 0;
|
||||
pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 22);
|
||||
pduConf.destId.setValue(cfdp::WidthInBytes::ONE_BYTE, 48);
|
||||
pduConf.sourceId.setValueAndWidth(cfdp::WidthInBytes::ONE_BYTE, 22);
|
||||
pduConf.destId.setValueAndWidth(cfdp::WidthInBytes::ONE_BYTE, 48);
|
||||
result = creator.serialize(&serTarget, &serSize, serBuf.size(), SerializeIF::Endianness::BIG);
|
||||
reader.getSourceId(sourceDestId);
|
||||
REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE);
|
||||
|
@ -14,7 +14,7 @@ TEST_CASE("EOF PDU", "[cfdp][pdu]") {
|
||||
size_t sz = 0;
|
||||
EntityId destId(WidthInBytes::TWO_BYTES, 2);
|
||||
EntityIdTlv faultLoc(destId);
|
||||
FileSize fileSize(12);
|
||||
Fss fileSize(12);
|
||||
// We can already set the fault location, it will be ignored
|
||||
EofInfo eofInfo(cfdp::ConditionCode::NO_ERROR, 5, fileSize, &faultLoc);
|
||||
TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15);
|
||||
|
@ -22,7 +22,7 @@ TEST_CASE("File Data PDU", "[cfdp][pdu]") {
|
||||
for (uint8_t idx = 0; idx < 10; idx++) {
|
||||
fileBuffer[idx] = idx;
|
||||
}
|
||||
FileSize offset(50);
|
||||
Fss offset(50);
|
||||
FileDataInfo info(offset, fileBuffer.data(), 10);
|
||||
|
||||
SECTION("Serialization") {
|
||||
@ -107,8 +107,7 @@ TEST_CASE("File Data PDU", "[cfdp][pdu]") {
|
||||
serializer.serialize(&buffer, &sz, fileDataBuffer.size(), SerializeIF::Endianness::NETWORK);
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
|
||||
FileSize emptyOffset;
|
||||
FileDataInfo emptyInfo(emptyOffset);
|
||||
FileDataInfo emptyInfo;
|
||||
FileDataReader deserializer(fileDataBuffer.data(), fileDataBuffer.size(), emptyInfo);
|
||||
result = deserializer.parseData();
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
|
@ -16,7 +16,7 @@ TEST_CASE("Keep Alive PDU", "[cfdp][pdu]") {
|
||||
EntityId sourceId(WidthInBytes::TWO_BYTES, 1);
|
||||
PduConfig pduConf(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum);
|
||||
|
||||
FileSize progress(0x50);
|
||||
Fss progress(0x50);
|
||||
|
||||
SECTION("Serialize") {
|
||||
KeepAlivePduCreator serializer(pduConf, progress);
|
||||
|
@ -6,11 +6,10 @@
|
||||
#include "fsfw/cfdp/pdu/MetadataPduReader.h"
|
||||
#include "fsfw/cfdp/tlv/FilestoreResponseTlv.h"
|
||||
#include "fsfw/cfdp/tlv/MessageToUserTlv.h"
|
||||
#include "fsfw/globalfunctions/arrayprinter.h"
|
||||
|
||||
TEST_CASE("Metadata PDU", "[cfdp][pdu]") {
|
||||
using namespace cfdp;
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
ReturnValue_t result;
|
||||
std::array<uint8_t, 256> mdBuffer = {};
|
||||
uint8_t* buffer = mdBuffer.data();
|
||||
size_t sz = 0;
|
||||
@ -22,30 +21,22 @@ TEST_CASE("Metadata PDU", "[cfdp][pdu]") {
|
||||
std::string firstFileName = "hello.txt";
|
||||
cfdp::StringLv sourceFileName(firstFileName);
|
||||
cfdp::StringLv destFileName;
|
||||
FileSize fileSize(35);
|
||||
MetadataInfo info(false, ChecksumType::MODULAR, fileSize, sourceFileName, destFileName);
|
||||
Fss fileSize(35);
|
||||
MetadataGenericInfo info(false, ChecksumType::MODULAR, fileSize);
|
||||
|
||||
FilestoreResponseTlv response(FilestoreActionCode::CREATE_DIRECTORY, FSR_CREATE_NOT_ALLOWED,
|
||||
sourceFileName, nullptr);
|
||||
std::array<uint8_t, 3> msg = {0x41, 0x42, 0x43};
|
||||
cfdp::Tlv responseTlv;
|
||||
std::array<uint8_t, 64> responseBuf = {};
|
||||
uint8_t* responseBufPtr = responseBuf.data();
|
||||
response.convertToTlv(responseTlv, buffer, responseBuf.size(), SerializeIF::Endianness::MACHINE);
|
||||
MessageToUserTlv msgToUser(msg.data(), msg.size());
|
||||
std::array<Tlv*, 2> options{&responseTlv, &msgToUser};
|
||||
std::array<Tlv, 5> tlvDeser{};
|
||||
REQUIRE(options[0]->getSerializedSize() == 2 + 1 + 10 + 1);
|
||||
REQUIRE(options[1]->getSerializedSize() == 5);
|
||||
|
||||
SECTION("Serialize") {
|
||||
MetadataPduCreator serializer(pduConf, info);
|
||||
result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK);
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
REQUIRE(serializer.getWholePduSize() == 27);
|
||||
REQUIRE(info.getSourceFileName().getSerializedSize() == 10);
|
||||
REQUIRE(info.getDestFileName().getSerializedSize() == 1);
|
||||
REQUIRE(info.getSerializedSize() == 16);
|
||||
REQUIRE((mdBuffer[1] << 8 | mdBuffer[2]) == 17);
|
||||
auto metadataCheckPartOne = [&]() {
|
||||
REQUIRE(mdBuffer[10] == FileDirective::METADATA);
|
||||
// no closure requested and checksum type is modular => 0x00
|
||||
REQUIRE(mdBuffer[11] == 0x00);
|
||||
@ -64,20 +55,59 @@ TEST_CASE("Metadata PDU", "[cfdp][pdu]") {
|
||||
REQUIRE(mdBuffer[23] == 't');
|
||||
REQUIRE(mdBuffer[24] == 'x');
|
||||
REQUIRE(mdBuffer[25] == 't');
|
||||
REQUIRE(mdBuffer[26] == 0);
|
||||
};
|
||||
|
||||
SECTION("Serialize with empty dest name") {
|
||||
MetadataPduCreator serializer(pduConf, info, sourceFileName, destFileName, nullptr, 0);
|
||||
result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK);
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
CHECK(sz == serializer.getSerializedSize());
|
||||
// 10 byte heater + 1 byte PDU directive field + 1 byte PDU content + FSS field (4) + source
|
||||
// name field (10) + dest name field (1).
|
||||
REQUIRE(serializer.getWholePduSize() == 27);
|
||||
REQUIRE(serializer.getSourceFileName().getSerializedSize() == 10);
|
||||
REQUIRE(serializer.getDestFileName().getSerializedSize() == 1);
|
||||
REQUIRE(info.getSerializedSize() == 5);
|
||||
REQUIRE((mdBuffer[1] << 8 | mdBuffer[2]) == 17);
|
||||
REQUIRE(serializer.getSerializedSize() == serializer.getWholePduSize());
|
||||
metadataCheckPartOne();
|
||||
REQUIRE(mdBuffer[26] == 0);
|
||||
}
|
||||
|
||||
SECTION("Serialize with dest name") {
|
||||
std::string secondFileName = "hello2.txt";
|
||||
cfdp::StringLv destFileName2(secondFileName);
|
||||
MetadataPduCreator serializer(pduConf, info, sourceFileName, destFileName2, nullptr, 0);
|
||||
result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK);
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
// 10 byte heater + 1 byte PDU directive field + 1 byte PDU content + FSS field (4) + source
|
||||
// name field (10) + dest name field (11).
|
||||
REQUIRE(serializer.getWholePduSize() == 37);
|
||||
CHECK(sz == serializer.getSerializedSize());
|
||||
REQUIRE((mdBuffer[1] << 8 | mdBuffer[2]) == 27);
|
||||
REQUIRE(serializer.getSerializedSize() == serializer.getWholePduSize());
|
||||
metadataCheckPartOne();
|
||||
// Size of destination name field
|
||||
REQUIRE(mdBuffer[26] == 10);
|
||||
REQUIRE(mdBuffer[27] == 'h');
|
||||
REQUIRE(mdBuffer[28] == 'e');
|
||||
REQUIRE(mdBuffer[29] == 'l');
|
||||
REQUIRE(mdBuffer[30] == 'l');
|
||||
REQUIRE(mdBuffer[31] == 'o');
|
||||
REQUIRE(mdBuffer[32] == '2');
|
||||
REQUIRE(mdBuffer[33] == '.');
|
||||
REQUIRE(mdBuffer[34] == 't');
|
||||
REQUIRE(mdBuffer[35] == 'x');
|
||||
REQUIRE(mdBuffer[36] == 't');
|
||||
}
|
||||
|
||||
SECTION("Serialize with 2 options") {
|
||||
std::string otherFileName = "hello2.txt";
|
||||
cfdp::StringLv otherFileNameLv(otherFileName.data(), otherFileName.size());
|
||||
info.setSourceFileName(otherFileNameLv);
|
||||
size_t sizeOfOptions = options.size();
|
||||
info.setOptionsArray(options.data(), sizeOfOptions, sizeOfOptions);
|
||||
REQUIRE(info.getMaxOptionsLen() == 2);
|
||||
info.setMaxOptionsLen(3);
|
||||
REQUIRE(info.getMaxOptionsLen() == 3);
|
||||
MetadataPduCreator serializer(pduConf, info, otherFileNameLv, destFileName, options.data(),
|
||||
options.size());
|
||||
info.setChecksumType(cfdp::ChecksumType::CRC_32C);
|
||||
info.setClosureRequested(true);
|
||||
uint8_t* buffer = mdBuffer.data();
|
||||
size_t sz = 0;
|
||||
serializer.updateDirectiveFieldLen();
|
||||
|
||||
result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK);
|
||||
@ -98,49 +128,47 @@ TEST_CASE("Metadata PDU", "[cfdp][pdu]") {
|
||||
// TLV unittests
|
||||
REQUIRE(sz == 10 + 37);
|
||||
for (size_t maxSz = 0; maxSz < sz; maxSz++) {
|
||||
uint8_t* buffer = mdBuffer.data();
|
||||
size_t sz = 0;
|
||||
buffer = mdBuffer.data();
|
||||
sz = 0;
|
||||
result = serializer.serialize(&buffer, &sz, maxSz, SerializeIF::Endianness::NETWORK);
|
||||
REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT);
|
||||
}
|
||||
for (size_t initSz = 1; initSz < 47; initSz++) {
|
||||
uint8_t* buffer = mdBuffer.data();
|
||||
size_t sz = initSz;
|
||||
buffer = mdBuffer.data();
|
||||
sz = initSz;
|
||||
result = serializer.serialize(&buffer, &sz, 46, SerializeIF::Endianness::NETWORK);
|
||||
REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT);
|
||||
}
|
||||
info.setDestFileName(destFileName);
|
||||
}
|
||||
|
||||
SECTION("Deserialize") {
|
||||
MetadataPduCreator serializer(pduConf, info);
|
||||
MetadataPduCreator serializer(pduConf, info, sourceFileName, destFileName, nullptr, 0);
|
||||
result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK);
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
|
||||
MetadataPduReader deserializer(mdBuffer.data(), mdBuffer.size(), info);
|
||||
MetadataPduReader deserializer(mdBuffer.data(), mdBuffer.size(), info, nullptr, 0);
|
||||
result = deserializer.parseData();
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
size_t fullSize = deserializer.getWholePduSize();
|
||||
for (size_t maxSz = 0; maxSz < fullSize; maxSz++) {
|
||||
MetadataPduReader invalidSzDeser(mdBuffer.data(), maxSz, info);
|
||||
MetadataPduReader invalidSzDeser(mdBuffer.data(), maxSz, info, nullptr, 0);
|
||||
result = invalidSzDeser.parseData();
|
||||
REQUIRE(result != returnvalue::OK);
|
||||
}
|
||||
size_t sizeOfOptions = options.size();
|
||||
size_t maxSize = 4;
|
||||
info.setOptionsArray(options.data(), sizeOfOptions, maxSize);
|
||||
REQUIRE(info.getOptionsLen() == 2);
|
||||
}
|
||||
|
||||
SECTION("Deserialize with 2 options") {
|
||||
MetadataPduCreator serializer(pduConf, info, sourceFileName, destFileName, options.data(),
|
||||
options.size());
|
||||
info.setChecksumType(cfdp::ChecksumType::CRC_32C);
|
||||
info.setClosureRequested(true);
|
||||
uint8_t* buffer = mdBuffer.data();
|
||||
size_t sz = 0;
|
||||
serializer.updateDirectiveFieldLen();
|
||||
|
||||
info.setSourceFileName(sourceFileName);
|
||||
result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK);
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
|
||||
MetadataPduReader deserializer2(mdBuffer.data(), mdBuffer.size(), info);
|
||||
MetadataPduReader deserializer2(mdBuffer.data(), mdBuffer.size(), info, tlvDeser.data(),
|
||||
tlvDeser.max_size());
|
||||
result = deserializer2.parseData();
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
REQUIRE(options[0]->getType() == cfdp::TlvType::FILESTORE_RESPONSE);
|
||||
@ -151,12 +179,15 @@ TEST_CASE("Metadata PDU", "[cfdp][pdu]") {
|
||||
for (size_t invalidFieldLen = 0; invalidFieldLen < 36; invalidFieldLen++) {
|
||||
mdBuffer[1] = (invalidFieldLen >> 8) & 0xff;
|
||||
mdBuffer[2] = invalidFieldLen & 0xff;
|
||||
if (invalidFieldLen == 17) {
|
||||
volatile uint32_t dummy = 0;
|
||||
}
|
||||
result = deserializer2.parseData();
|
||||
if (invalidFieldLen == 17) {
|
||||
REQUIRE(info.getOptionsLen() == 0);
|
||||
REQUIRE(deserializer2.getNumberOfParsedOptions() == 0);
|
||||
}
|
||||
if (invalidFieldLen == 31) {
|
||||
REQUIRE(info.getOptionsLen() == 1);
|
||||
REQUIRE(deserializer2.getNumberOfParsedOptions() == 1);
|
||||
}
|
||||
// This is the precise length where there are no options or one option
|
||||
if (invalidFieldLen != 17 and invalidFieldLen != 31) {
|
||||
@ -165,11 +196,25 @@ TEST_CASE("Metadata PDU", "[cfdp][pdu]") {
|
||||
}
|
||||
mdBuffer[1] = (36 >> 8) & 0xff;
|
||||
mdBuffer[2] = 36 & 0xff;
|
||||
info.setOptionsArray(nullptr, std::nullopt, std::nullopt);
|
||||
}
|
||||
|
||||
SECTION("Can not parse options") {
|
||||
MetadataPduCreator serializer(pduConf, info, sourceFileName, destFileName, options.data(),
|
||||
options.size());
|
||||
info.setChecksumType(cfdp::ChecksumType::CRC_32C);
|
||||
info.setClosureRequested(true);
|
||||
buffer = mdBuffer.data();
|
||||
sz = 0;
|
||||
serializer.updateDirectiveFieldLen();
|
||||
|
||||
// info.setSourceFileName(sourceFileName);
|
||||
result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK);
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
|
||||
MetadataPduReader deserializer2(mdBuffer.data(), mdBuffer.size(), info, nullptr, 0);
|
||||
REQUIRE(deserializer2.parseData() == cfdp::METADATA_CANT_PARSE_OPTIONS);
|
||||
info.setOptionsArray(options.data(), sizeOfOptions, std::nullopt);
|
||||
for (size_t maxSz = 0; maxSz < 46; maxSz++) {
|
||||
MetadataPduReader invalidSzDeser(mdBuffer.data(), maxSz, info);
|
||||
MetadataPduReader invalidSzDeser(mdBuffer.data(), maxSz, info, nullptr, 0);
|
||||
if (not invalidSzDeser.isNull()) {
|
||||
result = invalidSzDeser.parseData();
|
||||
REQUIRE(result == SerializeIF::STREAM_TOO_SHORT);
|
||||
|
@ -17,8 +17,8 @@ TEST_CASE("NAK PDU", "[cfdp][pdu]") {
|
||||
EntityId sourceId(WidthInBytes::TWO_BYTES, 1);
|
||||
PduConfig pduConf(sourceId, destId, TransmissionMode::ACKNOWLEDGED, seqNum);
|
||||
|
||||
FileSize startOfScope(50);
|
||||
FileSize endOfScope(1050);
|
||||
Fss startOfScope(50);
|
||||
Fss endOfScope(1050);
|
||||
NakInfo info(startOfScope, endOfScope);
|
||||
SECTION("Serializer") {
|
||||
NakPduCreator serializer(pduConf, info);
|
||||
@ -40,8 +40,8 @@ TEST_CASE("NAK PDU", "[cfdp][pdu]") {
|
||||
REQUIRE(result == returnvalue::OK);
|
||||
REQUIRE(scope == 1050);
|
||||
|
||||
NakInfo::SegmentRequest segReq0(cfdp::FileSize(2020), cfdp::FileSize(2520));
|
||||
NakInfo::SegmentRequest segReq1(cfdp::FileSize(2932), cfdp::FileSize(3021));
|
||||
NakInfo::SegmentRequest segReq0(cfdp::Fss(2020), cfdp::Fss(2520));
|
||||
NakInfo::SegmentRequest segReq1(cfdp::Fss(2932), cfdp::Fss(3021));
|
||||
// Now add 2 segment requests to NAK info and serialize them as well
|
||||
std::array<NakInfo::SegmentRequest, 2> segReqs = {segReq0, segReq1};
|
||||
size_t segReqsLen = segReqs.size();
|
||||
@ -100,8 +100,8 @@ TEST_CASE("NAK PDU", "[cfdp][pdu]") {
|
||||
REQUIRE(info.getStartOfScope().getSize() == 50);
|
||||
REQUIRE(info.getEndOfScope().getSize() == 1050);
|
||||
|
||||
NakInfo::SegmentRequest segReq0(cfdp::FileSize(2020), cfdp::FileSize(2520));
|
||||
NakInfo::SegmentRequest segReq1(cfdp::FileSize(2932), cfdp::FileSize(3021));
|
||||
NakInfo::SegmentRequest segReq0(cfdp::Fss(2020), cfdp::Fss(2520));
|
||||
NakInfo::SegmentRequest segReq1(cfdp::Fss(2932), cfdp::Fss(3021));
|
||||
// Now add 2 segment requests to NAK info and serialize them as well
|
||||
std::array<NakInfo::SegmentRequest, 2> segReqs = {segReq0, segReq1};
|
||||
size_t segReqsLen = segReqs.size();
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <cstring>
|
||||
|
||||
#include "fsfw/cfdp/FileSize.h"
|
||||
#include "fsfw/cfdp/Fss.h"
|
||||
#include "fsfw/cfdp/pdu/FileDirectiveCreator.h"
|
||||
#include "fsfw/cfdp/pdu/FileDirectiveReader.h"
|
||||
#include "fsfw/globalfunctions/arrayprinter.h"
|
||||
@ -79,7 +79,7 @@ TEST_CASE("CFDP Base", "[cfdp]") {
|
||||
std::array<uint8_t, 8> fssBuf = {};
|
||||
uint8_t* buffer = fssBuf.data();
|
||||
size_t size = 0;
|
||||
cfdp::FileSize fss;
|
||||
cfdp::Fss fss;
|
||||
REQUIRE(fss.getSize() == 0);
|
||||
fss.setFileSize(0x20, false);
|
||||
result = fss.serialize(&buffer, &size, fssBuf.size(), SerializeIF::Endianness::MACHINE);
|
||||
|
@ -23,12 +23,6 @@ TEST_CASE("CFDP LV", "[cfdp][lv]") {
|
||||
auto lv = cfdp::Lv(lvRawBuf.data(), 2);
|
||||
REQUIRE(lv.getSerializedSize() == 3);
|
||||
|
||||
SECTION("Copy") {
|
||||
auto lvCopy = cfdp::Lv(lv);
|
||||
REQUIRE(lvCopy.getSerializedSize() == 3);
|
||||
REQUIRE(lv.getValue(nullptr) == lvCopy.getValue(nullptr));
|
||||
}
|
||||
|
||||
serPtr = rawBuf.data();
|
||||
deserSize = 0;
|
||||
REQUIRE(lv.serialize(&serPtr, &deserSize, rawBuf.size(), SerializeIF::Endianness::NETWORK) ==
|
||||
@ -41,6 +35,16 @@ TEST_CASE("CFDP LV", "[cfdp][lv]") {
|
||||
REQUIRE(sourceIdRaw == 0x0ff0);
|
||||
}
|
||||
|
||||
SECTION("Move LV") {
|
||||
std::array<uint8_t, 8> lvRawBuf{};
|
||||
serPtr = lvRawBuf.data();
|
||||
REQUIRE(sourceId.serialize(&serPtr, &deserSize, lvRawBuf.size(),
|
||||
SerializeIF::Endianness::NETWORK) == returnvalue::OK);
|
||||
auto lv = cfdp::Lv(lvRawBuf.data(), 2);
|
||||
auto lvMovedCopy = cfdp::Lv(std::move(lv));
|
||||
REQUIRE(lvMovedCopy.getSerializedSize() == 3);
|
||||
}
|
||||
|
||||
SECTION("Empty Serialization") {
|
||||
auto lvEmpty = Lv();
|
||||
REQUIRE(lvEmpty.getSerializedSize() == 1);
|
||||
|
49
unittests/cfdp/testReservedMsgCreator.cpp
Normal file
49
unittests/cfdp/testReservedMsgCreator.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
#include <array>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "fsfw/cfdp/VarLenFields.h"
|
||||
#include "fsfw/cfdp/tlv/ReservedMessageCreator.h"
|
||||
#include "fsfw/cfdp/tlv/StringLv.h"
|
||||
|
||||
TEST_CASE("Reserved Message Creator", "[cfdp][tlv]") {
|
||||
using namespace cfdp;
|
||||
using namespace returnvalue;
|
||||
|
||||
std::string srcFileName = "hello.txt";
|
||||
std::string destFileName = "hello2.txt";
|
||||
std::array<uint8_t, 64> buffer{};
|
||||
uint8_t msgBuf[32]{};
|
||||
EntityId entityId(cfdp::WidthInBytes::ONE_BYTE, 5);
|
||||
uint8_t* msgBufPtr = msgBuf;
|
||||
size_t serLen = 0;
|
||||
cfdp::StringLv srcName(srcFileName);
|
||||
cfdp::StringLv destName(destFileName);
|
||||
CHECK(entityId.serializeAsLv(&msgBufPtr, &serLen, sizeof(msgBuf)) == OK);
|
||||
CHECK(srcName.serialize(&msgBufPtr, &serLen, sizeof(msgBuf), SerializeIF::Endianness::NETWORK) ==
|
||||
OK);
|
||||
CHECK(destName.serialize(&msgBufPtr, &serLen, sizeof(msgBuf), SerializeIF::Endianness::NETWORK) ==
|
||||
OK);
|
||||
ReservedMessageCreator creator(static_cast<uint8_t>(ProxyOpMessageType::PUT_REQUEST), msgBuf,
|
||||
serLen);
|
||||
serLen = 0;
|
||||
ReturnValue_t result = creator.serializeBe(buffer.data(), serLen, buffer.size());
|
||||
CHECK(result == returnvalue::OK);
|
||||
CHECK(buffer[0] == TlvType::MSG_TO_USER);
|
||||
// 4 bytes "cfdp" header, 1 byte message type, entity ID LV, source name LV and dest name LV
|
||||
CHECK(buffer[1] ==
|
||||
5 + 1 + entityId.getSerializedSize() + 1 + srcFileName.size() + 1 + destFileName.size());
|
||||
CHECK(buffer[2] == 'c');
|
||||
CHECK(buffer[3] == 'f');
|
||||
CHECK(buffer[4] == 'd');
|
||||
CHECK(buffer[5] == 'p');
|
||||
CHECK(buffer[6] == static_cast<uint8_t>(ProxyOpMessageType::PUT_REQUEST));
|
||||
CHECK(buffer[7] == 1);
|
||||
CHECK(buffer[8] == entityId.getValue());
|
||||
CHECK(buffer[9] == srcFileName.size());
|
||||
size_t currentIdx = 10;
|
||||
CHECK(std::string(reinterpret_cast<const char*>(buffer.data()) + currentIdx,
|
||||
srcFileName.size()) == srcFileName);
|
||||
currentIdx += srcFileName.size() + 1;
|
||||
CHECK(std::string(reinterpret_cast<const char*>(buffer.data()) + currentIdx,
|
||||
destFileName.size()) == destFileName);
|
||||
}
|
@ -40,7 +40,7 @@ TEST_CASE("CFDP TLV", "[cfdp][tlv]") {
|
||||
SECTION("TLV Other Value") {
|
||||
auto tlv = Tlv(TlvType::ENTITY_ID, rawBuf.data(), deserSize);
|
||||
// Set new value
|
||||
sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 12);
|
||||
sourceId.setValueAndWidth(cfdp::WidthInBytes::FOUR_BYTES, 12);
|
||||
REQUIRE(sourceId.serialize(&serPtr, &deserSize, rawBuf.size(),
|
||||
SerializeIF::Endianness::NETWORK) == returnvalue::OK);
|
||||
tlv.setValue(rawBuf.data(), cfdp::WidthInBytes::FOUR_BYTES);
|
||||
|
@ -82,7 +82,7 @@ TEST_CASE("Local Pool Manager Tests", "[LocManTest]") {
|
||||
REQUIRE(poolOwnerMock.getNextSentMessage(subscriberId, messageSent) == returnvalue::OK);
|
||||
CHECK(messageSent.getCommand() ==
|
||||
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET));
|
||||
REQUIRE(poolOwnerMock.getNextSentMessage(messageSent) == returnvalue::OK);
|
||||
REQUIRE(poolOwnerMock.getNextSentMessageToDefaultDest(messageSent) == returnvalue::OK);
|
||||
CHECK(messageSent.getCommand() == static_cast<int>(HousekeepingMessage::HK_REPORT));
|
||||
/* Clear message to avoid memory leak, our mock won't do it for us (yet) */
|
||||
CommandMessageCleaner::clearCommandMessage(&messageSent);
|
||||
@ -259,11 +259,11 @@ TEST_CASE("Local Pool Manager Tests", "[LocManTest]") {
|
||||
CHECK(messageSent.getCommand() ==
|
||||
static_cast<int>(HousekeepingMessage::UPDATE_NOTIFICATION_SET));
|
||||
REQUIRE(poolOwnerMock.clearLastSentMessage(subscriberId) == returnvalue::OK);
|
||||
REQUIRE(poolOwnerMock.getNextSentMessage(messageSent) == returnvalue::OK);
|
||||
REQUIRE(poolOwnerMock.getNextSentMessageToDefaultDest(messageSent) == returnvalue::OK);
|
||||
CHECK(messageSent.getCommand() == static_cast<int>(HousekeepingMessage::HK_REPORT));
|
||||
REQUIRE(poolOwnerMock.clearLastSentMessage() == returnvalue::OK);
|
||||
REQUIRE(poolOwnerMock.getNextSentMessage(subscriberId, messageSent) == MessageQueueIF::EMPTY);
|
||||
REQUIRE(poolOwnerMock.getNextSentMessage(messageSent) == MessageQueueIF::EMPTY);
|
||||
REQUIRE(poolOwnerMock.getNextSentMessageToDefaultDest(messageSent) == MessageQueueIF::EMPTY);
|
||||
}
|
||||
|
||||
SECTION("PeriodicHKAndMessaging") {
|
||||
|
@ -9,8 +9,8 @@ class AcceptsTmMock : public SystemObject, public AcceptsTelemetryIF {
|
||||
AcceptsTmMock(object_id_t registeredId, MessageQueueId_t queueToReturn);
|
||||
explicit AcceptsTmMock(MessageQueueId_t queueToReturn);
|
||||
|
||||
MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel) const override;
|
||||
const char* getName() const override;
|
||||
[[nodiscard]] MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel) const override;
|
||||
[[nodiscard]] const char* getName() const override;
|
||||
|
||||
MessageQueueId_t returnedQueue;
|
||||
};
|
||||
|
@ -39,7 +39,8 @@ ReturnValue_t FilesystemMock::readFromFile(FileOpParams params, uint8_t **buffer
|
||||
if (readSize + readLen > maxSize) {
|
||||
return SerializeIF::STREAM_TOO_SHORT;
|
||||
}
|
||||
std::copy(info.fileRaw.data() + params.offset, info.fileRaw.data() + readLen, *buffer);
|
||||
std::copy(info.fileRaw.data() + params.offset, info.fileRaw.data() + params.offset + readLen,
|
||||
*buffer);
|
||||
*buffer += readLen;
|
||||
readSize += readLen;
|
||||
}
|
||||
@ -80,7 +81,7 @@ ReturnValue_t FilesystemMock::removeDirectory(FilesystemParams params, bool dele
|
||||
|
||||
ReturnValue_t FilesystemMock::rename(const char *oldPath, const char *newPath,
|
||||
FileSystemArgsIF *args) {
|
||||
renameQueue.push(RenameInfo(oldPath, newPath));
|
||||
renameQueue.emplace(oldPath, newPath);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
@ -90,7 +91,7 @@ void FilesystemMock::createOrAddToFile(FileOpParams params, const uint8_t *data)
|
||||
if (iter == fileMap.end()) {
|
||||
FileSegmentQueue queue;
|
||||
if (params.size > 0) {
|
||||
queue.push(FileWriteInfo(filename, params.offset, data, params.size));
|
||||
queue.emplace(filename, params.offset, data, params.size);
|
||||
}
|
||||
FileInfo info;
|
||||
info.fileSegQueue = queue;
|
||||
@ -100,7 +101,7 @@ void FilesystemMock::createOrAddToFile(FileOpParams params, const uint8_t *data)
|
||||
fileMap.emplace(filename, info);
|
||||
} else {
|
||||
FileInfo &info = iter->second;
|
||||
info.fileSegQueue.push(FileWriteInfo(filename, params.offset, data, params.size));
|
||||
info.fileSegQueue.emplace(filename, params.offset, data, params.size);
|
||||
if (data == nullptr) {
|
||||
return;
|
||||
}
|
||||
@ -145,3 +146,13 @@ ReturnValue_t FilesystemMock::getBaseFilename(FilesystemParams params, char *nam
|
||||
}
|
||||
|
||||
bool FilesystemMock::isDirectory(const char *path) { return false; }
|
||||
|
||||
bool FilesystemMock::getFileSize(FilesystemParams params, size_t &fileSize) {
|
||||
std::string filename(params.path);
|
||||
auto iter = fileMap.find(filename);
|
||||
if (iter != fileMap.end()) {
|
||||
fileSize = iter->second.fileRaw.size();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -62,6 +62,7 @@ class FilesystemMock : public HasFileSystemIF {
|
||||
bool isDirectory(const char *path) override;
|
||||
bool fileExists(FilesystemParams params) override;
|
||||
ReturnValue_t truncateFile(FilesystemParams params) override;
|
||||
bool getFileSize(FilesystemParams params, size_t &fileSize) override;
|
||||
|
||||
ReturnValue_t writeToFile(FileOpParams params, const uint8_t *data) override;
|
||||
ReturnValue_t readFromFile(FileOpParams params, uint8_t **buffer, size_t &readSize,
|
||||
|
@ -124,7 +124,7 @@ ReturnValue_t MessageQueueMock::getNextSentMessage(MessageQueueId_t id,
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t MessageQueueMock::getNextSentMessage(MessageQueueMessageIF& message) {
|
||||
ReturnValue_t MessageQueueMock::getNextSentMessageToDefaultDest(MessageQueueMessageIF& message) {
|
||||
return getNextSentMessage(MessageQueueBase::getDefaultDestination(), message);
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ class MessageQueueMock : public MessageQueueBase {
|
||||
explicit MessageQueueMock(MessageQueueId_t queueId);
|
||||
|
||||
//! Get next message which was sent to the default destination
|
||||
ReturnValue_t getNextSentMessage(MessageQueueMessageIF& message);
|
||||
ReturnValue_t getNextSentMessageToDefaultDest(MessageQueueMessageIF& message);
|
||||
//! Get message which was sent to a specific ID
|
||||
ReturnValue_t getNextSentMessage(MessageQueueId_t id, MessageQueueMessageIF& message);
|
||||
[[nodiscard]] bool wasMessageSent() const;
|
||||
|
@ -32,6 +32,7 @@ class StorageManagerMock : public LocalPool {
|
||||
std::pair<bool, ReturnValue_t> nextFreeElementCallFails;
|
||||
|
||||
using LocalPool::getFreeElement;
|
||||
using StorageManagerIF::getData;
|
||||
|
||||
void reset();
|
||||
};
|
||||
|
@ -4,19 +4,20 @@ namespace cfdp {
|
||||
|
||||
cfdp::UserMock::UserMock(HasFileSystemIF& vfs) : UserBase(vfs) {}
|
||||
|
||||
void UserMock::transactionIndication(const TransactionId& id) {}
|
||||
void UserMock::eofSentIndication(const TransactionId& id) {}
|
||||
void UserMock::transactionIndication(const TransactionId& id) { transactionIndicRecvd.emplace(id); }
|
||||
|
||||
void UserMock::eofSentIndication(const TransactionId& id) { eofSentRecvd.emplace(id); }
|
||||
void UserMock::abandonedIndication(const TransactionId& id, cfdp::ConditionCode code,
|
||||
uint64_t progress) {}
|
||||
|
||||
void UserMock::eofRecvIndication(const TransactionId& id) { eofsRevd.push(id); }
|
||||
void UserMock::eofRecvIndication(const TransactionId& id) { eofRecvdRecvd.push(id); }
|
||||
|
||||
void UserMock::transactionFinishedIndication(const TransactionFinishedParams& finishedParams) {
|
||||
finishedRecvd.push({finishedParams.id, finishedParams});
|
||||
finishedRecvd.emplace(finishedParams.id, finishedParams);
|
||||
}
|
||||
|
||||
void UserMock::metadataRecvdIndication(const MetadataRecvdParams& params) {
|
||||
metadataRecvd.push({params.id, params});
|
||||
metadataRecvd.emplace(params.id, params);
|
||||
}
|
||||
|
||||
void UserMock::fileSegmentRecvdIndication(const FileSegmentRecvdParams& params) {}
|
||||
@ -27,7 +28,7 @@ void UserMock::faultIndication(const TransactionId& id, cfdp::ConditionCode code
|
||||
}
|
||||
|
||||
void UserMock::reset() {
|
||||
std::queue<TransactionId>().swap(eofsRevd);
|
||||
std::queue<TransactionId>().swap(eofRecvdRecvd);
|
||||
std::queue<std::pair<TransactionId, cfdp::MetadataRecvdParams>>().swap(metadataRecvd);
|
||||
std::queue<std::pair<TransactionId, cfdp::TransactionFinishedParams>>().swap(finishedRecvd);
|
||||
}
|
||||
|
@ -23,8 +23,10 @@ class UserMock : public UserBase {
|
||||
void resumedIndication(const TransactionId& id, size_t progress) override;
|
||||
void faultIndication(const TransactionId& id, ConditionCode code, size_t progress) override;
|
||||
|
||||
std::queue<TransactionId> transactionIndicRecvd;
|
||||
std::queue<std::pair<TransactionId, MetadataRecvdParams>> metadataRecvd;
|
||||
std::queue<TransactionId> eofsRevd;
|
||||
std::queue<TransactionId> eofRecvdRecvd;
|
||||
std::queue<TransactionId> eofSentRecvd;
|
||||
std::queue<std::pair<TransactionId, TransactionFinishedParams>> finishedRecvd;
|
||||
void reset();
|
||||
};
|
||||
|
@ -71,7 +71,7 @@ TEST_CASE("TM Send Helper", "[tm-send-helper]") {
|
||||
REQUIRE(msgQueue.wasMessageSent());
|
||||
REQUIRE(msgQueue.numberOfSentMessagesToDefault() == 1);
|
||||
TmTcMessage msg;
|
||||
REQUIRE(msgQueue.getNextSentMessage(msg) == returnvalue::OK);
|
||||
REQUIRE(msgQueue.getNextSentMessageToDefaultDest(msg) == returnvalue::OK);
|
||||
REQUIRE(msg.getStorageId() == storeId);
|
||||
REQUIRE(pool.hasDataAtId(msg.getStorageId()));
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ TEST_CASE("TM Store And Send Helper", "[tm-store-send-helper]") {
|
||||
REQUIRE(msgQueue.wasMessageSent());
|
||||
REQUIRE(msgQueue.numberOfSentMessagesToDefault() == 1);
|
||||
TmTcMessage msg;
|
||||
REQUIRE(msgQueue.getNextSentMessage(msg) == returnvalue::OK);
|
||||
REQUIRE(msgQueue.getNextSentMessageToDefaultDest(msg) == returnvalue::OK);
|
||||
REQUIRE(msg.getStorageId() == storeId);
|
||||
REQUIRE(pool.hasDataAtId(msg.getStorageId()));
|
||||
storeHelper.deletePacket();
|
||||
|
@ -1 +1,2 @@
|
||||
target_sources(${FSFW_TEST_TGT} PRIVATE testUnsignedByteField.cpp)
|
||||
target_sources(${FSFW_TEST_TGT} PRIVATE testUnsignedByteField.cpp
|
||||
testSeqCountProvider.cpp)
|
||||
|
35
unittests/util/testSeqCountProvider.cpp
Normal file
35
unittests/util/testSeqCountProvider.cpp
Normal file
@ -0,0 +1,35 @@
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
#include "fsfw/util/SeqCountProvider.h"
|
||||
|
||||
TEST_CASE("Seq Count Providers", "[util]") {
|
||||
auto genericProviderTest = [](ProvidesSeqCountIF& provider, unsigned expectedWidth) {
|
||||
CHECK(provider.get() == 0);
|
||||
CHECK(provider.bitWidth() == expectedWidth);
|
||||
CHECK(provider.getAndIncrement() == 0);
|
||||
CHECK(provider.getAndIncrement() == 1);
|
||||
CHECK(provider.get() == 2);
|
||||
provider.increment();
|
||||
provider.increment();
|
||||
CHECK(provider.get() == 4);
|
||||
};
|
||||
{
|
||||
SeqCountProviderU16 provider;
|
||||
genericProviderTest(provider, 16);
|
||||
}
|
||||
|
||||
{
|
||||
SeqCountProviderU32 provider;
|
||||
genericProviderTest(provider, 32);
|
||||
}
|
||||
|
||||
{
|
||||
SeqCountProviderU8 provider;
|
||||
genericProviderTest(provider, 8);
|
||||
for (unsigned i = 4; i < UINT8_MAX + 1; i++) {
|
||||
provider.increment();
|
||||
}
|
||||
// Verify wrap-around.
|
||||
CHECK(provider.get() == 0);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user