blob: 565bf11aa355c36b2703fdf72caaac36f90760ad [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>
Austin Schuhf2a50ba2016-12-24 16:16:26 -08005#include <chrono>
Ben Fredricksond69f38b2015-01-28 20:06:15 -08006
7#include "gtest/gtest.h"
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -05008
John Park33858a32018-09-28 23:05:48 -07009#include "aos/actions/actions.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070010#include "aos/actions/actions_generated.h"
Austin Schuh1bf8a212019-05-26 22:13:14 -070011#include "aos/actions/actor.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070012#include "aos/actions/test_action_generated.h"
13#include "aos/events/simulated_event_loop.h"
Ben Fredricksond69f38b2015-01-28 20:06:15 -080014
Ben Fredricksond69f38b2015-01-28 20:06:15 -080015namespace aos {
16namespace common {
17namespace actions {
18namespace testing {
19
Austin Schuhf2a50ba2016-12-24 16:16:26 -080020namespace chrono = ::std::chrono;
21
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080022class TestActorIndex
Alex Perrycb7da4b2019-08-28 19:35:56 -070023 : public aos::common::actions::ActorBase<actions::TestActionGoal> {
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080024 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070025 typedef TypedActionFactory<actions::TestActionGoal> Factory;
Austin Schuh1bf8a212019-05-26 22:13:14 -070026
27 explicit TestActorIndex(::aos::EventLoop *event_loop)
Alex Perrycb7da4b2019-08-28 19:35:56 -070028 : aos::common::actions::ActorBase<actions::TestActionGoal>(
29 event_loop, "/test_action") {}
Austin Schuh1bf8a212019-05-26 22:13:14 -070030
31 static Factory MakeFactory(::aos::EventLoop *event_loop) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070032 return Factory(event_loop, "/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -070033 }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080034
Alex Perrycb7da4b2019-08-28 19:35:56 -070035 bool RunAction(const UInt *new_index) override {
36 VLOG(1) << "New index " << FlatbufferToJson(new_index);
37 index = new_index->val();
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080038 return true;
39 }
40
41 uint32_t index = 0;
42};
43
Ben Fredricksond69f38b2015-01-28 20:06:15 -080044class TestActorNOP
Alex Perrycb7da4b2019-08-28 19:35:56 -070045 : public aos::common::actions::ActorBase<actions::TestActionGoal> {
Ben Fredricksond69f38b2015-01-28 20:06:15 -080046 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070047 typedef TypedActionFactory<actions::TestActionGoal> Factory;
Austin Schuh1bf8a212019-05-26 22:13:14 -070048
49 explicit TestActorNOP(::aos::EventLoop *event_loop)
Alex Perrycb7da4b2019-08-28 19:35:56 -070050 : actions::ActorBase<actions::TestActionGoal>(
51 event_loop, "/test_action") {}
Austin Schuh1bf8a212019-05-26 22:13:14 -070052
53 static Factory MakeFactory(::aos::EventLoop *event_loop) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070054 return Factory(event_loop, "/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -070055 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -080056
Alex Perrycb7da4b2019-08-28 19:35:56 -070057 bool RunAction(const UInt *) override { return true; }
Ben Fredricksond69f38b2015-01-28 20:06:15 -080058};
59
Ben Fredricksond69f38b2015-01-28 20:06:15 -080060class TestActorShouldCancel
Alex Perrycb7da4b2019-08-28 19:35:56 -070061 : public aos::common::actions::ActorBase<actions::TestActionGoal> {
Ben Fredricksond69f38b2015-01-28 20:06:15 -080062 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070063 typedef TypedActionFactory<actions::TestActionGoal> Factory;
Austin Schuh1bf8a212019-05-26 22:13:14 -070064
65 explicit TestActorShouldCancel(::aos::EventLoop *event_loop)
Alex Perrycb7da4b2019-08-28 19:35:56 -070066 : aos::common::actions::ActorBase<actions::TestActionGoal>(
67 event_loop, "/test_action") {}
Austin Schuh1bf8a212019-05-26 22:13:14 -070068
69 static Factory MakeFactory(::aos::EventLoop *event_loop) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070070 return Factory(event_loop, "/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -070071 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -080072
Alex Perrycb7da4b2019-08-28 19:35:56 -070073 bool RunAction(const UInt *) override {
Ben Fredricksond69f38b2015-01-28 20:06:15 -080074 while (!ShouldCancel()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070075 AOS_LOG(FATAL, "NOT CANCELED!!\n");
Ben Fredricksond69f38b2015-01-28 20:06:15 -080076 }
Daniel Petti3b1e48f2015-02-15 15:57:53 -080077 return true;
Ben Fredricksond69f38b2015-01-28 20:06:15 -080078 }
79};
80
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080081class TestActor2Nop
Alex Perrycb7da4b2019-08-28 19:35:56 -070082 : public aos::common::actions::ActorBase<actions::TestAction2Goal> {
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080083 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070084 typedef TypedActionFactory<actions::TestAction2Goal> Factory;
Austin Schuh1bf8a212019-05-26 22:13:14 -070085
86 explicit TestActor2Nop(::aos::EventLoop *event_loop)
Alex Perrycb7da4b2019-08-28 19:35:56 -070087 : actions::ActorBase<actions::TestAction2Goal>(
88 event_loop, "/test_action2") {}
Austin Schuh1bf8a212019-05-26 22:13:14 -070089
90 static Factory MakeFactory(::aos::EventLoop *event_loop) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070091 return Factory(event_loop, "/test_action2");
Austin Schuh1bf8a212019-05-26 22:13:14 -070092 }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080093
Alex Perrycb7da4b2019-08-28 19:35:56 -070094 bool RunAction(const actions::MyParams *) { return true; }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080095};
96
Ben Fredricksond69f38b2015-01-28 20:06:15 -080097class ActionTest : public ::testing::Test {
98 protected:
Austin Schuh1bf8a212019-05-26 22:13:14 -070099 ActionTest()
Alex Perrycb7da4b2019-08-28 19:35:56 -0700100 : configuration_(
101 configuration::ReadConfig("aos/actions/action_test_config.json")),
102 event_loop_factory_(&configuration_.message()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800103 actor1_event_loop_(event_loop_factory_.MakeEventLoop("actor1")),
104 actor2_event_loop_(event_loop_factory_.MakeEventLoop("actor2")),
Brian Silverman13065ed2020-12-16 15:15:27 -0800105 test_event_loop_(event_loop_factory_.MakeEventLoop("test")) {}
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800106
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800107 void RunAt(monotonic_clock::time_point exec_time, std::function<void()> fn) {
108 TimerHandler *timer = test_event_loop_->AddTimer(fn);
109 test_event_loop_->OnRun([timer, exec_time]() { timer->Setup(exec_time); });
110 }
111
Alex Perrycb7da4b2019-08-28 19:35:56 -0700112 FlatbufferDetachedBuffer<Configuration> configuration_;
113
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800114 // Bring up and down Core.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700115 ::aos::SimulatedEventLoopFactory event_loop_factory_;
116
117 ::std::unique_ptr<::aos::EventLoop> actor1_event_loop_;
118 ::std::unique_ptr<::aos::EventLoop> actor2_event_loop_;
119 ::std::unique_ptr<::aos::EventLoop> test_event_loop_;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800120};
121
122// Tests that the the actions exist in a safe state at startup.
123TEST_F(ActionTest, DoesNothing) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700124 ActionQueue action_queue;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800125 // Tick an empty queue and make sure it was not running.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700126 EXPECT_FALSE(action_queue.Running());
127 action_queue.Tick();
128 EXPECT_FALSE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800129}
130
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700131// Tests that starting with an old run message in the goal queue actually works.
132// This used to result in the client hanging, waiting for a response to its
133// cancel message.
134TEST_F(ActionTest, StartWithOldGoal) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700135 ::std::unique_ptr<::aos::EventLoop> test2_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800136 event_loop_factory_.MakeEventLoop("test2");
Alex Perrycb7da4b2019-08-28 19:35:56 -0700137 ::aos::Sender<TestActionGoal> goal_sender =
138 test2_event_loop->MakeSender<TestActionGoal>("/test_action");
139 ::aos::Fetcher<Status> status_fetcher =
140 test2_event_loop->MakeFetcher<Status>("/test_action");
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700141
Austin Schuh1bf8a212019-05-26 22:13:14 -0700142 TestActorIndex::Factory nop_actor_factory =
143 TestActorNOP::MakeFactory(test_event_loop_.get());
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700144
Austin Schuh1bf8a212019-05-26 22:13:14 -0700145 ActionQueue action_queue;
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700146
Austin Schuh1bf8a212019-05-26 22:13:14 -0700147 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700148 ::aos::Sender<TestActionGoal>::Builder builder =
149 goal_sender.MakeBuilder();
150
151 TestActionGoal::Builder goal_builder =
152 builder.MakeBuilder<TestActionGoal>();
153
154 goal_builder.add_run(971);
155 ASSERT_TRUE(builder.Send(goal_builder.Finish()));
Austin Schuh1bf8a212019-05-26 22:13:14 -0700156 }
157
158 TestActorNOP nop_act(actor1_event_loop_.get());
159
160 ASSERT_FALSE(status_fetcher.Fetch());
161
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800162 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
163 ASSERT_TRUE(status_fetcher.Fetch());
164 EXPECT_EQ(0u, status_fetcher->running());
165 EXPECT_EQ(0u, status_fetcher->last_running());
Austin Schuh1bf8a212019-05-26 22:13:14 -0700166
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800167 {
168 UIntT uint;
169 uint.val = 0;
170 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
171 }
Austin Schuh1bf8a212019-05-26 22:13:14 -0700172
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800173 // We started an action and it should be running.
174 EXPECT_TRUE(action_queue.Running());
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700175
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800176 action_queue.CancelAllActions();
177 action_queue.Tick();
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700178
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800179 EXPECT_TRUE(action_queue.Running());
180 });
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700181
182 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800183 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
184 action_queue.Tick();
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700185
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800186 // Make sure it stopped.
187 EXPECT_FALSE(action_queue.Running());
188 });
189
190 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800191}
192
193// Tests that an action starts and stops.
194TEST_F(ActionTest, ActionQueueWasRunning) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700195 TestActorNOP nop_act(actor1_event_loop_.get());
196
197 TestActorIndex::Factory nop_actor_factory =
198 TestActorNOP::MakeFactory(test_event_loop_.get());
199
200 ActionQueue action_queue;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800201
202 // Tick an empty queue and make sure it was not running.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800203 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
204 action_queue.Tick();
205 EXPECT_FALSE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800206
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800207 {
208 UIntT uint;
209 uint.val = 0;
210 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
211 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800212
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800213 // We started an action and it should be running.
214 EXPECT_TRUE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800215
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800216 // Tick it and make sure it is still running.
217 action_queue.Tick();
218 EXPECT_TRUE(action_queue.Running());
219 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800220
221 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800222 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
223 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800224
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800225 // Make sure it stopped.
226 EXPECT_FALSE(action_queue.Running());
227 });
228
229 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800230}
231
232// Tests that we can cancel two actions and have them both stop.
233TEST_F(ActionTest, ActionQueueCancelAll) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700234 TestActorNOP nop_act(actor1_event_loop_.get());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800235
Austin Schuh1bf8a212019-05-26 22:13:14 -0700236 TestActorIndex::Factory nop_actor_factory =
237 TestActorNOP::MakeFactory(test_event_loop_.get());
238
239 ActionQueue action_queue;
240
241 // Let the actor and action queue start up and confirm nothing is running.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800242 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
243 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700244
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800245 EXPECT_FALSE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800246
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800247 // Enqueue two actions to test both cancel. We can have an action and a next
248 // action so we want to test that.
249 {
250 UIntT uint;
251 uint.val = 0;
252 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
253 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
254 }
Austin Schuh1bf8a212019-05-26 22:13:14 -0700255
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800256 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800257
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800258 // Check that current and next exist.
259 EXPECT_TRUE(action_queue.GetCurrentActionState(nullptr, nullptr, nullptr,
260 nullptr, nullptr, nullptr));
261 EXPECT_TRUE(action_queue.GetNextActionState(nullptr, nullptr, nullptr,
262 nullptr, nullptr, nullptr));
263
264 action_queue.CancelAllActions();
265 action_queue.Tick();
266
267 // It should still be running as the actor could not have signaled.
268 EXPECT_TRUE(action_queue.Running());
269
270 bool sent_started, sent_cancel, interrupted;
271 EXPECT_TRUE(action_queue.GetCurrentActionState(
272 nullptr, &sent_started, &sent_cancel, &interrupted, nullptr, nullptr));
273 EXPECT_TRUE(sent_started);
274 EXPECT_TRUE(sent_cancel);
275 EXPECT_FALSE(interrupted);
276
277 EXPECT_FALSE(action_queue.GetNextActionState(nullptr, nullptr, nullptr,
Austin Schuh1bf8a212019-05-26 22:13:14 -0700278 nullptr, nullptr, nullptr));
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800279 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800280
281 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800282 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
283 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700284
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800285 // Make sure it stopped.
286 EXPECT_FALSE(action_queue.Running());
287 EXPECT_EQ(1, nop_act.running_count());
288 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800289
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800290 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800291}
292
293// Tests that an action that would block forever stops when canceled.
294TEST_F(ActionTest, ActionQueueCancelOne) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700295 TestActorShouldCancel cancel_act(actor1_event_loop_.get());
296
297 TestActorShouldCancel::Factory cancel_action_factory =
298 TestActorShouldCancel::MakeFactory(test_event_loop_.get());
299
300 ActionQueue action_queue;
301
302 // Let the actor and action queue start up.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800303 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
304 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800305
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800306 // Enqueue blocking action.
307 {
308 UIntT uint;
309 uint.val = 0;
310 action_queue.EnqueueAction(cancel_action_factory.Make(uint));
311 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800312
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800313 action_queue.Tick();
314 EXPECT_TRUE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800315
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800316 // Tell action to cancel.
317 action_queue.CancelCurrentAction();
318 action_queue.Tick();
319 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800320
321 // This will block forever on failure.
322 // TODO(ben): prolly a bad way to fail
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800323 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
324 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800325
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800326 // It should still be running as the actor could not have signalled.
327 EXPECT_FALSE(action_queue.Running());
328 });
329
330 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800331}
332
Austin Schuh1bf8a212019-05-26 22:13:14 -0700333// Tests that 2 actions in a row causes the second one to cancel the first one.
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800334TEST_F(ActionTest, ActionQueueTwoActions) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700335 TestActorNOP nop_actor(actor1_event_loop_.get());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800336
Austin Schuh1bf8a212019-05-26 22:13:14 -0700337 TestActorIndex::Factory nop_actor_factory =
338 TestActorNOP::MakeFactory(test_event_loop_.get());
339
340 ActionQueue action_queue;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800341
342 // id for the first time run.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700343 uint32_t nop_actor_id = 0;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800344 // Check the internal state and write down id for later use.
345 bool sent_started, sent_cancel, interrupted;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800346 // id for the second run.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700347 uint32_t nop_actor2_id = 0;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800348
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800349 // Tick an empty queue and make sure it was not running.
350 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
351 action_queue.Tick();
352 EXPECT_FALSE(action_queue.Running());
353
354 // Enqueue action to be canceled.
355 {
356 UIntT uint;
357 uint.val = 0;
358 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
359 }
360 action_queue.Tick();
361
362 // Should still be running as the actor could not have signalled.
363 EXPECT_TRUE(action_queue.Running());
364
365 EXPECT_TRUE(action_queue.GetCurrentActionState(nullptr, &sent_started,
366 &sent_cancel, &interrupted,
367 &nop_actor_id, nullptr));
368 EXPECT_TRUE(sent_started);
369 EXPECT_FALSE(sent_cancel);
370 EXPECT_FALSE(interrupted);
371 ASSERT_NE(0u, nop_actor_id);
372
373 // Add the next action which should ensure the first stopped.
374 {
375 UIntT uint;
376 uint.val = 0;
377 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
378 }
379
380 // Check the internal state and write down id for later use.
381 EXPECT_TRUE(action_queue.GetNextActionState(nullptr, &sent_started,
382 &sent_cancel, &interrupted,
383 &nop_actor2_id, nullptr));
384 EXPECT_NE(nop_actor_id, nop_actor2_id);
385 EXPECT_FALSE(sent_started);
386 EXPECT_FALSE(sent_cancel);
387 EXPECT_FALSE(interrupted);
388 ASSERT_NE(0u, nop_actor2_id);
389
390 action_queue.Tick();
391 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800392
393 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800394 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
395 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800396
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800397 // Check the new action is the right one.
398 uint32_t test_id = 0;
399 EXPECT_TRUE(action_queue.GetCurrentActionState(
400 nullptr, &sent_started, &sent_cancel, &interrupted, &test_id, nullptr));
401 EXPECT_TRUE(sent_started);
402 EXPECT_FALSE(sent_cancel);
403 EXPECT_FALSE(interrupted);
404 EXPECT_EQ(nop_actor2_id, test_id);
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800405
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800406 // Make sure it is still going.
407 EXPECT_TRUE(action_queue.Running());
408 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800409
Austin Schuh1bf8a212019-05-26 22:13:14 -0700410 // Now let everything finish.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800411 RunAt(monotonic_clock::time_point(chrono::seconds(3)), [&]() {
412 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800413
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800414 // Make sure it stopped.
415 EXPECT_FALSE(action_queue.Running());
416 });
417
418 event_loop_factory_.RunFor(chrono::seconds(4));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800419}
420
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800421// Tests that we do get an index with our goal
422TEST_F(ActionTest, ActionIndex) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700423 TestActorIndex idx_actor(actor1_event_loop_.get());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800424
Austin Schuh1bf8a212019-05-26 22:13:14 -0700425 TestActorIndex::Factory test_actor_index_factory =
426 TestActorIndex::MakeFactory(test_event_loop_.get());
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800427 ::aos::Fetcher<actions::TestActionGoal> goal_fetcher_ =
428 test_event_loop_->MakeFetcher<actions::TestActionGoal>("/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -0700429
430 ActionQueue action_queue;
431 // Tick an empty queue and make sure it was not running. Also tick the
432 // factory to allow it to send out the initial cancel message.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800433 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
434 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700435
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800436 EXPECT_FALSE(action_queue.Running());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800437
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800438 // Enqueue action to post index.
439 {
440 UIntT uint;
441 uint.val = 5;
442 action_queue.EnqueueAction(test_actor_index_factory.Make(uint));
443 }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800444
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800445 ASSERT_TRUE(goal_fetcher_.Fetch());
446 EXPECT_EQ(5u, goal_fetcher_->params()->val());
447 EXPECT_EQ(0u, idx_actor.index);
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800448
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800449 action_queue.Tick();
450 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800451
452 // Run the next action so it can accomplish signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800453 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
454 action_queue.Tick();
455 EXPECT_EQ(5u, idx_actor.index);
Austin Schuh1bf8a212019-05-26 22:13:14 -0700456
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800457 // Enqueue action to post index.
458 {
459 UIntT uint;
460 uint.val = 3;
461 action_queue.EnqueueAction(test_actor_index_factory.Make(uint));
462 }
463 ASSERT_TRUE(goal_fetcher_.Fetch());
464 EXPECT_EQ(3u, goal_fetcher_->params()->val());
465 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800466
467 // Run the next action so it can accomplish signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800468 RunAt(monotonic_clock::time_point(chrono::seconds(3)), [&]() {
469 action_queue.Tick();
470 EXPECT_EQ(3u, idx_actor.index);
471 });
Austin Schuh1bf8a212019-05-26 22:13:14 -0700472
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800473 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800474}
475
476// Tests that an action with a structure params works.
477TEST_F(ActionTest, StructParamType) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700478 TestActor2Nop nop_actor(actor2_event_loop_.get());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800479
Austin Schuh1bf8a212019-05-26 22:13:14 -0700480 TestActor2Nop::Factory test_action_2_nop_factory =
481 TestActor2Nop::MakeFactory(test_event_loop_.get());
482
483 ActionQueue action_queue;
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800484
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800485 RunAt(monotonic_clock::time_point(chrono::seconds(0)), [&]() {
486 // Tick an empty queue and make sure it was not running.
487 action_queue.Tick();
488 EXPECT_FALSE(action_queue.Running());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800489
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800490 actions::MyParamsT p;
491 p.param1 = 5.0;
492 p.param2 = 7;
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800493
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800494 action_queue.EnqueueAction(test_action_2_nop_factory.Make(p));
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800495
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800496 // We started an action and it should be running.
497 EXPECT_TRUE(action_queue.Running());
498
499 // Tick it and make sure it is still running.
500 action_queue.Tick();
501 EXPECT_TRUE(action_queue.Running());
502 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800503
504 // Run the action so it can signal completion.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700505 // The actor takes no time, but running for a second is the best way to get it
506 // to go.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800507 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
508 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700509
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800510 // Make sure it stopped.
511 EXPECT_FALSE(action_queue.Running());
512 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800513
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800514 event_loop_factory_.RunFor(chrono::seconds(2));
Brian Silverman237a5542015-03-29 17:59:29 -0400515}
516
517} // namespace testing
518} // namespace actions
519} // namespace common
520} // namespace aos