add CFDP fault handler mock

This commit is contained in:
2022-08-09 14:55:08 +02:00
parent eccb629ba8
commit dba3f9960e
22 changed files with 113 additions and 37 deletions

View File

@ -0,0 +1,13 @@
target_sources(
${FSFW_TEST_TGT}
PRIVATE testAckPdu.cpp
testAckPdu.cpp
testEofPdu.cpp
testNakPdu.cpp
testFinishedPdu.cpp
testPromptPdu.cpp
testKeepAlivePdu.cpp
testMetadataPdu.cpp
testFileData.cpp
testCfdpHeader.cpp
testFileDirective.cpp)

View File

@ -0,0 +1,100 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/pdu/AckPduDeserializer.h"
#include "fsfw/cfdp/pdu/AckPduSerializer.h"
#include "fsfw/globalfunctions/arrayprinter.h"
TEST_CASE("ACK PDU", "[cfdp][pdu]") {
using namespace cfdp;
ReturnValue_t result;
std::array<uint8_t, 256> buf = {};
uint8_t* bufptr = buf.data();
size_t maxsz = buf.size();
size_t sz = 0;
auto seqNum = TransactionSeqNum(WidthInBytes::TWO_BYTES, 15);
auto sourceId = EntityId(WidthInBytes::TWO_BYTES, 1);
auto destId = EntityId(WidthInBytes::TWO_BYTES, 2);
auto pduConf = PduConfig(sourceId, destId, TransmissionModes::ACKNOWLEDGED, seqNum);
AckInfo ackInfo(FileDirectives::EOF_DIRECTIVE, ConditionCode::NO_ERROR,
AckTransactionStatus::ACTIVE);
auto ackSerializer = AckPduSerializer(ackInfo, pduConf);
result = ackSerializer.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
SECTION("Serialize") {
REQUIRE(buf[sz - 3] == cfdp::FileDirectives::ACK);
REQUIRE((buf[sz - 2] >> 4) == FileDirectives::EOF_DIRECTIVE);
REQUIRE((buf[sz - 2] & 0x0f) == 0);
REQUIRE(buf[sz - 1] == AckTransactionStatus::ACTIVE);
ackInfo.setAckedDirective(FileDirectives::FINISH);
ackInfo.setAckedConditionCode(ConditionCode::FILESTORE_REJECTION);
ackInfo.setTransactionStatus(AckTransactionStatus::TERMINATED);
auto ackSerializer2 = AckPduSerializer(ackInfo, pduConf);
bufptr = buf.data();
sz = 0;
result = ackSerializer2.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(buf[sz - 3] == cfdp::FileDirectives::ACK);
REQUIRE((buf[sz - 2] >> 4) == FileDirectives::FINISH);
REQUIRE((buf[sz - 2] & 0x0f) == 0b0001);
REQUIRE((buf[sz - 1] >> 4) == ConditionCode::FILESTORE_REJECTION);
REQUIRE((buf[sz - 1] & 0b11) == AckTransactionStatus::TERMINATED);
bufptr = buf.data();
sz = 0;
ackInfo.setAckedDirective(FileDirectives::KEEP_ALIVE);
auto ackSerializer3 = AckPduSerializer(ackInfo, pduConf);
result = ackSerializer3.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK);
// Invalid file directive
REQUIRE(result != HasReturnvaluesIF::RETURN_OK);
ackInfo.setAckedDirective(FileDirectives::FINISH);
// buffer too small
result = ackSerializer.serialize(&bufptr, &sz, 8, SerializeIF::Endianness::NETWORK);
REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT);
}
SECTION("Deserialize") {
AckInfo ackInfo2;
auto reader = AckPduDeserializer(buf.data(), sz, ackInfo2);
result = reader.parseData();
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(ackInfo2.getAckedDirective() == FileDirectives::EOF_DIRECTIVE);
REQUIRE(ackInfo2.getAckedConditionCode() == ConditionCode::NO_ERROR);
REQUIRE(ackInfo2.getDirectiveSubtypeCode() == 0);
REQUIRE(ackInfo2.getTransactionStatus() == AckTransactionStatus::ACTIVE);
AckInfo newInfo = AckInfo(FileDirectives::FINISH, ConditionCode::FILESTORE_REJECTION,
AckTransactionStatus::TERMINATED);
auto ackSerializer2 = AckPduSerializer(newInfo, pduConf);
bufptr = buf.data();
sz = 0;
result = ackSerializer2.serialize(&bufptr, &sz, maxsz, SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
auto reader2 = AckPduDeserializer(buf.data(), sz, ackInfo2);
result = reader2.parseData();
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(ackInfo2.getAckedDirective() == FileDirectives::FINISH);
REQUIRE(ackInfo2.getAckedConditionCode() == ConditionCode::FILESTORE_REJECTION);
REQUIRE(ackInfo2.getDirectiveSubtypeCode() == 0b0001);
REQUIRE(ackInfo2.getTransactionStatus() == AckTransactionStatus::TERMINATED);
uint8_t prevVal = buf[sz - 2];
buf[sz - 2] = FileDirectives::INVALID_DIRECTIVE << 4;
result = reader2.parseData();
REQUIRE(result == cfdp::INVALID_ACK_DIRECTIVE_FIELDS);
buf[sz - 2] = FileDirectives::FINISH << 4 | 0b1111;
result = reader2.parseData();
REQUIRE(result == cfdp::INVALID_ACK_DIRECTIVE_FIELDS);
buf[sz - 2] = prevVal;
buf[sz - 3] = cfdp::FileDirectives::INVALID_DIRECTIVE;
result = reader2.parseData();
REQUIRE(result == cfdp::INVALID_DIRECTIVE_FIELDS);
buf[sz - 3] = cfdp::FileDirectives::ACK;
auto maxSizeTooSmall = AckPduDeserializer(buf.data(), sz - 2, ackInfo2);
result = maxSizeTooSmall.parseData();
REQUIRE(result == SerializeIF::STREAM_TOO_SHORT);
}
}

View File

