Skip to content

Commit

Permalink
test(daemon): cover domain layer with unit tests
Browse files Browse the repository at this point in the history
Covers (most of) the domain layer with unit tests, also fixes some bugs found along the way.
  • Loading branch information
LordTermor committed Oct 16, 2024
1 parent b592fcb commit 6b76549
Show file tree
Hide file tree
Showing 29 changed files with 950 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
################################################################################
cmake_minimum_required(VERSION 3.23)
project(bxt C CXX)
enable_testing()

list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
Expand All @@ -15,6 +16,7 @@ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++abi")
set(FETCHCONTENT_QUIET FALSE)

option(BXT_EXPERIMENTAL_COPY_MOVE "Enable experimental copy/move operations" OFF)
option(BXT_BUILD_TESTS "Build unit tests" OFF)

################################################################################
# Dependencies: Fetch and configure external libraries not available in Conan
Expand Down
4 changes: 3 additions & 1 deletion CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
"inherits": "base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
"BXT_BUILD_TESTS": "ON",
"CONAN_INSTALL_ARGS": "--build=missing;-o testing=True"
}
},
{
Expand Down
12 changes: 11 additions & 1 deletion conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@
class BxtConanFile(ConanFile):
settings = "os", "arch", "compiler", "build_type"
generators = "CMakeDeps"

options = {
"testing": [True, False],
}
default_options = {
"testing": False,
}

def requirements(self):
# to link to them you need to change cmake/deps.cmake
self.requires("openssl/3.3.1")
Expand All @@ -27,6 +33,10 @@ def requirements(self):
self.requires("cereal/1.3.2")
self.requires("libcoro/0.12.1")
self.requires("scope-lite/0.2.0")

if self.options.testing:
print("Testing enabled")
self.requires("catch2/3.7.0")

def configure(self):
self.options["boost/*"].shared = True
Expand Down
7 changes: 6 additions & 1 deletion daemon/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ project(bxtd LANGUAGES CXX)
################################################################################
add_subdirectory(swagger)

if(BXT_BUILD_TESTS)
add_subdirectory(tests)
endif()

file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS "*.cpp")
list(FILTER SOURCES EXCLUDE REGEX "tests/.*")

################################################################################
# Executable Configuration
Expand Down Expand Up @@ -41,4 +46,4 @@ target_link_libraries(${PROJECT_NAME} PRIVATE
reflectcpp
)

add_dependencies(${PROJECT_NAME} deploy_swagger)
add_dependencies(${PROJECT_NAME} deploy_swagger daemon_tests)
1 change: 1 addition & 0 deletions daemon/core/domain/entities/Section.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class Section {
std::string string() const {
return fmt::format("{}/{}/{}", branch(), repository(), architecture());
}
auto operator<=>(Section const& other) const = default;

private:
Name m_branch;
Expand Down
7 changes: 7 additions & 0 deletions daemon/core/domain/services/PermissionMatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
*/
#include "PermissionMatcher.h"

#include <algorithm>

namespace bxt::Core::Domain::PermissionMatcher {

bool match(Permission const& lh, Permission const& rh) {
Expand All @@ -23,6 +25,11 @@ bool match(Permission const& lh, Permission const& rh) {
}
}

if (ltags.size() != rtags.size() && !std::ranges::contains(ltags, "*")
&& !std::ranges::contains(rtags, "*")) {
return false;
}

return true;
}

Expand Down
4 changes: 4 additions & 0 deletions daemon/core/domain/value_objects/PackageVersion.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ struct PackageVersion {
return compare(*this, rh);
};

auto operator==(PackageVersion const& rh) const {
return compare(*this, rh) == 0;
}

static ParseResult from_string(std::string_view str);
std::string string() const;

Expand Down
2 changes: 2 additions & 0 deletions daemon/event_log/domain/entities/PackageLogEntry.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ class PackageLogEntry {
return m_version;
}

bool operator==(PackageLogEntry const& other) const = default;

private:
LogEntryType m_type;
Core::Domain::Section m_section;
Expand Down
2 changes: 2 additions & 0 deletions daemon/event_log/domain/entities/PackageUpdateLogEntry.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ class PackageUpdateLogEntry {
return previous_package_log_entry;
}

bool operator==(PackageUpdateLogEntry const& other) const = default;

private:
PackageLogEntry package_log_entry;
PackageLogEntry previous_package_log_entry;
Expand Down
53 changes: 53 additions & 0 deletions daemon/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
################################################################################
# Test Configuration
################################################################################
enable_testing()
include(CTest)

find_package(Catch2 REQUIRED)

################################################################################
# Test Sources
################################################################################

file(GLOB_RECURSE TEST_SOURCES "src/unit/*/**.cpp")
file(GLOB_RECURSE BXT_SOURCES "../*/**.cpp")

################################################################################
# Test Executable
################################################################################

add_executable(daemon_tests
${TEST_SOURCES} ${BXT_SOURCES}
)

target_link_libraries(daemon_tests PRIVATE
Catch2::Catch2WithMain
deps
reflectcpp
Dexode::EventBus
)

target_include_directories(daemon_tests PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/../
${lmdbxx_SOURCE_DIR}/include
)

set_target_properties(daemon_tests PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/tests
)


################################################################################
# Test Data
################################################################################

get_target_property(TESTS_RUNTIME_OUTPUT_DIRECTORY daemon_tests RUNTIME_OUTPUT_DIRECTORY)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/data DESTINATION ${TESTS_RUNTIME_OUTPUT_DIRECTORY})

