gtest_coroutines.cpp
Go to the documentation of this file.
3 #include <chrono>
4 #include <future>
5 #include <gtest/gtest.h>
6 
7 using namespace std::chrono;
8 
9 using Millisecond = std::chrono::milliseconds;
10 using Timepoint = std::chrono::time_point<std::chrono::steady_clock>;
11 
13 {
14 public:
15  SimpleCoroAction(milliseconds timeout, bool will_fail, const std::string& node_name,
16  const BT::NodeConfig& config)
17  : BT::CoroActionNode(node_name, config)
18  , will_fail_(will_fail)
19  , timeout_(timeout)
20  , start_time_(Timepoint::min())
21  {}
22 
23  virtual void halt() override
24  {
25  std::cout << "Action was halted. doing cleanup here" << std::endl;
26  start_time_ = Timepoint::min();
27  halted_ = true;
29  }
30 
31  bool wasHalted()
32  {
33  return halted_;
34  }
35 
37  {
38  timeout_ = ms;
39  }
40 
41 protected:
42  virtual BT::NodeStatus tick() override
43  {
44  std::cout << "Starting action " << std::endl;
45  halted_ = false;
46 
47  if(start_time_ == Timepoint::min())
48  {
49  start_time_ = std::chrono::steady_clock::now();
50  }
51 
52  while(std::chrono::steady_clock::now() < (start_time_ + timeout_))
53  {
54  setStatusRunningAndYield();
55  }
56 
57  halted_ = false;
58 
59  std::cout << "Done" << std::endl;
60  start_time_ = Timepoint::min();
61  return (will_fail_ ? BT::NodeStatus::FAILURE : BT::NodeStatus::SUCCESS);
62  }
63 
64 public:
65  bool will_fail_;
66 
67 private:
68  std::chrono::milliseconds timeout_;
70  bool halted_;
71 };
72 
74 {
75  auto status = node.executeTick();
76  while(status == BT::NodeStatus::RUNNING)
77  {
78  status = node.executeTick();
79  std::this_thread::sleep_for(Millisecond(1));
80  }
81  return status;
82 }
83 
84 TEST(CoroTest, do_action)
85 {
86  BT::NodeConfig node_config_;
87  node_config_.blackboard = BT::Blackboard::create();
88  BT::assignDefaultRemapping<SimpleCoroAction>(node_config_);
89  SimpleCoroAction node(milliseconds(200), false, "Action", node_config_);
90 
92  EXPECT_FALSE(node.wasHalted());
93 
94  EXPECT_EQ(BT::NodeStatus::SUCCESS, executeWhileRunning(node)) << "Second call to coro "
95  "action";
96  EXPECT_FALSE(node.wasHalted());
97 
98  node.will_fail_ = true;
99  EXPECT_EQ(BT::NodeStatus::FAILURE, executeWhileRunning(node)) << "Should execute again "
100  "and retun failure";
101  EXPECT_FALSE(node.wasHalted());
102 
103  EXPECT_EQ(BT::NodeStatus::FAILURE, executeWhileRunning(node)) << "Shoudln't fail "
104  "because we set "
105  "status to idle";
106  EXPECT_FALSE(node.wasHalted());
107 }
108 
109 TEST(CoroTest, do_action_timeout)
110 {
111  BT::NodeConfig node_config_;
112  node_config_.blackboard = BT::Blackboard::create();
113  BT::assignDefaultRemapping<SimpleCoroAction>(node_config_);
114 
115  SimpleCoroAction node(milliseconds(300), false, "Action", node_config_);
116  BT::TimeoutNode timeout("TimeoutAction", 200);
117 
118  timeout.setChild(&node);
119 
120  EXPECT_EQ(BT::NodeStatus::FAILURE, executeWhileRunning(timeout)) << "should timeout";
121  EXPECT_TRUE(node.wasHalted());
122 
123  node.setRequiredTime(Millisecond(100));
124 
125  EXPECT_EQ(BT::NodeStatus::SUCCESS, executeWhileRunning(timeout));
126  EXPECT_FALSE(node.wasHalted());
127 }
128 
129 TEST(CoroTest, sequence_child)
130 {
131  BT::NodeConfig node_config_;
132  node_config_.blackboard = BT::Blackboard::create();
133  BT::assignDefaultRemapping<SimpleCoroAction>(node_config_);
134 
135  SimpleCoroAction actionA(milliseconds(200), false, "action_A", node_config_);
136  SimpleCoroAction actionB(milliseconds(200), false, "action_B", node_config_);
137  BT::TimeoutNode timeout("timeout", 300);
138  BT::SequenceNode sequence("sequence");
139 
140  timeout.setChild(&sequence);
141  sequence.addChild(&actionA);
142  sequence.addChild(&actionB);
143 
144  EXPECT_EQ(BT::NodeStatus::FAILURE, executeWhileRunning(timeout)) << "should timeout";
145  EXPECT_FALSE(actionA.wasHalted());
146  EXPECT_TRUE(actionB.wasHalted());
147 }
148 
149 TEST(CoroTest, OtherThreadHalt)
150 {
151  BT::NodeConfig node_config_;
152  node_config_.blackboard = BT::Blackboard::create();
153  BT::assignDefaultRemapping<SimpleCoroAction>(node_config_);
154 
155  SimpleCoroAction actionA(milliseconds(200), false, "action_A", node_config_);
156  actionA.executeTick();
157 
158  std::cout << "----- 1 ------ " << std::endl;
159  auto handle = std::async(std::launch::async, [&]() { actionA.halt(); });
160  handle.wait();
161  std::cout << "----- 2 ------ " << std::endl;
162  EXPECT_TRUE(actionA.wasHalted());
163 
164  std::cout << "----- 3------ " << std::endl;
165  handle = std::async(std::launch::async, [&]() { actionA.executeTick(); });
166  handle.wait();
167  std::cout << "----- 4 ------ " << std::endl;
168 }
TEST
TEST(CoroTest, do_action)
Definition: gtest_coroutines.cpp:84
BT
Definition: ex01_wrap_legacy.cpp:29
SimpleCoroAction::SimpleCoroAction
SimpleCoroAction(milliseconds timeout, bool will_fail, const std::string &node_name, const BT::NodeConfig &config)
Definition: gtest_coroutines.cpp:15
SimpleCoroAction::halt
virtual void halt() override
Definition: gtest_coroutines.cpp:23
SimpleCoroAction::will_fail_
bool will_fail_
Definition: gtest_coroutines.cpp:65
BT::CoroActionNode::executeTick
virtual NodeStatus executeTick() override final
The method that should be used to invoke tick() and setStatus();.
Definition: action_node.cpp:94
BT::TreeNode::executeTick
virtual BT::NodeStatus executeTick()
The method that should be used to invoke tick() and setStatus();.
Definition: tree_node.cpp:71
SimpleCoroAction
Definition: gtest_coroutines.cpp:12
Millisecond
std::chrono::milliseconds Millisecond
Definition: gtest_coroutines.cpp:9
BT::TreeNode
Abstract base class for Behavior Tree Nodes.
Definition: tree_node.h:118
SimpleCoroAction::timeout_
std::chrono::milliseconds timeout_
Definition: gtest_coroutines.cpp:68
SimpleCoroAction::setRequiredTime
void setRequiredTime(Millisecond ms)
Definition: gtest_coroutines.cpp:36
timeout_node.h
BT::CoroActionNode::halt
void halt() override
Definition: action_node.cpp:129
BT::NodeConfig::blackboard
Blackboard::Ptr blackboard
Definition: tree_node.h:79
BT::NodeStatus::FAILURE
@ FAILURE
SimpleCoroAction::start_time_
Timepoint start_time_
Definition: gtest_coroutines.cpp:69
behavior_tree.h
SimpleCoroAction::halted_
bool halted_
Definition: gtest_coroutines.cpp:70
BT::Blackboard::create
static Blackboard::Ptr create(Blackboard::Ptr parent={})
Definition: blackboard.h:63
BT::NodeStatus::SUCCESS
@ SUCCESS
BT::NodeStatus::RUNNING
@ RUNNING
BT::DecoratorNode::setChild
void setChild(TreeNode *child)
Definition: decorator_node.cpp:22
BT::SequenceNode
The SequenceNode is used to tick children in an ordered sequence. If any child returns RUNNING,...
Definition: sequence_node.h:34
executeWhileRunning
BT::NodeStatus executeWhileRunning(BT::TreeNode &node)
Definition: gtest_coroutines.cpp:73
SimpleCoroAction::wasHalted
bool wasHalted()
Definition: gtest_coroutines.cpp:31
BT::TimeoutNode
The TimeoutNode will halt() a running child if the latter has been RUNNING longer than a given time....
Definition: timeout_node.h:35
Timepoint
std::chrono::time_point< std::chrono::steady_clock > Timepoint
Definition: gtest_coroutines.cpp:10
BT::NodeConfig
Definition: tree_node.h:73
BT::ControlNode::addChild
void addChild(TreeNode *child)
The method used to add nodes to the children vector.
Definition: control_node.cpp:22
lexy::do_action
constexpr auto do_action(Handler &&handler, State *state, Reader &reader)
Definition: action/base.hpp:221
SimpleCoroAction::tick
virtual BT::NodeStatus tick() override
Method to be implemented by the user.
Definition: gtest_coroutines.cpp:42
BT::NodeStatus
NodeStatus
Definition: basic_types.h:33
BT::CoroActionNode
The CoroActionNode class is an a good candidate for asynchronous actions which need to communicate wi...
Definition: action_node.h:196


behaviortree_cpp_v4
Author(s): Davide Faconti
autogenerated on Fri Jun 28 2024 02:20:07