test_goal_queueing.cpp
Go to the documentation of this file.
1 #include <gtest/gtest.h>
2 #include <ros/ros.h>
5 #include <move_base_msgs/MoveBaseAction.h>
7 #include <queue>
8 #include <memory>
9 #include <mutex>
10 #include <condition_variable>
11 
12 class GoalQueueSuite : public ::testing::Test {
13 protected:
14  virtual void SetUp() {
15  resetFlags();
16  ros::NodeHandle actionNh("");
17  qserv.reset(new actionlib::QueuedActionServer<move_base_msgs::MoveBaseAction> (actionNh, "queue_server", boost::bind(&GoalQueueSuite::executeCallback, this, _1)));
18  cli.reset(new actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction> ("queue_server", true)); // true -> don't need ros::spin()
19 
20  qserv->start();
21  }
22 
23  virtual void TearDown() {
24  // Kill the executeCallback if it is running
25  // New Scope so that lock_guard destructs and unlocks
26  {
27  std::lock_guard<std::mutex> lk1(execute_lock);
28  finish_executing = true;
29  execute_cv.notify_one(); // Releases one waiting thread
30  }
31  qserv->shutdown();
32  }
33 
34  void executeCallback(const move_base_msgs::MoveBaseGoalConstPtr &msg) {
35  resetFlags();
36  got_goal = true;
37  received_goal = msg;
38  while (true) {
39  goal_preempted = qserv->isPreemptRequested() ? true : false;
40  next_goal_available = qserv->isNewGoalAvailable() ? true : false;
41 
42  // Test fixture can continue
43  execution = true;
44  sleep_cv.notify_one();
45  // Wait until signalled to end
46  std::unique_lock<std::mutex> lk(execute_lock);
47  execute_cv.wait(lk,
48  //lambda function to wait on our bool variables
49  [this](){return finish_executing || resume_executing;} // blocks only if lambda returns false
50  );
51  execution = false;
52  // We were requested to stop, so we stop
53  if (finish_executing) {
54  break;
55  }
56  }
57 
58  // Signal that we are done here
59  std::lock_guard<std::mutex> lk(execute_done_lock);
60  execute_done = true;
61  execute_done_cv.notify_all();
62  }
63 
64  // Helper function to signal the executeCallback to end
65  void finishExecuting() {
66  // New Scope so that lock_guard destructs and unlocks
67  {
68  std::lock_guard<std::mutex> lk1(execute_lock);
69  finish_executing = true;
70  execute_cv.notify_one(); //unlocks lambda waiting function in ExecuteCallback
71  }
72 
73  // Wait for execute callback to actually finish
74  std::unique_lock<std::mutex> lk2(execute_done_lock);
75  execute_done_cv.wait(lk2, [this]() {return execute_done;}); // at the end of ExecuteCallback
76  }
77 
78  // Helper function to signal the executeCallback to resume
79  // This is useful for seeing if the callback code sees a preempt
80  void resumeExecuting() {
81  std::lock_guard<std::mutex> lk(execute_lock);
82  resume_executing = true;
83  execute_cv.notify_one();
84  }
85 
86  // Helper function to wait to for flags to update in ExecuteCallback
87  void sleepExecuting() {
88  std::unique_lock<std::mutex> slk(sleep_lock);
89  sleep_cv.wait(slk,
90  [this](){return execution;}
91  );
92  }
93 
94  // Helper function to wait for execution variable to update
95  void updateExecuting() {
96  std::unique_lock<std::mutex> ulk(update_lock);
97  sleep_cv.wait(ulk,
98  [this](){return !execution;}
99  );
100  }
101 
102  void resetFlags() {
103  got_goal = false;
104  goal_preempted = false;
105  next_goal_available = false;
106  received_goal = nullptr;
107 
108  // Signal flags
109  execution = false;
110  finish_executing = false;
111  resume_executing = false;
112  execute_done = false;
113  }
114 
115  // Flags for assertions
116  bool got_goal;
119  move_base_msgs::MoveBaseGoalConstPtr received_goal;
120 
121  // Signaling variables
122  bool execution;
126  std::mutex sleep_lock;
127  std::mutex update_lock;
128  std::mutex execute_lock;
129  std::mutex execute_done_lock;
130  std::condition_variable sleep_cv;
131  std::condition_variable execute_cv;
132  std::condition_variable execute_done_cv;
133 
134  std::unique_ptr<actionlib::QueuedActionServer<move_base_msgs::MoveBaseAction>> qserv;
135  std::unique_ptr<actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction>> cli;
136 };
137 
138 
139 TEST_F(GoalQueueSuite, addGoalWhileExecuting) {
140  move_base_msgs::MoveBaseGoal goal;
141 
142  // First goal
143  goal.target_pose.pose.position.x = 3.0;
144  cli->sendGoal(goal);
145  ros::spinOnce();
146  sleepExecuting();
147  EXPECT_TRUE(got_goal);
148  EXPECT_FALSE(goal_preempted);
149  EXPECT_FALSE(next_goal_available);
150  EXPECT_EQ(3.0, received_goal->target_pose.pose.position.x);
151 
152  // Second goal
153  goal.target_pose.pose.position.x = 7.0;
154  cli->sendGoal(goal);
155  ros::spinOnce();
156 
157  resumeExecuting();
158  updateExecuting();
159  sleepExecuting();
160  EXPECT_TRUE(next_goal_available);
161 
162  // Cancel the last goal sent
163  cli->cancelGoal();
164  ros::Duration(1.0).sleep();
165  ros::spinOnce();
166  EXPECT_EQ(3.0, received_goal->target_pose.pose.position.x); // Making sure we are in the first goal thread
167  finishExecuting(); // Finish 1st goal
168  ros::Duration(0.5).sleep();
169 
170  EXPECT_TRUE(goal_preempted);
171  finishExecuting(); // Finish 2nd (canceled) goal
172 
173  // New goal
174  goal.target_pose.pose.position.x = 13.0;
175  cli->sendGoal(goal);
176  ros::spinOnce();
177  sleepExecuting();
178  EXPECT_TRUE(got_goal);
179  EXPECT_FALSE(goal_preempted);
180  EXPECT_EQ(13.0, received_goal->target_pose.pose.position.x);
181  finishExecuting();
182 }
183 
184 TEST_F(GoalQueueSuite, stopAfterCancel) {
185  move_base_msgs::MoveBaseGoal goal;
186 
187  // One goal -> Cancel request -> Stop
188  goal.target_pose.pose.position.x = 3.0;
189  cli->sendGoal(goal);
190  ros::spinOnce();
191  sleepExecuting();
192  EXPECT_TRUE(got_goal);
193  EXPECT_EQ(3.0, received_goal->target_pose.pose.position.x);
194 
195  cli->cancelGoal();
196  ros::Duration(1.0).sleep();
197  ros::spinOnce();
198  resumeExecuting();
199  updateExecuting();
200  sleepExecuting();
201  ros::Duration(0.5).sleep();
202  // TODO: Investigate why line 203 is failling - succeed only 7/10 times
203 // EXPECT_TRUE(goal_preempted);
204  finishExecuting();
205  ros::Duration(0.5).sleep();
206  EXPECT_FALSE(qserv->isActive());
207 }
208 
209 TEST_F(GoalQueueSuite, continueAfterCancel) {
210  move_base_msgs::MoveBaseGoal goal;
211 
212  // Two goals -> Cancel current goal -> Start executing the second
213  goal.target_pose.pose.position.x = 3.0;
214  cli->sendGoal(goal);
215  ros::spinOnce();
216  sleepExecuting();
217  EXPECT_TRUE(got_goal);
218  EXPECT_EQ(3.0, received_goal->target_pose.pose.position.x);
219 
220  // Cancelling the first goal - PITFALL
221  cli->cancelGoal();
222  ros::Duration(1.0).sleep();
223  ros::spinOnce();
224  resumeExecuting();
225  updateExecuting();
226  sleepExecuting();
227  ASSERT_TRUE(goal_preempted);
228  finishExecuting();
229 
230  // "Second" goal
231  goal.target_pose.pose.position.x = 7.0;
232  cli->sendGoal(goal);
233  ros::spinOnce();
234  sleepExecuting();
235  EXPECT_TRUE(got_goal);
236  ASSERT_EQ(7.0, received_goal->target_pose.pose.position.x);
237  finishExecuting();
238 }
239 
240 TEST_F(GoalQueueSuite, goalCancelling) {
241  move_base_msgs::MoveBaseGoal goal;
242  goal.target_pose.pose.position.x = 3.0;
243 
244  // Two goals -> Cancel current goal -> Start executing the second
245  cli->sendGoal(goal);
246  ros::spinOnce();
247  sleepExecuting();
248  ASSERT_TRUE(got_goal);
249  ASSERT_EQ(3.0, received_goal->target_pose.pose.position.x);
250 
251  // Second goal
252  goal.target_pose.pose.position.x = 7.0;
253  cli->sendGoal(goal);
254  ros::spinOnce();
255 
256  resumeExecuting();
257  updateExecuting();
258  sleepExecuting();
259  ASSERT_EQ(3.0, received_goal->target_pose.pose.position.x);
260  EXPECT_TRUE(next_goal_available);
261 
262  // Cancelling the second goal
263  cli->cancelGoal();
264  ros::Duration(1.0).sleep();
265  ros::spinOnce();
266 
267  finishExecuting(); // finish 1st goal
268  ros::Duration(0.5).sleep(); // Needs to wait so the executeCallback can finish
269 
270  EXPECT_TRUE(goal_preempted);
271  finishExecuting(); // Finish the cancelled goal
272 }
273 
274 // Two more TEST_F missing
275 
276 int main(int argc, char **argv) {
277  ros::init(argc, argv, "goal_queueing_test");
278  testing::InitGoogleTest(&argc, argv);
279  return RUN_ALL_TESTS();
280 }
std::condition_variable execute_cv
int main(int argc, char **argv)
std::mutex execute_done_lock
TEST_F(GoalQueueSuite, addGoalWhileExecuting)
bool sleep() const
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
std::unique_ptr< actionlib::QueuedActionServer< move_base_msgs::MoveBaseAction > > qserv
virtual void SetUp()
std::unique_ptr< actionlib::SimpleActionClient< move_base_msgs::MoveBaseAction > > cli
std::condition_variable sleep_cv
void executeCallback(const move_base_msgs::MoveBaseGoalConstPtr &msg)
std::condition_variable execute_done_cv
ROSCPP_DECL void spinOnce()
virtual void TearDown()
move_base_msgs::MoveBaseGoalConstPtr received_goal


move_basic
Author(s): Jim Vaughan
autogenerated on Fri Mar 26 2021 02:46:58