diff --git a/README.md b/README.md index 63c8c9ab9..3452ae745 100644 --- a/README.md +++ b/README.md @@ -133,3 +133,10 @@ This project uses pre-commit to maintain high quality of the source code. Instal ```bash pre-commit install ``` + +### Unit testing + +```bash +colcon build --symlink-install --packages-up-to husarion_ugv --cmake-args -DCMAKE_BUILD_TYPE=Release -DTEST_INTEGRATION=OFF +colcon test --packages-up-to husarion_ugv +``` diff --git a/husarion_ugv_manager/CMakeLists.txt b/husarion_ugv_manager/CMakeLists.txt index 82f9b5282..29863b3d5 100644 --- a/husarion_ugv_manager/CMakeLists.txt +++ b/husarion_ugv_manager/CMakeLists.txt @@ -61,9 +61,8 @@ foreach(bt_plugin ${plugin_libs}) ament_target_dependencies(${bt_plugin} ${PACKAGE_DEPENDENCIES}) endforeach() -add_executable( - safety_manager_node src/safety_manager_node_main.cpp - src/safety_manager_node.cpp src/behavior_tree_manager.cpp) +add_executable(safety_manager_node src/safety_manager_node_main.cpp + src/safety_manager_node.cpp) ament_target_dependencies( safety_manager_node behaviortree_ros2 @@ -78,9 +77,8 @@ generate_parameter_library(safety_manager_parameters target_link_libraries(safety_manager_node ${plugin_libs} safety_manager_parameters) -add_executable( - lights_manager_node src/lights_manager_node_main.cpp - src/lights_manager_node.cpp src/behavior_tree_manager.cpp) +add_executable(lights_manager_node src/lights_manager_node_main.cpp + src/lights_manager_node.cpp) ament_target_dependencies( lights_manager_node behaviortree_ros2 @@ -133,12 +131,6 @@ if(BUILD_TESTING) src/plugins/action/signal_shutdown_node.cpp) list(APPEND plugin_tests ${PROJECT_NAME}_test_signal_shutdown_node) - ament_add_gtest( - ${PROJECT_NAME}_test_shutdown_single_host_node - test/plugins/action/test_shutdown_single_host_node.cpp - src/plugins/action/shutdown_single_host_node.cpp) - list(APPEND plugin_tests ${PROJECT_NAME}_test_shutdown_single_host_node) - ament_add_gtest( ${PROJECT_NAME}_test_shutdown_hosts_from_file_node test/plugins/action/test_shutdown_hosts_from_file_node.cpp @@ -159,6 +151,15 @@ if(BUILD_TESTING) test/plugins/test_shutdown_hosts_node.cpp) list(APPEND plugin_tests ${PROJECT_NAME}_test_shutdown_hosts_node) + option(TEST_INTEGRATION "Run integration tests" ON) + if(TEST_INTEGRATION) + ament_add_gtest( + ${PROJECT_NAME}_test_shutdown_single_host_node + test/plugins/action/test_shutdown_single_host_node.cpp + src/plugins/action/shutdown_single_host_node.cpp) + list(APPEND plugin_tests ${PROJECT_NAME}_test_shutdown_single_host_node) + endif() + foreach(bt_node_test ${plugin_tests}) target_include_directories( ${bt_node_test} @@ -180,9 +181,8 @@ if(BUILD_TESTING) ${PROJECT_NAME}_test_behavior_tree_utils behaviortree_cpp behaviortree_ros2 husarion_ugv_utils) - ament_add_gtest( - ${PROJECT_NAME}_test_behavior_tree_manager - test/test_behavior_tree_manager.cpp src/behavior_tree_manager.cpp) + ament_add_gtest(${PROJECT_NAME}_test_behavior_tree_manager + test/test_behavior_tree_manager.cpp) target_include_directories( ${PROJECT_NAME}_test_behavior_tree_manager PUBLIC $ @@ -190,9 +190,8 @@ if(BUILD_TESTING) ament_target_dependencies(${PROJECT_NAME}_test_behavior_tree_manager behaviortree_cpp husarion_ugv_utils) - ament_add_gtest( - ${PROJECT_NAME}_test_lights_manager_node test/test_lights_manager_node.cpp - src/lights_manager_node.cpp src/behavior_tree_manager.cpp) + ament_add_gtest(${PROJECT_NAME}_test_lights_manager_node + test/test_lights_manager_node.cpp src/lights_manager_node.cpp) target_include_directories( ${PROJECT_NAME}_test_lights_manager_node PUBLIC $ @@ -211,8 +210,7 @@ if(BUILD_TESTING) ament_add_gtest( ${PROJECT_NAME}_test_lights_behavior_tree - test/test_lights_behavior_tree.cpp src/lights_manager_node.cpp - src/behavior_tree_manager.cpp) + test/test_lights_behavior_tree.cpp src/lights_manager_node.cpp) target_include_directories( ${PROJECT_NAME}_test_lights_behavior_tree PUBLIC $ @@ -229,9 +227,8 @@ if(BUILD_TESTING) target_link_libraries(${PROJECT_NAME}_test_lights_behavior_tree lights_manager_parameters) - ament_add_gtest( - ${PROJECT_NAME}_test_safety_manager_node test/test_safety_manager_node.cpp - src/safety_manager_node.cpp src/behavior_tree_manager.cpp) + ament_add_gtest(${PROJECT_NAME}_test_safety_manager_node + test/test_safety_manager_node.cpp src/safety_manager_node.cpp) target_include_directories( ${PROJECT_NAME}_test_safety_manager_node PUBLIC $ @@ -250,8 +247,7 @@ if(BUILD_TESTING) ament_add_gtest( ${PROJECT_NAME}_test_safety_behavior_tree - test/test_safety_behavior_tree.cpp src/safety_manager_node.cpp - src/behavior_tree_manager.cpp) + test/test_safety_behavior_tree.cpp src/safety_manager_node.cpp) target_include_directories( ${PROJECT_NAME}_test_safety_behavior_tree PUBLIC $ diff --git a/husarion_ugv_manager/include/husarion_ugv_manager/behavior_tree_manager.hpp b/husarion_ugv_manager/include/husarion_ugv_manager/behavior_tree_manager.hpp index 831a0c7bf..e420933db 100644 --- a/husarion_ugv_manager/include/husarion_ugv_manager/behavior_tree_manager.hpp +++ b/husarion_ugv_manager/include/husarion_ugv_manager/behavior_tree_manager.hpp @@ -58,7 +58,12 @@ class BehaviorTreeManager * * @param factory The factory object used to create the tree. */ - void Initialize(BT::BehaviorTreeFactory & factory); + inline void Initialize(BT::BehaviorTreeFactory & factory) + { + config_ = CreateBTConfig(initial_blackboard_); + tree_ = factory.createTree(tree_name_, config_.blackboard); + groot_publisher_ = std::make_unique(tree_, groot_port_); + } void TickOnce() { tree_status_ = tree_.tickOnce(); } void TickExactlyOnce() { tree_status_ = tree_.tickExactlyOnce(); } @@ -80,7 +85,36 @@ class BehaviorTreeManager * entry type. * @return A BehaviorTree configuration object. */ - BT::NodeConfig CreateBTConfig(const std::map & bb_values) const; + inline BT::NodeConfig CreateBTConfig(const std::map & bb_values) const + { + BT::NodeConfig config; + config.blackboard = BT::Blackboard::create(); + + for (auto & [name, value] : bb_values) { + const std::type_info & type = value.type(); + if (type == typeid(bool)) { + config.blackboard->set(name, std::any_cast(value)); + } else if (type == typeid(int)) { + config.blackboard->set(name, std::any_cast(value)); + } else if (type == typeid(unsigned)) { + config.blackboard->set(name, std::any_cast(value)); + } else if (type == typeid(float)) { + config.blackboard->set(name, std::any_cast(value)); + } else if (type == typeid(double)) { + config.blackboard->set(name, std::any_cast(value)); + } else if (type == typeid(const char *)) { + config.blackboard->set(name, std::any_cast(value)); + } else if (type == typeid(std::string)) { + config.blackboard->set(name, std::any_cast(value)); + } else { + throw std::invalid_argument( + "Invalid type for blackboard entry. Valid types are: bool, int, unsigned, float, double, " + "const char*, std::string"); + } + } + + return config; + } private: const std::string tree_name_; diff --git a/husarion_ugv_manager/src/behavior_tree_manager.cpp b/husarion_ugv_manager/src/behavior_tree_manager.cpp deleted file mode 100644 index c5beb1a46..000000000 --- a/husarion_ugv_manager/src/behavior_tree_manager.cpp +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2024 Husarion sp. z o.o. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#include - -#include -#include -#include -#include -#include -#include - -#include "behaviortree_cpp/loggers/groot2_publisher.h" -#include "rclcpp/rclcpp.hpp" - -namespace husarion_ugv_manager -{ - -void BehaviorTreeManager::Initialize(BT::BehaviorTreeFactory & factory) -{ - config_ = CreateBTConfig(initial_blackboard_); - tree_ = factory.createTree(tree_name_, config_.blackboard); - groot_publisher_ = std::make_unique(tree_, groot_port_); -} - -BT::NodeConfig BehaviorTreeManager::CreateBTConfig( - const std::map & bb_values) const -{ - BT::NodeConfig config; - config.blackboard = BT::Blackboard::create(); - - for (auto & [name, value] : bb_values) { - const std::type_info & type = value.type(); - if (type == typeid(bool)) { - config.blackboard->set(name, std::any_cast(value)); - } else if (type == typeid(int)) { - config.blackboard->set(name, std::any_cast(value)); - } else if (type == typeid(unsigned)) { - config.blackboard->set(name, std::any_cast(value)); - } else if (type == typeid(float)) { - config.blackboard->set(name, std::any_cast(value)); - } else if (type == typeid(double)) { - config.blackboard->set(name, std::any_cast(value)); - } else if (type == typeid(const char *)) { - config.blackboard->set(name, std::any_cast(value)); - } else if (type == typeid(std::string)) { - config.blackboard->set(name, std::any_cast(value)); - } else { - throw std::invalid_argument( - "Invalid type for blackboard entry. Valid types are: bool, int, unsigned, float, double, " - "const char*, std::string"); - } - } - - return config; -} - -} // namespace husarion_ugv_manager