Skip to content

Commit f258501

Browse files
committed
Implement tests using xml_txt trees and dummy nodes
Signed-off-by: redvinaa <redvinaa@gmail.com>
1 parent 470491a commit f258501

File tree

8 files changed

+387
-81
lines changed

8 files changed

+387
-81
lines changed

nav2_behavior_tree/include/nav2_behavior_tree/plugins/control/pause_resume_controller.hpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,16 @@ const std::map<state_t, uint16_t> child_indices = {
6969
*
7070
* <!-- ON_RESUME branch (optional) -->
7171
* </Pause>
72+
*
73+
* The controller starts in RESUMED state, and ticks it until it returns success.
74+
* When the pause service is called, ON_PAUSE is ticked until completion,
75+
* then the controller switches to PAUSED state.
76+
* When the resume service is called, ON_RESUME is ticked until completion,
77+
* then the controller switches back to RESUMED state.
78+
*
79+
* The controller only returns success when the RESUMED child returns success.
80+
* The controller returns failure if any child returns failure.
81+
* In any other case, it returns running.
7282
*/
7383

7484

@@ -99,6 +109,11 @@ class PauseResumeController : public BT::ControlNode
99109
};
100110
}
101111

112+
[[nodiscard]] inline state_t getState() const
113+
{
114+
return state_;
115+
}
116+
102117
private:
103118
//! @brief Set state to PAUSE_REQUESTED
104119
void pauseServiceCallback(

nav2_behavior_tree/plugins/control/pause_resume_controller.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,19 @@ BT::NodeStatus PauseResumeController::tick()
9292
// If child is used, tick it
9393
const BT::NodeStatus child_status =
9494
children_nodes_[child_indices.at(state_)]->executeTick();
95+
9596
switch (child_status) {
9697
case BT::NodeStatus::RUNNING:
9798
return BT::NodeStatus::RUNNING;
9899
case BT::NodeStatus::SUCCESS:
99100
case BT::NodeStatus::SKIPPED:
101+
if (state_ == RESUMED) {
102+
// Resumed child returned SUCCESS, we're done
103+
return BT::NodeStatus::SUCCESS;
104+
}
100105
switchToNextState();
101-
return BT::NodeStatus::SUCCESS;
106+
// If any branch other than RESUMED returned SUCCESS, keep ticking
107+
return BT::NodeStatus::RUNNING;
102108
case BT::NodeStatus::FAILURE:
103109
RCLCPP_ERROR(
104110
logger_, "%s child returned FAILURE", state_names.at(state_).c_str());

nav2_behavior_tree/plugins/control/sequence_with_blackboard_memory.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ BT::NodeStatus SequenceWithBlackboardMemoryNode::tick()
6161
} // end while loop
6262

6363
// The entire while loop completed. This means that all the children returned SUCCESS.
64-
if (current_child_idx == children_count) {
64+
if (current_child_idx >= children_count) {
6565
resetChildren();
6666
setOutput("current_child_idx", 0);
6767
}

nav2_behavior_tree/test/plugins/control/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ plugin_add_test(test_control_round_robin_node test_round_robin_node.cpp nav2_rou
66

77
plugin_add_test(test_control_pause_resume_controller
88
test_pause_resume_controller.cpp nav2_pause_resume_controller_bt_node)
9+
10+
plugin_add_test(test_sequence_with_blackboard_memory
11+
test_sequence_with_blackboard_memory.cpp nav2_sequence_with_blackboard_memory_bt_node)

nav2_behavior_tree/test/plugins/control/test_pause_resume_controller.cpp

Lines changed: 113 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@
1717

1818
#include "utils/test_behavior_tree_fixture.hpp"
1919
#include "utils/test_dummy_tree_node.hpp"
20+
#include "utils/get_node_from_tree.hpp"
2021
#include "nav2_behavior_tree/plugins/control/pause_resume_controller.hpp"
2122
#include "std_srvs/srv/trigger.hpp"
2223

2324
class PauseResumeControllerTestFixture : public nav2_behavior_tree::BehaviorTreeTestFixture
2425
{
2526
public:
26-
void SetUp() override
27+
static void SetUpTestCase()
2728
{
2829
node_ = std::make_shared<rclcpp::Node>("pause_resume_controller_test_fixture");
2930
executor_ =
@@ -36,49 +37,36 @@ class PauseResumeControllerTestFixture : public nav2_behavior_tree::BehaviorTree
3637
resume_client_ = node_->create_client<std_srvs::srv::Trigger>(
3738
"resume", rclcpp::ServicesQoS(), cb_group_);
3839

39-
config_->input_ports["pause_service_name"] = "pause";
40-
config_->input_ports["resume_service_name"] = "resume";
40+
factory_ = std::make_shared<BT::BehaviorTreeFactory>();
41+
config_ = new BT::NodeConfiguration();
4142
config_->blackboard = BT::Blackboard::create();
4243
config_->blackboard->set<rclcpp::Node::SharedPtr>("node", node_);
4344

44-
bt_node_ = std::make_shared<nav2_behavior_tree::PauseResumeController>(
45-
"pause_resume_controller", *config_);
46-
resumed_child_ = std::make_shared<nav2_behavior_tree::DummyNode>();
47-
paused_child_ = std::make_shared<nav2_behavior_tree::DummyNode>();
48-
on_pause_child_ = std::make_shared<nav2_behavior_tree::DummyNode>();
49-
on_resume_child_ = std::make_shared<nav2_behavior_tree::DummyNode>();
50-
resumed_child_->changeStatus(BT::NodeStatus::SUCCESS);
51-
paused_child_->changeStatus(BT::NodeStatus::SUCCESS);
52-
on_pause_child_->changeStatus(BT::NodeStatus::SUCCESS);
53-
on_resume_child_->changeStatus(BT::NodeStatus::SUCCESS);
54-
bt_node_->addChild(resumed_child_.get());
55-
bt_node_->addChild(paused_child_.get());
56-
bt_node_->addChild(on_pause_child_.get());
57-
bt_node_->addChild(on_resume_child_.get());
45+
factory_->registerNodeType<nav2_behavior_tree::PauseResumeController>("PauseResumeController");
46+
47+
// Register dummy node for testing
48+
factory_->registerNodeType<nav2_behavior_tree::DummyNode>("DummyNode");
49+
}
50+
51+
static void TearDownTestCase()
52+
{
53+
if (config_) {
54+
delete config_;
55+
config_ = nullptr;
56+
}
57+
tree_.reset();
5858
}
5959

6060
protected:
61-
static std::shared_ptr<nav2_behavior_tree::PauseResumeController> bt_node_;
62-
static std::shared_ptr<nav2_behavior_tree::DummyNode> paused_child_;
63-
static std::shared_ptr<nav2_behavior_tree::DummyNode> resumed_child_;
64-
static std::shared_ptr<nav2_behavior_tree::DummyNode> on_pause_child_;
65-
static std::shared_ptr<nav2_behavior_tree::DummyNode> on_resume_child_;
61+
static BT::NodeConfiguration * config_;
62+
static std::shared_ptr<BT::BehaviorTreeFactory> factory_;
63+
static std::shared_ptr<BT::Tree> tree_;
6664
static rclcpp::executors::SingleThreadedExecutor::SharedPtr executor_;
6765
static rclcpp::CallbackGroup::SharedPtr cb_group_;
6866
static rclcpp::Client<std_srvs::srv::Trigger>::SharedPtr pause_client_;
6967
static rclcpp::Client<std_srvs::srv::Trigger>::SharedPtr resume_client_;
7068
};
7169

72-
std::shared_ptr<nav2_behavior_tree::PauseResumeController>
73-
PauseResumeControllerTestFixture::bt_node_ = nullptr;
74-
std::shared_ptr<nav2_behavior_tree::DummyNode>
75-
PauseResumeControllerTestFixture::paused_child_ = nullptr;
76-
std::shared_ptr<nav2_behavior_tree::DummyNode>
77-
PauseResumeControllerTestFixture::resumed_child_ = nullptr;
78-
std::shared_ptr<nav2_behavior_tree::DummyNode>
79-
PauseResumeControllerTestFixture::on_pause_child_ = nullptr;
80-
std::shared_ptr<nav2_behavior_tree::DummyNode>
81-
PauseResumeControllerTestFixture::on_resume_child_ = nullptr;
8270
rclcpp::executors::SingleThreadedExecutor::SharedPtr
8371
PauseResumeControllerTestFixture::executor_ = nullptr;
8472
rclcpp::CallbackGroup::SharedPtr
@@ -87,51 +75,104 @@ rclcpp::Client<std_srvs::srv::Trigger>::SharedPtr
8775
PauseResumeControllerTestFixture::pause_client_ = nullptr;
8876
rclcpp::Client<std_srvs::srv::Trigger>::SharedPtr
8977
PauseResumeControllerTestFixture::resume_client_ = nullptr;
78+
BT::NodeConfiguration * PauseResumeControllerTestFixture::config_ = nullptr;
79+
std::shared_ptr<BT::BehaviorTreeFactory> PauseResumeControllerTestFixture::factory_ = nullptr;
80+
std::shared_ptr<BT::Tree> PauseResumeControllerTestFixture::tree_ = nullptr;
9081

9182
TEST_F(PauseResumeControllerTestFixture, test_behavior)
9283
{
93-
resumed_child_->changeStatus(BT::NodeStatus::SUCCESS);
94-
paused_child_->changeStatus(BT::NodeStatus::SUCCESS);
95-
on_pause_child_->changeStatus(BT::NodeStatus::SUCCESS);
96-
on_resume_child_->changeStatus(BT::NodeStatus::SUCCESS);
97-
EXPECT_EQ(bt_node_->executeTick(), BT::NodeStatus::SUCCESS);
98-
99-
// Set on_pause to RUNNING, call pause service, expect RUNNING
100-
on_pause_child_->changeStatus(BT::NodeStatus::RUNNING);
101-
auto res = pause_client_->async_send_request(
84+
// create tree
85+
std::string xml_txt =
86+
R"(
87+
<root BTCPP_format="4">
88+
<BehaviorTree ID="MainTree">
89+
<PauseResumeController
90+
pause_service_name="pause"
91+
resume_service_name="resume">
92+
<DummyNode/> <!-- RESUMED -->
93+
<DummyNode/> <!-- PAUSED -->
94+
<DummyNode/> <!-- ON_PAUSE -->
95+
<DummyNode/> <!-- ON_RESUME -->
96+
</PauseResumeController>
97+
</BehaviorTree>
98+
</root>)";
99+
tree_ = std::make_shared<BT::Tree>(factory_->createTreeFromText(xml_txt, config_->blackboard));
100+
101+
// get pause_resume_controller so we can check state
102+
auto pause_bt_node =
103+
nav2_behavior_tree::get_node_from_tree<nav2_behavior_tree::PauseResumeController>(tree_);
104+
ASSERT_NE(pause_bt_node, nullptr);
105+
using state_t = nav2_behavior_tree::state_t;
106+
107+
// get dummy nodes so we can change their status
108+
auto resumed_child =
109+
nav2_behavior_tree::get_node_from_tree<nav2_behavior_tree::DummyNode>(tree_, 0);
110+
auto paused_child =
111+
nav2_behavior_tree::get_node_from_tree<nav2_behavior_tree::DummyNode>(tree_, 1);
112+
auto on_pause_child =
113+
nav2_behavior_tree::get_node_from_tree<nav2_behavior_tree::DummyNode>(tree_, 2);
114+
auto on_resume_child =
115+
nav2_behavior_tree::get_node_from_tree<nav2_behavior_tree::DummyNode>(tree_, 3);
116+
ASSERT_NE(resumed_child, nullptr);
117+
ASSERT_NE(paused_child, nullptr);
118+
ASSERT_NE(on_pause_child, nullptr);
119+
ASSERT_NE(on_resume_child, nullptr);
120+
121+
resumed_child->changeStatus(BT::NodeStatus::RUNNING);
122+
paused_child->changeStatus(BT::NodeStatus::RUNNING);
123+
on_pause_child->changeStatus(BT::NodeStatus::RUNNING);
124+
on_resume_child->changeStatus(BT::NodeStatus::RUNNING);
125+
126+
EXPECT_EQ(tree_->rootNode()->executeTick(), BT::NodeStatus::RUNNING);
127+
EXPECT_EQ(pause_bt_node->getState(), state_t::RESUMED);
128+
129+
const auto & check_request_succeeded = [](
130+
rclcpp::Client<std_srvs::srv::Trigger>::FutureAndRequestId & future)
131+
{
132+
executor_->spin_until_future_complete(future, std::chrono::seconds(1));
133+
ASSERT_EQ(future.wait_for(std::chrono::seconds(0)), std::future_status::ready);
134+
EXPECT_EQ(future.get()->success, true);
135+
};
136+
137+
// Call pause service, set ON_PAUSE child to RUNNING, expect RUNNING and ON_PAUSE
138+
auto future = pause_client_->async_send_request(
102139
std::make_shared<std_srvs::srv::Trigger::Request>());
103-
EXPECT_EQ(bt_node_->executeTick(), BT::NodeStatus::RUNNING);
104-
executor_->spin_until_future_complete(res, std::chrono::seconds(1));
105-
ASSERT_EQ(res.wait_for(std::chrono::seconds(1)), std::future_status::ready);
106-
EXPECT_EQ(res.get()->success, true);
107-
108-
// Change on_pause to SUCCESS, paused child to FAILURE
109-
// Expect SUCCESS (from on_pause), then FAILURE (from paused child)
110-
on_pause_child_->changeStatus(BT::NodeStatus::SUCCESS);
111-
paused_child_->changeStatus(BT::NodeStatus::FAILURE);
112-
EXPECT_EQ(bt_node_->executeTick(), BT::NodeStatus::SUCCESS);
113-
EXPECT_EQ(bt_node_->executeTick(), BT::NodeStatus::FAILURE);
114-
115-
// Set paused to SUCCESS, tick again, expect SUCCESS
116-
paused_child_->changeStatus(BT::NodeStatus::SUCCESS);
117-
EXPECT_EQ(bt_node_->executeTick(), BT::NodeStatus::SUCCESS);
118-
119-
// Set on_resume to SKIPPED, call resume service, expect SUCCESS (treated same as SKIPPED)
120-
on_resume_child_->changeStatus(BT::NodeStatus::SKIPPED);
121-
res = resume_client_->async_send_request(
140+
EXPECT_EQ(tree_->rootNode()->executeTick(), BT::NodeStatus::RUNNING);
141+
EXPECT_EQ(pause_bt_node->getState(), state_t::ON_PAUSE);
142+
check_request_succeeded(future);
143+
144+
// Change ON_PAUSE child to SUCCESS, expect RUNNING and PAUSED
145+
on_pause_child->changeStatus(BT::NodeStatus::SUCCESS);
146+
EXPECT_EQ(tree_->rootNode()->executeTick(), BT::NodeStatus::RUNNING);
147+
EXPECT_EQ(pause_bt_node->getState(), state_t::PAUSED);
148+
149+
// Set PAUSED child to SUCCESS, expect RUNNING and PAUSED
150+
// (should keep ticking unless RESUMED branch succeeds)
151+
paused_child->changeStatus(BT::NodeStatus::SUCCESS);
152+
EXPECT_EQ(tree_->rootNode()->executeTick(), BT::NodeStatus::RUNNING);
153+
EXPECT_EQ(pause_bt_node->getState(), state_t::PAUSED);
154+
155+
// Set PAUSED child to SKIPPED, expect RUNNING and PAUSED
156+
paused_child->changeStatus(BT::NodeStatus::SKIPPED);
157+
EXPECT_EQ(tree_->rootNode()->executeTick(), BT::NodeStatus::RUNNING);
158+
EXPECT_EQ(pause_bt_node->getState(), state_t::PAUSED);
159+
160+
// Call resume service, change ON_RESUME child to FAILURE, expect FAILURE
161+
future = resume_client_->async_send_request(
122162
std::make_shared<std_srvs::srv::Trigger::Request>());
123-
EXPECT_EQ(bt_node_->executeTick(), BT::NodeStatus::SUCCESS);
124-
executor_->spin_until_future_complete(res, std::chrono::seconds(1));
125-
ASSERT_EQ(res.wait_for(std::chrono::seconds(1)), std::future_status::ready);
126-
EXPECT_EQ(res.get()->success, true);
127-
128-
// Set resumed to RUNNING, expect RUNNING
129-
resumed_child_->changeStatus(BT::NodeStatus::RUNNING);
130-
EXPECT_EQ(bt_node_->executeTick(), BT::NodeStatus::RUNNING);
131-
132-
// Change resumed to SUCCESS, expect SUCCESS
133-
resumed_child_->changeStatus(BT::NodeStatus::SUCCESS);
134-
EXPECT_EQ(bt_node_->executeTick(), BT::NodeStatus::SUCCESS);
163+
on_resume_child->changeStatus(BT::NodeStatus::FAILURE);
164+
EXPECT_EQ(tree_->rootNode()->executeTick(), BT::NodeStatus::FAILURE);
165+
check_request_succeeded(future);
166+
167+
// Halt the tree, expect RUNNING and RESUMED
168+
tree_->haltTree();
169+
EXPECT_EQ(tree_->rootNode()->executeTick(), BT::NodeStatus::RUNNING);
170+
EXPECT_EQ(pause_bt_node->getState(), state_t::RESUMED);
171+
172+
// Set resumed child to SUCCESS, expect SUCCESS and RESUMED
173+
resumed_child->changeStatus(BT::NodeStatus::SUCCESS);
174+
EXPECT_EQ(tree_->rootNode()->executeTick(), BT::NodeStatus::SUCCESS);
175+
EXPECT_EQ(pause_bt_node->getState(), state_t::RESUMED);
135176
}
136177

137178
int main(int argc, char ** argv)

0 commit comments

Comments
 (0)