From 7b1f2e00f73d3da021dcaf42c637228946cd826e Mon Sep 17 00:00:00 2001 From: Gwangmu Lee Date: Thu, 25 Jul 2024 11:26:09 +0000 Subject: [PATCH] Resolve the 'test_utility' dependency of 'libsarus' --- src/libsarus/test/CMakeLists.txt | 26 +-- src/libsarus/test/DeviceParserChecker.hpp | 93 ----------- src/libsarus/test/MountParserChecker.hpp | 110 ------------- src/libsarus/test/aux/CMakeLists.txt | 4 + src/libsarus/test/aux/filesystem.cpp | 188 ++++++++++++++++++++++ src/libsarus/test/aux/filesystem.hpp | 43 +++++ src/libsarus/test/aux/hook.cpp | 101 ++++++++++++ src/libsarus/test/aux/hook.hpp | 32 ++++ src/libsarus/test/aux/misc.cpp | 46 ++++++ src/libsarus/test/aux/misc.hpp | 22 +++ src/libsarus/test/aux/unitTestMain.hpp | 34 ++++ src/libsarus/test/test_CLIArguments.cpp | 9 +- src/libsarus/test/test_DeviceAccess.cpp | 3 +- src/libsarus/test/test_DeviceMount.cpp | 49 +++--- src/libsarus/test/test_DeviceParser.cpp | 97 ++++++++--- src/libsarus/test/test_Error.cpp | 17 +- src/libsarus/test/test_Flock.cpp | 5 +- src/libsarus/test/test_HookUtility.cpp | 15 +- src/libsarus/test/test_Lockfile.cpp | 7 +- src/libsarus/test/test_Logger.cpp | 5 +- src/libsarus/test/test_Mount.cpp | 40 +++-- src/libsarus/test/test_MountParser.cpp | 98 ++++++++++- src/libsarus/test/test_MountUtility.cpp | 13 +- src/libsarus/test/test_PasswdDB.cpp | 4 +- src/libsarus/test/test_Utility.cpp | 15 +- 25 files changed, 743 insertions(+), 333 deletions(-) delete mode 100644 src/libsarus/test/DeviceParserChecker.hpp delete mode 100644 src/libsarus/test/MountParserChecker.hpp create mode 100644 src/libsarus/test/aux/CMakeLists.txt create mode 100644 src/libsarus/test/aux/filesystem.cpp create mode 100644 src/libsarus/test/aux/filesystem.hpp create mode 100644 src/libsarus/test/aux/hook.cpp create mode 100644 src/libsarus/test/aux/hook.hpp create mode 100644 src/libsarus/test/aux/misc.cpp create mode 100644 src/libsarus/test/aux/misc.hpp create mode 100644 src/libsarus/test/aux/unitTestMain.hpp diff --git a/src/libsarus/test/CMakeLists.txt b/src/libsarus/test/CMakeLists.txt index eeeb3dbf..3d894b24 100644 --- a/src/libsarus/test/CMakeLists.txt +++ b/src/libsarus/test/CMakeLists.txt @@ -1,18 +1,18 @@ +add_subdirectory(aux) + include(add_unit_test) -set(link_libraries "test_utility_library") -set(object_files_directory - "${CMAKE_BINARY_DIR}/src/common/CMakeFiles/common_library.dir") +set(link_libraries "libsarus_testaux") -add_unit_test(libsarus_Utility_AsRoot test_Utility.cpp "${link_libraries}") -add_unit_test_as_root(libsarus_MountUtility test_MountUtility.cpp "${link_libraries}") -add_unit_test(libsarus_HookUtility_AsRoot test_HookUtility.cpp "${link_libraries}") -add_unit_test(libsarus_Logger test_Logger.cpp "${link_libraries}") -add_unit_test(libsarus_Error test_Error.cpp "${link_libraries}") add_unit_test(libsarus_CLIArguments test_CLIArguments.cpp "${link_libraries}") -add_unit_test_as_root(libsarus_Mount test_Mount.cpp "${link_libraries}") -add_unit_test_as_root(libsarus_DeviceParser test_DeviceParser.cpp "${link_libraries}") +add_unit_test(libsarus_Error test_Error.cpp "${link_libraries}") +add_unit_test(libsarus_Flock test_Flock.cpp "${link_libraries}") +add_unit_test(libsarus_HookUtility test_HookUtility.cpp "${link_libraries}") +add_unit_test(libsarus_Lockfile test_Lockfile.cpp "${link_libraries}") +add_unit_test(libsarus_Logger test_Logger.cpp "${link_libraries}") add_unit_test(libsarus_MountParser test_MountParser.cpp "${link_libraries}") add_unit_test(libsarus_PasswdDB test_PasswdDB.cpp "${link_libraries}") -add_unit_test(libsarus_Lockfile test_Lockfile.cpp "${link_libraries}") -add_unit_test(libsarus_Flock test_Flock.cpp "${link_libraries}") -add_unit_test_as_root(libsarus_DeviceMount_AsRoot test_DeviceMount.cpp "${link_libraries}") +add_unit_test_as_root(libsarus_DeviceMount test_DeviceMount.cpp "${link_libraries}") +add_unit_test_as_root(libsarus_DeviceParser test_DeviceParser.cpp "${link_libraries}") +add_unit_test_as_root(libsarus_MountUtility test_MountUtility.cpp "${link_libraries}") +add_unit_test_as_root(libsarus_Mount test_Mount.cpp "${link_libraries}") +add_unit_test_as_root(libsarus_Utility test_Utility.cpp "${link_libraries}") diff --git a/src/libsarus/test/DeviceParserChecker.hpp b/src/libsarus/test/DeviceParserChecker.hpp deleted file mode 100644 index 50c10fe5..00000000 --- a/src/libsarus/test/DeviceParserChecker.hpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Sarus - * - * Copyright (c) 2018-2023, ETH Zurich. All rights reserved. - * - * Please, refer to the LICENSE file in the root directory. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef libsarus_test_DeviceParserChecker_hpp -#define libsarus_test_DeviceParserChecker_hpp - -#include - -#include "test_utility/config.hpp" -#include "libsarus/Error.hpp" -#include "libsarus/DeviceParser.hpp" - -#include // boost library must be included before CppUTest - -namespace libsarus { -namespace test { - -class DeviceParserChecker { -public: - DeviceParserChecker(const std::string& deviceRequest) - : deviceRequest(deviceRequest) - {} - - DeviceParserChecker& expectSource(const std::string& expectedSource) { - this->expectedSource = expectedSource; - return *this; - } - - DeviceParserChecker& expectDestination(const std::string& expectedDestination) { - this->expectedDestination = expectedDestination; - return *this; - } - - DeviceParserChecker& expectAccess(const std::string& expectedAccess) { - this->expectedAccess = expectedAccess; - return *this; - } - - DeviceParserChecker& expectParseError() { - isParseErrorExpected = true; - return *this; - } - - ~DeviceParserChecker() { - auto configRAII = test_utility::config::makeConfig(); - auto userIdentity = configRAII.config->userIdentity; - auto rootfsDir = boost::filesystem::path{ configRAII.config->json["OCIBundleDir"].GetString() } - / configRAII.config->json["rootfsFolder"].GetString(); - - auto parser = libsarus::DeviceParser{configRAII.config->getRootfsDirectory(), configRAII.config->userIdentity}; - - if(isParseErrorExpected) { - CHECK_THROWS(libsarus::Error, parser.parseDeviceRequest(deviceRequest)); - return; - } - - auto mountObject = parser.parseDeviceRequest(deviceRequest); - - if(expectedSource) { - CHECK(mountObject->getSource() == *expectedSource); - } - - if(expectedDestination) { - CHECK(mountObject->getDestination() == *expectedDestination); - } - - if(expectedAccess) { - CHECK(mountObject->getAccess().string() == *expectedAccess); - } - - CHECK_EQUAL(mountObject->getFlags(), *expectedFlags); - } - -private: - std::string deviceRequest; - boost::optional expectedSource{}; - boost::optional expectedDestination{}; - boost::optional expectedAccess{"rwm"}; - boost::optional expectedFlags{MS_REC | MS_PRIVATE}; - - bool isParseErrorExpected = false; -}; - -}} - -#endif diff --git a/src/libsarus/test/MountParserChecker.hpp b/src/libsarus/test/MountParserChecker.hpp deleted file mode 100644 index c6eb48d0..00000000 --- a/src/libsarus/test/MountParserChecker.hpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Sarus - * - * Copyright (c) 2018-2023, ETH Zurich. All rights reserved. - * - * Please, refer to the LICENSE file in the root directory. - * SPDX-License-Identifier: BSD-3-Clause - * - */ - -#ifndef libsarus_test_MountParserChecker_hpp -#define libsarus_test_MountParserChecker_hpp - -#include -#include -#include -#include - -#include - -#include "test_utility/config.hpp" -#include "libsarus/Utility.hpp" -#include "common/Config.hpp" -#include "libsarus/Error.hpp" -#include "libsarus/Mount.hpp" -#include "libsarus/MountParser.hpp" - -#include // boost library must be included before CppUTest - -namespace libsarus { -namespace test { - -class MountParserChecker { -public: - MountParserChecker(const std::string& mountRequest) - : mountRequest(mountRequest) - {} - - MountParserChecker& parseAsSiteMount() { - this->isSiteMount = true; - return *this; - } - - MountParserChecker& expectSource(const std::string& expectedSource) { - this->expectedSource = expectedSource; - return *this; - } - - MountParserChecker& expectDestination(const std::string& expectedDestination) { - this->expectedDestination = expectedDestination; - return *this; - } - - MountParserChecker& expectFlags(const size_t flags) { - this->expectedFlags = flags; - return *this; - } - - MountParserChecker& expectParseError() { - isParseErrorExpected = true; - return *this; - } - - ~MountParserChecker() { - auto configRAII = test_utility::config::makeConfig(); - auto userIdentity = configRAII.config->userIdentity; - auto rootfsDir = boost::filesystem::path{ configRAII.config->json["OCIBundleDir"].GetString() } - / configRAII.config->json["rootfsFolder"].GetString(); - - libsarus::MountParser parser = libsarus::MountParser{configRAII.config->getRootfsDirectory(), configRAII.config->userIdentity}; - - if (!isSiteMount && configRAII.config->json.HasMember("userMounts")) { - parser.setMountDestinationRestrictions(configRAII.config->json["userMounts"]); - } - - auto map = libsarus::string::parseMap(mountRequest); - - if(isParseErrorExpected) { - CHECK_THROWS(libsarus::Error, parser.parseMountRequest(map)); - return; - } - - auto mountObject = parser.parseMountRequest(map); - - if(expectedSource) { - CHECK(mountObject->getSource() == *expectedSource); - } - - if(expectedDestination) { - CHECK(mountObject->getDestination() == *expectedDestination); - } - - if(expectedFlags) { - CHECK_EQUAL(mountObject->getFlags(), *expectedFlags); - } - } - -private: - std::string mountRequest; - bool isSiteMount = false; - boost::optional expectedSource = {}; - boost::optional expectedDestination = {}; - boost::optional expectedFlags = {}; - - bool isParseErrorExpected = false; -}; - -}} - -#endif diff --git a/src/libsarus/test/aux/CMakeLists.txt b/src/libsarus/test/aux/CMakeLists.txt new file mode 100644 index 00000000..35549eda --- /dev/null +++ b/src/libsarus/test/aux/CMakeLists.txt @@ -0,0 +1,4 @@ +file(GLOB libsarus_testaux_srcs "*.cpp") +add_library(libsarus_testaux STATIC ${libsarus_testaux_srcs}) +target_link_libraries(libsarus_testaux ${Boost_LIBRARIES} libsarus) +set_target_properties(libsarus_testaux PROPERTIES PREFIX "") diff --git a/src/libsarus/test/aux/filesystem.cpp b/src/libsarus/test/aux/filesystem.cpp new file mode 100644 index 00000000..2d2cbab2 --- /dev/null +++ b/src/libsarus/test/aux/filesystem.cpp @@ -0,0 +1,188 @@ +/* + * Sarus + * + * Copyright (c) 2018-2023, ETH Zurich. All rights reserved. + * + * Please, refer to the LICENSE file in the root directory. + * SPDX-License-Identifier: BSD-3-Clause + * + **/ + +/** + * @brief Filesystem utility functions to be used in the tests. + **/ + +#include "filesystem.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libsarus/Utility.hpp" + + +namespace libsarus { +namespace test { +namespace aux { +namespace filesystem { + +bool areDirectoriesEqual(const std::string& dir1, const std::string& dir2, bool compare_file_attributes) +{ + struct dirent **namelist1, **namelist2; + struct stat statData1, statData2; + std::vector subdirs1, subdirs2; + bool ret = true; + int n1, n2; + + // Retrieve sorted list of directories contents + n1 = scandir(dir1.c_str(), &namelist1, NULL, alphasort); + if (n1 == -1) { + perror("scandir"); + return 1; + } + + n2 = scandir(dir2.c_str(), &namelist2, NULL, alphasort); + if (n2 == -1) { + perror("scandir"); + return 1; + } + + // Check number of files in both directories + if (n1 != n2) + ret = false; + + // Check directories contents + for (int i=0; id_name); + std::string fullname1(dir1+"/"+filename1); + + std::string filename2(namelist2[i]->d_name); + std::string fullname2(dir2+"/"+filename2); + + if (filename1 != filename2) { + ret = false; + break; + } + + // Stat files + if (stat(fullname1.c_str(), &statData1) != 0 + || stat(fullname2.c_str(), &statData2) != 0) { + perror("stat"); + ret = false; + break; + } + + // If these are sub-directories, save their names for later + if (S_ISDIR(statData1.st_mode) + && filename1 != ".." + && filename1 != ".") { + subdirs1.push_back(fullname1); + subdirs2.push_back(fullname2); + } + + // If preservation of attributes was requested, check attributes + if (compare_file_attributes && filename1 != ".." && filename1 != ".") { + bool mode_check = ( (statData1.st_mode & 0000777) + != (statData2.st_mode & 0000777) ); + bool owner_check = (statData1.st_uid != statData2.st_uid); + bool group_check = (statData1.st_gid != statData2.st_gid); + + if (mode_check || owner_check || group_check) { + ret = false; + break; + } + } + } + + // Cleanup dirent structures + while (n1--) { + free(namelist1[n1]); + } + free(namelist1); + + while (n2--) { + free(namelist2[n2]); + } + free(namelist2); + + //Descend into subdirectories + for (uint i=0; i getDeviceIDAndINodeNumber(const boost::filesystem::path& path) { + struct stat sb; + if(stat(path.c_str(), &sb) != 0) { + auto message = boost::format("Failed to stat %s: %s") % path % strerror(errno); + SARUS_THROW_ERROR(message.str()); + } + return std::tuple{sb.st_dev, sb.st_ino}; +} + +bool isSameBindMountedFile(const boost::filesystem::path& file0, const boost::filesystem::path& file1) { + return getDeviceIDAndINodeNumber(file0) == getDeviceIDAndINodeNumber(file1); +} + +static int clearFileTypeBits(const mode_t fileMode) { + return fileMode & ~(S_IFREG | S_IFCHR | S_IFBLK | S_IFIFO | S_IFSOCK); +} + +static void createFilesystemNode(const boost::filesystem::path& path, const mode_t mode, const dev_t deviceID) { + if (mknod(path.c_str(), mode, deviceID) != 0) { + auto message = boost::format("Failed to mknod test device file %s: %s") % path % strerror(errno); + SARUS_THROW_ERROR(message.str().c_str()); + } +} + +void createCharacterDeviceFile(const boost::filesystem::path& path, const int majorID, const int minorID, const mode_t mode) { + auto fileMode = clearFileTypeBits(mode); + fileMode = S_IFCHR | mode; + auto deviceID = makedev(majorID, minorID); + createFilesystemNode(path, fileMode, deviceID); +} + +void createBlockDeviceFile(const boost::filesystem::path& path, const int majorID, const int minorID, const mode_t mode) { + auto fileMode = clearFileTypeBits(mode); + fileMode = S_IFBLK | mode; + auto deviceID = makedev(majorID, minorID); + createFilesystemNode(path, fileMode, deviceID); +} + +void createTestDirectoryTree(const std::string& dir) { + libsarus::process::executeCommand("mkdir -p " + dir); + libsarus::process::executeCommand("touch " + dir + "/a.txt"); + libsarus::process::executeCommand("touch " + dir + "/b.md"); + libsarus::process::executeCommand("touch " + dir + "/c.h"); + libsarus::process::executeCommand("chmod 755 " + dir + "/a.txt"); + libsarus::process::executeCommand("chmod 644 " + dir + "/b.md"); + libsarus::process::executeCommand("chmod 700 " + dir + "/c.h"); + + libsarus::process::executeCommand("mkdir -p " + dir + "/sub1"); + libsarus::process::executeCommand("touch " + dir + "/sub1/d.cpp"); + libsarus::process::executeCommand("touch " + dir + "/sub1/e.so"); + libsarus::process::executeCommand("chmod 600 " + dir + "/sub1/d.cpp"); + libsarus::process::executeCommand("chmod 775 " + dir + "/sub1/e.so"); + + libsarus::process::executeCommand("mkdir -p " + dir + "/sub1/ssub11"); + libsarus::process::executeCommand("touch " + dir + "/sub1/ssub11/g.pdf"); + libsarus::process::executeCommand("touch " + dir + "/sub1/ssub11/h.py"); + libsarus::process::executeCommand("chmod 665 " + dir + "/sub1/ssub11/g.pdf"); + libsarus::process::executeCommand("chmod 777 " + dir + "/sub1/ssub11/h.py"); + + libsarus::process::executeCommand("mkdir -p " + dir + "/sub2"); + libsarus::process::executeCommand("touch " + dir + "/sub2/f.a"); + libsarus::process::executeCommand("chmod 666 " + dir + "/sub2/f.a"); +} + +}}}} diff --git a/src/libsarus/test/aux/filesystem.hpp b/src/libsarus/test/aux/filesystem.hpp new file mode 100644 index 00000000..f4561441 --- /dev/null +++ b/src/libsarus/test/aux/filesystem.hpp @@ -0,0 +1,43 @@ +/* + * Sarus + * + * Copyright (c) 2018-2023, ETH Zurich. All rights reserved. + * + * Please, refer to the LICENSE file in the root directory. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +/** + * @brief Filesystem utility functions to be used in the tests. + */ + +#ifndef libsarus_test_aux_filesystem_hpp +#define libsarus_test_aux_filesystem_hpp + +#include +#include + +#include + + +namespace libsarus { +namespace test { +namespace aux { +namespace filesystem { + +bool areDirectoriesEqual(const std::string& dir1, const std::string& dir2, bool compare_file_attributes); +bool isSameBindMountedFile(const boost::filesystem::path&, const boost::filesystem::path&); +void createCharacterDeviceFile(const boost::filesystem::path& path, + const int majorID, + const int minorID, + const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); +void createBlockDeviceFile(const boost::filesystem::path& path, + const int majorID, + const int minorID, + const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); +void createTestDirectoryTree(const std::string& dir); + +}}}} + +#endif diff --git a/src/libsarus/test/aux/hook.cpp b/src/libsarus/test/aux/hook.cpp new file mode 100644 index 00000000..5a7a5c5e --- /dev/null +++ b/src/libsarus/test/aux/hook.cpp @@ -0,0 +1,101 @@ +/* + * Sarus + * + * Copyright (c) 2018-2023, ETH Zurich. All rights reserved. + * + * Please, refer to the LICENSE file in the root directory. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include "hook.hpp" + +#include +#include +#include + +#include + +#include "libsarus/Error.hpp" + + +namespace libsarus { +namespace test { +namespace aux { +namespace hook { + +void writeOCIContainerStateToStdin(const boost::filesystem::path& bundleDir) { + auto state = boost::format{ + "{" + "\"ociVersion\": \"dummy-version\", " + "\"id\": \"container-mpi-hook-test\", " + "\"status\": \"running\", " + "\"pid\": %d, " + "\"bundle\": %s" + "}" + } % getpid() % bundleDir; + + boost::filesystem::path simulatedStdin = bundleDir / "simulated_stdin.txt"; + + { + std::ofstream os(simulatedStdin.c_str()); + os << state << std::endl; + } + + if(std::freopen(simulatedStdin.c_str(), "r", stdin) == nullptr) { + SARUS_THROW_ERROR("Failed to replace stdin with text file"); + } + // Replacing stdin through std::freopen might result in a std::cin's error state when the + // reader reaches the end of the stream. Let's clear the error state, in case that an error + // was generated in a previous test. + std::cin.clear(); +} + +rapidjson::Document createOCIBaseConfigJSON(const boost::filesystem::path& rootfsDir, const std::tuple& idsOfUser) { + namespace rj = rapidjson; + + auto doc = rj::Document{rj::kObjectType}; + auto& allocator = doc.GetAllocator(); + + // root + doc.AddMember( + "root", + rj::Value{rj::kObjectType}, + allocator); + doc["root"].AddMember( + "path", + rj::Value{rootfsDir.filename().c_str(), allocator}, + allocator); + + // process + doc.AddMember( + "process", + rj::Document{rj::kObjectType}, + allocator); + doc["process"].AddMember( + "user", + rj::Document{rj::kObjectType}, + allocator); + doc["process"]["user"].AddMember( + "uid", + rj::Value{std::get<0>(idsOfUser)}, + allocator); + doc["process"]["user"].AddMember( + "gid", + rj::Value{std::get<1>(idsOfUser)}, + allocator); + doc["process"].AddMember( + "env", + rj::Document{rj::kArrayType}, + allocator); + + // annotations + doc.AddMember( + "annotations", + rj::Document{rj::kObjectType}, + allocator); + + return doc; +} + +}}}} diff --git a/src/libsarus/test/aux/hook.hpp b/src/libsarus/test/aux/hook.hpp new file mode 100644 index 00000000..5fe9751e --- /dev/null +++ b/src/libsarus/test/aux/hook.hpp @@ -0,0 +1,32 @@ +/* + * Sarus + * + * Copyright (c) 2018-2023, ETH Zurich. All rights reserved. + * + * Please, refer to the LICENSE file in the root directory. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef libsarus_test_aux_hook_hpp +#define libsarus_test_aux_hook_hpp + +#include +#include + +#include +#include + + +namespace libsarus { +namespace test { +namespace aux { +namespace hook { + +void writeOCIContainerStateToStdin(const boost::filesystem::path& bundleDir); +rapidjson::Document createOCIBaseConfigJSON(const boost::filesystem::path& rootfsDir, + const std::tuple& idsOfUser); + +}}}} + +#endif diff --git a/src/libsarus/test/aux/misc.cpp b/src/libsarus/test/aux/misc.cpp new file mode 100644 index 00000000..ddf092a1 --- /dev/null +++ b/src/libsarus/test/aux/misc.cpp @@ -0,0 +1,46 @@ +/* + * Sarus + * + * Copyright (c) 2018-2023, ETH Zurich. All rights reserved. + * + * Please, refer to the LICENSE file in the root directory. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef libsarus_test_aux_misc_hpp +#define libsarus_test_aux_misc_hpp + +#include "misc.hpp" + +#include + +#include + +#include "libsarus/Error.hpp" +#include "libsarus/PasswdDB.hpp" +#include "libsarus/Utility.hpp" + + +namespace libsarus { +namespace test { +namespace aux { +namespace misc { + +std::tuple getNonRootUserIds() { + auto out = libsarus::process::executeCommand("getent passwd"); + std::stringstream ss{out}; + auto passwd = libsarus::PasswdDB{ss}; + + for(const auto& entry : passwd.getEntries()) { + if(entry.uid != 0) { + return std::tuple{entry.uid, entry.gid}; + } + } + + SARUS_THROW_ERROR("Failed to find non-root user ids"); +} + +}}}} + +#endif diff --git a/src/libsarus/test/aux/misc.hpp b/src/libsarus/test/aux/misc.hpp new file mode 100644 index 00000000..c79db4fc --- /dev/null +++ b/src/libsarus/test/aux/misc.hpp @@ -0,0 +1,22 @@ +/* + * Sarus + * + * Copyright (c) 2018-2023, ETH Zurich. All rights reserved. + * + * Please, refer to the LICENSE file in the root directory. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include +#include + + +namespace libsarus { +namespace test { +namespace aux { +namespace misc { + +std::tuple getNonRootUserIds(); + +}}}} diff --git a/src/libsarus/test/aux/unitTestMain.hpp b/src/libsarus/test/aux/unitTestMain.hpp new file mode 100644 index 00000000..998df415 --- /dev/null +++ b/src/libsarus/test/aux/unitTestMain.hpp @@ -0,0 +1,34 @@ +/* + * Sarus + * + * Copyright (c) 2018-2023, ETH Zurich. All rights reserved. + * + * Please, refer to the LICENSE file in the root directory. + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef libsarus_test_aux_unitTestMain_hpp +#define libsarus_test_aux_unitTestMain_hpp + +#include "libsarus/Error.hpp" +#include "libsarus/Logger.hpp" + +// WATCH OUT! +// boost libraries must be included before CppUTest, so in order to be +// on the safe side include this file as the last header file in the test code +#include + + +#define SARUS_UNITTEST_MAIN_FUNCTION() \ +int main(int argc, char **argv) { \ + try { \ + return CommandLineTestRunner::RunAllTests(argc, argv); \ + } \ + catch(const libsarus::Error& e) { \ + libsarus::Logger::getInstance().logErrorTrace(e, "test"); \ + throw; \ + } \ +} + +#endif diff --git a/src/libsarus/test/test_CLIArguments.cpp b/src/libsarus/test/test_CLIArguments.cpp index d62fc76f..d4b7812f 100644 --- a/src/libsarus/test/test_CLIArguments.cpp +++ b/src/libsarus/test/test_CLIArguments.cpp @@ -8,15 +8,18 @@ * */ +// NOTE: Boost library must be included before CppUTest + #include -// boost library must be included before CppUTest + #include +#include "aux/unitTestMain.hpp" #include "libsarus/Error.hpp" +#include "libsarus/Lockfile.hpp" #include "libsarus/Logger.hpp" #include "libsarus/Utility.hpp" -#include "libsarus/Lockfile.hpp" -#include "test_utility/unittest_main_function.hpp" + namespace libsarus { namespace test { diff --git a/src/libsarus/test/test_DeviceAccess.cpp b/src/libsarus/test/test_DeviceAccess.cpp index f10204d5..dda4bea9 100644 --- a/src/libsarus/test/test_DeviceAccess.cpp +++ b/src/libsarus/test/test_DeviceAccess.cpp @@ -8,8 +8,9 @@ * */ +#include "aux/unitTestMain.hpp" #include "libsarus/DeviceAccess.hpp" -#include "test_utility/unittest_main_function.hpp" + namespace libsarus { namespace test { diff --git a/src/libsarus/test/test_DeviceMount.cpp b/src/libsarus/test/test_DeviceMount.cpp index 27a77aeb..7875d6a2 100644 --- a/src/libsarus/test/test_DeviceMount.cpp +++ b/src/libsarus/test/test_DeviceMount.cpp @@ -9,18 +9,16 @@ */ #include - #include #include -#include "test_utility/config.hpp" -#include "test_utility/filesystem.hpp" -#include "libsarus/DeviceMount.hpp" +#include "aux/filesystem.hpp" +#include "aux/unitTestMain.hpp" #include "libsarus/DeviceAccess.hpp" +#include "libsarus/DeviceMount.hpp" #include "libsarus/PathRAII.hpp" #include "libsarus/Utility.hpp" -#include "test_utility/filesystem.hpp" -#include "test_utility/unittest_main_function.hpp" + namespace libsarus { namespace test { @@ -37,8 +35,9 @@ IGNORE_TEST(DeviceMountTestGroup, constructor) { libsarus::filesystem::makeUniquePathWithRandomSuffix(boost::filesystem::current_path() / "deviceMount-test-constructor")); libsarus::filesystem::createFoldersIfNecessary(testDir.getPath()); - auto configRAII = test_utility::config::makeConfig(); - auto& config = configRAII.config; + auto bundleDirRAII = libsarus::PathRAII{libsarus::filesystem::makeUniquePathWithRandomSuffix(boost::filesystem::absolute("test-bundle-dir"))}; + const auto& rootfsDir = bundleDirRAII.getPath() / "rootfs"; + libsarus::UserIdentity userIdentity; size_t mount_flags = 0; auto devAccess = libsarus::DeviceAccess("rwm"); @@ -48,8 +47,8 @@ IGNORE_TEST(DeviceMountTestGroup, constructor) { auto testDeviceFile = testDir.getPath() / "testDevice"; auto majorID = 511u; auto minorID = 511u; - test_utility::filesystem::createCharacterDeviceFile(testDeviceFile, majorID, minorID); - auto mountObject = libsarus::Mount{testDeviceFile, testDeviceFile, mount_flags, config->getRootfsDirectory(), config->userIdentity}; + aux::filesystem::createCharacterDeviceFile(testDeviceFile, majorID, minorID); + auto mountObject = libsarus::Mount{testDeviceFile, testDeviceFile, mount_flags, rootfsDir, userIdentity}; DeviceMount(std::move(mountObject), devAccess); } @@ -57,7 +56,7 @@ IGNORE_TEST(DeviceMountTestGroup, constructor) { { auto noDeviceFile = testDir.getPath() / "notADevice"; libsarus::filesystem::createFileIfNecessary(noDeviceFile); - auto mountObject = libsarus::Mount{noDeviceFile, noDeviceFile, mount_flags, config->getRootfsDirectory(), config->userIdentity}; + auto mountObject = libsarus::Mount{noDeviceFile, noDeviceFile, mount_flags, rootfsDir, userIdentity}; CHECK_THROWS(libsarus::Error, DeviceMount(std::move(mountObject), devAccess)); } @@ -72,8 +71,9 @@ IGNORE_TEST(DeviceMountTestGroup, getters) { libsarus::filesystem::makeUniquePathWithRandomSuffix(boost::filesystem::current_path() / "deviceMount-test-getters")); libsarus::filesystem::createFoldersIfNecessary(testDir.getPath()); - auto configRAII = test_utility::config::makeConfig(); - auto& config = configRAII.config; + auto bundleDirRAII = libsarus::PathRAII{libsarus::filesystem::makeUniquePathWithRandomSuffix(boost::filesystem::absolute("test-bundle-dir"))}; + const auto& rootfsDir = bundleDirRAII.getPath() / "rootfs"; + libsarus::UserIdentity userIdentity; size_t mount_flags = 0; @@ -82,9 +82,9 @@ IGNORE_TEST(DeviceMountTestGroup, getters) { auto testDeviceFile = testDir.getPath() / "sarusTestDevice0"; auto majorID = 511u; auto minorID = 511u; - test_utility::filesystem::createCharacterDeviceFile(testDeviceFile, majorID, minorID); + aux::filesystem::createCharacterDeviceFile(testDeviceFile, majorID, minorID); - auto mountObject = libsarus::Mount{testDeviceFile, testDeviceFile, mount_flags, config->getRootfsDirectory(), config->userIdentity}; + auto mountObject = libsarus::Mount{testDeviceFile, testDeviceFile, mount_flags, rootfsDir, userIdentity}; auto devAccess = libsarus::DeviceAccess("rwm"); auto devMount = DeviceMount(std::move(mountObject), devAccess); @@ -99,9 +99,9 @@ IGNORE_TEST(DeviceMountTestGroup, getters) { auto testDeviceFile = testDir.getPath() / "sarusTestDevice1"; auto majorID = 477u; auto minorID = 488u; - test_utility::filesystem::createBlockDeviceFile(testDeviceFile, majorID, minorID); + aux::filesystem::createBlockDeviceFile(testDeviceFile, majorID, minorID); - auto mountObject = libsarus::Mount{testDeviceFile, testDeviceFile, mount_flags, config->getRootfsDirectory(), config->userIdentity}; + auto mountObject = libsarus::Mount{testDeviceFile, testDeviceFile, mount_flags, rootfsDir, userIdentity}; auto devAccess = libsarus::DeviceAccess("rw"); auto devMount = DeviceMount(std::move(mountObject), devAccess); @@ -123,12 +123,11 @@ IGNORE_TEST(DeviceMountTestGroup, performMount) { libsarus::filesystem::makeUniquePathWithRandomSuffix(boost::filesystem::current_path() / "deviceMount-test-performMount")); libsarus::filesystem::createFoldersIfNecessary(testDir.getPath()); - auto configRAII = test_utility::config::makeConfig(); - auto& config = configRAII.config; - - auto bundleDirRAII = libsarus::PathRAII{boost::filesystem::path{config->json["OCIBundleDir"].GetString()}}; + auto bundleDirRAII = libsarus::PathRAII{libsarus::filesystem::makeUniquePathWithRandomSuffix(boost::filesystem::absolute("test-bundle-dir"))}; const auto& bundleDir = bundleDirRAII.getPath(); - auto rootfsDir = bundleDir / boost::filesystem::path{config->json["rootfsFolder"].GetString()}; + auto rootfsDir = bundleDir / "rootfs"; + libsarus::UserIdentity userIdentity; + libsarus::filesystem::createFoldersIfNecessary(rootfsDir); auto sourceFile = testDir.getPath() / "sarusTestDevice0"; @@ -136,15 +135,15 @@ IGNORE_TEST(DeviceMountTestGroup, performMount) { auto majorID = 511u; auto minorID = 511u; - test_utility::filesystem::createCharacterDeviceFile(sourceFile, majorID, minorID); + aux::filesystem::createCharacterDeviceFile(sourceFile, majorID, minorID); size_t mount_flags = 0; - auto mountObject = libsarus::Mount{sourceFile, destinationFile, mount_flags, config->getRootfsDirectory(), config->userIdentity}; + auto mountObject = libsarus::Mount{sourceFile, destinationFile, mount_flags, rootfsDir, userIdentity}; auto devAccess = libsarus::DeviceAccess("rwm"); // perform the mount libsarus::DeviceMount{std::move(mountObject), devAccess}.performMount(); - CHECK(test_utility::filesystem::isSameBindMountedFile(sourceFile, rootfsDir / destinationFile)); + CHECK(aux::filesystem::isSameBindMountedFile(sourceFile, rootfsDir / destinationFile)); CHECK(libsarus::filesystem::getDeviceID(rootfsDir / destinationFile) == makedev(majorID, minorID)); CHECK(libsarus::filesystem::getDeviceType(rootfsDir / destinationFile) == 'c'); diff --git a/src/libsarus/test/test_DeviceParser.cpp b/src/libsarus/test/test_DeviceParser.cpp index 18de47a4..8835dac1 100644 --- a/src/libsarus/test/test_DeviceParser.cpp +++ b/src/libsarus/test/test_DeviceParser.cpp @@ -8,16 +8,82 @@ * */ +#include "aux/filesystem.hpp" +#include "aux/unitTestMain.hpp" +#include "libsarus/DeviceParser.hpp" #include "libsarus/Logger.hpp" #include "libsarus/PathRAII.hpp" -#include "libsarus/DeviceParser.hpp" -#include "DeviceParserChecker.hpp" -#include "test_utility/filesystem.hpp" -#include "test_utility/unittest_main_function.hpp" +#include "libsarus/Utility.hpp" + namespace libsarus { namespace test { +class DeviceParserChecker { +public: + DeviceParserChecker(const std::string& deviceRequest) + : deviceRequest(deviceRequest) + {} + + DeviceParserChecker& expectSource(const std::string& expectedSource) { + this->expectedSource = expectedSource; + return *this; + } + + DeviceParserChecker& expectDestination(const std::string& expectedDestination) { + this->expectedDestination = expectedDestination; + return *this; + } + + DeviceParserChecker& expectAccess(const std::string& expectedAccess) { + this->expectedAccess = expectedAccess; + return *this; + } + + DeviceParserChecker& expectParseError() { + isParseErrorExpected = true; + return *this; + } + + ~DeviceParserChecker() { + libsarus::UserIdentity userIdentity; + auto bundleDirRAII = libsarus::PathRAII{libsarus::filesystem::makeUniquePathWithRandomSuffix(boost::filesystem::absolute("test-bundle-dir"))}; + auto rootfsDir = bundleDirRAII.getPath() / "rootfs"; + + auto parser = libsarus::DeviceParser{rootfsDir, userIdentity}; + + if(isParseErrorExpected) { + CHECK_THROWS(libsarus::Error, parser.parseDeviceRequest(deviceRequest)); + return; + } + + auto mountObject = parser.parseDeviceRequest(deviceRequest); + + if(expectedSource) { + CHECK(mountObject->getSource() == *expectedSource); + } + + if(expectedDestination) { + CHECK(mountObject->getDestination() == *expectedDestination); + } + + if(expectedAccess) { + CHECK(mountObject->getAccess().string() == *expectedAccess); + } + + CHECK_EQUAL(mountObject->getFlags(), *expectedFlags); + } + +private: + std::string deviceRequest; + boost::optional expectedSource{}; + boost::optional expectedDestination{}; + boost::optional expectedAccess{"rwm"}; + boost::optional expectedFlags{MS_REC | MS_PRIVATE}; + + bool isParseErrorExpected = false; +}; + TEST_GROUP(DeviceParserTestGroup) { void setup() { auto testDevice = boost::filesystem::path("/dev/sarusTestDevice0"); @@ -26,7 +92,7 @@ TEST_GROUP(DeviceParserTestGroup) { if (boost::filesystem::exists(testDevice)) { boost::filesystem::remove(testDevice); } - test_utility::filesystem::createCharacterDeviceFile(testDevice, testDeviceMajorID, testDeviceMinorID); + aux::filesystem::createCharacterDeviceFile(testDevice, testDeviceMajorID, testDeviceMinorID); } void teardown() { @@ -106,27 +172,6 @@ IGNORE_TEST(DeviceParserTestGroup, access) { DeviceParserChecker{"/dev/sarusTestDevice0:/dev/containerDevice:"}.expectParseError(); } -#ifdef ASROOT -TEST(DeviceParserTestGroup, constructors) { -#else -IGNORE_TEST(DeviceParserTestGroup, constructors) { -#endif - auto configRAII = test_utility::config::makeConfig(); - auto userIdentity = configRAII.config->userIdentity; - auto rootfsDir = boost::filesystem::path{ configRAII.config->json["OCIBundleDir"].GetString() } - / configRAII.config->json["rootfsFolder"].GetString(); - - auto requestString = std::string("/dev/sarusTestDevice0:/dev/containerDevice:r"); - - auto ctor1 = DeviceParser{configRAII.config->getRootfsDirectory(), configRAII.config->userIdentity}.parseDeviceRequest(requestString); - auto ctor2 = DeviceParser{rootfsDir, userIdentity}.parseDeviceRequest(requestString); - - CHECK(ctor1->getSource() == ctor2->getSource()); - CHECK(ctor1->getDestination() == ctor2->getDestination()); - CHECK(ctor1->getFlags() == ctor2->getFlags()); - CHECK(ctor1->getAccess().string() == ctor2->getAccess().string()); -} - }} SARUS_UNITTEST_MAIN_FUNCTION(); diff --git a/src/libsarus/test/test_Error.cpp b/src/libsarus/test/test_Error.cpp index 0eb86fbd..047b7fa6 100644 --- a/src/libsarus/test/test_Error.cpp +++ b/src/libsarus/test/test_Error.cpp @@ -10,8 +10,9 @@ #include +#include "aux/unitTestMain.hpp" #include "libsarus/Error.hpp" -#include "test_utility/unittest_main_function.hpp" + namespace libsarus { namespace test { @@ -56,7 +57,7 @@ TEST(ErrorTestGroup, oneStackTraceEntry) { functionThatThrows(); } catch(const libsarus::Error& error) { - auto expectedFirstEntry = libsarus::Error::ErrorTraceEntry{"first error message", "test_Error.cpp", 23, "functionThatThrows"}; + auto expectedFirstEntry = libsarus::Error::ErrorTraceEntry{"first error message", "test_Error.cpp", 24, "functionThatThrows"}; CHECK_EQUAL(error.getErrorTrace().size(), 1); CHECK(error.getErrorTrace()[0] == expectedFirstEntry); @@ -69,8 +70,8 @@ TEST(ErrorTestGroup, twoStackTraceEntries) { functionThatRethrows(); } catch (const libsarus::Error& error) { - auto expectedFirstEntry = libsarus::Error::ErrorTraceEntry{"first error message", "test_Error.cpp", 23, "functionThatThrows"}; - auto expectedSecondEntry = libsarus::Error::ErrorTraceEntry{"second error message", "test_Error.cpp", 31, "functionThatRethrows"}; + auto expectedFirstEntry = libsarus::Error::ErrorTraceEntry{"first error message", "test_Error.cpp", 24, "functionThatThrows"}; + auto expectedSecondEntry = libsarus::Error::ErrorTraceEntry{"second error message", "test_Error.cpp", 32, "functionThatRethrows"}; CHECK_EQUAL(error.getErrorTrace().size(), 2); CHECK(error.getErrorTrace()[0] == expectedFirstEntry); @@ -85,7 +86,7 @@ TEST(ErrorTestGroup, fromStdException) { } catch(const libsarus::Error& error) { auto expectedFirstEntry = libsarus::Error::ErrorTraceEntry{"first error message", "unspecified location", -1, "runtime error"}; - auto expectedSecondEntry = libsarus::Error::ErrorTraceEntry{"second error message", "test_Error.cpp", 38, "functionThatThrowsFromStdException"}; + auto expectedSecondEntry = libsarus::Error::ErrorTraceEntry{"second error message", "test_Error.cpp", 39, "functionThatThrowsFromStdException"}; CHECK_EQUAL(error.getErrorTrace().size(), 2); CHECK(error.getErrorTrace()[0] == expectedFirstEntry); @@ -99,7 +100,7 @@ TEST(ErrorTestGroup, oneStackTraceEntry_throwWithLogLevelDebug) { functionThatThrowsWithLogLevelDebug(); } catch(const libsarus::Error& error) { - auto expectedFirstEntry = libsarus::Error::ErrorTraceEntry{"first error message", "test_Error.cpp", 42, "functionThatThrowsWithLogLevelDebug"}; + auto expectedFirstEntry = libsarus::Error::ErrorTraceEntry{"first error message", "test_Error.cpp", 43, "functionThatThrowsWithLogLevelDebug"}; CHECK_EQUAL(error.getErrorTrace().size(), 1); CHECK(error.getErrorTrace()[0] == expectedFirstEntry); @@ -112,8 +113,8 @@ TEST(ErrorTestGroup, twoStackTraceEntries_rethrowWithLogLevelDebug) { functionThatRethrowsWithLogLevelDebug(); } catch (const libsarus::Error& error) { - auto expectedFirstEntry = libsarus::Error::ErrorTraceEntry{"first error message", "test_Error.cpp", 23, "functionThatThrows"}; - auto expectedSecondEntry = libsarus::Error::ErrorTraceEntry{"second error message", "test_Error.cpp", 50, "functionThatRethrowsWithLogLevelDebug"}; + auto expectedFirstEntry = libsarus::Error::ErrorTraceEntry{"first error message", "test_Error.cpp", 24, "functionThatThrows"}; + auto expectedSecondEntry = libsarus::Error::ErrorTraceEntry{"second error message", "test_Error.cpp", 51, "functionThatRethrowsWithLogLevelDebug"}; CHECK_EQUAL(error.getErrorTrace().size(), 2); CHECK(error.getErrorTrace()[0] == expectedFirstEntry); diff --git a/src/libsarus/test/test_Flock.cpp b/src/libsarus/test/test_Flock.cpp index a3411c35..d395b5ae 100644 --- a/src/libsarus/test/test_Flock.cpp +++ b/src/libsarus/test/test_Flock.cpp @@ -10,12 +10,13 @@ #include +#include + +#include "aux/unitTestMain.hpp" #include "libsarus/Error.hpp" #include "libsarus/Flock.hpp" #include "libsarus/Utility.hpp" -#include "test_utility/unittest_main_function.hpp" -#include namespace libsarus { namespace test { diff --git a/src/libsarus/test/test_HookUtility.cpp b/src/libsarus/test/test_HookUtility.cpp index 067dfa5c..450c5da0 100644 --- a/src/libsarus/test/test_HookUtility.cpp +++ b/src/libsarus/test/test_HookUtility.cpp @@ -18,11 +18,12 @@ #include #include -#include "libsarus/Utility.hpp" +#include "aux/hook.hpp" +#include "aux/misc.hpp" +#include "aux/unitTestMain.hpp" #include "libsarus/PathRAII.hpp" -#include "test_utility/Misc.hpp" -#include "test_utility/OCIHooks.hpp" -#include "test_utility/unittest_main_function.hpp" +#include "libsarus/Utility.hpp" + namespace libsarus { namespace test { @@ -41,7 +42,7 @@ TEST(HooksUtilityTestGroup, parseStateOfContainerFromStdin) { auto returnedBundleDir = boost::filesystem::path(); pid_t returnedPid; - test_utility::ocihooks::writeContainerStateToStdin(expectedBundleDir.getPath()); + aux::hook::writeOCIContainerStateToStdin(expectedBundleDir.getPath()); auto containerState = parseStateOfContainerFromStdin(); CHECK(containerState.bundle() == expectedBundleDir.getPath()); @@ -54,8 +55,8 @@ TEST(HooksUtilityTestGroup, getEnvironmentVariableValueFromOCIBundle) { libsarus::filesystem::createFoldersIfNecessary(testBundleDir.getPath()); auto bundleConfigFile = testBundleDir.getPath() / "config.json"; - auto config = test_utility::ocihooks::createBaseConfigJSON(testBundleDir.getPath() / "rootfs", - test_utility::misc::getNonRootUserIds()); + auto config = aux::hook::createOCIBaseConfigJSON(testBundleDir.getPath() / "rootfs", + aux::misc::getNonRootUserIds()); auto& allocator = config.GetAllocator(); // Variable set and non-empty diff --git a/src/libsarus/test/test_Lockfile.cpp b/src/libsarus/test/test_Lockfile.cpp index ed4b94e5..51d9d113 100644 --- a/src/libsarus/test/test_Lockfile.cpp +++ b/src/libsarus/test/test_Lockfile.cpp @@ -10,12 +10,13 @@ #include +#include + +#include "aux/unitTestMain.hpp" #include "libsarus/Error.hpp" -#include "libsarus/Utility.hpp" #include "libsarus/Lockfile.hpp" +#include "libsarus/Utility.hpp" -#include -#include "test_utility/unittest_main_function.hpp" namespace libsarus { namespace test { diff --git a/src/libsarus/test/test_Logger.cpp b/src/libsarus/test/test_Logger.cpp index cada8cec..756808b3 100644 --- a/src/libsarus/test/test_Logger.cpp +++ b/src/libsarus/test/test_Logger.cpp @@ -8,16 +8,17 @@ * */ +#include #include #include -#include #include #include #include +#include "aux/unitTestMain.hpp" #include "libsarus/Logger.hpp" -#include "test_utility/unittest_main_function.hpp" + namespace libsarus { namespace test { diff --git a/src/libsarus/test/test_Mount.cpp b/src/libsarus/test/test_Mount.cpp index e883f9e2..e9860225 100644 --- a/src/libsarus/test/test_Mount.cpp +++ b/src/libsarus/test/test_Mount.cpp @@ -13,16 +13,15 @@ */ #include - -#include #include +#include -#include "test_utility/config.hpp" -#include "test_utility/filesystem.hpp" +#include "aux/filesystem.hpp" +#include "aux/unitTestMain.hpp" #include "libsarus/Mount.hpp" #include "libsarus/PathRAII.hpp" #include "libsarus/Utility.hpp" -#include "test_utility/unittest_main_function.hpp" + namespace libsarus { namespace test { @@ -35,14 +34,11 @@ TEST(MountTestGroup, mount_test) { #else IGNORE_TEST(MountTestGroup, mount_test) { #endif - auto configRAII = test_utility::config::makeConfig(); - auto& config = configRAII.config; + libsarus::UserIdentity userIdentity; - auto bundleDirRAII = libsarus::PathRAII{boost::filesystem::path{config->json["OCIBundleDir"].GetString()}}; + auto bundleDirRAII = libsarus::PathRAII{libsarus::filesystem::makeUniquePathWithRandomSuffix(boost::filesystem::absolute("test-bundle-dir"))}; const auto& bundleDir = bundleDirRAII.getPath(); - auto rootfsDir = bundleDir / boost::filesystem::path{config->json["rootfsFolder"].GetString()}; - auto overlayfsLowerDir = bundleDir / "overlay/rootfs-lower"; // hardcoded so in production code being tested - libsarus::filesystem::createFoldersIfNecessary(overlayfsLowerDir); + auto rootfsDir = bundleDir / "rootfs"; auto sourceDirRAII = libsarus::PathRAII{boost::filesystem::path{"./user_mounts_source"}}; const auto& sourceDir = sourceDirRAII.getPath(); @@ -55,7 +51,7 @@ IGNORE_TEST(MountTestGroup, mount_test) { // Create files and directories libsarus::filesystem::createFoldersIfNecessary(rootfsDir); - test_utility::filesystem::create_test_directory_tree(sourceDir.string()); + aux::filesystem::createTestDirectoryTree(sourceDir.string()); libsarus::filesystem::createFileIfNecessary(sourceFile.getPath()); auto command = "echo \"test data\" >" + sourceFile.getPath().string(); auto ret = std::system(command.c_str()); @@ -63,8 +59,8 @@ IGNORE_TEST(MountTestGroup, mount_test) { // test mount of non-existing destination directory { - libsarus::Mount{sourceDir, destinationDir, mount_flags, config->getRootfsDirectory(), config->userIdentity}.performMount(); - CHECK(test_utility::filesystem::are_directories_equal(sourceDir.string(), (rootfsDir / destinationDir).string(), 1)); + libsarus::Mount{sourceDir, destinationDir, mount_flags, rootfsDir, userIdentity}.performMount(); + CHECK(aux::filesystem::areDirectoriesEqual(sourceDir.string(), (rootfsDir / destinationDir).string(), 1)); // cleanup CHECK(umount((rootfsDir / destinationDir).c_str()) == 0); @@ -73,8 +69,8 @@ IGNORE_TEST(MountTestGroup, mount_test) { // test mount of existing destination directory { libsarus::filesystem::createFoldersIfNecessary(rootfsDir / destinationDir); - libsarus::Mount{sourceDir, destinationDir.c_str(), mount_flags, config->getRootfsDirectory(), config->userIdentity}.performMount(); - CHECK(test_utility::filesystem::are_directories_equal(sourceDir.string(), (rootfsDir / destinationDir).string(), 1)); + libsarus::Mount{sourceDir, destinationDir.c_str(), mount_flags, rootfsDir, userIdentity}.performMount(); + CHECK(aux::filesystem::areDirectoriesEqual(sourceDir.string(), (rootfsDir / destinationDir).string(), 1)); // cleanup CHECK(umount((rootfsDir / destinationDir).c_str()) == 0); @@ -82,25 +78,25 @@ IGNORE_TEST(MountTestGroup, mount_test) { } // test mount of individual file { - libsarus::Mount{sourceFile.getPath(), destinationFile.getPath(), mount_flags, config->getRootfsDirectory(), config->userIdentity}.performMount(); - CHECK(test_utility::filesystem::isSameBindMountedFile(sourceFile.getPath(), rootfsDir / destinationFile.getPath())); + libsarus::Mount{sourceFile.getPath(), destinationFile.getPath(), mount_flags, rootfsDir, userIdentity}.performMount(); + CHECK(aux::filesystem::isSameBindMountedFile(sourceFile.getPath(), rootfsDir / destinationFile.getPath())); // cleanup CHECK(umount((rootfsDir / destinationFile.getPath()).c_str()) == 0); } // test ctor with 5 arguments { - libsarus::Mount{sourceFile.getPath(), destinationFile.getPath(), mount_flags, rootfsDir, config->userIdentity}.performMount(); - CHECK(test_utility::filesystem::isSameBindMountedFile(sourceFile.getPath(), rootfsDir / destinationFile.getPath())); + libsarus::Mount{sourceFile.getPath(), destinationFile.getPath(), mount_flags, rootfsDir, userIdentity}.performMount(); + CHECK(aux::filesystem::isSameBindMountedFile(sourceFile.getPath(), rootfsDir / destinationFile.getPath())); // cleanup CHECK(umount((rootfsDir / destinationFile.getPath()).c_str()) == 0); } // test default move ctor { - auto mountObject = libsarus::Mount{sourceFile.getPath(), destinationFile.getPath(), mount_flags, config->getRootfsDirectory(), config->userIdentity}; + auto mountObject = libsarus::Mount{sourceFile.getPath(), destinationFile.getPath(), mount_flags, rootfsDir, userIdentity}; libsarus::Mount{std::move(mountObject)}.performMount(); - CHECK(test_utility::filesystem::isSameBindMountedFile(sourceFile.getPath(), rootfsDir / destinationFile.getPath())); + CHECK(aux::filesystem::isSameBindMountedFile(sourceFile.getPath(), rootfsDir / destinationFile.getPath())); // cleanup CHECK(umount((rootfsDir / destinationFile.getPath()).c_str()) == 0); diff --git a/src/libsarus/test/test_MountParser.cpp b/src/libsarus/test/test_MountParser.cpp index 397bd002..8720d552 100644 --- a/src/libsarus/test/test_MountParser.cpp +++ b/src/libsarus/test/test_MountParser.cpp @@ -8,14 +8,108 @@ * */ +#include +#include + +#include "aux/unitTestMain.hpp" #include "libsarus/Logger.hpp" #include "libsarus/MountParser.hpp" -#include "MountParserChecker.hpp" -#include "test_utility/unittest_main_function.hpp" +#include "libsarus/PathRAII.hpp" +#include "libsarus/Utility.hpp" + namespace libsarus { namespace test { +class MountParserChecker { +public: + MountParserChecker(const std::string& mountRequest) + : mountRequest(mountRequest) + {} + + MountParserChecker& parseAsSiteMount() { + this->isSiteMount = true; + return *this; + } + + MountParserChecker& expectSource(const std::string& expectedSource) { + this->expectedSource = expectedSource; + return *this; + } + + MountParserChecker& expectDestination(const std::string& expectedDestination) { + this->expectedDestination = expectedDestination; + return *this; + } + + MountParserChecker& expectFlags(const size_t flags) { + this->expectedFlags = flags; + return *this; + } + + MountParserChecker& expectParseError() { + isParseErrorExpected = true; + return *this; + } + + ~MountParserChecker() { + libsarus::UserIdentity userIdentity; + auto bundleDirRAII = libsarus::PathRAII{libsarus::filesystem::makeUniquePathWithRandomSuffix(boost::filesystem::absolute("test-bundle-dir"))}; + auto rootfsDir = bundleDirRAII.getPath() / "rootfs"; + + libsarus::MountParser parser = libsarus::MountParser{rootfsDir, userIdentity}; + + if (!isSiteMount) { + // Populate "userMount", originally done by "ConfigRAII" in Sarus 1.6.4. + rapidjson::MemoryPoolAllocator<> allocator; + rapidjson::Value userMountsValue(rapidjson::kObjectType); + + rapidjson::Value disallowWithPrefixValue(rapidjson::kArrayType); + disallowWithPrefixValue.PushBack("/etc", allocator); + disallowWithPrefixValue.PushBack("/var", allocator); + disallowWithPrefixValue.PushBack("/opt/sarus", allocator); + userMountsValue.AddMember("notAllowedPrefixesOfPath", disallowWithPrefixValue, allocator); + + rapidjson::Value disallowExactValue(rapidjson::kArrayType); + disallowExactValue.PushBack("/opt", allocator); + userMountsValue.AddMember("notAllowedPaths", disallowExactValue, allocator); + + // Inject "userMount". + parser.setMountDestinationRestrictions(userMountsValue); + } + + auto map = libsarus::string::parseMap(mountRequest); + + if(isParseErrorExpected) { + CHECK_THROWS(libsarus::Error, parser.parseMountRequest(map)); + return; + } + + auto mountObject = parser.parseMountRequest(map); + + if(expectedSource) { + CHECK(mountObject->getSource() == *expectedSource); + } + + if(expectedDestination) { + CHECK(mountObject->getDestination() == *expectedDestination); + } + + if(expectedFlags) { + CHECK_EQUAL(mountObject->getFlags(), *expectedFlags); + } + } + +private: + std::string mountRequest; + bool isSiteMount = false; + boost::optional expectedSource = {}; + boost::optional expectedDestination = {}; + boost::optional expectedFlags = {}; + + bool isParseErrorExpected = false; +}; + TEST_GROUP(MountParserTestGroup) { }; diff --git a/src/libsarus/test/test_MountUtility.cpp b/src/libsarus/test/test_MountUtility.cpp index df3a56e0..79285da0 100644 --- a/src/libsarus/test/test_MountUtility.cpp +++ b/src/libsarus/test/test_MountUtility.cpp @@ -13,14 +13,13 @@ */ #include - #include -#include "test_utility/config.hpp" -#include "test_utility/filesystem.hpp" +#include "aux/filesystem.hpp" +#include "aux/unitTestMain.hpp" #include "libsarus/PathRAII.hpp" #include "libsarus/Utility.hpp" -#include "test_utility/unittest_main_function.hpp" + namespace libsarus { namespace test { @@ -51,11 +50,9 @@ TEST(MountUtilitiesTestGroup, get_validated_mount_source_test) { } TEST(MountUtilitiesTestGroup, get_validated_mount_destination_test) { - auto configRAII = test_utility::config::makeConfig(); - auto& config = *configRAII.config; - auto bundleDirRAII = libsarus::PathRAII{boost::filesystem::path{config.json["OCIBundleDir"].GetString()}}; + auto bundleDirRAII = libsarus::PathRAII{libsarus::filesystem::makeUniquePathWithRandomSuffix(boost::filesystem::absolute("test-bundle-dir"))}; const auto& bundleDir = bundleDirRAII.getPath(); - auto rootfsDir = bundleDir / boost::filesystem::path{config.json["rootfsFolder"].GetString()}; + auto rootfsDir = bundleDir / "rootfs"; libsarus::filesystem::createFoldersIfNecessary(bundleDir / "overlay/rootfs-lower"); // Test invalid input arguments diff --git a/src/libsarus/test/test_PasswdDB.cpp b/src/libsarus/test/test_PasswdDB.cpp index 82a2522e..8cbb4cf2 100644 --- a/src/libsarus/test/test_PasswdDB.cpp +++ b/src/libsarus/test/test_PasswdDB.cpp @@ -10,11 +10,13 @@ #include #include + #include +#include "aux/unitTestMain.hpp" #include "libsarus/PasswdDB.hpp" #include "libsarus/PathRAII.hpp" -#include "test_utility/unittest_main_function.hpp" + namespace libsarus { namespace test { diff --git a/src/libsarus/test/test_Utility.cpp b/src/libsarus/test/test_Utility.cpp index e760caaa..9dd6bf29 100644 --- a/src/libsarus/test/test_Utility.cpp +++ b/src/libsarus/test/test_Utility.cpp @@ -9,19 +9,20 @@ */ #include -#include -#include -#include #include +#include +#include +#include #include #include #include +#include "aux/misc.hpp" +#include "aux/unitTestMain.hpp" #include "libsarus/PathRAII.hpp" #include "libsarus/Utility.hpp" -#include "test_utility/Misc.hpp" -#include "test_utility/unittest_main_function.hpp" + namespace libsarus { namespace test { @@ -125,7 +126,7 @@ TEST(UtilityTestGroup, switchIdentity) { uid_t unprivilegedUid; gid_t unprivilegedGid; - std::tie(unprivilegedUid, unprivilegedGid) = test_utility::misc::getNonRootUserIds(); + std::tie(unprivilegedUid, unprivilegedGid) = aux::misc::getNonRootUserIds(); auto unprivilegedIdentity = libsarus::UserIdentity{unprivilegedUid, unprivilegedGid, {}}; libsarus::process::switchIdentity(unprivilegedIdentity); @@ -150,7 +151,7 @@ TEST(UtilityTestGroup, setFilesystemUid) { // switch to unprivileged user uid_t unprivilegedUid; gid_t unprivilegedGid; - std::tie(unprivilegedUid, unprivilegedGid) = test_utility::misc::getNonRootUserIds(); + std::tie(unprivilegedUid, unprivilegedGid) = aux::misc::getNonRootUserIds(); auto unprivilegedIdentity = libsarus::UserIdentity{unprivilegedUid, unprivilegedGid, {}}; auto rootIdentity = libsarus::UserIdentity{};