.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
150 lines
5.3 KiB
C++
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
|