fprime/Svc/ActiveTextLogger/test/ut/ActiveTextLoggerTester.cpp
M Starch cddf38bb6f
Make Os::Queues use Fw::MemAllocator pattern for memory (#4451)
* Queues use MemAllocator pattern

* Derive queue allocation from MallocRegistry

* Formatting

* Fix UTs

* Fix CI

* Fix alignment in UT

* Formatting and sp

* Formatting, bad header

* More formatting

* Add queue teardown

* Deinit components

* Fix priority queue test

* Fix bug in priority queue allocation

* Correct comments

* Fix FppTest and Ref UTs

* Fix max heap teardown

* Fix review comment on max heap

* Fix null -> nullptr
2025-12-02 17:36:15 -08:00

380 lines
14 KiB
C++

// \copyright
// Copyright 2009-2015, by the California Institute of Technology.
// ALL RIGHTS RESERVED. United States Government Sponsorship
// acknowledged.
#include "ActiveTextLoggerTester.hpp"
#include <fstream>
#include "Fw/Types/StringUtils.hpp"
#define INSTANCE 0
#define MAX_HISTORY_SIZE 10
#define QUEUE_DEPTH 10
namespace Svc {
// ----------------------------------------------------------------------
// Construction and destruction
// ----------------------------------------------------------------------
ActiveTextLoggerTester ::ActiveTextLoggerTester()
: ActiveTextLoggerGTestBase("Tester", MAX_HISTORY_SIZE), component("ActiveTextLogger") {
this->initComponents();
this->connectPorts();
}
ActiveTextLoggerTester ::~ActiveTextLoggerTester() {
this->component.deinit();
}
// ----------------------------------------------------------------------
// Tests
// ----------------------------------------------------------------------
void ActiveTextLoggerTester ::runNominalTest() {
printf("Testing writing to console\n");
// Verifying initial state:
ASSERT_FALSE(this->component.m_log_file.m_openFile);
FwEventIdType id = 1;
Fw::Time timeTag(TimeBase::TB_NONE, 3, 6);
Fw::LogSeverity severity = Fw::LogSeverity::ACTIVITY_HI;
Fw::TextLogString text("This component is the greatest!");
this->invoke_to_TextLogger(0, id, timeTag, severity, text);
this->component.doDispatch();
id = 2;
timeTag.set(TimeBase::TB_PROC_TIME, 4, 7);
severity = Fw::LogSeverity::ACTIVITY_LO;
text = "This component is the probably the greatest!";
this->invoke_to_TextLogger(0, id, timeTag, severity, text);
this->component.doDispatch();
// This will output in a different format b/c WORKSTATION_TIME
id = 3;
timeTag.set(TimeBase::TB_WORKSTATION_TIME, 5, 876);
severity = Fw::LogSeverity::WARNING_LO;
text = "This component is maybe the greatest!";
this->invoke_to_TextLogger(0, id, timeTag, severity, text);
this->component.doDispatch();
// No way to verify internal interface was called, but
// can manually see the print out to the console
printf("Testing writing to console and file\n");
// Setup file for writing to:
bool stat = this->component.set_log_file("test_file", 512);
ASSERT_TRUE(stat);
ASSERT_TRUE(this->component.m_log_file.m_openFile);
EXPECT_STREQ("test_file", this->component.m_log_file.m_fileName.toChar());
ASSERT_EQ(0U, this->component.m_log_file.m_currentFileSize);
ASSERT_EQ(512U, this->component.m_log_file.m_maxFileSize);
id = 4;
timeTag.set(TimeBase::TB_NONE, 5, 8);
severity = Fw::LogSeverity::WARNING_LO;
const char* severityString = "WARNING_LO";
text = "This component may be the greatest!";
this->invoke_to_TextLogger(0, id, timeTag, severity, text);
this->component.doDispatch();
ASSERT_TRUE(this->component.m_log_file.m_openFile);
ASSERT_EQ(strlen(text.toChar()) + 32, this->component.m_log_file.m_currentFileSize);
ASSERT_EQ(512U, this->component.m_log_file.m_maxFileSize);
U32 past_size = strlen(text.toChar()) + 32;
// Read file to verify contents:
std::ifstream stream1("test_file");
char oldLine[256];
while (stream1) {
char buf[256];
stream1.getline(buf, 256);
if (stream1) {
std::cout << "readLine: " << buf << std::endl;
char textStr[512];
snprintf(textStr, sizeof(textStr), "EVENT: (%" PRI_FwEventIdType ") (%d:%d,%d) %s: %s", id,
static_cast<FwTimeBaseStoreType>(timeTag.getTimeBase()), timeTag.getSeconds(),
timeTag.getUSeconds(), severityString, text.toChar());
ASSERT_STREQ(textStr, buf);
(void)Fw::StringUtils::string_copy(oldLine, buf, static_cast<FwSizeType>(sizeof(oldLine)));
}
}
stream1.close();
id = 5;
timeTag.set(TimeBase::TB_PROC_TIME, 6, 9);
severity = Fw::LogSeverity::WARNING_HI;
severityString = "WARNING_HI";
text = "This component is probably not the greatest!";
this->invoke_to_TextLogger(0, id, timeTag, severity, text);
this->component.doDispatch();
ASSERT_TRUE(this->component.m_log_file.m_openFile);
ASSERT_EQ(past_size + strlen(text.toChar()) + 32, this->component.m_log_file.m_currentFileSize);
ASSERT_EQ(512U, this->component.m_log_file.m_maxFileSize);
// Test predicted size matches actual:
FwSizeType fileSize = 0;
Os::FileSystem::getFileSize("test_file", fileSize);
ASSERT_EQ(fileSize, this->component.m_log_file.m_currentFileSize);
// Read file to verify contents:
std::ifstream stream2("test_file");
U32 iter = 0;
while (stream2) {
char buf[256];
stream2.getline(buf, 256);
if (stream2) {
std::cout << "readLine: " << buf << std::endl;
// Verify first printed line is still there
if (iter == 0) {
ASSERT_EQ(0, strcmp(oldLine, buf));
}
// Verify new printed line
else {
char textStr[512];
snprintf(textStr, sizeof(textStr), "EVENT: (%" PRI_FwEventIdType ") (%d:%d,%d) %s: %s", id,
static_cast<FwTimeBaseStoreType>(timeTag.getTimeBase()), timeTag.getSeconds(),
timeTag.getUSeconds(), severityString, text.toChar());
ASSERT_EQ(0, strcmp(textStr, buf));
}
}
++iter;
}
stream2.close();
// Clean up:
remove("test_file");
}
void ActiveTextLoggerTester ::runOffNominalTest() {
// TODO file errors- use the Os/Stubs?
FwSizeType tmp;
printf("Testing writing text that is larger than FW_INTERNAL_INTERFACE_STRING_MAX_SIZE\n");
// Can't test this b/c max size of TextLogString is 256 and
// FW_INTERNAL_INTERFACE_STRING_MAX_SIZE is 512
printf("Testing writing more than the max file size\n");
// Setup file for writing to:
bool stat = this->component.set_log_file("test_file_max", 45);
ASSERT_TRUE(stat);
ASSERT_TRUE(this->component.m_log_file.m_openFile);
ASSERT_STREQ("test_file_max", this->component.m_log_file.m_fileName.toChar());
ASSERT_EQ(0U, this->component.m_log_file.m_currentFileSize);
ASSERT_EQ(45U, this->component.m_log_file.m_maxFileSize);
ASSERT_EQ(Os::FileSystem::OP_OK, Os::FileSystem::getFileSize("test_file_max", tmp));
// Write once to the file:
FwEventIdType id = 1;
Fw::Time timeTag(TimeBase::TB_NONE, 3, 6);
Fw::LogSeverity severity = Fw::LogSeverity::ACTIVITY_HI;
const char* severityString = "ACTIVITY_HI";
Fw::TextLogString text("abcd");
this->invoke_to_TextLogger(0, id, timeTag, severity, text);
this->component.doDispatch();
ASSERT_TRUE(this->component.m_log_file.m_openFile);
ASSERT_EQ(strlen(text.toChar()) + 33, this->component.m_log_file.m_currentFileSize);
ASSERT_EQ(45U, this->component.m_log_file.m_maxFileSize);
U32 past_size = strlen(text.toChar()) + 33;
// Read file to verify contents:
std::ifstream stream1("test_file_max");
char oldLine[256];
while (stream1) {
char buf[256];
stream1.getline(buf, 256);
if (stream1) {
std::cout << "readLine: " << buf << std::endl;
char textStr[512];
snprintf(textStr, sizeof(textStr), "EVENT: (%" PRI_FwEventIdType ") (%d:%d,%d) %s: %s", id,
static_cast<FwTimeBaseStoreType>(timeTag.getTimeBase()), timeTag.getSeconds(),
timeTag.getUSeconds(), severityString, text.toChar());
ASSERT_EQ(0, strcmp(textStr, buf));
(void)Fw::StringUtils::string_copy(oldLine, buf, static_cast<FwSizeType>(sizeof(oldLine)));
}
}
stream1.close();
// Write again to the file going over the max:
text = "This will go over max size of the file!";
this->invoke_to_TextLogger(0, id, timeTag, severity, text);
this->component.doDispatch();
// Verify file was closed and size didn't increase:
ASSERT_FALSE(this->component.m_log_file.m_openFile);
ASSERT_EQ(past_size, this->component.m_log_file.m_currentFileSize);
ASSERT_EQ(45U, this->component.m_log_file.m_maxFileSize);
// Read file to verify contents didn't change:
std::ifstream stream2("test_file_max");
while (stream2) {
char buf[256];
stream2.getline(buf, 256);
if (stream2) {
std::cout << "readLine: " << buf << std::endl;
ASSERT_EQ(0, strcmp(oldLine, buf));
}
}
stream2.close();
printf("Testing with file name that already exists\n");
// Setup file for writing to that is a duplicate name:
stat = this->component.set_log_file("test_file_max", 50);
// Verify made file with 0 suffix:
ASSERT_TRUE(stat);
ASSERT_TRUE(this->component.m_log_file.m_openFile);
ASSERT_STREQ("test_file_max0", this->component.m_log_file.m_fileName.toChar());
ASSERT_EQ(0U, this->component.m_log_file.m_currentFileSize);
ASSERT_EQ(50U, this->component.m_log_file.m_maxFileSize);
ASSERT_EQ(Os::FileSystem::OP_OK, Os::FileSystem::getFileSize("test_file_max0", tmp));
printf("Testing file name larger than string size\n");
// Setup filename larger than file name string can accept
// Maximum valid file name is Fw::FileNameString::STRING_SIZE, add 1 to be too long, and an extra for the \0
char longFileName[Fw::FileNameString::STRING_SIZE + 2];
for (U32 i = 0; i < Fw::FileNameString::STRING_SIZE + 1; ++i) {
longFileName[i] = 'a';
}
longFileName[Fw::FileNameString::STRING_SIZE + 1] = 0;
stat = this->component.set_log_file(longFileName, 50);
// Verify file not made:
ASSERT_FALSE(stat);
ASSERT_FALSE(this->component.m_log_file.m_openFile);
ASSERT_NE(Os::FileSystem::OP_OK, Os::FileSystem::getFileSize(longFileName, tmp));
printf("Testing file name of max size and file already exists\n");
// Maximum valid file name is Fw::FileNameString::STRING_SIZE add one for \0
char longFileNameDup[Fw::FileNameString::STRING_SIZE + 1];
for (U32 i = 0; i < Fw::FileNameString::STRING_SIZE; ++i) {
longFileNameDup[i] = 'a';
}
longFileNameDup[Fw::FileNameString::STRING_SIZE] = 0;
stat = this->component.set_log_file(longFileNameDup, 50);
// Verify file made successful:
ASSERT_TRUE(stat);
ASSERT_TRUE(this->component.m_log_file.m_openFile);
ASSERT_EQ(Os::FileSystem::OP_OK, Os::FileSystem::getFileSize(longFileNameDup, tmp));
// Try to make the same one again:
stat = this->component.set_log_file(longFileNameDup, 50);
// Verify file not made:
ASSERT_FALSE(stat);
ASSERT_FALSE(this->component.m_log_file.m_openFile);
char longFileNameDupS[81] = "0";
ASSERT_NE(Os::FileSystem::OP_OK, Os::FileSystem::getFileSize(longFileNameDupS, tmp));
printf("Testing with file name that already exists and the next 10 suffixes\n");
// Create 11 files with the same name, and verify 11th fails, and re-uses the original
const char* baseName = "test_mult_dup";
// Create first file:
stat = this->component.set_log_file(baseName, 50);
ASSERT_TRUE(stat);
ASSERT_TRUE(this->component.m_log_file.m_openFile);
ASSERT_EQ(0, strcmp(baseName, this->component.m_log_file.m_fileName.toChar()));
ASSERT_EQ(Os::FileSystem::OP_OK, Os::FileSystem::getFileSize(baseName, tmp));
// Create 10 more, which all should succeed:
char baseNameWithSuffix[128];
U32 i;
for (i = 0; i < 10; ++i) {
stat = this->component.set_log_file(baseName, 50);
snprintf(baseNameWithSuffix, sizeof(baseNameWithSuffix), "%s%d", baseName, i);
ASSERT_TRUE(stat);
ASSERT_TRUE(this->component.m_log_file.m_openFile);
ASSERT_EQ(0, strcmp(baseNameWithSuffix, this->component.m_log_file.m_fileName.toChar()));
ASSERT_EQ(Os::FileSystem::OP_OK, Os::FileSystem::getFileSize(baseNameWithSuffix, tmp));
}
// Create 11th which will fail and re-use the original:
stat = this->component.set_log_file(baseName, 50);
ASSERT_TRUE(stat);
ASSERT_TRUE(this->component.m_log_file.m_openFile);
printf("<< %s %s\n", baseName, this->component.m_log_file.m_fileName.toChar());
ASSERT_EQ(0, strcmp(baseName, this->component.m_log_file.m_fileName.toChar()));
ASSERT_EQ(Os::FileSystem::OP_OK, Os::FileSystem::getFileSize(baseName, tmp));
// Clean up:
remove("test_file_max");
remove("test_file_max0");
remove(longFileNameDup);
remove(baseName);
for (i = 0; i < 10; ++i) {
snprintf(baseNameWithSuffix, sizeof(baseNameWithSuffix), "%s%d", baseName, i);
remove(baseNameWithSuffix);
}
}
void ActiveTextLoggerTester ::testWorkstationTimestamp() {
printf("Testing workstation timestamp\n");
// Setup file for writing to:
const char* logFileName = "test_file";
bool stat = this->component.set_log_file(logFileName, 512);
ASSERT_TRUE(stat);
ASSERT_TRUE(this->component.m_log_file.m_openFile);
// Log message:
FwEventIdType id = 1;
Fw::Time timeTag(TimeBase::TB_WORKSTATION_TIME, 3, 6);
Fw::LogSeverity severity = Fw::LogSeverity::ACTIVITY_HI;
const char* severityString = "ACTIVITY_HI";
Fw::TextLogString text("This line has a valid timestamp.");
this->invoke_to_TextLogger(0, id, timeTag, severity, text);
this->component.doDispatch();
// Read file to verify contents:
std::ifstream logStream(logFileName);
while (logStream) {
char buf[256];
logStream.getline(buf, 256);
if (logStream) {
std::cout << "readLine: " << buf << std::endl;
char textStr[512];
snprintf(textStr, sizeof(textStr), "EVENT: (%" PRI_FwEventIdType ") (%d:%d,%d) %s: %s", id,
static_cast<FwTimeBaseStoreType>(timeTag.getTimeBase()), timeTag.getSeconds(),
timeTag.getUSeconds(), severityString, text.toChar());
ASSERT_EQ(0, strcmp(textStr, buf));
}
}
logStream.close();
// Clean up:
remove(logFileName);
}
// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------
void ActiveTextLoggerTester ::connectPorts() {
// TextLogger
this->connect_to_TextLogger(0, this->component.get_TextLogger_InputPort(0));
}
void ActiveTextLoggerTester ::initComponents() {
this->init();
this->component.init(QUEUE_DEPTH, INSTANCE);
}
} // end namespace Svc