@ -0,0 +1,316 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/pdu/HeaderCreator.h"
#include "fsfw/cfdp/pdu/HeaderReader.h"
#include "fsfw/returnvalues/HasReturnvaluesIF.h"
TEST_CASE("CFDP Header", "[cfdp]") {
using namespace cfdp;
std::array<uint8_t, 32> serBuf{};
ReturnValue_t result;
cfdp::TransactionSeqNum seqNum = TransactionSeqNum(cfdp::WidthInBytes::ONE_BYTE, 2);
cfdp::EntityId sourceId = EntityId(cfdp::WidthInBytes::ONE_BYTE, 0);
cfdp::EntityId destId = EntityId(cfdp::WidthInBytes::ONE_BYTE, 1);
PduConfig pduConf =
PduConfig(sourceId, destId, cfdp::TransmissionModes::ACKNOWLEDGED, seqNum, false);
uint8_t* serTarget = serBuf.data();
const uint8_t* deserTarget = serTarget;
size_t serSize = 0;
auto headerSerializer = HeaderCreator(pduConf, cfdp::PduType::FILE_DIRECTIVE, 0);
SECTION("Header State") {
REQUIRE(seqNum.getSerializedSize() == 1);
REQUIRE(headerSerializer.getPduDataFieldLen() == 0);
REQUIRE(headerSerializer.getSerializedSize() == 7);
REQUIRE(headerSerializer.getWholePduSize() == 7);
REQUIRE(headerSerializer.getCrcFlag() == false);
REQUIRE(headerSerializer.getDirection() == cfdp::Direction::TOWARDS_RECEIVER);
REQUIRE(headerSerializer.getLargeFileFlag() == false);
REQUIRE(headerSerializer.getLenEntityIds() == 1);
REQUIRE(headerSerializer.getLenSeqNum() == 1);
REQUIRE(headerSerializer.getPduType() == cfdp::PduType::FILE_DIRECTIVE);
REQUIRE(headerSerializer.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::NOT_PRESENT);
REQUIRE(headerSerializer.getSegmentationControl() == false);
REQUIRE(headerSerializer.getTransmissionMode() == cfdp::TransmissionModes::ACKNOWLEDGED);
cfdp::TransactionSeqNum seqNumLocal;
headerSerializer.getTransactionSeqNum(seqNumLocal);
REQUIRE(seqNumLocal.getWidth() == cfdp::WidthInBytes::ONE_BYTE);
REQUIRE(seqNumLocal.getValue() == 2);
cfdp::EntityId sourceDestId;
headerSerializer.getSourceId(sourceDestId);
REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE);
REQUIRE(sourceDestId.getValue() == 0);
headerSerializer.getDestId(sourceDestId);
REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE);
REQUIRE(sourceDestId.getValue() == 1);
}
SECTION("Deserialization fails") {
const uint8_t** dummyPtr = nullptr;
REQUIRE(headerSerializer.deSerialize(dummyPtr, &serSize, SerializeIF::Endianness::NETWORK) ==
result::FAILED);
}
SECTION("Serialization fails") {
REQUIRE(headerSerializer.serialize(nullptr, &serSize, serBuf.size(),
SerializeIF::Endianness::NETWORK) == result::FAILED);
}
SECTION("Buffer Too Short") {
for (uint8_t idx = 0; idx < 7; idx++) {
result = headerSerializer.serialize(&serTarget, &serSize, idx, SerializeIF::Endianness::BIG);
REQUIRE(result == static_cast<int>(SerializeIF::BUFFER_TOO_SHORT));
}
}
SECTION("Set Data Field Len") {
// Set PDU data field len
headerSerializer.setPduDataFieldLen(0x0ff0);
REQUIRE(headerSerializer.getPduDataFieldLen() == 0x0ff0);
REQUIRE(headerSerializer.getSerializedSize() == 7);
REQUIRE(headerSerializer.getWholePduSize() == 7 + 0x0ff0);
serTarget = serBuf.data();
serSize = 0;
result = headerSerializer.serialize(&serTarget, &serSize, serBuf.size(),
SerializeIF::Endianness::BIG);
REQUIRE(serBuf[1] == 0x0f);
REQUIRE(serBuf[2] == 0xf0);
}
SECTION("Serialize with Fields Flipped") {
pduConf.crcFlag = true;
pduConf.largeFile = true;
pduConf.direction = cfdp::Direction::TOWARDS_SENDER;
pduConf.mode = cfdp::TransmissionModes::UNACKNOWLEDGED;
headerSerializer.setSegmentationControl(
cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION);
headerSerializer.setPduType(cfdp::PduType::FILE_DATA);
headerSerializer.setSegmentMetadataFlag(cfdp::SegmentMetadataFlag::PRESENT);
serTarget = serBuf.data();
serSize = 0;
SECTION("Regular") {
// Everything except version bit flipped to one now
REQUIRE(headerSerializer.serialize(&serTarget, &serSize, serBuf.size(),
SerializeIF::Endianness::BIG) == result::OK);
CHECK(serBuf[0] == 0x3f);
CHECK(serBuf[3] == 0x99);
REQUIRE(headerSerializer.getCrcFlag() == true);
REQUIRE(headerSerializer.getDirection() == cfdp::Direction::TOWARDS_SENDER);
REQUIRE(headerSerializer.getLargeFileFlag() == true);
REQUIRE(headerSerializer.getLenEntityIds() == 1);
REQUIRE(headerSerializer.getLenSeqNum() == 1);
REQUIRE(headerSerializer.getPduType() == cfdp::PduType::FILE_DATA);
REQUIRE(headerSerializer.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT);
REQUIRE(headerSerializer.getTransmissionMode() == cfdp::TransmissionModes::UNACKNOWLEDGED);
REQUIRE(headerSerializer.getSegmentationControl() == true);
}
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);
REQUIRE(pduConf.sourceId.getSerializedSize() == 4);
REQUIRE(headerSerializer.getSerializedSize() == 14);
REQUIRE(headerSerializer.serialize(&serTarget, &serSize, serBuf.size(),
SerializeIF::Endianness::BIG) == result::OK);
REQUIRE(headerSerializer.getCrcFlag() == true);
REQUIRE(headerSerializer.getDirection() == cfdp::Direction::TOWARDS_SENDER);
REQUIRE(headerSerializer.getLargeFileFlag() == true);
REQUIRE(headerSerializer.getLenEntityIds() == 4);
REQUIRE(headerSerializer.getLenSeqNum() == 2);
REQUIRE(headerSerializer.getPduType() == cfdp::PduType::FILE_DATA);
REQUIRE(headerSerializer.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT);
REQUIRE(headerSerializer.getTransmissionMode() == cfdp::TransmissionModes::UNACKNOWLEDGED);
REQUIRE(headerSerializer.getSegmentationControl() == true);
// Last three bits are 2 now (length of seq number) and bit 1 to bit 3 is 4 (len entity IDs)
REQUIRE(serBuf[3] == 0b11001010);
uint32_t entityId = 0;
size_t deSerSize = 0;
SerializeAdapter::deSerialize(&entityId, serBuf.data() + 4, &deSerSize,
SerializeIF::Endianness::NETWORK);
CHECK(deSerSize == 4);
CHECK(entityId == 0xff00ff00);
uint16_t seqNumRaw = 0;
SerializeAdapter::deSerialize(&seqNumRaw, serBuf.data() + 8, &deSerSize,
SerializeIF::Endianness::NETWORK);
CHECK(deSerSize == 2);
CHECK(seqNumRaw == 0x0fff);
SerializeAdapter::deSerialize(&entityId, serBuf.data() + 10, &deSerSize,
SerializeIF::Endianness::NETWORK);
CHECK(deSerSize == 4);
CHECK(entityId == 0x00ff00ff);
}
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);
for (uint8_t idx = 0; idx < 14; idx++) {
REQUIRE(
headerSerializer.serialize(&serTarget, &serSize, idx, SerializeIF::Endianness::BIG) ==
SerializeIF::BUFFER_TOO_SHORT);
}
}
}
SECTION("Invalid Variable Sized Fields") {
result = pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 0xfff);
REQUIRE(result == result::FAILED);
result = pduConf.sourceId.setValue(cfdp::WidthInBytes::TWO_BYTES, 0xfffff);
REQUIRE(result == result::FAILED);
result = pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xfffffffff);
REQUIRE(result == result::FAILED);
}
SECTION("Header Serialization") {
result = headerSerializer.serialize(&serTarget, &serSize, serBuf.size(),
SerializeIF::Endianness::BIG);
REQUIRE(result == result::OK);
REQUIRE(serSize == 7);
// Only version bits are set
REQUIRE(serBuf[0] == 0b00100000);
// PDU data field length is 0
REQUIRE(serBuf[1] == 0);
REQUIRE(serBuf[2] == 0);
// Entity and Transaction Sequence number are 1 byte large
REQUIRE(serBuf[3] == 0b00010001);
// Source ID
REQUIRE(serBuf[4] == 0);
// Transaction Seq Number
REQUIRE(serBuf[5] == 2);
// Dest ID
REQUIRE(serBuf[6] == 1);
uint8_t oneByteSourceId = 32;
serTarget = &oneByteSourceId;
size_t deserLen = 1;
pduConf.sourceId.deSerialize(cfdp::WidthInBytes::ONE_BYTE,
const_cast<const uint8_t**>(&serTarget), &deserLen,
SerializeIF::Endianness::MACHINE);
REQUIRE(pduConf.sourceId.getValue() == 32);
uint16_t twoByteSourceId = 0xf0f0;
serTarget = reinterpret_cast<uint8_t*>(&twoByteSourceId);
deserLen = 2;
pduConf.sourceId.deSerialize(cfdp::WidthInBytes::TWO_BYTES,
const_cast<const uint8_t**>(&serTarget), &deserLen,
SerializeIF::Endianness::MACHINE);
REQUIRE(pduConf.sourceId.getValue() == 0xf0f0);
uint32_t fourByteSourceId = 0xf0f0f0f0;
serTarget = reinterpret_cast<uint8_t*>(&fourByteSourceId);
deserLen = 4;
pduConf.sourceId.deSerialize(cfdp::WidthInBytes::FOUR_BYTES,
const_cast<const uint8_t**>(&serTarget), &deserLen,
SerializeIF::Endianness::MACHINE);
REQUIRE(pduConf.sourceId.getValue() == 0xf0f0f0f0);
pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 1);
serTarget = serBuf.data();
serSize = 1;
result = pduConf.sourceId.serialize(&serTarget, &serSize, 1, SerializeIF::Endianness::MACHINE);
REQUIRE(result == static_cast<int>(SerializeIF::BUFFER_TOO_SHORT));
}
SECTION("Header Deserialization") {
REQUIRE(headerSerializer.serialize(&serTarget, &serSize, serBuf.size(),
SerializeIF::Endianness::BIG) == result::OK);
REQUIRE(serBuf[1] == 0);
REQUIRE(serBuf[2] == 0);
// Entity and Transaction Sequence number are 1 byte large
REQUIRE(serBuf[3] == 0b00010001);
REQUIRE(serSize == 7);
// Deser call not strictly necessary
auto headerDeser = HeaderReader(serBuf.data(), serBuf.size());
ReturnValue_t serResult = headerDeser.parseData();
REQUIRE(serResult == result::OK);
REQUIRE(headerDeser.getPduDataFieldLen() == 0);
REQUIRE(headerDeser.getHeaderSize() == 7);
REQUIRE(headerDeser.getWholePduSize() == 7);
REQUIRE(headerDeser.getCrcFlag() == false);
REQUIRE(headerDeser.getDirection() == cfdp::Direction::TOWARDS_RECEIVER);
REQUIRE(headerDeser.getLargeFileFlag() == false);
REQUIRE(headerDeser.getLenEntityIds() == 1);
REQUIRE(headerDeser.getLenSeqNum() == 1);
REQUIRE(headerDeser.getPduType() == cfdp::PduType::FILE_DIRECTIVE);
REQUIRE(headerDeser.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::NOT_PRESENT);
REQUIRE(headerDeser.getSegmentationControl() == false);
REQUIRE(headerDeser.getTransmissionMode() == cfdp::TransmissionModes::ACKNOWLEDGED);
pduConf.crcFlag = true;
pduConf.largeFile = true;
pduConf.direction = cfdp::Direction::TOWARDS_SENDER;
pduConf.mode = cfdp::TransmissionModes::UNACKNOWLEDGED;
headerSerializer.setSegmentationControl(
cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION);
headerSerializer.setPduType(cfdp::PduType::FILE_DATA);
headerSerializer.setSegmentMetadataFlag(cfdp::SegmentMetadataFlag::PRESENT);
result = pduConf.seqNum.setValue(cfdp::WidthInBytes::TWO_BYTES, 0x0fff);
REQUIRE(result == result::OK);
result = pduConf.sourceId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0xff00ff00);
REQUIRE(result == result::OK);
result = pduConf.destId.setValue(cfdp::WidthInBytes::FOUR_BYTES, 0x00ff00ff);
REQUIRE(result == result::OK);
serTarget = serBuf.data();
serSize = 0;
result = headerSerializer.serialize(&serTarget, &serSize, serBuf.size(),
SerializeIF::Endianness::BIG);
headerDeser = HeaderReader(serBuf.data(), serBuf.size());
result = headerDeser.parseData();
REQUIRE(result == result::OK);
// Everything except version bit flipped to one now
REQUIRE(serBuf[0] == 0x3f);
REQUIRE(serBuf[3] == 0b11001010);
REQUIRE(headerDeser.getWholePduSize() == 14);
REQUIRE(headerDeser.getCrcFlag() == true);
REQUIRE(headerDeser.getDirection() == cfdp::Direction::TOWARDS_SENDER);
REQUIRE(headerDeser.getLargeFileFlag() == true);
REQUIRE(headerDeser.getLenEntityIds() == 4);
REQUIRE(headerDeser.getLenSeqNum() == 2);
REQUIRE(headerDeser.getPduType() == cfdp::PduType::FILE_DATA);
REQUIRE(headerDeser.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT);
REQUIRE(headerDeser.getSegmentationControl() == true);
REQUIRE(headerDeser.getTransmissionMode() == cfdp::TransmissionModes::UNACKNOWLEDGED);
cfdp::TransactionSeqNum seqNumLocal;
headerDeser.getTransactionSeqNum(seqNumLocal);
REQUIRE(seqNumLocal.getWidth() == cfdp::WidthInBytes::TWO_BYTES);
REQUIRE(seqNumLocal.getValue() == 0x0fff);
cfdp::EntityId sourceDestId;
headerDeser.getSourceId(sourceDestId);
REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::FOUR_BYTES);
REQUIRE(sourceDestId.getValue() == 0xff00ff00);
headerDeser.getDestId(sourceDestId);
REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::FOUR_BYTES);
REQUIRE(sourceDestId.getValue() == 0x00ff00ff);
size_t deSerSize = headerDeser.getWholePduSize();
serTarget = serBuf.data();
const auto** serTargetConst = const_cast<const uint8_t**>(&serTarget);
result = headerDeser.parseData();
REQUIRE(result == result::OK);
CHECK(headerDeser.setData(nullptr, -1) != result::OK);
REQUIRE(headerDeser.getHeaderSize() == 14);
headerDeser.setData(serBuf.data(), serBuf.size());
serTarget = serBuf.data();
serSize = 0;
pduConf.sourceId.setValue(cfdp::WidthInBytes::ONE_BYTE, 22);
pduConf.destId.setValue(cfdp::WidthInBytes::ONE_BYTE, 48);
result = headerSerializer.serialize(&serTarget, &serSize, serBuf.size(),
SerializeIF::Endianness::BIG);
REQUIRE(result == result::OK);
REQUIRE(headerDeser.getWholePduSize() == 8);
headerDeser.setData(serBuf.data(), serBuf.size());
headerDeser.getSourceId(sourceDestId);
REQUIRE(sourceDestId.getWidth() == cfdp::WidthInBytes::ONE_BYTE);
REQUIRE(sourceDestId.getValue() == 22);
}
}

