blob: 2638cdc43860b57b53770a4f3a6f0296212f5a60 [file] [log] [blame]
Ben Fredricksond69f38b2015-01-28 20:06:15 -08001#include <unistd.h>
2
milind1f1dca32021-07-03 13:50:07 -07003#include <chrono>
Ben Fredricksond69f38b2015-01-28 20:06:15 -08004#include <memory>
Brian Silvermana2ae62d2015-03-15 15:55:22 -07005#include <thread>
Ben Fredricksond69f38b2015-01-28 20:06:15 -08006
John Park33858a32018-09-28 23:05:48 -07007#include "aos/actions/actions.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -07008#include "aos/actions/actions_generated.h"
Austin Schuh1bf8a212019-05-26 22:13:14 -07009#include "aos/actions/actor.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070010#include "aos/actions/test_action_generated.h"
11#include "aos/events/simulated_event_loop.h"
Austin Schuh373f1762021-06-02 21:07:09 -070012#include "aos/testing/path.h"
Austin Schuh60e77942022-05-16 17:48:24 -070013#include "gtest/gtest.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)
milind1f1dca32021-07-03 13:50:07 -070050 : actions::ActorBase<actions::TestActionGoal>(event_loop,
51 "/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)
milind1f1dca32021-07-03 13:50:07 -070087 : actions::ActorBase<actions::TestAction2Goal>(event_loop,
88 "/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()
Austin Schuh373f1762021-06-02 21:07:09 -0700100 : configuration_(configuration::ReadConfig(
101 aos::testing::ArtifactPath("aos/actions/action_test_config.json"))),
Alex Perrycb7da4b2019-08-28 19:35:56 -0700102 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 {
milind1f1dca32021-07-03 13:50:07 -0700148 ::aos::Sender<TestActionGoal>::Builder builder = goal_sender.MakeBuilder();
Alex Perrycb7da4b2019-08-28 19:35:56 -0700149
150 TestActionGoal::Builder goal_builder =
151 builder.MakeBuilder<TestActionGoal>();
152
153 goal_builder.add_run(971);
milind1f1dca32021-07-03 13:50:07 -0700154 builder.CheckOk(builder.Send(goal_builder.Finish()));
Austin Schuh1bf8a212019-05-26 22:13:14 -0700155 }
156
157 TestActorNOP nop_act(actor1_event_loop_.get());
158
159 ASSERT_FALSE(status_fetcher.Fetch());
160
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800161 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
162 ASSERT_TRUE(status_fetcher.Fetch());
163 EXPECT_EQ(0u, status_fetcher->running());
164 EXPECT_EQ(0u, status_fetcher->last_running());
Austin Schuh1bf8a212019-05-26 22:13:14 -0700165
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800166 {
167 UIntT uint;
168 uint.val = 0;
169 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
170 }
Austin Schuh1bf8a212019-05-26 22:13:14 -0700171
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800172 // We started an action and it should be running.
173 EXPECT_TRUE(action_queue.Running());
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700174
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800175 action_queue.CancelAllActions();
176 action_queue.Tick();
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700177
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800178 EXPECT_TRUE(action_queue.Running());
179 });
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700180
181 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800182 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
183 action_queue.Tick();
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700184
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800185 // Make sure it stopped.
186 EXPECT_FALSE(action_queue.Running());
187 });
188
189 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800190}
191
192// Tests that an action starts and stops.
193TEST_F(ActionTest, ActionQueueWasRunning) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700194 TestActorNOP nop_act(actor1_event_loop_.get());
195
196 TestActorIndex::Factory nop_actor_factory =
197 TestActorNOP::MakeFactory(test_event_loop_.get());
198
199 ActionQueue action_queue;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800200
201 // Tick an empty queue and make sure it was not running.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800202 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
203 action_queue.Tick();
204 EXPECT_FALSE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800205
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800206 {
207 UIntT uint;
208 uint.val = 0;
209 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
210 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800211
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800212 // We started an action and it should be running.
213 EXPECT_TRUE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800214
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800215 // Tick it and make sure it is still running.
216 action_queue.Tick();
217 EXPECT_TRUE(action_queue.Running());
218 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800219
220 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800221 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
222 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800223
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800224 // Make sure it stopped.
225 EXPECT_FALSE(action_queue.Running());
226 });
227
228 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800229}
230
231// Tests that we can cancel two actions and have them both stop.
232TEST_F(ActionTest, ActionQueueCancelAll) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700233 TestActorNOP nop_act(actor1_event_loop_.get());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800234
Austin Schuh1bf8a212019-05-26 22:13:14 -0700235 TestActorIndex::Factory nop_actor_factory =
236 TestActorNOP::MakeFactory(test_event_loop_.get());
237
238 ActionQueue action_queue;
239
240 // Let the actor and action queue start up and confirm nothing is running.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800241 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
242 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700243
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800244 EXPECT_FALSE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800245
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800246 // Enqueue two actions to test both cancel. We can have an action and a next
247 // action so we want to test that.
248 {
249 UIntT uint;
250 uint.val = 0;
251 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
252 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
253 }
Austin Schuh1bf8a212019-05-26 22:13:14 -0700254
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800255 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800256
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800257 // Check that current and next exist.
258 EXPECT_TRUE(action_queue.GetCurrentActionState(nullptr, nullptr, nullptr,
259 nullptr, nullptr, nullptr));
260 EXPECT_TRUE(action_queue.GetNextActionState(nullptr, nullptr, nullptr,
261 nullptr, nullptr, nullptr));
262
263 action_queue.CancelAllActions();
264 action_queue.Tick();
265
266 // It should still be running as the actor could not have signaled.
267 EXPECT_TRUE(action_queue.Running());
268
269 bool sent_started, sent_cancel, interrupted;
270 EXPECT_TRUE(action_queue.GetCurrentActionState(
271 nullptr, &sent_started, &sent_cancel, &interrupted, nullptr, nullptr));
272 EXPECT_TRUE(sent_started);
273 EXPECT_TRUE(sent_cancel);
274 EXPECT_FALSE(interrupted);
275
276 EXPECT_FALSE(action_queue.GetNextActionState(nullptr, nullptr, nullptr,
Austin Schuh1bf8a212019-05-26 22:13:14 -0700277 nullptr, nullptr, nullptr));
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800278 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800279
280 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800281 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
282 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700283
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800284 // Make sure it stopped.
285 EXPECT_FALSE(action_queue.Running());
286 EXPECT_EQ(1, nop_act.running_count());
287 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800288
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800289 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800290}
291
292// Tests that an action that would block forever stops when canceled.
293TEST_F(ActionTest, ActionQueueCancelOne) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700294 TestActorShouldCancel cancel_act(actor1_event_loop_.get());
295
296 TestActorShouldCancel::Factory cancel_action_factory =
297 TestActorShouldCancel::MakeFactory(test_event_loop_.get());
298
299 ActionQueue action_queue;
300
301 // Let the actor and action queue start up.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800302 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
303 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800304
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800305 // Enqueue blocking action.
306 {
307 UIntT uint;
308 uint.val = 0;
309 action_queue.EnqueueAction(cancel_action_factory.Make(uint));
310 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800311
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800312 action_queue.Tick();
313 EXPECT_TRUE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800314
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800315 // Tell action to cancel.
316 action_queue.CancelCurrentAction();
317 action_queue.Tick();
318 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800319
320 // This will block forever on failure.
321 // TODO(ben): prolly a bad way to fail
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800322 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
323 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800324
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800325 // It should still be running as the actor could not have signalled.
326 EXPECT_FALSE(action_queue.Running());
327 });
328
329 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800330}
331
Austin Schuh1bf8a212019-05-26 22:13:14 -0700332// Tests that 2 actions in a row causes the second one to cancel the first one.
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800333TEST_F(ActionTest, ActionQueueTwoActions) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700334 TestActorNOP nop_actor(actor1_event_loop_.get());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800335
Austin Schuh1bf8a212019-05-26 22:13:14 -0700336 TestActorIndex::Factory nop_actor_factory =
337 TestActorNOP::MakeFactory(test_event_loop_.get());
338
339 ActionQueue action_queue;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800340
341 // id for the first time run.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700342 uint32_t nop_actor_id = 0;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800343 // Check the internal state and write down id for later use.
344 bool sent_started, sent_cancel, interrupted;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800345 // id for the second run.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700346 uint32_t nop_actor2_id = 0;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800347
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800348 // Tick an empty queue and make sure it was not running.
349 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
350 action_queue.Tick();
351 EXPECT_FALSE(action_queue.Running());
352
353 // Enqueue action to be canceled.
354 {
355 UIntT uint;
356 uint.val = 0;
357 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
358 }
359 action_queue.Tick();
360
361 // Should still be running as the actor could not have signalled.
362 EXPECT_TRUE(action_queue.Running());
363
364 EXPECT_TRUE(action_queue.GetCurrentActionState(nullptr, &sent_started,
365 &sent_cancel, &interrupted,
366 &nop_actor_id, nullptr));
367 EXPECT_TRUE(sent_started);
368 EXPECT_FALSE(sent_cancel);
369 EXPECT_FALSE(interrupted);
370 ASSERT_NE(0u, nop_actor_id);
371
372 // Add the next action which should ensure the first stopped.
373 {
374 UIntT uint;
375 uint.val = 0;
376 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
377 }
378
379 // Check the internal state and write down id for later use.
380 EXPECT_TRUE(action_queue.GetNextActionState(nullptr, &sent_started,
381 &sent_cancel, &interrupted,
382 &nop_actor2_id, nullptr));
383 EXPECT_NE(nop_actor_id, nop_actor2_id);
384 EXPECT_FALSE(sent_started);
385 EXPECT_FALSE(sent_cancel);
386 EXPECT_FALSE(interrupted);
387 ASSERT_NE(0u, nop_actor2_id);
388
389 action_queue.Tick();
390 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800391
392 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800393 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
394 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800395
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800396 // Check the new action is the right one.
397 uint32_t test_id = 0;
398 EXPECT_TRUE(action_queue.GetCurrentActionState(
399 nullptr, &sent_started, &sent_cancel, &interrupted, &test_id, nullptr));
400 EXPECT_TRUE(sent_started);
401 EXPECT_FALSE(sent_cancel);
402 EXPECT_FALSE(interrupted);
403 EXPECT_EQ(nop_actor2_id, test_id);
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800404
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800405 // Make sure it is still going.
406 EXPECT_TRUE(action_queue.Running());
407 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800408
Austin Schuh1bf8a212019-05-26 22:13:14 -0700409 // Now let everything finish.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800410 RunAt(monotonic_clock::time_point(chrono::seconds(3)), [&]() {
411 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800412
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800413 // Make sure it stopped.
414 EXPECT_FALSE(action_queue.Running());
415 });
416
417 event_loop_factory_.RunFor(chrono::seconds(4));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800418}
419
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800420// Tests that we do get an index with our goal
421TEST_F(ActionTest, ActionIndex) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700422 TestActorIndex idx_actor(actor1_event_loop_.get());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800423
Austin Schuh1bf8a212019-05-26 22:13:14 -0700424 TestActorIndex::Factory test_actor_index_factory =
425 TestActorIndex::MakeFactory(test_event_loop_.get());
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800426 ::aos::Fetcher<actions::TestActionGoal> goal_fetcher_ =
427 test_event_loop_->MakeFetcher<actions::TestActionGoal>("/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -0700428
429 ActionQueue action_queue;
430 // Tick an empty queue and make sure it was not running. Also tick the
431 // factory to allow it to send out the initial cancel message.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800432 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
433 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700434
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800435 EXPECT_FALSE(action_queue.Running());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800436
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800437 // Enqueue action to post index.
438 {
439 UIntT uint;
440 uint.val = 5;
441 action_queue.EnqueueAction(test_actor_index_factory.Make(uint));
442 }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800443
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800444 ASSERT_TRUE(goal_fetcher_.Fetch());
445 EXPECT_EQ(5u, goal_fetcher_->params()->val());
446 EXPECT_EQ(0u, idx_actor.index);
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800447
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800448 action_queue.Tick();
449 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800450
451 // Run the next action so it can accomplish signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800452 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
453 action_queue.Tick();
454 EXPECT_EQ(5u, idx_actor.index);
Austin Schuh1bf8a212019-05-26 22:13:14 -0700455
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800456 // Enqueue action to post index.
457 {
458 UIntT uint;
459 uint.val = 3;
460 action_queue.EnqueueAction(test_actor_index_factory.Make(uint));
461 }
462 ASSERT_TRUE(goal_fetcher_.Fetch());
463 EXPECT_EQ(3u, goal_fetcher_->params()->val());
464 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800465
466 // Run the next action so it can accomplish signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800467 RunAt(monotonic_clock::time_point(chrono::seconds(3)), [&]() {
468 action_queue.Tick();
469 EXPECT_EQ(3u, idx_actor.index);
470 });
Austin Schuh1bf8a212019-05-26 22:13:14 -0700471
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800472 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800473}
474
475// Tests that an action with a structure params works.
476TEST_F(ActionTest, StructParamType) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700477 TestActor2Nop nop_actor(actor2_event_loop_.get());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800478
Austin Schuh1bf8a212019-05-26 22:13:14 -0700479 TestActor2Nop::Factory test_action_2_nop_factory =
480 TestActor2Nop::MakeFactory(test_event_loop_.get());
481
482 ActionQueue action_queue;
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800483
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800484 RunAt(monotonic_clock::time_point(chrono::seconds(0)), [&]() {
485 // Tick an empty queue and make sure it was not running.
486 action_queue.Tick();
487 EXPECT_FALSE(action_queue.Running());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800488
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800489 actions::MyParamsT p;
490 p.param1 = 5.0;
491 p.param2 = 7;
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800492
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800493 action_queue.EnqueueAction(test_action_2_nop_factory.Make(p));
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800494
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800495 // We started an action and it should be running.
496 EXPECT_TRUE(action_queue.Running());
497
498 // Tick it and make sure it is still running.
499 action_queue.Tick();
500 EXPECT_TRUE(action_queue.Running());
501 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800502
503 // Run the action so it can signal completion.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700504 // The actor takes no time, but running for a second is the best way to get it
505 // to go.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800506 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
507 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700508
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800509 // Make sure it stopped.
510 EXPECT_FALSE(action_queue.Running());
511 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800512
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800513 event_loop_factory_.RunFor(chrono::seconds(2));
Brian Silverman237a5542015-03-29 17:59:29 -0400514}
515
516} // namespace testing
517} // namespace actions
518} // namespace common
519} // namespace aos