blob: 124b3e46d2b9e8872eb4f1ff39dfe0b793ed6915 [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"
Austin Schuh1bf8a212019-05-26 22:13:14 -070014#include "aos/testing/test_logging.h"
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -050015#include "aos/testing/test_shm.h"
Ben Fredricksond69f38b2015-01-28 20:06:15 -080016
Ben Fredricksond69f38b2015-01-28 20:06:15 -080017namespace aos {
18namespace common {
19namespace actions {
20namespace testing {
21
Austin Schuhf2a50ba2016-12-24 16:16:26 -080022namespace chrono = ::std::chrono;
23
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080024class TestActorIndex
Alex Perrycb7da4b2019-08-28 19:35:56 -070025 : public aos::common::actions::ActorBase<actions::TestActionGoal> {
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080026 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070027 typedef TypedActionFactory<actions::TestActionGoal> Factory;
Austin Schuh1bf8a212019-05-26 22:13:14 -070028
29 explicit TestActorIndex(::aos::EventLoop *event_loop)
Alex Perrycb7da4b2019-08-28 19:35:56 -070030 : aos::common::actions::ActorBase<actions::TestActionGoal>(
31 event_loop, "/test_action") {}
Austin Schuh1bf8a212019-05-26 22:13:14 -070032
33 static Factory MakeFactory(::aos::EventLoop *event_loop) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070034 return Factory(event_loop, "/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -070035 }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080036
Alex Perrycb7da4b2019-08-28 19:35:56 -070037 bool RunAction(const UInt *new_index) override {
38 VLOG(1) << "New index " << FlatbufferToJson(new_index);
39 index = new_index->val();
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080040 return true;
41 }
42
43 uint32_t index = 0;
44};
45
Ben Fredricksond69f38b2015-01-28 20:06:15 -080046class TestActorNOP
Alex Perrycb7da4b2019-08-28 19:35:56 -070047 : public aos::common::actions::ActorBase<actions::TestActionGoal> {
Ben Fredricksond69f38b2015-01-28 20:06:15 -080048 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070049 typedef TypedActionFactory<actions::TestActionGoal> Factory;
Austin Schuh1bf8a212019-05-26 22:13:14 -070050
51 explicit TestActorNOP(::aos::EventLoop *event_loop)
Alex Perrycb7da4b2019-08-28 19:35:56 -070052 : actions::ActorBase<actions::TestActionGoal>(
53 event_loop, "/test_action") {}
Austin Schuh1bf8a212019-05-26 22:13:14 -070054
55 static Factory MakeFactory(::aos::EventLoop *event_loop) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070056 return Factory(event_loop, "/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -070057 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -080058
Alex Perrycb7da4b2019-08-28 19:35:56 -070059 bool RunAction(const UInt *) override { return true; }
Ben Fredricksond69f38b2015-01-28 20:06:15 -080060};
61
Ben Fredricksond69f38b2015-01-28 20:06:15 -080062class TestActorShouldCancel
Alex Perrycb7da4b2019-08-28 19:35:56 -070063 : public aos::common::actions::ActorBase<actions::TestActionGoal> {
Ben Fredricksond69f38b2015-01-28 20:06:15 -080064 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070065 typedef TypedActionFactory<actions::TestActionGoal> Factory;
Austin Schuh1bf8a212019-05-26 22:13:14 -070066
67 explicit TestActorShouldCancel(::aos::EventLoop *event_loop)
Alex Perrycb7da4b2019-08-28 19:35:56 -070068 : aos::common::actions::ActorBase<actions::TestActionGoal>(
69 event_loop, "/test_action") {}
Austin Schuh1bf8a212019-05-26 22:13:14 -070070
71 static Factory MakeFactory(::aos::EventLoop *event_loop) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070072 return Factory(event_loop, "/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -070073 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -080074
Alex Perrycb7da4b2019-08-28 19:35:56 -070075 bool RunAction(const UInt *) override {
Ben Fredricksond69f38b2015-01-28 20:06:15 -080076 while (!ShouldCancel()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070077 AOS_LOG(FATAL, "NOT CANCELED!!\n");
Ben Fredricksond69f38b2015-01-28 20:06:15 -080078 }
Daniel Petti3b1e48f2015-02-15 15:57:53 -080079 return true;
Ben Fredricksond69f38b2015-01-28 20:06:15 -080080 }
81};
82
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080083class TestActor2Nop
Alex Perrycb7da4b2019-08-28 19:35:56 -070084 : public aos::common::actions::ActorBase<actions::TestAction2Goal> {
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080085 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070086 typedef TypedActionFactory<actions::TestAction2Goal> Factory;
Austin Schuh1bf8a212019-05-26 22:13:14 -070087
88 explicit TestActor2Nop(::aos::EventLoop *event_loop)
Alex Perrycb7da4b2019-08-28 19:35:56 -070089 : actions::ActorBase<actions::TestAction2Goal>(
90 event_loop, "/test_action2") {}
Austin Schuh1bf8a212019-05-26 22:13:14 -070091
92 static Factory MakeFactory(::aos::EventLoop *event_loop) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070093 return Factory(event_loop, "/test_action2");
Austin Schuh1bf8a212019-05-26 22:13:14 -070094 }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080095
Alex Perrycb7da4b2019-08-28 19:35:56 -070096 bool RunAction(const actions::MyParams *) { return true; }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080097};
98
Ben Fredricksond69f38b2015-01-28 20:06:15 -080099class ActionTest : public ::testing::Test {
100 protected:
Austin Schuh1bf8a212019-05-26 22:13:14 -0700101 ActionTest()
Alex Perrycb7da4b2019-08-28 19:35:56 -0700102 : configuration_(
103 configuration::ReadConfig("aos/actions/action_test_config.json")),
104 event_loop_factory_(&configuration_.message()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800105 actor1_event_loop_(event_loop_factory_.MakeEventLoop("actor1")),
106 actor2_event_loop_(event_loop_factory_.MakeEventLoop("actor2")),
107 test_event_loop_(event_loop_factory_.MakeEventLoop("test")) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700108 ::aos::testing::EnableTestLogging();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800109 }
110
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800111 void RunAt(monotonic_clock::time_point exec_time, std::function<void()> fn) {
112 TimerHandler *timer = test_event_loop_->AddTimer(fn);
113 test_event_loop_->OnRun([timer, exec_time]() { timer->Setup(exec_time); });
114 }
115
Alex Perrycb7da4b2019-08-28 19:35:56 -0700116 FlatbufferDetachedBuffer<Configuration> configuration_;
117
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800118 // Bring up and down Core.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700119 ::aos::SimulatedEventLoopFactory event_loop_factory_;
120
121 ::std::unique_ptr<::aos::EventLoop> actor1_event_loop_;
122 ::std::unique_ptr<::aos::EventLoop> actor2_event_loop_;
123 ::std::unique_ptr<::aos::EventLoop> test_event_loop_;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800124};
125
126// Tests that the the actions exist in a safe state at startup.
127TEST_F(ActionTest, DoesNothing) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700128 ActionQueue action_queue;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800129 // Tick an empty queue and make sure it was not running.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700130 EXPECT_FALSE(action_queue.Running());
131 action_queue.Tick();
132 EXPECT_FALSE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800133}
134
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700135// Tests that starting with an old run message in the goal queue actually works.
136// This used to result in the client hanging, waiting for a response to its
137// cancel message.
138TEST_F(ActionTest, StartWithOldGoal) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700139 ::std::unique_ptr<::aos::EventLoop> test2_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800140 event_loop_factory_.MakeEventLoop("test2");
Alex Perrycb7da4b2019-08-28 19:35:56 -0700141 ::aos::Sender<TestActionGoal> goal_sender =
142 test2_event_loop->MakeSender<TestActionGoal>("/test_action");
143 ::aos::Fetcher<Status> status_fetcher =
144 test2_event_loop->MakeFetcher<Status>("/test_action");
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700145
Austin Schuh1bf8a212019-05-26 22:13:14 -0700146 TestActorIndex::Factory nop_actor_factory =
147 TestActorNOP::MakeFactory(test_event_loop_.get());
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700148
Austin Schuh1bf8a212019-05-26 22:13:14 -0700149 ActionQueue action_queue;
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700150
Austin Schuh1bf8a212019-05-26 22:13:14 -0700151 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700152 ::aos::Sender<TestActionGoal>::Builder builder =
153 goal_sender.MakeBuilder();
154
155 TestActionGoal::Builder goal_builder =
156 builder.MakeBuilder<TestActionGoal>();
157
158 goal_builder.add_run(971);
159 ASSERT_TRUE(builder.Send(goal_builder.Finish()));
Austin Schuh1bf8a212019-05-26 22:13:14 -0700160 }
161
162 TestActorNOP nop_act(actor1_event_loop_.get());
163
164 ASSERT_FALSE(status_fetcher.Fetch());
165
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800166 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
167 ASSERT_TRUE(status_fetcher.Fetch());
168 EXPECT_EQ(0u, status_fetcher->running());
169 EXPECT_EQ(0u, status_fetcher->last_running());
Austin Schuh1bf8a212019-05-26 22:13:14 -0700170
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800171 {
172 UIntT uint;
173 uint.val = 0;
174 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
175 }
Austin Schuh1bf8a212019-05-26 22:13:14 -0700176
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800177 // We started an action and it should be running.
178 EXPECT_TRUE(action_queue.Running());
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700179
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800180 action_queue.CancelAllActions();
181 action_queue.Tick();
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700182
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800183 EXPECT_TRUE(action_queue.Running());
184 });
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700185
186 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800187 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
188 action_queue.Tick();
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700189
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800190 // Make sure it stopped.
191 EXPECT_FALSE(action_queue.Running());
192 });
193
194 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800195}
196
197// Tests that an action starts and stops.
198TEST_F(ActionTest, ActionQueueWasRunning) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700199 TestActorNOP nop_act(actor1_event_loop_.get());
200
201 TestActorIndex::Factory nop_actor_factory =
202 TestActorNOP::MakeFactory(test_event_loop_.get());
203
204 ActionQueue action_queue;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800205
206 // Tick an empty queue and make sure it was not running.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800207 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
208 action_queue.Tick();
209 EXPECT_FALSE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800210
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800211 {
212 UIntT uint;
213 uint.val = 0;
214 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
215 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800216
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800217 // We started an action and it should be running.
218 EXPECT_TRUE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800219
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800220 // Tick it and make sure it is still running.
221 action_queue.Tick();
222 EXPECT_TRUE(action_queue.Running());
223 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800224
225 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800226 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
227 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800228
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800229 // Make sure it stopped.
230 EXPECT_FALSE(action_queue.Running());
231 });
232
233 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800234}
235
236// Tests that we can cancel two actions and have them both stop.
237TEST_F(ActionTest, ActionQueueCancelAll) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700238 TestActorNOP nop_act(actor1_event_loop_.get());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800239
Austin Schuh1bf8a212019-05-26 22:13:14 -0700240 TestActorIndex::Factory nop_actor_factory =
241 TestActorNOP::MakeFactory(test_event_loop_.get());
242
243 ActionQueue action_queue;
244
245 // Let the actor and action queue start up and confirm nothing is running.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800246 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
247 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700248
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800249 EXPECT_FALSE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800250
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800251 // Enqueue two actions to test both cancel. We can have an action and a next
252 // action so we want to test that.
253 {
254 UIntT uint;
255 uint.val = 0;
256 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
257 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
258 }
Austin Schuh1bf8a212019-05-26 22:13:14 -0700259
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800260 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800261
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800262 // Check that current and next exist.
263 EXPECT_TRUE(action_queue.GetCurrentActionState(nullptr, nullptr, nullptr,
264 nullptr, nullptr, nullptr));
265 EXPECT_TRUE(action_queue.GetNextActionState(nullptr, nullptr, nullptr,
266 nullptr, nullptr, nullptr));
267
268 action_queue.CancelAllActions();
269 action_queue.Tick();
270
271 // It should still be running as the actor could not have signaled.
272 EXPECT_TRUE(action_queue.Running());
273
274 bool sent_started, sent_cancel, interrupted;
275 EXPECT_TRUE(action_queue.GetCurrentActionState(
276 nullptr, &sent_started, &sent_cancel, &interrupted, nullptr, nullptr));
277 EXPECT_TRUE(sent_started);
278 EXPECT_TRUE(sent_cancel);
279 EXPECT_FALSE(interrupted);
280
281 EXPECT_FALSE(action_queue.GetNextActionState(nullptr, nullptr, nullptr,
Austin Schuh1bf8a212019-05-26 22:13:14 -0700282 nullptr, nullptr, nullptr));
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800283 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800284
285 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800286 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
287 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700288
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800289 // Make sure it stopped.
290 EXPECT_FALSE(action_queue.Running());
291 EXPECT_EQ(1, nop_act.running_count());
292 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800293
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800294 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800295}
296
297// Tests that an action that would block forever stops when canceled.
298TEST_F(ActionTest, ActionQueueCancelOne) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700299 TestActorShouldCancel cancel_act(actor1_event_loop_.get());
300
301 TestActorShouldCancel::Factory cancel_action_factory =
302 TestActorShouldCancel::MakeFactory(test_event_loop_.get());
303
304 ActionQueue action_queue;
305
306 // Let the actor and action queue start up.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800307 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
308 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800309
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800310 // Enqueue blocking action.
311 {
312 UIntT uint;
313 uint.val = 0;
314 action_queue.EnqueueAction(cancel_action_factory.Make(uint));
315 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800316
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800317 action_queue.Tick();
318 EXPECT_TRUE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800319
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800320 // Tell action to cancel.
321 action_queue.CancelCurrentAction();
322 action_queue.Tick();
323 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800324
325 // This will block forever on failure.
326 // TODO(ben): prolly a bad way to fail
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800327 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
328 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800329
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800330 // It should still be running as the actor could not have signalled.
331 EXPECT_FALSE(action_queue.Running());
332 });
333
334 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800335}
336
Austin Schuh1bf8a212019-05-26 22:13:14 -0700337// Tests that 2 actions in a row causes the second one to cancel the first one.
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800338TEST_F(ActionTest, ActionQueueTwoActions) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700339 TestActorNOP nop_actor(actor1_event_loop_.get());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800340
Austin Schuh1bf8a212019-05-26 22:13:14 -0700341 TestActorIndex::Factory nop_actor_factory =
342 TestActorNOP::MakeFactory(test_event_loop_.get());
343
344 ActionQueue action_queue;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800345
346 // id for the first time run.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700347 uint32_t nop_actor_id = 0;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800348 // Check the internal state and write down id for later use.
349 bool sent_started, sent_cancel, interrupted;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800350 // id for the second run.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700351 uint32_t nop_actor2_id = 0;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800352
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800353 // Tick an empty queue and make sure it was not running.
354 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
355 action_queue.Tick();
356 EXPECT_FALSE(action_queue.Running());
357
358 // Enqueue action to be canceled.
359 {
360 UIntT uint;
361 uint.val = 0;
362 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
363 }
364 action_queue.Tick();
365
366 // Should still be running as the actor could not have signalled.
367 EXPECT_TRUE(action_queue.Running());
368
369 EXPECT_TRUE(action_queue.GetCurrentActionState(nullptr, &sent_started,
370 &sent_cancel, &interrupted,
371 &nop_actor_id, nullptr));
372 EXPECT_TRUE(sent_started);
373 EXPECT_FALSE(sent_cancel);
374 EXPECT_FALSE(interrupted);
375 ASSERT_NE(0u, nop_actor_id);
376
377 // Add the next action which should ensure the first stopped.
378 {
379 UIntT uint;
380 uint.val = 0;
381 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
382 }
383
384 // Check the internal state and write down id for later use.
385 EXPECT_TRUE(action_queue.GetNextActionState(nullptr, &sent_started,
386 &sent_cancel, &interrupted,
387 &nop_actor2_id, nullptr));
388 EXPECT_NE(nop_actor_id, nop_actor2_id);
389 EXPECT_FALSE(sent_started);
390 EXPECT_FALSE(sent_cancel);
391 EXPECT_FALSE(interrupted);
392 ASSERT_NE(0u, nop_actor2_id);
393
394 action_queue.Tick();
395 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800396
397 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800398 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
399 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800400
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800401 // Check the new action is the right one.
402 uint32_t test_id = 0;
403 EXPECT_TRUE(action_queue.GetCurrentActionState(
404 nullptr, &sent_started, &sent_cancel, &interrupted, &test_id, nullptr));
405 EXPECT_TRUE(sent_started);
406 EXPECT_FALSE(sent_cancel);
407 EXPECT_FALSE(interrupted);
408 EXPECT_EQ(nop_actor2_id, test_id);
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800409
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800410 // Make sure it is still going.
411 EXPECT_TRUE(action_queue.Running());
412 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800413
Austin Schuh1bf8a212019-05-26 22:13:14 -0700414 // Now let everything finish.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800415 RunAt(monotonic_clock::time_point(chrono::seconds(3)), [&]() {
416 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800417
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800418 // Make sure it stopped.
419 EXPECT_FALSE(action_queue.Running());
420 });
421
422 event_loop_factory_.RunFor(chrono::seconds(4));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800423}
424
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800425// Tests that we do get an index with our goal
426TEST_F(ActionTest, ActionIndex) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700427 TestActorIndex idx_actor(actor1_event_loop_.get());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800428
Austin Schuh1bf8a212019-05-26 22:13:14 -0700429 TestActorIndex::Factory test_actor_index_factory =
430 TestActorIndex::MakeFactory(test_event_loop_.get());
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800431 ::aos::Fetcher<actions::TestActionGoal> goal_fetcher_ =
432 test_event_loop_->MakeFetcher<actions::TestActionGoal>("/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -0700433
434 ActionQueue action_queue;
435 // Tick an empty queue and make sure it was not running. Also tick the
436 // factory to allow it to send out the initial cancel message.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800437 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
438 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700439
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800440 EXPECT_FALSE(action_queue.Running());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800441
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800442 // Enqueue action to post index.
443 {
444 UIntT uint;
445 uint.val = 5;
446 action_queue.EnqueueAction(test_actor_index_factory.Make(uint));
447 }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800448
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800449 ASSERT_TRUE(goal_fetcher_.Fetch());
450 EXPECT_EQ(5u, goal_fetcher_->params()->val());
451 EXPECT_EQ(0u, idx_actor.index);
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800452
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800453 action_queue.Tick();
454 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800455
456 // Run the next action so it can accomplish signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800457 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
458 action_queue.Tick();
459 EXPECT_EQ(5u, idx_actor.index);
Austin Schuh1bf8a212019-05-26 22:13:14 -0700460
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800461 // Enqueue action to post index.
462 {
463 UIntT uint;
464 uint.val = 3;
465 action_queue.EnqueueAction(test_actor_index_factory.Make(uint));
466 }
467 ASSERT_TRUE(goal_fetcher_.Fetch());
468 EXPECT_EQ(3u, goal_fetcher_->params()->val());
469 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800470
471 // Run the next action so it can accomplish signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800472 RunAt(monotonic_clock::time_point(chrono::seconds(3)), [&]() {
473 action_queue.Tick();
474 EXPECT_EQ(3u, idx_actor.index);
475 });
Austin Schuh1bf8a212019-05-26 22:13:14 -0700476
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800477 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800478}
479
480// Tests that an action with a structure params works.
481TEST_F(ActionTest, StructParamType) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700482 TestActor2Nop nop_actor(actor2_event_loop_.get());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800483
Austin Schuh1bf8a212019-05-26 22:13:14 -0700484 TestActor2Nop::Factory test_action_2_nop_factory =
485 TestActor2Nop::MakeFactory(test_event_loop_.get());
486
487 ActionQueue action_queue;
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800488
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800489 RunAt(monotonic_clock::time_point(chrono::seconds(0)), [&]() {
490 // Tick an empty queue and make sure it was not running.
491 action_queue.Tick();
492 EXPECT_FALSE(action_queue.Running());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800493
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800494 actions::MyParamsT p;
495 p.param1 = 5.0;
496 p.param2 = 7;
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800497
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800498 action_queue.EnqueueAction(test_action_2_nop_factory.Make(p));
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800499
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800500 // We started an action and it should be running.
501 EXPECT_TRUE(action_queue.Running());
502
503 // Tick it and make sure it is still running.
504 action_queue.Tick();
505 EXPECT_TRUE(action_queue.Running());
506 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800507
508 // Run the action so it can signal completion.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700509 // The actor takes no time, but running for a second is the best way to get it
510 // to go.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800511 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
512 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700513
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800514 // Make sure it stopped.
515 EXPECT_FALSE(action_queue.Running());
516 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800517
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800518 event_loop_factory_.RunFor(chrono::seconds(2));
Brian Silverman237a5542015-03-29 17:59:29 -0400519}
520
521} // namespace testing
522} // namespace actions
523} // namespace common
524} // namespace aos