################################################################################
# CTest Integration
################################################################################
include(Catch)

catch_discover_tests(daemon_tests WORKING_DIRECTORY ${TESTS_RUNTIME_OUTPUT_DIRECTORY})
Binary file added daemon/tests/data/dummy-1-1-any.pkg.tar.zst
Binary file not shown.
Binary file added daemon/tests/data/dummy-1-1-any.pkg.tar.zst.sig
Binary file not shown.
27 changes: 27 additions & 0 deletions daemon/tests/src/unit/core/domain/entities/PackageTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* === This file is part of bxt ===
*
* SPDX-FileCopyrightText: 2024 Artem Grinev <[email protected]>
* SPDX-License-Identifier: AGPL-3.0-or-later
*
*/
#include "core/domain/entities/Package.h"

#include <catch2/catch_test_macros.hpp>

using namespace bxt::Core::Domain;

TEST_CASE("Package", "[core][domain][entities]") {
SECTION("Parse file name") {
REQUIRE(Package::parse_file_name("package-1.0.0-1-x86_64.pkg.tar.zst").value()
== "package");
REQUIRE(Package::parse_file_name("package-1.0.0-1-any.pkg.tar.zst").value() == "package");
REQUIRE(Package::parse_file_name("lib32-package-1.0.0-1-x86_64.pkg.tar.zst").value()
== "lib32-package");

// Invalid cases
REQUIRE(Package::parse_file_name("package.pkg.tar.zst") == std::nullopt);
REQUIRE(Package::parse_file_name("1.0.0-1-x86_64.pkg.tar.zst") == std::nullopt);
REQUIRE(Package::parse_file_name("package-") == std::nullopt);
REQUIRE(Package::parse_file_name("package-1.0.0-1.pkg.tar.zst") == std::nullopt);
}
}
49 changes: 49 additions & 0 deletions daemon/tests/src/unit/core/domain/entities/SectionTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/* === This file is part of bxt ===
*
* SPDX-FileCopyrightText: 2024 Artem Grinev <[email protected]>
* SPDX-License-Identifier: AGPL-3.0-or-later
*
*/
#include "core/domain/entities/Section.h"

#include <catch2/catch_test_macros.hpp>

using namespace bxt::Core::Domain;

TEST_CASE("Section entity", "[core][domain][entities]") {
SECTION("Construction and getters") {
Section section(Name("stable"), Name("core"), Name("x86_64"));

REQUIRE(section.branch() == Name("stable"));
REQUIRE(section.repository() == Name("core"));
REQUIRE(section.architecture() == Name("x86_64"));
}

SECTION("Setters") {
Section section(Name("stable"), Name("core"), Name("x86_64"));

section.set_branch(Name("testing"));
REQUIRE(section.branch() == Name("testing"));

section.set_repository(Name("extra"));
REQUIRE(section.repository() == Name("extra"));

section.set_architecture(Name("aarch64"));
REQUIRE(section.architecture() == Name("aarch64"));
}

SECTION("ID generation") {
Section section(Name("stable"), Name("core"), Name("x86_64"));
REQUIRE(section.id() == "stable/core/x86_64");
}

SECTION("String representation") {
Section section(Name("stable"), Name("core"), Name("x86_64"));
REQUIRE(section.string() == "stable/core/x86_64");
}

SECTION("to_string function") {
Section section(Name("stable"), Name("core"), Name("x86_64"));
REQUIRE(bxt::to_string(section) == "stable/core/x86_64");
}
}
59 changes: 59 additions & 0 deletions daemon/tests/src/unit/core/domain/entities/UserTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* === This file is part of bxt ===
*
* SPDX-FileCopyrightText: 2024 Artem Grinev <[email protected]>
* SPDX-License-Identifier: AGPL-3.0-or-later
*
*/
#include "core/domain/entities/User.h"

