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