1
0
forked from fsfw/fsfw
Files
.idea
automation
cmake
contrib
docs
misc
scripts
src
unittests
action
cfdp
container
datapoollocal
devicehandler
globalfunctions
hal
CMakeLists.txt
testCommandExecutor.cpp
testFsMock.cpp
testHostFilesystem.cpp
internalerror
mocks
osal
power
pus
serialize
storagemanager
tcdistributor
testcfg
testtemplate
timemanager
tmtcpacket
tmtcservices
util
CMakeLists.txt
CatchDefinitions.cpp
CatchDefinitions.h
CatchFactory.cpp
CatchFactory.h
CatchRunner.cpp
CatchRunner.h
CatchSetup.cpp
lcov_epilog.html
printChar.cpp
printChar.h
testVersion.cpp
.clang-format
.gitignore
.gitmodules
CHANGELOG.md
CMakeLists.txt
FSFWVersion.h.in
LICENSE
NOTICE
README.md
fsfw/unittests/hal/testCommandExecutor.cpp

150 lines
5.3 KiB
C++

#include <unistd.h>
#include <catch2/catch_test_macros.hpp>
#include <fstream>
#include <iostream>
#include "fsfw/container/DynamicFIFO.h"
#include "fsfw/container/SimpleRingBuffer.h"
#include "fsfw/platform.h"
#include "fsfw/serviceinterface.h"
#include "fsfw_hal/linux/CommandExecutor.h"
#include "tests/TestsConfig.h"
#ifdef PLATFORM_UNIX
static const char TEST_FILE_NAME[] = "/tmp/fsfw-unittest-test.txt";
TEST_CASE("Command Executor", "[hal][linux]") {
// Check blocking mode first
CommandExecutor cmdExecutor(1024);
std::string cmd = "echo \"test\" >> " + std::string(TEST_FILE_NAME);
REQUIRE(cmdExecutor.getCurrentState() == CommandExecutor::States::IDLE);
ReturnValue_t result = cmdExecutor.load(cmd, true, true);
REQUIRE(cmdExecutor.getCurrentState() == CommandExecutor::States::COMMAND_LOADED);
REQUIRE(result == returnvalue::OK);
REQUIRE(cmdExecutor.execute() == returnvalue::OK);
// Check that file exists with contents
std::ifstream file(TEST_FILE_NAME);
std::string line;
std::getline(file, line);
CHECK(line == "test");
std::remove(TEST_FILE_NAME);
REQUIRE(cmdExecutor.getCurrentState() == CommandExecutor::States::IDLE);
// Now check non-blocking mode
SimpleRingBuffer outputBuffer(524, true);
DynamicFIFO<uint16_t> sizesFifo(12);
cmdExecutor.setRingBuffer(&outputBuffer, &sizesFifo);
result = cmdExecutor.load("echo \"Hello World\"", false, false);
REQUIRE(result == returnvalue::OK);
cmdExecutor.execute();
bool bytesHaveBeenRead = false;
size_t limitIdx = 0;
while (result != CommandExecutor::EXECUTION_FINISHED) {
limitIdx++;
result = cmdExecutor.check(bytesHaveBeenRead);
// to have constant assertion count, we first check condition
// and then force a failed assertion
if (result == CommandExecutor::COMMAND_ERROR) {
REQUIRE(result != CommandExecutor::COMMAND_ERROR);
}
usleep(500);
// same as above
if (limitIdx >= 500) {
REQUIRE(limitIdx < 500);
}
}
limitIdx = 0;
CHECK(bytesHaveBeenRead == true);
CHECK(result == CommandExecutor::EXECUTION_FINISHED);
uint16_t readBytes = 0;
sizesFifo.retrieve(&readBytes);
REQUIRE(readBytes == 12);
REQUIRE(outputBuffer.getAvailableReadData() == 12);
uint8_t readBuffer[32] = {};
REQUIRE(outputBuffer.readData(readBuffer, 12) == returnvalue::OK);
std::string readString(reinterpret_cast<char*>(readBuffer));
std::string cmpString = "Hello World\n";
CHECK(readString == cmpString);
outputBuffer.deleteData(12, true);
// Issues with CI/CD
#if FSFW_CICD_BUILD == 0
// Test more complex command
result = cmdExecutor.load("ping -c 1 localhost", false, false);
REQUIRE(cmdExecutor.getCurrentState() == CommandExecutor::States::COMMAND_LOADED);
REQUIRE(cmdExecutor.execute() == returnvalue::OK);
REQUIRE(cmdExecutor.getCurrentState() == CommandExecutor::States::PENDING);
limitIdx = 0;
while (result != CommandExecutor::EXECUTION_FINISHED) {
limitIdx++;
result = cmdExecutor.check(bytesHaveBeenRead);
// to have constant assertion count, we first check condition
// and then force a failed assertion
if (result == CommandExecutor::COMMAND_ERROR) {
REQUIRE(result != CommandExecutor::COMMAND_ERROR);
}
// This ensures that the tests do not block indefinitely
usleep(500);
// same as above
if (limitIdx >= 500) {
REQUIRE(limitIdx < 500);
}
}
limitIdx = 0;
CHECK(bytesHaveBeenRead == true);
CHECK(result == CommandExecutor::EXECUTION_FINISHED);
REQUIRE(cmdExecutor.getCurrentState() == CommandExecutor::States::IDLE);
readBytes = 0;
sizesFifo.retrieve(&readBytes);
uint8_t largerReadBuffer[1024] = {};
// That's about the size of the reply
bool beTrue = (readBytes > 100) and (readBytes < 400);
if (not beTrue) {
size_t readLen = outputBuffer.getAvailableReadData();
if (readLen > sizeof(largerReadBuffer) - 1) {
readLen = sizeof(largerReadBuffer) - 1;
}
outputBuffer.readData(largerReadBuffer, readLen);
std::string readString(reinterpret_cast<char*>(largerReadBuffer));
std::cerr << "Catch2 tag cmd-exec: Read " << readBytes << ": " << std::endl;
std::cerr << readString << std::endl;
}
REQUIRE(beTrue);
outputBuffer.readData(largerReadBuffer, readBytes);
// You can also check this output in the debugger
std::string allTheReply(reinterpret_cast<char*>(largerReadBuffer));
// I am just going to assume that this string is the same across ping implementations
// of different Linux systems
REQUIRE(allTheReply.find("PING localhost") != std::string::npos);
#endif
// Now check failing command
result = cmdExecutor.load("false", false, false);
REQUIRE(result == returnvalue::OK);
result = cmdExecutor.execute();
REQUIRE(result == returnvalue::OK);
while (result != CommandExecutor::EXECUTION_FINISHED and result != returnvalue::FAILED) {
limitIdx++;
result = cmdExecutor.check(bytesHaveBeenRead);
// to have constant assertion count, we first check condition
// and then force a failed assertion
if (result == CommandExecutor::COMMAND_ERROR) {
REQUIRE(result != CommandExecutor::COMMAND_ERROR);
}
// This ensures that the tests do not block indefinitely
usleep(500);
// same as above
if (limitIdx >= 500) {
REQUIRE(limitIdx < 500);
}
}
REQUIRE(result == returnvalue::FAILED);
REQUIRE(cmdExecutor.getLastError() == 1);
}
#endif