blob: eb863e32428be964fafedbe893b6f81e28361c8b [file] [log] [blame]
Ben Fredricksond69f38b2015-01-28 20:06:15 -08001#include <unistd.h>
2
3#include <memory>
Brian Silvermana2ae62d2015-03-15 15:55:22 -07004#include <thread>
Ben Fredricksond69f38b2015-01-28 20:06:15 -08005
6#include "gtest/gtest.h"
7#include "aos/common/queue.h"
8#include "aos/common/queue_testutils.h"
9#include "aos/common/actions/actor.h"
10#include "aos/common/actions/actions.h"
11#include "aos/common/actions/actions.q.h"
12#include "aos/common/actions/test_action.q.h"
13
14using ::aos::time::Time;
15
16namespace aos {
17namespace common {
18namespace actions {
19namespace testing {
20
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080021class TestActorIndex
22 : public aos::common::actions::ActorBase<actions::TestActionQueueGroup> {
23 public:
24 explicit TestActorIndex(actions::TestActionQueueGroup *s)
25 : aos::common::actions::ActorBase<actions::TestActionQueueGroup>(s) {}
26
27 bool RunAction(const uint32_t &new_index) override {
28 index = new_index;
29 return true;
30 }
31
32 uint32_t index = 0;
33};
34
35::std::unique_ptr<
36 aos::common::actions::TypedAction<actions::TestActionQueueGroup>>
37MakeTestActionIndex(uint32_t index) {
38 return ::std::unique_ptr<
39 aos::common::actions::TypedAction<actions::TestActionQueueGroup>>(
40 new aos::common::actions::TypedAction<actions::TestActionQueueGroup>(
41 &actions::test_action, index));
42}
43
Ben Fredricksond69f38b2015-01-28 20:06:15 -080044class TestActorNOP
45 : public aos::common::actions::ActorBase<actions::TestActionQueueGroup> {
46 public:
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080047 explicit TestActorNOP(actions::TestActionQueueGroup *s)
Ben Fredricksond69f38b2015-01-28 20:06:15 -080048 : actions::ActorBase<actions::TestActionQueueGroup>(s) {}
49
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080050 bool RunAction(const uint32_t &) override { return true; }
Ben Fredricksond69f38b2015-01-28 20:06:15 -080051};
52
53::std::unique_ptr<
54 aos::common::actions::TypedAction<actions::TestActionQueueGroup>>
55MakeTestActionNOP() {
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080056 return MakeTestActionIndex(0);
Ben Fredricksond69f38b2015-01-28 20:06:15 -080057}
58
59class TestActorShouldCancel
60 : public aos::common::actions::ActorBase<actions::TestActionQueueGroup> {
61 public:
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080062 explicit TestActorShouldCancel(actions::TestActionQueueGroup *s)
Ben Fredricksond69f38b2015-01-28 20:06:15 -080063 : aos::common::actions::ActorBase<actions::TestActionQueueGroup>(s) {}
64
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080065 bool RunAction(const uint32_t &) override {
Ben Fredricksond69f38b2015-01-28 20:06:15 -080066 while (!ShouldCancel()) {
67 LOG(FATAL, "NOT CANCELED!!\n");
68 }
Daniel Petti3b1e48f2015-02-15 15:57:53 -080069 return true;
Ben Fredricksond69f38b2015-01-28 20:06:15 -080070 }
71};
72
73::std::unique_ptr<
74 aos::common::actions::TypedAction<actions::TestActionQueueGroup>>
75MakeTestActionShouldCancel() {
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080076 return MakeTestActionIndex(0);
77}
78
79class TestActor2Nop
80 : public aos::common::actions::ActorBase<actions::TestAction2QueueGroup> {
81 public:
82 explicit TestActor2Nop(actions::TestAction2QueueGroup *s)
83 : actions::ActorBase<actions::TestAction2QueueGroup>(s) {}
84
85 bool RunAction(const actions::MyParams &) { return true; }
86};
87
88::std::unique_ptr<
89 aos::common::actions::TypedAction<actions::TestAction2QueueGroup>>
90MakeTestAction2NOP(const actions::MyParams &params) {
Ben Fredricksond69f38b2015-01-28 20:06:15 -080091 return ::std::unique_ptr<
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080092 aos::common::actions::TypedAction<actions::TestAction2QueueGroup>>(
93 new aos::common::actions::TypedAction<actions::TestAction2QueueGroup>(
94 &actions::test_action2, params));
Ben Fredricksond69f38b2015-01-28 20:06:15 -080095}
96
97class ActionTest : public ::testing::Test {
98 protected:
99 ActionTest() {
100 // Flush the robot state queue so we can use clean shared memory for this.
101 // test.
102 actions::test_action.goal.Clear();
103 actions::test_action.status.Clear();
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800104 actions::test_action2.goal.Clear();
105 actions::test_action2.status.Clear();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800106 }
107
108 virtual ~ActionTest() {
109 actions::test_action.goal.Clear();
110 actions::test_action.status.Clear();
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800111 actions::test_action2.goal.Clear();
112 actions::test_action2.status.Clear();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800113 }
114
115 // Bring up and down Core.
116 ::aos::common::testing::GlobalCoreInstance my_core;
117 ::aos::common::actions::ActionQueue action_queue_;
118};
119
120// Tests that the the actions exist in a safe state at startup.
121TEST_F(ActionTest, DoesNothing) {
122 // Tick an empty queue and make sure it was not running.
123 EXPECT_FALSE(action_queue_.Running());
124 action_queue_.Tick();
125 EXPECT_FALSE(action_queue_.Running());
126}
127
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700128// Tests that starting with an old run message in the goal queue actually works.
129// This used to result in the client hanging, waiting for a response to its
130// cancel message.
131TEST_F(ActionTest, StartWithOldGoal) {
132 ASSERT_TRUE(actions::test_action.goal.MakeWithBuilder().run(971).Send());
133
134 TestActorNOP nop_act(&actions::test_action);
135
136 ASSERT_FALSE(actions::test_action.status.FetchLatest());
137 ::std::thread init_thread([&nop_act]() { nop_act.Initialize(); });
138 ::aos::time::SleepFor(::aos::time::Time::InSeconds(0.01));
139 ASSERT_TRUE(actions::test_action.goal.MakeWithBuilder().run(1).Send());
140 init_thread.join();
141 ASSERT_TRUE(actions::test_action.status.FetchLatest());
142 EXPECT_EQ(0u, actions::test_action.status->running);
143 EXPECT_EQ(0u, actions::test_action.status->last_running);
144
145 action_queue_.EnqueueAction(MakeTestActionNOP());
146 nop_act.WaitForActionRequest();
147
148 // We started an action and it should be running.
149 EXPECT_TRUE(action_queue_.Running());
150
151 action_queue_.CancelAllActions();
152 action_queue_.Tick();
153
154 EXPECT_TRUE(action_queue_.Running());
155
156 // Run the action so it can signal completion.
157 nop_act.RunIteration();
158 action_queue_.Tick();
159
160 // Make sure it stopped.
161 EXPECT_FALSE(action_queue_.Running());
162}
163
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800164// Tests that the queues are properly configured for testing. Tests that queues
165// work exactly as used in the tests.
166TEST_F(ActionTest, QueueCheck) {
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800167 actions::TestActionQueueGroup *send_side = &actions::test_action;
168 actions::TestActionQueueGroup *recv_side = &actions::test_action;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800169
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800170 send_side->goal.MakeWithBuilder().run(1).Send();
171
172 EXPECT_TRUE(recv_side->goal.FetchLatest());
173 EXPECT_TRUE(recv_side->goal->run);
174
175 send_side->goal.MakeWithBuilder().run(0).Send();
176
177 EXPECT_TRUE(recv_side->goal.FetchLatest());
178 EXPECT_FALSE(recv_side->goal->run);
179
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800180 send_side->status.MakeWithBuilder().running(5).last_running(6).Send();
181
182 EXPECT_TRUE(recv_side->status.FetchLatest());
183 EXPECT_EQ(5, static_cast<int>(recv_side->status->running));
184 EXPECT_EQ(6, static_cast<int>(recv_side->status->last_running));
185}
186
187// Tests that an action starts and stops.
188TEST_F(ActionTest, ActionQueueWasRunning) {
189 TestActorNOP nop_act(&actions::test_action);
190
191 // Tick an empty queue and make sure it was not running.
192 action_queue_.Tick();
193 EXPECT_FALSE(action_queue_.Running());
194
195 action_queue_.EnqueueAction(MakeTestActionNOP());
196 nop_act.WaitForActionRequest();
197
198 // We started an action and it should be running.
199 EXPECT_TRUE(action_queue_.Running());
200
201 // Tick it and make sure it is still running.
202 action_queue_.Tick();
203 EXPECT_TRUE(action_queue_.Running());
204
205 // Run the action so it can signal completion.
206 nop_act.RunIteration();
207 action_queue_.Tick();
208
209 // Make sure it stopped.
210 EXPECT_FALSE(action_queue_.Running());
211}
212
213// Tests that we can cancel two actions and have them both stop.
214TEST_F(ActionTest, ActionQueueCancelAll) {
215 TestActorNOP nop_act(&actions::test_action);
216
217 // Tick an empty queue and make sure it was not running.
218 action_queue_.Tick();
219 EXPECT_FALSE(action_queue_.Running());
220
221 // Enqueue two actions to test both cancel. We can have an action and a next
222 // action so we want to test that.
223 action_queue_.EnqueueAction(MakeTestActionNOP());
224 action_queue_.EnqueueAction(MakeTestActionNOP());
225 nop_act.WaitForActionRequest();
226 action_queue_.Tick();
227
228 // Check that current and next exist.
229 EXPECT_TRUE(action_queue_.GetCurrentActionState(nullptr, nullptr, nullptr,
230 nullptr, nullptr, nullptr));
231 EXPECT_TRUE(action_queue_.GetNextActionState(nullptr, nullptr, nullptr,
232 nullptr, nullptr, nullptr));
233
234 action_queue_.CancelAllActions();
235 action_queue_.Tick();
236
237 // It should still be running as the actor could not have signaled.
238 EXPECT_TRUE(action_queue_.Running());
239
240 bool sent_started, sent_cancel, interrupted;
241 EXPECT_TRUE(action_queue_.GetCurrentActionState(
242 nullptr, &sent_started, &sent_cancel, &interrupted, nullptr, nullptr));
243 EXPECT_TRUE(sent_started);
244 EXPECT_TRUE(sent_cancel);
245 EXPECT_FALSE(interrupted);
246
247 EXPECT_FALSE(action_queue_.GetNextActionState(nullptr, nullptr, nullptr,
248 nullptr, nullptr, nullptr));
249
250 // Run the action so it can signal completion.
251 nop_act.RunIteration();
252 action_queue_.Tick();
253
254 // Make sure it stopped.
255 EXPECT_FALSE(action_queue_.Running());
256}
257
258// Tests that an action that would block forever stops when canceled.
259TEST_F(ActionTest, ActionQueueCancelOne) {
260 TestActorShouldCancel cancel_act(&actions::test_action);
261
262 // Enqueue blocking action.
263 action_queue_.EnqueueAction(MakeTestActionShouldCancel());
264
265 cancel_act.WaitForActionRequest();
266 action_queue_.Tick();
267 EXPECT_TRUE(action_queue_.Running());
268
269 // Tell action to cancel.
270 action_queue_.CancelCurrentAction();
271 action_queue_.Tick();
272
273 // This will block forever on failure.
274 // TODO(ben): prolly a bad way to fail
275 cancel_act.RunIteration();
276 action_queue_.Tick();
277
278 // It should still be running as the actor could not have signalled.
279 EXPECT_FALSE(action_queue_.Running());
280}
281
282// Tests that an action starts and stops.
283TEST_F(ActionTest, ActionQueueTwoActions) {
284 TestActorNOP nop_act(&actions::test_action);
285
286 // Tick an empty queue and make sure it was not running.
287 action_queue_.Tick();
288 EXPECT_FALSE(action_queue_.Running());
289
290 // Enqueue action to be canceled.
291 action_queue_.EnqueueAction(MakeTestActionNOP());
292 nop_act.WaitForActionRequest();
293 action_queue_.Tick();
294
295 // Should still be running as the actor could not have signalled.
296 EXPECT_TRUE(action_queue_.Running());
297
298 // id for the first time run.
299 uint32_t nop_act_id = 0;
300 // Check the internal state and write down id for later use.
301 bool sent_started, sent_cancel, interrupted;
302 EXPECT_TRUE(action_queue_.GetCurrentActionState(nullptr, &sent_started,
303 &sent_cancel, &interrupted,
304 &nop_act_id, nullptr));
305 EXPECT_TRUE(sent_started);
306 EXPECT_FALSE(sent_cancel);
307 EXPECT_FALSE(interrupted);
308 ASSERT_NE(0u, nop_act_id);
309
310 // Add the next action which should ensure the first stopped.
311 action_queue_.EnqueueAction(MakeTestActionNOP());
312
313 // id for the second run.
314 uint32_t nop_act2_id = 0;
315 // Check the internal state and write down id for later use.
316 EXPECT_TRUE(action_queue_.GetNextActionState(nullptr, &sent_started,
317 &sent_cancel, &interrupted,
318 &nop_act2_id, nullptr));
319 EXPECT_NE(nop_act_id, nop_act2_id);
320 EXPECT_FALSE(sent_started);
321 EXPECT_FALSE(sent_cancel);
322 EXPECT_FALSE(interrupted);
323 ASSERT_NE(0u, nop_act2_id);
324
325 action_queue_.Tick();
326
327 // Run the action so it can signal completion.
328 nop_act.RunIteration();
329 action_queue_.Tick();
330 // Wait for the first id to finish, needed for the correct number of fetches.
331 nop_act.WaitForStop(nop_act_id);
332
333 // Start the next action on the actor side.
334 nop_act.WaitForActionRequest();
335
336 // Check the new action is the right one.
337 uint32_t test_id = 0;
338 EXPECT_TRUE(action_queue_.GetCurrentActionState(
339 nullptr, &sent_started, &sent_cancel, &interrupted, &test_id, nullptr));
340 EXPECT_TRUE(sent_started);
341 EXPECT_FALSE(sent_cancel);
342 EXPECT_FALSE(interrupted);
343 EXPECT_EQ(nop_act2_id, test_id);
344
345 // Make sure it is still going.
346 EXPECT_TRUE(action_queue_.Running());
347
348 // Run the next action so it can accomplish signal completion.
349 nop_act.RunIteration();
350 action_queue_.Tick();
351 nop_act.WaitForStop(nop_act_id);
352
353 // Make sure it stopped.
354 EXPECT_FALSE(action_queue_.Running());
355}
356
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800357// Tests that we do get an index with our goal
358TEST_F(ActionTest, ActionIndex) {
359 TestActorIndex idx_act(&actions::test_action);
360
361 // Tick an empty queue and make sure it was not running.
362 action_queue_.Tick();
363 EXPECT_FALSE(action_queue_.Running());
364
365 // Enqueue action to post index.
366 action_queue_.EnqueueAction(MakeTestActionIndex(5));
367 EXPECT_TRUE(actions::test_action.goal.FetchLatest());
368 EXPECT_EQ(5u, actions::test_action.goal->params);
369 EXPECT_EQ(0u, idx_act.index);
370
371 idx_act.WaitForActionRequest();
372 action_queue_.Tick();
373
374 // Check the new action is the right one.
375 uint32_t test_id = 0;
376 EXPECT_TRUE(action_queue_.GetCurrentActionState(nullptr, nullptr, nullptr,
377 nullptr, &test_id, nullptr));
378
379 // Run the next action so it can accomplish signal completion.
380 idx_act.RunIteration();
381 action_queue_.Tick();
382 idx_act.WaitForStop(test_id);
383 EXPECT_EQ(5u, idx_act.index);
384
385 // Enqueue action to post index.
386 action_queue_.EnqueueAction(MakeTestActionIndex(3));
387 EXPECT_TRUE(actions::test_action.goal.FetchLatest());
388 EXPECT_EQ(3u, actions::test_action.goal->params);
389
390 // Run the next action so it can accomplish signal completion.
391 idx_act.RunIteration();
392 action_queue_.Tick();
393 idx_act.WaitForStop(test_id);
394 EXPECT_EQ(3u, idx_act.index);
395}
396
397// Tests that an action with a structure params works.
398TEST_F(ActionTest, StructParamType) {
399 TestActor2Nop nop_act(&actions::test_action2);
400
401 // Tick an empty queue and make sure it was not running.
402 action_queue_.Tick();
403 EXPECT_FALSE(action_queue_.Running());
404
405 actions::MyParams p;
406 p.param1 = 5.0;
407 p.param2 = 7;
408
409 action_queue_.EnqueueAction(MakeTestAction2NOP(p));
410 nop_act.WaitForActionRequest();
411
412 // We started an action and it should be running.
413 EXPECT_TRUE(action_queue_.Running());
414
415 // Tick it and make sure it is still running.
416 action_queue_.Tick();
417 EXPECT_TRUE(action_queue_.Running());
418
419 // Run the action so it can signal completion.
420 nop_act.RunIteration();
421 action_queue_.Tick();
422
423 // Make sure it stopped.
424 EXPECT_FALSE(action_queue_.Running());
425}
426
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800427} // namespace testing.
428} // namespace actions.
429} // namespace common.
430} // namespace aos.