#include <catch2/catch_test_macros.hpp>

using namespace bxt::Core::Domain;

TEST_CASE("User entity", "[core][domain][entities]") {
SECTION("Construction and getters") {
User user(Name("testuser"), "password123");

REQUIRE(user.name() == Name("testuser"));
REQUIRE(user.password() == "password123");
REQUIRE(user.permissions().empty());
}

SECTION("Setters") {
User user(Name("testuser"), "password123");

user.set_name("newuser");
REQUIRE(user.name() == Name("newuser"));

user.set_password("newpassword");
REQUIRE(user.password() == "newpassword");

std::set<Permission> new_permissions = {Permission("read"), Permission("write")};
user.set_permissions(new_permissions);
REQUIRE(user.permissions() == new_permissions);
}

SECTION("ID") {
User user(Name("testuser"), "password123");
REQUIRE(user.id() == Name("testuser"));
}

SECTION("Permission checking") {
User user(Name("testuser"), "password123");
std::set<Permission> permissions = {Permission("sections.*.*.*"),
Permission("packages.get.stable.core.x86_64")};
user.set_permissions(permissions);

REQUIRE(user.has_permission("sections.stable.core.x86_64"));
REQUIRE(user.has_permission("packages.get.stable.core.x86_64"));
REQUIRE_FALSE(user.has_permission("packages.snap.stable.core.x86_64"));
REQUIRE_FALSE(user.has_permission("users.add"));
}

SECTION("Default constructor") {
User default_user;
REQUIRE(default_user.name() == Name("Unnamed"));
REQUIRE(default_user.password().empty());
REQUIRE(default_user.permissions().empty());
}
}
52 changes: 52 additions & 0 deletions daemon/tests/src/unit/core/domain/enums/PoolLocationTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* === This file is part of bxt ===
*
* SPDX-FileCopyrightText: 2024 Artem Grinev <[email protected]>
* SPDX-License-Identifier: AGPL-3.0-or-later
*
*/
#include "core/domain/enums/PoolLocation.h"

#include <catch2/catch_test_macros.hpp>
#include <map>

using namespace bxt::Core::Domain;

TEST_CASE("PoolLocation enum", "[core][domain][enums]") {
SECTION("to_string conversion") {
REQUIRE(bxt::to_string(PoolLocation::Sync) == "sync");
REQUIRE(bxt::to_string(PoolLocation::Overlay) == "overlay");
REQUIRE(bxt::to_string(PoolLocation::Automated) == "automated");
REQUIRE_THROWS(bxt::to_string(PoolLocation::Unknown));
}

SECTION("select_preferred_pool_location") {
SECTION("Empty map") {
std::map<PoolLocation, int> empty_map;
auto result = select_preferred_pool_location(empty_map);
REQUIRE_FALSE(result.has_value());
}

SECTION("Single element map") {
std::map<PoolLocation, int> single_map = {{PoolLocation::Sync, 1}};
auto result = select_preferred_pool_location(single_map);
REQUIRE(result.has_value());
REQUIRE(*result == PoolLocation::Sync);
}

SECTION("Multiple elements map") {
std::map<PoolLocation, int> multi_map = {
{PoolLocation::Sync, 1}, {PoolLocation::Overlay, 2}, {PoolLocation::Automated, 3}};
auto result = select_preferred_pool_location(multi_map);
REQUIRE(result.has_value());
REQUIRE(*result == PoolLocation::Overlay);
}

SECTION("Map with Unknown location") {
std::map<PoolLocation, int> map_with_unknown = {
{PoolLocation::Unknown, 0}, {PoolLocation::Automated, 1}, {PoolLocation::Sync, 2}};
auto result = select_preferred_pool_location(map_with_unknown);
REQUIRE(result.has_value());
REQUIRE(*result == PoolLocation::Automated);
}
}
}
Loading

0 comments on commit 6b76549

Please sign in to comment.