fprime/Svc/DpWriter/test/ut/Rules/BufferSendIn.cpp
Rob Bocchino b89b5d91c4
Add DpWriter (#2593)
* Pull in framework changes from data-products branch

* Pull in changes to DpManager from data-products branch

* Pull in DpWriter from data-products branch

* Fix spelling

* Revise FileNameString

* Fix warnings in CI

* Fix static analysis warnings

* Fix static analysis warnings

* Revise formatting and comments

* Revise banner comments

* Revise FileNameString per PR comment

* Revise path names in config headers

If a header H.hpp exists in the F Prime source base, then

is dangerous. Because [project root] and [fprime root] are both
in the list of include paths, it's not clear whether this means "include
[project root]/config/H.hpp" or "include [fprime root]/config/H.hpp."

On the other hand,

or

has no such ambiguity, because only one of [project root]/config
and [fprime root]/config is in the list of include paths.

* Revise path names in config headers

If a header H.hpp exists in the F Prime source base, then

`#include "config/H.hpp"`

is dangerous. Because [project root] and [fprime root] are both
in the list of include paths, it's not clear whether this means "include
[project root]/config/H.hpp" or "include [fprime root]/config/H.hpp."

On the other hand,

include <config/H.hpp>

or

`#include "config/H.hpp"`

has no such ambiguity, because only one of [project root]/config
and [fprime root]/config is in the list of include paths.
2024-03-28 16:09:38 -07:00

446 lines
16 KiB
C++

// ======================================================================
// \title BufferSendIn.cpp
// \author Rob Bocchino
// \brief BufferSendIn class implementation
//
// \copyright
// Copyright (C) 2024 California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government sponsorship
// acknowledged.
// ======================================================================
#include <limits>
#include <string>
#include "Os/Stub/test/File.hpp"
#include "STest/Pick/Pick.hpp"
#include "Svc/DpWriter/test/ut/Rules/BufferSendIn.hpp"
#include "Svc/DpWriter/test/ut/Rules/Testers.hpp"
namespace Svc {
// ----------------------------------------------------------------------
// Rule definitions
// ----------------------------------------------------------------------
bool TestState ::precondition__BufferSendIn__OK() const {
const auto& fileData = Os::Stub::File::Test::StaticData::data;
bool result = true;
result &= (fileData.openStatus == Os::File::Status::OP_OK);
result &= (fileData.writeStatus == Os::File::Status::OP_OK);
return result;
}
void TestState ::action__BufferSendIn__OK() {
// Clear the history
this->clearHistory();
// Reset the saved proc types
// These are updated in the from_procBufferSendOut handler
this->abstractState.m_procTypes = 0;
// Reset the file pointer in the stub file implementation
auto& fileData = Os::Stub::File::Test::StaticData::data;
fileData.pointer = 0;
// Update m_NumBuffersReceived
this->abstractState.m_NumBuffersReceived.value++;
// Construct a random buffer
Fw::Buffer buffer = this->abstractState.getDpBuffer();
// Send the buffer
this->invoke_to_bufferSendIn(0, buffer);
this->component.doDispatch();
// Deserialize the container header
Fw::DpContainer container;
container.setBuffer(buffer);
const Fw::SerializeStatus status = container.deserializeHeader();
ASSERT_EQ(status, Fw::FW_SERIALIZE_OK);
// Check events
ASSERT_EVENTS_SIZE(1);
ASSERT_EVENTS_FileWritten_SIZE(1);
Fw::FileNameString fileName;
this->constructDpFileName(container.getId(), container.getTimeTag(), fileName);
ASSERT_EVENTS_FileWritten(0, buffer.getSize(), fileName.toChar());
// Check processing types
this->checkProcTypes(container);
// Check DP notification
ASSERT_from_dpWrittenOut_SIZE(1);
ASSERT_from_dpWrittenOut(0, fileName, container.getPriority(), buffer.getSize());
// Check deallocation
ASSERT_from_deallocBufferSendOut_SIZE(1);
ASSERT_from_deallocBufferSendOut(0, buffer);
// Check file write
ASSERT_EQ(buffer.getSize(), fileData.pointer);
ASSERT_EQ(0, ::memcmp(buffer.getData(), fileData.writeResult, buffer.getSize()));
// Update m_NumBytesWritten
this->abstractState.m_NumBytesWritten.value += buffer.getSize();
// Update m_NumSuccessfulWrites
this->abstractState.m_NumSuccessfulWrites.value++;
}
bool TestState ::precondition__BufferSendIn__InvalidBuffer() const {
bool result = true;
return result;
}
void TestState ::action__BufferSendIn__InvalidBuffer() {
// Clear the history
this->clearHistory();
// Reset the file pointer in the stub file implementation
auto& fileData = Os::Stub::File::Test::StaticData::data;
fileData.pointer = 0;
// Update m_NumBuffersReceived
this->abstractState.m_NumBuffersReceived.value++;
// Construct an invalid buffer
Fw::Buffer buffer;
// Send the buffer
this->invoke_to_bufferSendIn(0, buffer);
this->component.doDispatch();
// Check events
if (this->abstractState.m_invalidBufferEventCount < DpWriterComponentBase::EVENTID_INVALIDBUFFER_THROTTLE) {
ASSERT_EVENTS_SIZE(1);
ASSERT_EVENTS_InvalidBuffer_SIZE(1);
this->abstractState.m_invalidBufferEventCount++;
} else {
ASSERT_EVENTS_SIZE(0);
}
// Verify no file output
ASSERT_EQ(fileData.pointer, 0);
// Verify no port output
ASSERT_FROM_PORT_HISTORY_SIZE(0);
// Increment m_NumErrors
this->abstractState.m_NumErrors.value++;
}
bool TestState ::precondition__BufferSendIn__BufferTooSmallForPacket() const {
bool result = true;
return result;
}
void TestState ::action__BufferSendIn__BufferTooSmallForPacket() {
// Clear the history
this->clearHistory();
// Reset the file pointer in the stub file implementation
auto& fileData = Os::Stub::File::Test::StaticData::data;
fileData.pointer = 0;
// Update m_NumBuffersReceived
this->abstractState.m_NumBuffersReceived.value++;
// Construct a buffer that is too small to hold a data packet
const FwSizeType minPacketSize = Fw::DpContainer::MIN_PACKET_SIZE;
ASSERT_GT(minPacketSize, 1);
const FwSizeType bufferSize = STest::Pick::lowerUpper(1, minPacketSize - 1);
Fw::Buffer buffer(this->abstractState.m_bufferData, bufferSize);
// Send the buffer
this->invoke_to_bufferSendIn(0, buffer);
this->component.doDispatch();
// Check events
if (this->abstractState.m_bufferTooSmallForPacketEventCount <
DpWriterComponentBase::EVENTID_BUFFERTOOSMALLFORPACKET_THROTTLE) {
ASSERT_EVENTS_SIZE(1);
ASSERT_EVENTS_BufferTooSmallForPacket(0, bufferSize, minPacketSize);
this->abstractState.m_bufferTooSmallForPacketEventCount++;
} else {
ASSERT_EVENTS_SIZE(0);
}
// Verify no file output
ASSERT_EQ(fileData.pointer, 0);
// Verify port output
ASSERT_FROM_PORT_HISTORY_SIZE(1);
ASSERT_from_deallocBufferSendOut(0, buffer);
// Increment m_NumErrors
this->abstractState.m_NumErrors.value++;
}
bool TestState ::precondition__BufferSendIn__InvalidHeaderHash() const {
bool result = true;
return result;
}
void TestState ::action__BufferSendIn__InvalidHeaderHash() {
// Clear the history
this->clearHistory();
// Reset the file pointer in the stub file implementation
auto& fileData = Os::Stub::File::Test::StaticData::data;
fileData.pointer = 0;
// Update m_NumBuffersReceived
this->abstractState.m_NumBuffersReceived.value++;
// Construct a valid buffer
Fw::Buffer buffer = this->abstractState.getDpBuffer();
// Set up the container
Fw::DpContainer container;
container.setBuffer(buffer);
// Get the header hash
const U32 computedHash = container.getHeaderHash().asBigEndianU32();
// Perturb the header hash
const U32 storedHash = computedHash + 1;
Utils::HashBuffer storedHashBuffer;
const Fw::SerializeStatus serialStatus = storedHashBuffer.serialize(storedHash);
ASSERT_EQ(serialStatus, Fw::FW_SERIALIZE_OK);
container.setHeaderHash(storedHashBuffer);
// Send the buffer
this->invoke_to_bufferSendIn(0, buffer);
this->component.doDispatch();
// Check events
if (this->abstractState.m_invalidHeaderHashEventCount < DpWriterComponentBase::EVENTID_INVALIDHEADERHASH_THROTTLE) {
ASSERT_EVENTS_SIZE(1);
ASSERT_EVENTS_InvalidHeaderHash(0, buffer.getSize(), storedHash, computedHash);
this->abstractState.m_invalidHeaderHashEventCount++;
} else {
ASSERT_EVENTS_SIZE(0);
}
// Verify no file output
ASSERT_EQ(fileData.pointer, 0);
// Verify port output
ASSERT_FROM_PORT_HISTORY_SIZE(1);
ASSERT_from_deallocBufferSendOut(0, buffer);
// Increment m_NumErrors
this->abstractState.m_NumErrors.value++;
}
bool TestState ::precondition__BufferSendIn__InvalidHeader() const {
bool result = true;
return result;
}
void TestState ::action__BufferSendIn__InvalidHeader() {
// Clear the history
this->clearHistory();
// Reset the file pointer in the stub file implementation
auto& fileData = Os::Stub::File::Test::StaticData::data;
fileData.pointer = 0;
// Update m_NumBuffersReceived
this->abstractState.m_NumBuffersReceived.value++;
// Construct a valid buffer
Fw::Buffer buffer = this->abstractState.getDpBuffer();
// Invalidate the packet descriptor
U8* const buffAddr = buffer.getData();
ASSERT_GT(static_cast<FwSizeType>(buffer.getSize()), static_cast<FwSizeType>(1));
buffAddr[0]++;
// Update the header hash
Fw::DpContainer container;
container.setBuffer(buffer);
container.updateHeaderHash();
// Send the buffer
this->invoke_to_bufferSendIn(0, buffer);
this->component.doDispatch();
// Check events
if (this->abstractState.m_invalidHeaderEventCount < DpWriterComponentBase::EVENTID_INVALIDHEADER_THROTTLE) {
ASSERT_EVENTS_SIZE(1);
ASSERT_EVENTS_InvalidHeader(0, buffer.getSize(), static_cast<U32>(Fw::FW_SERIALIZE_FORMAT_ERROR));
this->abstractState.m_invalidHeaderEventCount++;
} else {
ASSERT_EVENTS_SIZE(0);
}
// Verify no file output
ASSERT_EQ(fileData.pointer, 0);
// Verify port output
ASSERT_FROM_PORT_HISTORY_SIZE(1);
ASSERT_from_deallocBufferSendOut(0, buffer);
// Increment m_NumErrors
this->abstractState.m_NumErrors.value++;
}
bool TestState ::precondition__BufferSendIn__BufferTooSmallForData() const {
bool result = true;
return result;
}
void TestState ::action__BufferSendIn__BufferTooSmallForData() {
// Clear the history
this->clearHistory();
// Reset the file pointer in the stub file implementation
auto& fileData = Os::Stub::File::Test::StaticData::data;
fileData.pointer = 0;
// Update m_NumBuffersReceived
this->abstractState.m_NumBuffersReceived.value++;
// Construct a valid buffer
Fw::Buffer buffer = this->abstractState.getDpBuffer();
// Set up the container
Fw::DpContainer container;
container.setBuffer(buffer);
// Invalidate the data size
Fw::SerializeStatus serialStatus = container.deserializeHeader();
ASSERT_EQ(serialStatus, Fw::FW_SERIALIZE_OK);
const FwSizeType dataSize =
STest::Pick::lowerUpper(AbstractState::MAX_DATA_SIZE + 1, std::numeric_limits<FwSizeStoreType>::max());
container.setDataSize(dataSize);
container.updateHeaderHash();
container.serializeHeader();
// Send the buffer
this->invoke_to_bufferSendIn(0, buffer);
this->component.doDispatch();
// Check events
if (this->abstractState.m_bufferTooSmallForDataEventCount < DpWriterComponentBase::EVENTID_INVALIDHEADER_THROTTLE) {
ASSERT_EVENTS_SIZE(1);
ASSERT_EVENTS_BufferTooSmallForData(0, buffer.getSize(), container.getPacketSize());
this->abstractState.m_bufferTooSmallForDataEventCount++;
} else {
ASSERT_EVENTS_SIZE(0);
}
// Verify no file output
ASSERT_EQ(fileData.pointer, 0);
// Verify port output
ASSERT_from_procBufferSendOut_SIZE(0);
ASSERT_from_dpWrittenOut_SIZE(0);
ASSERT_from_deallocBufferSendOut_SIZE(1);
ASSERT_from_deallocBufferSendOut(0, buffer);
// Increment m_NumErrors
this->abstractState.m_NumErrors.value++;
}
bool TestState ::precondition__BufferSendIn__FileOpenError() const {
const auto& fileData = Os::Stub::File::Test::StaticData::data;
return (fileData.openStatus != Os::File::Status::OP_OK);
}
void TestState ::action__BufferSendIn__FileOpenError() {
// Clear the history
this->clearHistory();
// Reset the saved proc types
// These are updated in the from_procBufferSendOut handler
this->abstractState.m_procTypes = 0;
// Reset the file pointer in the stub file implementation
auto& fileData = Os::Stub::File::Test::StaticData::data;
fileData.pointer = 0;
// Update m_NumBuffersReceived
this->abstractState.m_NumBuffersReceived.value++;
// Construct a valid buffer
Fw::Buffer buffer = this->abstractState.getDpBuffer();
// Set up the container
Fw::DpContainer container;
container.setBuffer(buffer);
container.deserializeHeader();
// Send the buffer
this->invoke_to_bufferSendIn(0, buffer);
this->component.doDispatch();
// Check events
if (this->abstractState.m_fileOpenErrorEventCount < DpWriterComponentBase::EVENTID_FILEOPENERROR_THROTTLE) {
ASSERT_EVENTS_SIZE(1);
Fw::FileNameString fileName;
this->constructDpFileName(container.getId(), container.getTimeTag(), fileName);
const Os::File::Status openStatus = fileData.openStatus;
ASSERT_EVENTS_FileOpenError(0, static_cast<U32>(openStatus), fileName.toChar());
this->abstractState.m_fileOpenErrorEventCount++;
} else {
ASSERT_EVENTS_SIZE(0);
}
// Verify no file output
ASSERT_EQ(fileData.pointer, 0);
// Verify port output
this->checkProcTypes(container);
ASSERT_from_dpWrittenOut_SIZE(0);
ASSERT_from_deallocBufferSendOut_SIZE(1);
ASSERT_from_deallocBufferSendOut(0, buffer);
// Increment m_NumFailedWrites
this->abstractState.m_NumFailedWrites.value++;
// Increment m_NumErrors
this->abstractState.m_NumErrors.value++;
}
bool TestState ::precondition__BufferSendIn__FileWriteError() const {
const auto& fileData = Os::Stub::File::Test::StaticData::data;
bool result = true;
result &= (fileData.openStatus == Os::File::Status::OP_OK);
result &= (fileData.writeStatus != Os::File::Status::OP_OK);
return result;
}
void TestState ::action__BufferSendIn__FileWriteError() {
// Clear the history
this->clearHistory();
// Reset the saved proc types
// These are updated in the from_procBufferSendOut handler
this->abstractState.m_procTypes = 0;
// Update m_NumBuffersReceived
this->abstractState.m_NumBuffersReceived.value++;
// Construct a valid buffer
Fw::Buffer buffer = this->abstractState.getDpBuffer();
// Set up the container
Fw::DpContainer container;
container.setBuffer(buffer);
container.deserializeHeader();
// Get the file size
const FwSizeType fileSize = container.getPacketSize();
// Turn off file writing
auto& fileData = Os::Stub::File::Test::StaticData::data;
U8* const savedWriteResult = fileData.writeResult;
fileData.writeResult = nullptr;
// Adjust size result of write
fileData.writeSizeResult = STest::Pick::lowerUpper(0, fileSize);
// Send the buffer
this->invoke_to_bufferSendIn(0, buffer);
this->component.doDispatch();
// Check events
if (this->abstractState.m_fileWriteErrorEventCount < DpWriterComponentBase::EVENTID_FILEWRITEERROR_THROTTLE) {
ASSERT_EVENTS_SIZE(1);
Fw::FileNameString fileName;
this->constructDpFileName(container.getId(), container.getTimeTag(), fileName);
const Os::File::Status writeStatus = Os::Stub::File::Test::StaticData::data.writeStatus;
ASSERT_EVENTS_FileWriteError(0, static_cast<U32>(writeStatus), static_cast<U32>(fileData.writeSizeResult),
static_cast<U32>(fileSize), fileName.toChar());
this->abstractState.m_fileWriteErrorEventCount++;
} else {
ASSERT_EVENTS_SIZE(0);
}
// Verify port output
this->checkProcTypes(container);
ASSERT_from_dpWrittenOut_SIZE(0);
ASSERT_from_deallocBufferSendOut_SIZE(1);
ASSERT_from_deallocBufferSendOut(0, buffer);
// Increment m_NumFailedWrites
this->abstractState.m_NumFailedWrites.value++;
// Increment m_NumErrors
this->abstractState.m_NumErrors.value++;
// Turn on file writing
fileData.writeResult = savedWriteResult;
}
namespace BufferSendIn {
// ----------------------------------------------------------------------
// Tests
// ----------------------------------------------------------------------
void Tester::BufferTooSmallForData() {
this->ruleBufferTooSmallForData.apply(this->testState);
this->testState.printEvents();
}
void Tester::BufferTooSmallForPacket() {
this->ruleBufferTooSmallForPacket.apply(this->testState);
this->testState.printEvents();
}
void Tester::FileOpenError() {
Testers::fileOpenStatus.ruleError.apply(this->testState);
this->ruleFileOpenError.apply(this->testState);
this->testState.printEvents();
}
void Tester::FileWriteError() {
Testers::fileWriteStatus.ruleError.apply(this->testState);
this->ruleFileWriteError.apply(this->testState);
this->testState.printEvents();
}
void Tester::InvalidBuffer() {
this->ruleInvalidBuffer.apply(this->testState);
this->testState.printEvents();
}
void Tester::InvalidHeader() {
this->ruleInvalidHeader.apply(this->testState);
this->testState.printEvents();
}
void Tester::InvalidHeaderHash() {
this->ruleInvalidHeaderHash.apply(this->testState);
this->testState.printEvents();
}
void Tester::OK() {
this->ruleOK.apply(this->testState);
this->testState.printEvents();
}
} // namespace BufferSendIn
} // namespace Svc