View File

@ -0,0 +1,118 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/pdu/EofPduDeserializer.h"
#include "fsfw/cfdp/pdu/EofPduSerializer.h"
#include "fsfw/globalfunctions/arrayprinter.h"
TEST_CASE("EOF PDU", "[cfdp][pdu]") {
using namespace cfdp;
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
std::array<uint8_t, 128> buf = {};
uint8_t* bufPtr = buf.data();
size_t sz = 0;
EntityId destId(WidthInBytes::TWO_BYTES, 2);
EntityIdTlv faultLoc(destId);
FileSize 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);
EntityId sourceId(WidthInBytes::TWO_BYTES, 1);
PduConfig pduConf(sourceId, destId, TransmissionModes::ACKNOWLEDGED, seqNum);
auto eofSerializer = EofPduSerializer(pduConf, eofInfo);
SECTION("Serialize") {
result = eofSerializer.serialize(&bufPtr, &sz, buf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(((buf[1] << 8) | buf[2]) == 10);
uint32_t checksum = 0;
result = SerializeAdapter::deSerialize(&checksum, buf.data() + sz - 8, nullptr,
SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(checksum == 5);
uint32_t fileSizeVal = 0;
result = SerializeAdapter::deSerialize(&fileSizeVal, buf.data() + sz - 4, nullptr,
SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(fileSizeVal == 12);
REQUIRE(buf[sz - 10] == cfdp::FileDirectives::EOF_DIRECTIVE);
REQUIRE(buf[sz - 9] == 0x00);
REQUIRE(sz == 20);
eofInfo.setConditionCode(cfdp::ConditionCode::FILESTORE_REJECTION);
eofInfo.setFileSize(0x10ffffff10, true);
pduConf.largeFile = true;
// Should serialize with fault location now
auto serializeWithFaultLocation = EofPduSerializer(pduConf, eofInfo);
bufPtr = buf.data();
sz = 0;
result = serializeWithFaultLocation.serialize(&bufPtr, &sz, buf.size(),
SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(sz == 28);
REQUIRE(buf[10] == cfdp::FileDirectives::EOF_DIRECTIVE);
REQUIRE(buf[11] >> 4 == cfdp::ConditionCode::FILESTORE_REJECTION);
uint64_t fileSizeLarge = 0;
result = SerializeAdapter::deSerialize(&fileSizeLarge, buf.data() + 16, nullptr,
SerializeIF::Endianness::NETWORK);
REQUIRE(fileSizeLarge == 0x10ffffff10);
REQUIRE(buf[sz - 4] == cfdp::TlvTypes::ENTITY_ID);
// width of entity ID is 2
REQUIRE(buf[sz - 3] == 2);
uint16_t entityIdRaw = 0;
result = SerializeAdapter::deSerialize(&entityIdRaw, buf.data() + sz - 2, nullptr,
SerializeIF::Endianness::NETWORK);
REQUIRE(entityIdRaw == 2);
bufPtr = buf.data();
sz = 0;
for (size_t idx = 0; idx < 27; idx++) {
result =
serializeWithFaultLocation.serialize(&bufPtr, &sz, idx, SerializeIF::Endianness::NETWORK);
REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT);
bufPtr = buf.data();
sz = 0;
}
eofInfo.setChecksum(16);
eofInfo.setFaultLoc(nullptr);
}
SECTION("Deserialize") {
result = eofSerializer.serialize(&bufPtr, &sz, buf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
EntityIdTlv tlv(destId);
EofInfo emptyInfo(&tlv);
auto deserializer = EofPduDeserializer(buf.data(), buf.size(), emptyInfo);
result = deserializer.parseData();
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(emptyInfo.getConditionCode() == cfdp::ConditionCode::NO_ERROR);
REQUIRE(emptyInfo.getChecksum() == 5);
REQUIRE(emptyInfo.getFileSize().getSize() == 12);
eofInfo.setConditionCode(cfdp::ConditionCode::FILESTORE_REJECTION);
eofInfo.setFileSize(0x10ffffff10, true);
pduConf.largeFile = true;
// Should serialize with fault location now
auto serializeWithFaultLocation = EofPduSerializer(pduConf, eofInfo);
bufPtr = buf.data();
sz = 0;
result = serializeWithFaultLocation.serialize(&bufPtr, &sz, buf.size(),
SerializeIF::Endianness::NETWORK);
auto deserializer2 = EofPduDeserializer(buf.data(), buf.size(), emptyInfo);
result = deserializer2.parseData();
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(emptyInfo.getConditionCode() == cfdp::ConditionCode::FILESTORE_REJECTION);
REQUIRE(emptyInfo.getChecksum() == 5);
REQUIRE(emptyInfo.getFileSize().getSize() == 0x10ffffff10);
REQUIRE(emptyInfo.getFaultLoc()->getType() == cfdp::TlvTypes::ENTITY_ID);
REQUIRE(emptyInfo.getFaultLoc()->getSerializedSize() == 4);
uint16_t destId = emptyInfo.getFaultLoc()->getEntityId().getValue();
REQUIRE(destId == 2);
for (size_t maxSz = 0; maxSz < deserializer2.getWholePduSize() - 1; maxSz++) {
auto invalidDeser = EofPduDeserializer(buf.data(), maxSz, emptyInfo);
result = invalidDeser.parseData();
REQUIRE(result != HasReturnvaluesIF::RETURN_OK);
}
}
}

View File

@ -0,0 +1,171 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/pdu/FileDataCreator.h"
#include "fsfw/cfdp/pdu/FileDataReader.h"
#include "fsfw/globalfunctions/arrayprinter.h"
#include "fsfw/serviceinterface.h"
TEST_CASE("File Data PDU", "[cfdp][pdu]") {
using namespace cfdp;
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
std::array<uint8_t, 128> fileBuffer = {};
std::array<uint8_t, 256> fileDataBuffer = {};
uint8_t* buffer = fileDataBuffer.data();
size_t sz = 0;
EntityId destId(WidthInBytes::TWO_BYTES, 2);
TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15);
EntityId sourceId(WidthInBytes::TWO_BYTES, 1);
PduConfig pduConf(sourceId, destId, TransmissionModes::ACKNOWLEDGED, seqNum);
for (uint8_t idx = 0; idx < 10; idx++) {
fileBuffer[idx] = idx;
}
FileSize offset(50);
FileDataInfo info(offset, fileBuffer.data(), 10);
SECTION("Serialization") {
FileDataCreator serializer(pduConf, info);
result =
serializer.serialize(&buffer, &sz, fileDataBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(sz == 24);
// 10 file bytes plus 4 byte offset
REQUIRE(((fileDataBuffer[1] << 8) | fileDataBuffer[2]) == 14);
// File Data -> Fourth bit is one
REQUIRE(fileDataBuffer[0] == 0b00110000);
uint32_t offsetRaw = 0;
buffer = fileDataBuffer.data();
result = SerializeAdapter::deSerialize(&offsetRaw, buffer + 10, nullptr,
SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(offsetRaw == 50);
buffer = fileDataBuffer.data() + 14;
for (size_t idx = 0; idx < 10; idx++) {
REQUIRE(buffer[idx] == idx);
}
REQUIRE(info.hasSegmentMetadata() == false);
info.addSegmentMetadataInfo(cfdp::RecordContinuationState::CONTAINS_START_AND_END,
fileBuffer.data(), 10);
REQUIRE(info.hasSegmentMetadata() == true);
REQUIRE(info.getSegmentationControl() ==
cfdp::SegmentationControl::NO_RECORD_BOUNDARIES_PRESERVATION);
info.setSegmentationControl(cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION);
serializer.update();
REQUIRE(serializer.getSegmentationControl() ==
cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION);
buffer = fileDataBuffer.data();
sz = 0;
serializer.setSegmentationControl(cfdp::SegmentationControl::RECORD_BOUNDARIES_PRESERVATION);
result =
serializer.serialize(&buffer, &sz, fileDataBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(((fileDataBuffer[1] << 8) | fileDataBuffer[2]) == 25);
// First bit: Seg Ctrl is set
// Bits 1 to 3 length of enitity IDs is 2
// Bit 4: Segment metadata flag is set
// Bit 5 to seven: length of transaction seq num is 2
REQUIRE(fileDataBuffer[3] == 0b10101010);
REQUIRE((fileDataBuffer[10] >> 6) &
0b11 == cfdp::RecordContinuationState::CONTAINS_START_AND_END);
// Segment metadata length
REQUIRE((fileDataBuffer[10] & 0x3f) == 10);
buffer = fileDataBuffer.data() + 11;
// Check segment metadata
for (size_t idx = 0; idx < 10; idx++) {
REQUIRE(buffer[idx] == idx);
}
// Check filedata
buffer = fileDataBuffer.data() + 25;
for (size_t idx = 0; idx < 10; idx++) {
REQUIRE(buffer[idx] == idx);
}
for (size_t invalidStartSz = 1; invalidStartSz < sz; invalidStartSz++) {
buffer = fileDataBuffer.data();
sz = 0;
result = serializer.serialize(&buffer, &invalidStartSz, sz, SerializeIF::Endianness::NETWORK);
REQUIRE(result != HasReturnvaluesIF::RETURN_OK);
}
info.setSegmentMetadataFlag(true);
REQUIRE(info.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::PRESENT);
info.setSegmentMetadataFlag(false);
REQUIRE(info.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::NOT_PRESENT);
info.setRecordContinuationState(cfdp::RecordContinuationState::CONTAINS_END_NO_START);
info.setSegmentMetadataLen(10);
info.setSegmentMetadata(nullptr);
info.setFileData(nullptr, 0);
}
SECTION("Deserialization") {
FileDataCreator serializer(pduConf, info);
result =
serializer.serialize(&buffer, &sz, fileDataBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
FileSize emptyOffset;
FileDataInfo emptyInfo(emptyOffset);
FileDataReader deserializer(fileDataBuffer.data(), fileDataBuffer.size(), emptyInfo);
result = deserializer.parseData();
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(deserializer.getWholePduSize() == 24);
REQUIRE(deserializer.getPduDataFieldLen() == 14);
REQUIRE(deserializer.getSegmentationControl() ==
cfdp::SegmentationControl::NO_RECORD_BOUNDARIES_PRESERVATION);
REQUIRE(deserializer.getSegmentMetadataFlag() == cfdp::SegmentMetadataFlag::NOT_PRESENT);
REQUIRE(emptyInfo.getOffset().getSize() == 50);
REQUIRE(emptyInfo.hasSegmentMetadata() == false);
size_t emptyFileSize = 0;
const uint8_t* fileData = emptyInfo.getFileData(&emptyFileSize);
REQUIRE(emptyFileSize == 10);
for (size_t idx = 0; idx < 10; idx++) {
REQUIRE(fileData[idx] == idx);
}
deserializer.setEndianness(SerializeIF::Endianness::NETWORK);
info.addSegmentMetadataInfo(cfdp::RecordContinuationState::CONTAINS_START_AND_END,
fileBuffer.data(), 10);
serializer.update();
buffer = fileDataBuffer.data();
sz = 0;
result =
serializer.serialize(&buffer, &sz, fileDataBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
result = deserializer.parseData();
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(emptyInfo.getOffset().getSize() == 50);
REQUIRE(emptyInfo.hasSegmentMetadata() == true);
REQUIRE(emptyInfo.getRecordContinuationState() ==
cfdp::RecordContinuationState::CONTAINS_START_AND_END);
emptyFileSize = 0;
fileData = emptyInfo.getFileData(&emptyFileSize);
REQUIRE(emptyFileSize == 10);
for (size_t idx = 0; idx < 10; idx++) {
REQUIRE(fileData[idx] == idx);
}
size_t segmentMetadataLen = 0;
fileData = emptyInfo.getSegmentMetadata(&segmentMetadataLen);
REQUIRE(segmentMetadataLen == 10);
for (size_t idx = 0; idx < 10; idx++) {
REQUIRE(fileData[idx] == idx);
}
for (size_t invalidPduField = 0; invalidPduField < 24; invalidPduField++) {
fileDataBuffer[1] = (invalidPduField >> 8) & 0xff;
fileDataBuffer[2] = invalidPduField & 0xff;
result = deserializer.parseData();
// Starting at 15, the file data is parsed. There is not leading file data length
// field to the parser can't check whether the remaining length is valid
if (invalidPduField < 15) {
REQUIRE(result != HasReturnvaluesIF::RETURN_OK);
}
}
}
}

View File

@ -0,0 +1,85 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/pdu/FileDirectiveCreator.h"
#include "fsfw/cfdp/pdu/FileDirectiveReader.h"
TEST_CASE("CFDP File Directive", "[cfdp]") {
using namespace cfdp;
std::array<uint8_t, 32> serBuf{};
ReturnValue_t result;
cfdp::TransactionSeqNum seqNum = TransactionSeqNum(cfdp::WidthInBytes::ONE_BYTE, 2);
cfdp::EntityId sourceId = EntityId(cfdp::WidthInBytes::ONE_BYTE, 0);
cfdp::EntityId destId = EntityId(cfdp::WidthInBytes::ONE_BYTE, 1);
PduConfig pduConf =
PduConfig(sourceId, destId, cfdp::TransmissionModes::ACKNOWLEDGED, seqNum, false);
uint8_t* serTarget = serBuf.data();
const uint8_t* deserTarget = serTarget;
size_t serSize = 0;
auto fdSer = FileDirectiveCreator(pduConf, FileDirectives::ACK, 4);
SECTION("Serialization") {
REQUIRE(fdSer.getSerializedSize() == 8);
serTarget = serBuf.data();
serSize = 0;
result = fdSer.serialize(&serTarget, &serSize, serBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
// Only version bits are set
REQUIRE(serBuf[0] == 0b00100000);
// PDU data field length is 5 (4 + Directive code octet)
REQUIRE(serBuf[1] == 0);
REQUIRE(serBuf[2] == 5);
// Entity and Transaction Sequence number are 1 byte large
REQUIRE(serBuf[3] == 0b00010001);
// Source ID
REQUIRE(serBuf[4] == 0);
// Transaction Seq Number
REQUIRE(serBuf[5] == 2);
// Dest ID
REQUIRE(serBuf[6] == 1);
REQUIRE(serBuf[7] == FileDirectives::ACK);
}
SECTION("Serialization fails") {
REQUIRE(fdSer.serialize(nullptr, nullptr, 85, SerializeIF::Endianness::NETWORK) ==
HasReturnvaluesIF::RETURN_FAILED);
}
SECTION("Buffer Too Short") {
for (uint8_t idx = 0; idx < 8; idx++) {
serTarget = serBuf.data();
serSize = 0;
REQUIRE(fdSer.serialize(&serTarget, &serSize, idx, SerializeIF::Endianness::NETWORK) ==
SerializeIF::BUFFER_TOO_SHORT);
}
}
SECTION("Deserialize") {
CHECK(fdSer.serialize(&serTarget, &serSize, serBuf.size(), SerializeIF::Endianness::NETWORK) ==
result::OK);
serTarget = serBuf.data();
REQUIRE(fdSer.deSerialize(&deserTarget, &serSize, SerializeIF::Endianness::NETWORK) ==
HasReturnvaluesIF::RETURN_FAILED);
deserTarget = serBuf.data();
CHECK(serSize == 8);
auto fdDeser = FileDirectiveReader(deserTarget, serBuf.size());
REQUIRE(fdDeser.isNull());
REQUIRE(not fdDeser);
REQUIRE(fdDeser.getEndianness() == SerializeIF::Endianness::NETWORK);
fdDeser.setEndianness(SerializeIF::Endianness::MACHINE);
REQUIRE(fdDeser.getEndianness() == SerializeIF::Endianness::MACHINE);
fdDeser.setEndianness(SerializeIF::Endianness::NETWORK);
REQUIRE(fdDeser.parseData() == HasReturnvaluesIF::RETURN_OK);
REQUIRE(not fdDeser.isNull());
REQUIRE(fdDeser);
REQUIRE(fdDeser.getFileDirective() == FileDirectives::ACK);
REQUIRE(fdDeser.getPduDataFieldLen() == 5);
REQUIRE(fdDeser.getHeaderSize() == 8);
REQUIRE(fdDeser.getPduType() == cfdp::PduType::FILE_DIRECTIVE);
serBuf[7] = 0xff;
// Invalid file directive
REQUIRE(fdDeser.parseData() == cfdp::INVALID_DIRECTIVE_FIELDS);
}
}

View File

@ -0,0 +1,189 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/pdu/FinishedPduDeserializer.h"
#include "fsfw/cfdp/pdu/FinishedPduSerializer.h"
#include "fsfw/globalfunctions/arrayprinter.h"
TEST_CASE("Finished PDU", "[cfdp][pdu]") {
using namespace cfdp;
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
std::array<uint8_t, 256> fnBuffer = {};
uint8_t* buffer = fnBuffer.data();
size_t sz = 0;
EntityId destId(WidthInBytes::TWO_BYTES, 2);
TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15);
EntityId sourceId(WidthInBytes::TWO_BYTES, 1);
PduConfig pduConf(sourceId, destId, TransmissionModes::ACKNOWLEDGED, seqNum);
cfdp::Lv emptyFsMsg;
FinishedInfo info(cfdp::ConditionCode::INACTIVITY_DETECTED,
cfdp::FinishedDeliveryCode::DATA_INCOMPLETE,
cfdp::FinishedFileStatus::DISCARDED_DELIBERATELY);
SECTION("Serialize") {
FinishPduSerializer serializer(pduConf, info);
result = serializer.serialize(&buffer, &sz, fnBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(serializer.getSerializedSize() == 12);
REQUIRE(((fnBuffer[1] << 8) | fnBuffer[2]) == 2);
REQUIRE(fnBuffer[10] == cfdp::FileDirectives::FINISH);
REQUIRE(((fnBuffer[sz - 1] >> 4) & 0x0f) == cfdp::ConditionCode::INACTIVITY_DETECTED);
REQUIRE(((fnBuffer[sz - 1] >> 2) & 0x01) == cfdp::FinishedDeliveryCode::DATA_INCOMPLETE);
REQUIRE((fnBuffer[sz - 1] & 0b11) == cfdp::FinishedFileStatus::DISCARDED_DELIBERATELY);
REQUIRE(sz == 12);
// Add a filestore response
std::string firstName = "hello.txt";
cfdp::Lv firstNameLv(reinterpret_cast<const uint8_t*>(firstName.data()), firstName.size());
FilestoreResponseTlv response(cfdp::FilestoreActionCode::DELETE_FILE,
cfdp::FSR_APPEND_FILE_1_NOT_EXISTS, firstNameLv, nullptr);
FilestoreResponseTlv* responsePtr = &response;
REQUIRE(response.getSerializedSize() == 14);
size_t len = 1;
info.setFilestoreResponsesArray(&responsePtr, &len, &len);
serializer.updateDirectiveFieldLen();
REQUIRE(serializer.getSerializedSize() == 12 + 14);
sz = 0;
buffer = fnBuffer.data();
result = serializer.serialize(&buffer, &sz, fnBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(serializer.getSerializedSize() == 12 + 14);
REQUIRE(serializer.getPduDataFieldLen() == 16);
// Add two filestore responses and a fault location parameter
std::string secondName = "hello2.txt";
cfdp::Lv secondNameLv(reinterpret_cast<const uint8_t*>(secondName.data()), secondName.size());
FilestoreResponseTlv response2(cfdp::FilestoreActionCode::DENY_FILE, cfdp::FSR_SUCCESS,
secondNameLv, nullptr);
REQUIRE(response2.getSerializedSize() == 15);
len = 2;
std::array<FilestoreResponseTlv*, 2> responses{&response, &response2};
info.setFilestoreResponsesArray(responses.data(), &len, &len);
serializer.updateDirectiveFieldLen();
EntityIdTlv faultLoc(destId);
REQUIRE(faultLoc.getSerializedSize() == 4);
info.setFaultLocation(&faultLoc);
serializer.updateDirectiveFieldLen();
sz = 0;
buffer = fnBuffer.data();
result = serializer.serialize(&buffer, &sz, fnBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
info.setConditionCode(cfdp::ConditionCode::FILESTORE_REJECTION);
REQUIRE(serializer.getSerializedSize() == 12 + 14 + 15 + 4);
REQUIRE(sz == 12 + 14 + 15 + 4);
info.setFileStatus(cfdp::FinishedFileStatus::DISCARDED_FILESTORE_REJECTION);
REQUIRE(info.getFileStatus() == cfdp::FinishedFileStatus::DISCARDED_FILESTORE_REJECTION);
info.setDeliveryCode(cfdp::FinishedDeliveryCode::DATA_INCOMPLETE);
REQUIRE(info.getDeliveryCode() == cfdp::FinishedDeliveryCode::DATA_INCOMPLETE);
for (size_t maxSz = 0; maxSz < 45; maxSz++) {
sz = 0;
buffer = fnBuffer.data();
result = serializer.serialize(&buffer, &sz, maxSz, SerializeIF::Endianness::NETWORK);
REQUIRE(result != HasReturnvaluesIF::RETURN_OK);
}
}
SECTION("Deserialize") {
FinishedInfo emptyInfo;
FinishPduSerializer serializer(pduConf, info);
result = serializer.serialize(&buffer, &sz, fnBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
FinishPduDeserializer deserializer(fnBuffer.data(), fnBuffer.size(), emptyInfo);
result = deserializer.parseData();
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(emptyInfo.getFileStatus() == cfdp::FinishedFileStatus::DISCARDED_DELIBERATELY);
REQUIRE(emptyInfo.getConditionCode() == cfdp::ConditionCode::INACTIVITY_DETECTED);
REQUIRE(emptyInfo.getDeliveryCode() == cfdp::FinishedDeliveryCode::DATA_INCOMPLETE);
// Add a filestore response
sz = 0;
buffer = fnBuffer.data();
std::string firstName = "hello.txt";
cfdp::Lv firstNameLv(reinterpret_cast<const uint8_t*>(firstName.data()), firstName.size());
FilestoreResponseTlv response(cfdp::FilestoreActionCode::DELETE_FILE, cfdp::FSR_NOT_PERFORMED,
firstNameLv, nullptr);
FilestoreResponseTlv* responsePtr = &response;
size_t len = 1;
info.setFilestoreResponsesArray(&responsePtr, &len, &len);
serializer.updateDirectiveFieldLen();
REQUIRE(serializer.getPduDataFieldLen() == 16);
result = serializer.serialize(&buffer, &sz, fnBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
FilestoreResponseTlv emptyResponse(firstNameLv, nullptr);
responsePtr = &emptyResponse;
emptyInfo.setFilestoreResponsesArray(&responsePtr, nullptr, &len);
FinishPduDeserializer deserializer2(fnBuffer.data(), fnBuffer.size(), emptyInfo);
result = deserializer2.parseData();
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(emptyInfo.getFsResponsesLen() == 1);
FilestoreResponseTlv** responseArray = nullptr;
emptyInfo.getFilestoreResonses(&responseArray, nullptr, nullptr);
REQUIRE(responseArray[0]->getActionCode() == cfdp::FilestoreActionCode::DELETE_FILE);
REQUIRE(responseArray[0]->getStatusCode() == cfdp::FSR_NOT_PERFORMED);
auto& fileNameRef = responseArray[0]->getFirstFileName();
size_t stringSize = 0;
const char* string = reinterpret_cast<const char*>(fileNameRef.getValue(&stringSize));
std::string firstFileName(string, stringSize);
REQUIRE(firstFileName == "hello.txt");
// Add two filestore responses and a fault location parameter
std::string secondName = "hello2.txt";
cfdp::Lv secondNameLv(reinterpret_cast<const uint8_t*>(secondName.data()), secondName.size());
FilestoreResponseTlv response2(cfdp::FilestoreActionCode::DENY_FILE, cfdp::FSR_SUCCESS,
secondNameLv, nullptr);
REQUIRE(response2.getSerializedSize() == 15);
len = 2;
std::array<FilestoreResponseTlv*, 2> responses{&response, &response2};
info.setFilestoreResponsesArray(responses.data(), &len, &len);
serializer.updateDirectiveFieldLen();
EntityIdTlv faultLoc(destId);
info.setFaultLocation(&faultLoc);
serializer.updateDirectiveFieldLen();
sz = 0;
buffer = fnBuffer.data();
result = serializer.serialize(&buffer, &sz, fnBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
EntityId emptyId;
EntityIdTlv emptyFaultLoc(emptyId);
emptyInfo.setFaultLocation(&emptyFaultLoc);
response.setFilestoreMessage(&emptyFsMsg);
emptyInfo.setFilestoreResponsesArray(responses.data(), &len, &len);
response2.setFilestoreMessage(&emptyFsMsg);
FinishPduDeserializer deserializer3(fnBuffer.data(), fnBuffer.size(), emptyInfo);
result = deserializer3.parseData();
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
auto& infoRef = deserializer3.getInfo();
REQUIRE(deserializer3.getWholePduSize() == 45);
size_t invalidMaxLen = 1;
emptyInfo.setFilestoreResponsesArray(responses.data(), &len, &invalidMaxLen);
result = deserializer3.parseData();
REQUIRE(result == cfdp::FINISHED_CANT_PARSE_FS_RESPONSES);
emptyInfo.setFilestoreResponsesArray(nullptr, nullptr, nullptr);
result = deserializer3.parseData();
REQUIRE(result == cfdp::FINISHED_CANT_PARSE_FS_RESPONSES);
// Clear condition code
auto tmp = fnBuffer[11];
fnBuffer[11] = fnBuffer[11] & ~0xf0;
fnBuffer[11] = fnBuffer[11] | (cfdp::ConditionCode::NO_ERROR << 4);
emptyInfo.setFilestoreResponsesArray(responses.data(), &len, &len);
result = deserializer3.parseData();
REQUIRE(result == cfdp::INVALID_TLV_TYPE);
fnBuffer[11] = tmp;
// Invalid TLV type, should be entity ID
fnBuffer[sz - 4] = cfdp::TlvTypes::FILESTORE_REQUEST;
result = deserializer3.parseData();
REQUIRE(result == cfdp::INVALID_TLV_TYPE);
for (size_t maxSz = 0; maxSz < 45; maxSz++) {
FinishPduDeserializer faultyDeser(fnBuffer.data(), maxSz, emptyInfo);
result = faultyDeser.parseData();
REQUIRE(result != HasReturnvaluesIF::RETURN_OK);
}
}
}

View File

@ -0,0 +1,81 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/pdu/KeepAlivePduDeserializer.h"
#include "fsfw/cfdp/pdu/KeepAlivePduSerializer.h"
#include "fsfw/globalfunctions/arrayprinter.h"
TEST_CASE("Keep Alive PDU", "[cfdp][pdu]") {
using namespace cfdp;
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
std::array<uint8_t, 256> kaBuffer = {};
uint8_t* buffer = kaBuffer.data();
size_t sz = 0;
EntityId destId(WidthInBytes::TWO_BYTES, 2);
TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15);
EntityId sourceId(WidthInBytes::TWO_BYTES, 1);
PduConfig pduConf(sourceId, destId, TransmissionModes::ACKNOWLEDGED, seqNum);
FileSize progress(0x50);
SECTION("Serialize") {
KeepAlivePduSerializer serializer(pduConf, progress);
result = serializer.serialize(&buffer, &sz, kaBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(kaBuffer[10] == cfdp::FileDirectives::KEEP_ALIVE);
uint32_t fsRaw = 0;
result = SerializeAdapter::deSerialize(&fsRaw, kaBuffer.data() + 11, nullptr,
SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(fsRaw == 0x50);
REQUIRE(sz == 15);
REQUIRE(serializer.getWholePduSize() == 15);
REQUIRE(serializer.getPduDataFieldLen() == 5);
pduConf.largeFile = true;
serializer.updateDirectiveFieldLen();
buffer = kaBuffer.data();
sz = 0;
result = serializer.serialize(&buffer, &sz, kaBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(serializer.getWholePduSize() == 19);
REQUIRE(serializer.getPduDataFieldLen() == 9);
uint64_t fsRawLarge = 0;
result = SerializeAdapter::deSerialize(&fsRawLarge, kaBuffer.data() + 11, nullptr,
SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(fsRawLarge == 0x50);
for (size_t invalidMaxSz = 0; invalidMaxSz < sz; invalidMaxSz++) {
buffer = kaBuffer.data();
sz = 0;
result = serializer.serialize(&buffer, &sz, invalidMaxSz, SerializeIF::Endianness::NETWORK);
REQUIRE(result != HasReturnvaluesIF::RETURN_OK);
}
}
SECTION("Deserialize") {
KeepAlivePduSerializer serializer(pduConf, progress);
result = serializer.serialize(&buffer, &sz, kaBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
// Set another file size
progress.setFileSize(200, false);
KeepAlivePduDeserializer deserializer(kaBuffer.data(), kaBuffer.size(), progress);
result = deserializer.parseData();
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
auto& progRef = deserializer.getProgress();
// Should have been overwritten
REQUIRE(progRef.getSize() == 0x50);
sz = deserializer.getWholePduSize();
// invalid max size
for (size_t invalidMaxSz = 0; invalidMaxSz < sz; invalidMaxSz++) {
ReturnValue_t setResult = deserializer.setData(kaBuffer.data(), invalidMaxSz);
if (setResult == HasReturnvaluesIF::RETURN_OK) {
result = deserializer.parseData();
REQUIRE(result != HasReturnvaluesIF::RETURN_OK);
}
}
}
}

View File

@ -0,0 +1,181 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include <iostream>
#include "fsfw/cfdp/pdu/MetadataPduCreator.h"
#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 = HasReturnvaluesIF::RETURN_OK;
std::array<uint8_t, 256> mdBuffer = {};
uint8_t* buffer = mdBuffer.data();
size_t sz = 0;
EntityId destId(WidthInBytes::TWO_BYTES, 2);
TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15);
EntityId sourceId(WidthInBytes::TWO_BYTES, 1);
PduConfig pduConf(sourceId, destId, TransmissionModes::ACKNOWLEDGED, seqNum);
std::string firstFileName = "hello.txt";
cfdp::Lv sourceFileName(reinterpret_cast<const uint8_t*>(firstFileName.data()),
firstFileName.size());
cfdp::Lv destFileName;
FileSize fileSize(35);
MetadataInfo info(false, ChecksumType::MODULAR, fileSize, sourceFileName, destFileName);
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};
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 == HasReturnvaluesIF::RETURN_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);
REQUIRE(mdBuffer[10] == FileDirectives::METADATA);
// no closure requested and checksum type is modular => 0x00
REQUIRE(mdBuffer[11] == 0x00);
uint32_t fileSizeRaw = 0;
result = SerializeAdapter::deSerialize(&fileSizeRaw, mdBuffer.data() + 12, nullptr,
SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(fileSizeRaw == 35);
REQUIRE(mdBuffer[16] == 9);
REQUIRE(mdBuffer[17] == 'h');
REQUIRE(mdBuffer[18] == 'e');
REQUIRE(mdBuffer[19] == 'l');
REQUIRE(mdBuffer[20] == 'l');
REQUIRE(mdBuffer[21] == 'o');
REQUIRE(mdBuffer[22] == '.');
REQUIRE(mdBuffer[23] == 't');
REQUIRE(mdBuffer[24] == 'x');
REQUIRE(mdBuffer[25] == 't');
REQUIRE(mdBuffer[26] == 0);
std::string otherFileName = "hello2.txt";
cfdp::Lv otherFileNameLv(reinterpret_cast<const uint8_t*>(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);
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);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE((mdBuffer[1] << 8 | mdBuffer[2]) == 37);
auto checksumType = static_cast<cfdp::ChecksumType>(mdBuffer[11] & 0x0f);
REQUIRE(checksumType == cfdp::ChecksumType::CRC_32C);
bool closureRequested = mdBuffer[11] >> 6 & 0x01;
REQUIRE(closureRequested == true);
// The size of the two options is 19. Summing up:
// - 11 bytes of source file name
// - 1 byte for dest file name
// - 4 for FSS
// - 1 leading byte.
// - 1 byte for PDU type
// PDU header has 10 bytes.
// I am not going to check the options raw content, those are part of the dedicated
// TLV unittests
REQUIRE(sz == 10 + 37);
for (size_t maxSz = 0; maxSz < sz; maxSz++) {
uint8_t* buffer = mdBuffer.data();
size_t 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;
result = serializer.serialize(&buffer, &sz, 46, SerializeIF::Endianness::NETWORK);
REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT);
}
info.setDestFileName(destFileName);
}
SECTION("Deserialize") {
MetadataPduCreator serializer(pduConf, info);
result = serializer.serialize(&buffer, &sz, mdBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
MetadataPduReader deserializer(mdBuffer.data(), mdBuffer.size(), info);
result = deserializer.parseData();
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
size_t fullSize = deserializer.getWholePduSize();
for (size_t maxSz = 0; maxSz < fullSize; maxSz++) {
MetadataPduReader invalidSzDeser(mdBuffer.data(), maxSz, info);
result = invalidSzDeser.parseData();
REQUIRE(result != HasReturnvaluesIF::RETURN_OK);
}
size_t sizeOfOptions = options.size();
size_t maxSize = 4;
info.setOptionsArray(options.data(), &sizeOfOptions, &maxSize);
REQUIRE(info.getOptionsLen() == 2);
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 == HasReturnvaluesIF::RETURN_OK);
MetadataPduReader deserializer2(mdBuffer.data(), mdBuffer.size(), info);
result = deserializer2.parseData();
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(options[0]->getType() == cfdp::TlvTypes::FILESTORE_RESPONSE);
REQUIRE(options[0]->getSerializedSize() == 14);
REQUIRE(options[1]->getType() == cfdp::TlvTypes::MSG_TO_USER);
REQUIRE(options[1]->getSerializedSize() == 5);
for (size_t invalidFieldLen = 0; invalidFieldLen < 36; invalidFieldLen++) {
mdBuffer[1] = (invalidFieldLen >> 8) & 0xff;
mdBuffer[2] = invalidFieldLen & 0xff;
result = deserializer2.parseData();
if (invalidFieldLen == 17) {
REQUIRE(info.getOptionsLen() == 0);
}
if (invalidFieldLen == 31) {
REQUIRE(info.getOptionsLen() == 1);
}
// This is the precise length where there are no options or one option
if (invalidFieldLen != 17 and invalidFieldLen != 31) {
REQUIRE(result != HasReturnvaluesIF::RETURN_OK);
}
}
mdBuffer[1] = (36 >> 8) & 0xff;
mdBuffer[2] = 36 & 0xff;
info.setOptionsArray(nullptr, nullptr, nullptr);
REQUIRE(deserializer2.parseData() == cfdp::METADATA_CANT_PARSE_OPTIONS);
info.setOptionsArray(options.data(), &sizeOfOptions, nullptr);
for (size_t maxSz = 0; maxSz < 46; maxSz++) {
MetadataPduReader invalidSzDeser(mdBuffer.data(), maxSz, info);
if (not invalidSzDeser.isNull()) {
result = invalidSzDeser.parseData();
REQUIRE(result == SerializeIF::STREAM_TOO_SHORT);
}
}
}
}

View File

@ -0,0 +1,152 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/pdu/NakPduDeserializer.h"
#include "fsfw/cfdp/pdu/NakPduSerializer.h"
#include "fsfw/cfdp/pdu/PduConfig.h"
#include "fsfw/globalfunctions/arrayprinter.h"
TEST_CASE("NAK PDU", "[cfdp][pdu]") {
using namespace cfdp;
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
std::array<uint8_t, 256> nakBuffer = {};
uint8_t* buffer = nakBuffer.data();
size_t sz = 0;
EntityId destId(WidthInBytes::TWO_BYTES, 2);
TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15);
EntityId sourceId(WidthInBytes::TWO_BYTES, 1);
PduConfig pduConf(sourceId, destId, TransmissionModes::ACKNOWLEDGED, seqNum);
FileSize startOfScope(50);
FileSize endOfScope(1050);
NakInfo info(startOfScope, endOfScope);
SECTION("Serializer") {
NakPduSerializer serializer(pduConf, info);
result = serializer.serialize(&buffer, &sz, nakBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(serializer.getSerializedSize() == 19);
REQUIRE(serializer.FileDirectiveCreator::getSerializedSize() == 11);
REQUIRE(sz == 19);
REQUIRE(serializer.getPduDataFieldLen() == 9);
REQUIRE(((nakBuffer[1] << 8) | nakBuffer[2]) == 0x09);
REQUIRE(nakBuffer[10] == cfdp::FileDirectives::NAK);
uint32_t scope = 0;
result = SerializeAdapter::deSerialize(&scope, nakBuffer.data() + 11, nullptr,
SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(scope == 50);
result = SerializeAdapter::deSerialize(&scope, nakBuffer.data() + 15, nullptr,
SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(scope == 1050);
NakInfo::SegmentRequest segReq0(cfdp::FileSize(2020), cfdp::FileSize(2520));
NakInfo::SegmentRequest segReq1(cfdp::FileSize(2932), cfdp::FileSize(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();
info.setSegmentRequests(segReqs.data(), &segReqsLen, &segReqsLen);
uint8_t* buffer = nakBuffer.data();
size_t sz = 0;
serializer.updateDirectiveFieldLen();
result = serializer.serialize(&buffer, &sz, nakBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(serializer.getSerializedSize() == 35);
REQUIRE(serializer.getPduDataFieldLen() == 25);
REQUIRE(((nakBuffer[1] << 8) | nakBuffer[2]) == 25);
uint32_t segReqScopes = 0;
result = SerializeAdapter::deSerialize(&segReqScopes, nakBuffer.data() + 19, nullptr,
SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(segReqScopes == 2020);
result = SerializeAdapter::deSerialize(&segReqScopes, nakBuffer.data() + 23, nullptr,
SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(segReqScopes == 2520);
result = SerializeAdapter::deSerialize(&segReqScopes, nakBuffer.data() + 27, nullptr,
SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(segReqScopes == 2932);
result = SerializeAdapter::deSerialize(&segReqScopes, nakBuffer.data() + 31, nullptr,
SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(segReqScopes == 3021);
for (size_t maxSz = 0; maxSz < 35; maxSz++) {
uint8_t* buffer = nakBuffer.data();
size_t sz = 0;
result = serializer.serialize(&buffer, &sz, maxSz, SerializeIF::Endianness::NETWORK);
REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT);
}
for (size_t sz = 35; sz > 0; sz--) {
uint8_t* buffer = nakBuffer.data();
size_t locSize = sz;
result = serializer.serialize(&buffer, &locSize, 35, SerializeIF::Endianness::NETWORK);
REQUIRE(result == SerializeIF::BUFFER_TOO_SHORT);
}
}
SECTION("Deserializer") {
NakPduSerializer serializer(pduConf, info);
result = serializer.serialize(&buffer, &sz, nakBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
info.getStartOfScope().setFileSize(0, false);
info.getEndOfScope().setFileSize(0, false);
NakPduDeserializer deserializer(nakBuffer.data(), nakBuffer.size(), info);
result = deserializer.parseData();
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(deserializer.getWholePduSize() == 19);
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));
// 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();
info.setSegmentRequests(segReqs.data(), &segReqsLen, &segReqsLen);
uint8_t* buffer = nakBuffer.data();
size_t sz = 0;
serializer.updateDirectiveFieldLen();
result = serializer.serialize(&buffer, &sz, nakBuffer.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
NakPduDeserializer deserializeWithSegReqs(nakBuffer.data(), nakBuffer.size(), info);
result = deserializeWithSegReqs.parseData();
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
NakInfo::SegmentRequest* segReqsPtr = nullptr;
size_t readSegReqs = 0;
info.getSegmentRequests(&segReqsPtr, &readSegReqs, nullptr);
REQUIRE(readSegReqs == 2);
REQUIRE(segReqsPtr[0].first.getSize() == 2020);
REQUIRE(segReqsPtr[0].second.getSize() == 2520);
REQUIRE(segReqsPtr[1].first.getSize() == 2932);
REQUIRE(segReqsPtr[1].second.getSize() == 3021);
REQUIRE(deserializeWithSegReqs.getPduDataFieldLen() == 25);
REQUIRE(info.getSegmentRequestsLen() == 2);
for (size_t idx = 0; idx < 34; idx++) {
NakPduDeserializer faultyDeserializer(nakBuffer.data(), idx, info);
result = faultyDeserializer.parseData();
REQUIRE(result != HasReturnvaluesIF::RETURN_OK);
}
for (size_t pduFieldLen = 0; pduFieldLen < 25; pduFieldLen++) {
nakBuffer[1] = (pduFieldLen >> 8) & 0xff;
nakBuffer[2] = pduFieldLen & 0xff;
NakPduDeserializer faultyDeserializer(nakBuffer.data(), nakBuffer.size(), info);
result = faultyDeserializer.parseData();
if (pduFieldLen == 9) {
REQUIRE(info.getSegmentRequestsLen() == 0);
} else if (pduFieldLen == 17) {
REQUIRE(info.getSegmentRequestsLen() == 1);
} else if (pduFieldLen == 25) {
REQUIRE(info.getSegmentRequestsLen() == 2);
}
if (pduFieldLen != 9 and pduFieldLen != 17 and pduFieldLen != 25) {
REQUIRE(result != HasReturnvaluesIF::RETURN_OK);
}
}
info.setMaxSegmentRequestLen(5);
REQUIRE(info.getSegmentRequestsMaxLen() == 5);
}
}

View File

@ -0,0 +1,69 @@
#include <array>
#include <catch2/catch_test_macros.hpp>
#include "fsfw/cfdp/pdu/PromptPduDeserializer.h"
#include "fsfw/cfdp/pdu/PromptPduSerializer.h"
#include "fsfw/globalfunctions/arrayprinter.h"
TEST_CASE("Prompt PDU", "[cfdp][pdu]") {
using namespace cfdp;
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
std::array<uint8_t, 256> rawBuf = {};
uint8_t* buffer = rawBuf.data();
size_t sz = 0;
EntityId destId(WidthInBytes::TWO_BYTES, 2);
TransactionSeqNum seqNum(WidthInBytes::TWO_BYTES, 15);
EntityId sourceId(WidthInBytes::TWO_BYTES, 1);
PduConfig pduConf(sourceId, destId, TransmissionModes::ACKNOWLEDGED, seqNum);
SECTION("Serialize") {
PromptPduSerializer serializer(pduConf, cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE);
result = serializer.serialize(&buffer, &sz, rawBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(serializer.getWholePduSize() == 12);
REQUIRE(sz == 12);
REQUIRE(serializer.getPduDataFieldLen() == 2);
REQUIRE(rawBuf[10] == FileDirectives::PROMPT);
REQUIRE(((rawBuf[sz - 1] >> 7) & 0x01) == cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE);
for (size_t invalidMaxSz = 0; invalidMaxSz < sz; invalidMaxSz++) {
uint8_t* buffer = rawBuf.data();
size_t sz = 0;
result = serializer.serialize(&buffer, &sz, invalidMaxSz, SerializeIF::Endianness::NETWORK);
REQUIRE(result != HasReturnvaluesIF::RETURN_OK);
}
for (size_t invalidSz = 1; invalidSz < sz; invalidSz++) {
size_t locSz = invalidSz;
uint8_t* buffer = rawBuf.data();
result = serializer.serialize(&buffer, &locSz, sz, SerializeIF::Endianness::NETWORK);
REQUIRE(result != HasReturnvaluesIF::RETURN_OK);
}
}
SECTION("Deserialize") {
PromptPduSerializer serializer(pduConf, cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE);
result = serializer.serialize(&buffer, &sz, rawBuf.size(), SerializeIF::Endianness::NETWORK);
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
PromptPduDeserializer deserializer(rawBuf.data(), rawBuf.size());
result = deserializer.parseData();
REQUIRE(result == HasReturnvaluesIF::RETURN_OK);
REQUIRE(deserializer.getPromptResponseRequired() ==
cfdp::PromptResponseRequired::PROMPT_KEEP_ALIVE);
sz = deserializer.getWholePduSize();
// Set invalid size
rawBuf[2] = 1;
result = deserializer.parseData();
size_t sz2 = deserializer.getWholePduSize();
REQUIRE(result == SerializeIF::STREAM_TOO_SHORT);
rawBuf[2] = 2;
for (size_t invalidMaxSz = 0; invalidMaxSz < sz; invalidMaxSz++) {
ReturnValue_t setResult = deserializer.setData(rawBuf.data(), invalidMaxSz);
if (setResult == result::OK) {
result = deserializer.parseData();
REQUIRE(result != HasReturnvaluesIF::RETURN_OK);
}
}
}
}