blob: df204bc634dfda56b442de93f94a75b7803a0fda [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
20class TestActorNOP
21 : public aos::common::actions::ActorBase<actions::TestActionQueueGroup> {
22 public:
23 explicit TestActorNOP(actions::TestActionQueueGroup* s)
24 : actions::ActorBase<actions::TestActionQueueGroup>(s) {}
25
26 void RunAction() { return; }
27};
28
29::std::unique_ptr<
30 aos::common::actions::TypedAction<actions::TestActionQueueGroup>>
31MakeTestActionNOP() {
32 return ::std::unique_ptr<
33 aos::common::actions::TypedAction<actions::TestActionQueueGroup>>(
34 new aos::common::actions::TypedAction<actions::TestActionQueueGroup>(
35 &actions::test_action));
36}
37
38class TestActorShouldCancel
39 : public aos::common::actions::ActorBase<actions::TestActionQueueGroup> {
40 public:
41 explicit TestActorShouldCancel(actions::TestActionQueueGroup* s)
42 : aos::common::actions::ActorBase<actions::TestActionQueueGroup>(s) {}
43
44 void RunAction() {
45 while (!ShouldCancel()) {
46 LOG(FATAL, "NOT CANCELED!!\n");
47 }
48 return;
49 }
50};
51
52::std::unique_ptr<
53 aos::common::actions::TypedAction<actions::TestActionQueueGroup>>
54MakeTestActionShouldCancel() {
55 return ::std::unique_ptr<
56 aos::common::actions::TypedAction<actions::TestActionQueueGroup>>(
57 new aos::common::actions::TypedAction<actions::TestActionQueueGroup>(
58 &actions::test_action));
59}
60
61class ActionTest : public ::testing::Test {
62 protected:
63 ActionTest() {
64 // Flush the robot state queue so we can use clean shared memory for this.
65 // test.
66 actions::test_action.goal.Clear();
67 actions::test_action.status.Clear();
68 }
69
70 virtual ~ActionTest() {
71 actions::test_action.goal.Clear();
72 actions::test_action.status.Clear();
73 }
74
75 // Bring up and down Core.
76 ::aos::common::testing::GlobalCoreInstance my_core;
77 ::aos::common::actions::ActionQueue action_queue_;
78};
79
80// Tests that the the actions exist in a safe state at startup.
81TEST_F(ActionTest, DoesNothing) {
82 // Tick an empty queue and make sure it was not running.
83 EXPECT_FALSE(action_queue_.Running());
84 action_queue_.Tick();
85 EXPECT_FALSE(action_queue_.Running());
86}
87
88// Tests that the queues are properly configured for testing. Tests that queues
89// work exactly as used in the tests.
90TEST_F(ActionTest, QueueCheck) {
91 actions::TestActionQueueGroup* send_side = &actions::test_action;
92 actions::TestActionQueueGroup* recv_side = &actions::test_action;
93
94 send_side->goal.MakeMessage();
95 send_side->goal.MakeWithBuilder().run(1).Send();
96
97 EXPECT_TRUE(recv_side->goal.FetchLatest());
98 EXPECT_TRUE(recv_side->goal->run);
99
100 send_side->goal.MakeWithBuilder().run(0).Send();
101
102 EXPECT_TRUE(recv_side->goal.FetchLatest());
103 EXPECT_FALSE(recv_side->goal->run);
104
105 send_side->status.MakeMessage();
106 send_side->status.MakeWithBuilder().running(5).last_running(6).Send();
107
108 EXPECT_TRUE(recv_side->status.FetchLatest());
109 EXPECT_EQ(5, static_cast<int>(recv_side->status->running));
110 EXPECT_EQ(6, static_cast<int>(recv_side->status->last_running));
111}
112
113// Tests that an action starts and stops.
114TEST_F(ActionTest, ActionQueueWasRunning) {
115 TestActorNOP nop_act(&actions::test_action);
116
117 // Tick an empty queue and make sure it was not running.
118 action_queue_.Tick();
119 EXPECT_FALSE(action_queue_.Running());
120
121 action_queue_.EnqueueAction(MakeTestActionNOP());
122 nop_act.WaitForActionRequest();
123
124 // We started an action and it should be running.
125 EXPECT_TRUE(action_queue_.Running());
126
127 // Tick it and make sure it is still running.
128 action_queue_.Tick();
129 EXPECT_TRUE(action_queue_.Running());
130
131 // Run the action so it can signal completion.
132 nop_act.RunIteration();
133 action_queue_.Tick();
134
135 // Make sure it stopped.
136 EXPECT_FALSE(action_queue_.Running());
137}
138
139// Tests that we can cancel two actions and have them both stop.
140TEST_F(ActionTest, ActionQueueCancelAll) {
141 TestActorNOP nop_act(&actions::test_action);
142
143 // Tick an empty queue and make sure it was not running.
144 action_queue_.Tick();
145 EXPECT_FALSE(action_queue_.Running());
146
147 // Enqueue two actions to test both cancel. We can have an action and a next
148 // action so we want to test that.
149 action_queue_.EnqueueAction(MakeTestActionNOP());
150 action_queue_.EnqueueAction(MakeTestActionNOP());
151 nop_act.WaitForActionRequest();
152 action_queue_.Tick();
153
154 // Check that current and next exist.
155 EXPECT_TRUE(action_queue_.GetCurrentActionState(nullptr, nullptr, nullptr,
156 nullptr, nullptr, nullptr));
157 EXPECT_TRUE(action_queue_.GetNextActionState(nullptr, nullptr, nullptr,
158 nullptr, nullptr, nullptr));
159
160 action_queue_.CancelAllActions();
161 action_queue_.Tick();
162
163 // It should still be running as the actor could not have signaled.
164 EXPECT_TRUE(action_queue_.Running());
165
166 bool sent_started, sent_cancel, interrupted;
167 EXPECT_TRUE(action_queue_.GetCurrentActionState(
168 nullptr, &sent_started, &sent_cancel, &interrupted, nullptr, nullptr));
169 EXPECT_TRUE(sent_started);
170 EXPECT_TRUE(sent_cancel);
171 EXPECT_FALSE(interrupted);
172
173 EXPECT_FALSE(action_queue_.GetNextActionState(nullptr, nullptr, nullptr,
174 nullptr, nullptr, nullptr));
175
176 // Run the action so it can signal completion.
177 nop_act.RunIteration();
178 action_queue_.Tick();
179
180 // Make sure it stopped.
181 EXPECT_FALSE(action_queue_.Running());
182}
183
184// Tests that an action that would block forever stops when canceled.
185TEST_F(ActionTest, ActionQueueCancelOne) {
186 TestActorShouldCancel cancel_act(&actions::test_action);
187
188 // Enqueue blocking action.
189 action_queue_.EnqueueAction(MakeTestActionShouldCancel());
190
191 cancel_act.WaitForActionRequest();
192 action_queue_.Tick();
193 EXPECT_TRUE(action_queue_.Running());
194
195 // Tell action to cancel.
196 action_queue_.CancelCurrentAction();
197 action_queue_.Tick();
198
199 // This will block forever on failure.
200 // TODO(ben): prolly a bad way to fail
201 cancel_act.RunIteration();
202 action_queue_.Tick();
203
204 // It should still be running as the actor could not have signalled.
205 EXPECT_FALSE(action_queue_.Running());
206}
207
208// Tests that an action starts and stops.
209TEST_F(ActionTest, ActionQueueTwoActions) {
210 TestActorNOP nop_act(&actions::test_action);
211
212 // Tick an empty queue and make sure it was not running.
213 action_queue_.Tick();
214 EXPECT_FALSE(action_queue_.Running());
215
216 // Enqueue action to be canceled.
217 action_queue_.EnqueueAction(MakeTestActionNOP());
218 nop_act.WaitForActionRequest();
219 action_queue_.Tick();
220
221 // Should still be running as the actor could not have signalled.
222 EXPECT_TRUE(action_queue_.Running());
223
224 // id for the first time run.
225 uint32_t nop_act_id = 0;
226 // Check the internal state and write down id for later use.
227 bool sent_started, sent_cancel, interrupted;
228 EXPECT_TRUE(action_queue_.GetCurrentActionState(nullptr, &sent_started,
229 &sent_cancel, &interrupted,
230 &nop_act_id, nullptr));
231 EXPECT_TRUE(sent_started);
232 EXPECT_FALSE(sent_cancel);
233 EXPECT_FALSE(interrupted);
234 ASSERT_NE(0u, nop_act_id);
235
236 // Add the next action which should ensure the first stopped.
237 action_queue_.EnqueueAction(MakeTestActionNOP());
238
239 // id for the second run.
240 uint32_t nop_act2_id = 0;
241 // Check the internal state and write down id for later use.
242 EXPECT_TRUE(action_queue_.GetNextActionState(nullptr, &sent_started,
243 &sent_cancel, &interrupted,
244 &nop_act2_id, nullptr));
245 EXPECT_NE(nop_act_id, nop_act2_id);
246 EXPECT_FALSE(sent_started);
247 EXPECT_FALSE(sent_cancel);
248 EXPECT_FALSE(interrupted);
249 ASSERT_NE(0u, nop_act2_id);
250
251 action_queue_.Tick();
252
253 // Run the action so it can signal completion.
254 nop_act.RunIteration();
255 action_queue_.Tick();
256 // Wait for the first id to finish, needed for the correct number of fetches.
257 nop_act.WaitForStop(nop_act_id);
258
259 // Start the next action on the actor side.
260 nop_act.WaitForActionRequest();
261
262 // Check the new action is the right one.
263 uint32_t test_id = 0;
264 EXPECT_TRUE(action_queue_.GetCurrentActionState(
265 nullptr, &sent_started, &sent_cancel, &interrupted, &test_id, nullptr));
266 EXPECT_TRUE(sent_started);
267 EXPECT_FALSE(sent_cancel);
268 EXPECT_FALSE(interrupted);
269 EXPECT_EQ(nop_act2_id, test_id);
270
271 // Make sure it is still going.
272 EXPECT_TRUE(action_queue_.Running());
273
274 // Run the next action so it can accomplish signal completion.
275 nop_act.RunIteration();
276 action_queue_.Tick();
277 nop_act.WaitForStop(nop_act_id);
278
279 // Make sure it stopped.
280 EXPECT_FALSE(action_queue_.Running());
281}
282
283} // namespace testing.
284} // namespace actions.
285} // namespace common.
286} // namespace aos.