blob: 1c8e5066355f88a36af744f20ea90a4374724790 [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 Schuh373f1762021-06-02 21:07:09 -070014#include "aos/testing/path.h"
Ben Fredricksond69f38b2015-01-28 20:06:15 -080015
Ben Fredricksond69f38b2015-01-28 20:06:15 -080016namespace aos {
17namespace common {
18namespace actions {
19namespace testing {
20
Austin Schuhf2a50ba2016-12-24 16:16:26 -080021namespace chrono = ::std::chrono;
22
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080023class TestActorIndex
Alex Perrycb7da4b2019-08-28 19:35:56 -070024 : public aos::common::actions::ActorBase<actions::TestActionGoal> {
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080025 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070026 typedef TypedActionFactory<actions::TestActionGoal> Factory;
Austin Schuh1bf8a212019-05-26 22:13:14 -070027
28 explicit TestActorIndex(::aos::EventLoop *event_loop)
Alex Perrycb7da4b2019-08-28 19:35:56 -070029 : aos::common::actions::ActorBase<actions::TestActionGoal>(
30 event_loop, "/test_action") {}
Austin Schuh1bf8a212019-05-26 22:13:14 -070031
32 static Factory MakeFactory(::aos::EventLoop *event_loop) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070033 return Factory(event_loop, "/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -070034 }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080035
Alex Perrycb7da4b2019-08-28 19:35:56 -070036 bool RunAction(const UInt *new_index) override {
37 VLOG(1) << "New index " << FlatbufferToJson(new_index);
38 index = new_index->val();
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080039 return true;
40 }
41
42 uint32_t index = 0;
43};
44
Ben Fredricksond69f38b2015-01-28 20:06:15 -080045class TestActorNOP
Alex Perrycb7da4b2019-08-28 19:35:56 -070046 : public aos::common::actions::ActorBase<actions::TestActionGoal> {
Ben Fredricksond69f38b2015-01-28 20:06:15 -080047 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070048 typedef TypedActionFactory<actions::TestActionGoal> Factory;
Austin Schuh1bf8a212019-05-26 22:13:14 -070049
50 explicit TestActorNOP(::aos::EventLoop *event_loop)
Alex Perrycb7da4b2019-08-28 19:35:56 -070051 : actions::ActorBase<actions::TestActionGoal>(
52 event_loop, "/test_action") {}
Austin Schuh1bf8a212019-05-26 22:13:14 -070053
54 static Factory MakeFactory(::aos::EventLoop *event_loop) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070055 return Factory(event_loop, "/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -070056 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -080057
Alex Perrycb7da4b2019-08-28 19:35:56 -070058 bool RunAction(const UInt *) override { return true; }
Ben Fredricksond69f38b2015-01-28 20:06:15 -080059};
60
Ben Fredricksond69f38b2015-01-28 20:06:15 -080061class TestActorShouldCancel
Alex Perrycb7da4b2019-08-28 19:35:56 -070062 : public aos::common::actions::ActorBase<actions::TestActionGoal> {
Ben Fredricksond69f38b2015-01-28 20:06:15 -080063 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070064 typedef TypedActionFactory<actions::TestActionGoal> Factory;
Austin Schuh1bf8a212019-05-26 22:13:14 -070065
66 explicit TestActorShouldCancel(::aos::EventLoop *event_loop)
Alex Perrycb7da4b2019-08-28 19:35:56 -070067 : aos::common::actions::ActorBase<actions::TestActionGoal>(
68 event_loop, "/test_action") {}
Austin Schuh1bf8a212019-05-26 22:13:14 -070069
70 static Factory MakeFactory(::aos::EventLoop *event_loop) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070071 return Factory(event_loop, "/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -070072 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -080073
Alex Perrycb7da4b2019-08-28 19:35:56 -070074 bool RunAction(const UInt *) override {
Ben Fredricksond69f38b2015-01-28 20:06:15 -080075 while (!ShouldCancel()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070076 AOS_LOG(FATAL, "NOT CANCELED!!\n");
Ben Fredricksond69f38b2015-01-28 20:06:15 -080077 }
Daniel Petti3b1e48f2015-02-15 15:57:53 -080078 return true;
Ben Fredricksond69f38b2015-01-28 20:06:15 -080079 }
80};
81
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080082class TestActor2Nop
Alex Perrycb7da4b2019-08-28 19:35:56 -070083 : public aos::common::actions::ActorBase<actions::TestAction2Goal> {
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080084 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070085 typedef TypedActionFactory<actions::TestAction2Goal> Factory;
Austin Schuh1bf8a212019-05-26 22:13:14 -070086
87 explicit TestActor2Nop(::aos::EventLoop *event_loop)
Alex Perrycb7da4b2019-08-28 19:35:56 -070088 : actions::ActorBase<actions::TestAction2Goal>(
89 event_loop, "/test_action2") {}
Austin Schuh1bf8a212019-05-26 22:13:14 -070090
91 static Factory MakeFactory(::aos::EventLoop *event_loop) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070092 return Factory(event_loop, "/test_action2");
Austin Schuh1bf8a212019-05-26 22:13:14 -070093 }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080094
Alex Perrycb7da4b2019-08-28 19:35:56 -070095 bool RunAction(const actions::MyParams *) { return true; }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080096};
97
Ben Fredricksond69f38b2015-01-28 20:06:15 -080098class ActionTest : public ::testing::Test {
99 protected:
Austin Schuh1bf8a212019-05-26 22:13:14 -0700100 ActionTest()
Austin Schuh373f1762021-06-02 21:07:09 -0700101 : configuration_(configuration::ReadConfig(
102 aos::testing::ArtifactPath("aos/actions/action_test_config.json"))),
Alex Perrycb7da4b2019-08-28 19:35:56 -0700103 event_loop_factory_(&configuration_.message()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800104 actor1_event_loop_(event_loop_factory_.MakeEventLoop("actor1")),
105 actor2_event_loop_(event_loop_factory_.MakeEventLoop("actor2")),
Brian Silverman13065ed2020-12-16 15:15:27 -0800106 test_event_loop_(event_loop_factory_.MakeEventLoop("test")) {}
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800107
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800108 void RunAt(monotonic_clock::time_point exec_time, std::function<void()> fn) {
109 TimerHandler *timer = test_event_loop_->AddTimer(fn);
110 test_event_loop_->OnRun([timer, exec_time]() { timer->Setup(exec_time); });
111 }
112
Alex Perrycb7da4b2019-08-28 19:35:56 -0700113 FlatbufferDetachedBuffer<Configuration> configuration_;
114
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800115 // Bring up and down Core.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700116 ::aos::SimulatedEventLoopFactory event_loop_factory_;
117
118 ::std::unique_ptr<::aos::EventLoop> actor1_event_loop_;
119 ::std::unique_ptr<::aos::EventLoop> actor2_event_loop_;
120 ::std::unique_ptr<::aos::EventLoop> test_event_loop_;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800121};
122
123// Tests that the the actions exist in a safe state at startup.
124TEST_F(ActionTest, DoesNothing) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700125 ActionQueue action_queue;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800126 // Tick an empty queue and make sure it was not running.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700127 EXPECT_FALSE(action_queue.Running());
128 action_queue.Tick();
129 EXPECT_FALSE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800130}
131
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700132// Tests that starting with an old run message in the goal queue actually works.
133// This used to result in the client hanging, waiting for a response to its
134// cancel message.
135TEST_F(ActionTest, StartWithOldGoal) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700136 ::std::unique_ptr<::aos::EventLoop> test2_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800137 event_loop_factory_.MakeEventLoop("test2");
Alex Perrycb7da4b2019-08-28 19:35:56 -0700138 ::aos::Sender<TestActionGoal> goal_sender =
139 test2_event_loop->MakeSender<TestActionGoal>("/test_action");
140 ::aos::Fetcher<Status> status_fetcher =
141 test2_event_loop->MakeFetcher<Status>("/test_action");
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700142
Austin Schuh1bf8a212019-05-26 22:13:14 -0700143 TestActorIndex::Factory nop_actor_factory =
144 TestActorNOP::MakeFactory(test_event_loop_.get());
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700145
Austin Schuh1bf8a212019-05-26 22:13:14 -0700146 ActionQueue action_queue;
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700147
Austin Schuh1bf8a212019-05-26 22:13:14 -0700148 {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700149 ::aos::Sender<TestActionGoal>::Builder builder =
150 goal_sender.MakeBuilder();
151
152 TestActionGoal::Builder goal_builder =
153 builder.MakeBuilder<TestActionGoal>();
154
155 goal_builder.add_run(971);
156 ASSERT_TRUE(builder.Send(goal_builder.Finish()));
Austin Schuh1bf8a212019-05-26 22:13:14 -0700157 }
158
159 TestActorNOP nop_act(actor1_event_loop_.get());
160
161 ASSERT_FALSE(status_fetcher.Fetch());
162
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800163 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
164 ASSERT_TRUE(status_fetcher.Fetch());
165 EXPECT_EQ(0u, status_fetcher->running());
166 EXPECT_EQ(0u, status_fetcher->last_running());
Austin Schuh1bf8a212019-05-26 22:13:14 -0700167
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800168 {
169 UIntT uint;
170 uint.val = 0;
171 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
172 }
Austin Schuh1bf8a212019-05-26 22:13:14 -0700173
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800174 // We started an action and it should be running.
175 EXPECT_TRUE(action_queue.Running());
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700176
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800177 action_queue.CancelAllActions();
178 action_queue.Tick();
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700179
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800180 EXPECT_TRUE(action_queue.Running());
181 });
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700182
183 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800184 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
185 action_queue.Tick();
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700186
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800187 // Make sure it stopped.
188 EXPECT_FALSE(action_queue.Running());
189 });
190
191 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800192}
193
194// Tests that an action starts and stops.
195TEST_F(ActionTest, ActionQueueWasRunning) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700196 TestActorNOP nop_act(actor1_event_loop_.get());
197
198 TestActorIndex::Factory nop_actor_factory =
199 TestActorNOP::MakeFactory(test_event_loop_.get());
200
201 ActionQueue action_queue;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800202
203 // Tick an empty queue and make sure it was not running.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800204 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
205 action_queue.Tick();
206 EXPECT_FALSE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800207
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800208 {
209 UIntT uint;
210 uint.val = 0;
211 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
212 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800213
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800214 // We started an action and it should be running.
215 EXPECT_TRUE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800216
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800217 // Tick it and make sure it is still running.
218 action_queue.Tick();
219 EXPECT_TRUE(action_queue.Running());
220 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800221
222 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800223 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
224 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800225
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800226 // Make sure it stopped.
227 EXPECT_FALSE(action_queue.Running());
228 });
229
230 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800231}
232
233// Tests that we can cancel two actions and have them both stop.
234TEST_F(ActionTest, ActionQueueCancelAll) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700235 TestActorNOP nop_act(actor1_event_loop_.get());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800236
Austin Schuh1bf8a212019-05-26 22:13:14 -0700237 TestActorIndex::Factory nop_actor_factory =
238 TestActorNOP::MakeFactory(test_event_loop_.get());
239
240 ActionQueue action_queue;
241
242 // Let the actor and action queue start up and confirm nothing is running.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800243 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
244 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700245
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800246 EXPECT_FALSE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800247
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800248 // Enqueue two actions to test both cancel. We can have an action and a next
249 // action so we want to test that.
250 {
251 UIntT uint;
252 uint.val = 0;
253 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
254 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
255 }
Austin Schuh1bf8a212019-05-26 22:13:14 -0700256
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800257 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800258
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800259 // Check that current and next exist.
260 EXPECT_TRUE(action_queue.GetCurrentActionState(nullptr, nullptr, nullptr,
261 nullptr, nullptr, nullptr));
262 EXPECT_TRUE(action_queue.GetNextActionState(nullptr, nullptr, nullptr,
263 nullptr, nullptr, nullptr));
264
265 action_queue.CancelAllActions();
266 action_queue.Tick();
267
268 // It should still be running as the actor could not have signaled.
269 EXPECT_TRUE(action_queue.Running());
270
271 bool sent_started, sent_cancel, interrupted;
272 EXPECT_TRUE(action_queue.GetCurrentActionState(
273 nullptr, &sent_started, &sent_cancel, &interrupted, nullptr, nullptr));
274 EXPECT_TRUE(sent_started);
275 EXPECT_TRUE(sent_cancel);
276 EXPECT_FALSE(interrupted);
277
278 EXPECT_FALSE(action_queue.GetNextActionState(nullptr, nullptr, nullptr,
Austin Schuh1bf8a212019-05-26 22:13:14 -0700279 nullptr, nullptr, nullptr));
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800280 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800281
282 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800283 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
284 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700285
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800286 // Make sure it stopped.
287 EXPECT_FALSE(action_queue.Running());
288 EXPECT_EQ(1, nop_act.running_count());
289 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800290
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800291 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800292}
293
294// Tests that an action that would block forever stops when canceled.
295TEST_F(ActionTest, ActionQueueCancelOne) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700296 TestActorShouldCancel cancel_act(actor1_event_loop_.get());
297
298 TestActorShouldCancel::Factory cancel_action_factory =
299 TestActorShouldCancel::MakeFactory(test_event_loop_.get());
300
301 ActionQueue action_queue;
302
303 // Let the actor and action queue start up.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800304 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
305 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800306
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800307 // Enqueue blocking action.
308 {
309 UIntT uint;
310 uint.val = 0;
311 action_queue.EnqueueAction(cancel_action_factory.Make(uint));
312 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800313
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800314 action_queue.Tick();
315 EXPECT_TRUE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800316
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800317 // Tell action to cancel.
318 action_queue.CancelCurrentAction();
319 action_queue.Tick();
320 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800321
322 // This will block forever on failure.
323 // TODO(ben): prolly a bad way to fail
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800324 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
325 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800326
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800327 // It should still be running as the actor could not have signalled.
328 EXPECT_FALSE(action_queue.Running());
329 });
330
331 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800332}
333
Austin Schuh1bf8a212019-05-26 22:13:14 -0700334// Tests that 2 actions in a row causes the second one to cancel the first one.
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800335TEST_F(ActionTest, ActionQueueTwoActions) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700336 TestActorNOP nop_actor(actor1_event_loop_.get());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800337
Austin Schuh1bf8a212019-05-26 22:13:14 -0700338 TestActorIndex::Factory nop_actor_factory =
339 TestActorNOP::MakeFactory(test_event_loop_.get());
340
341 ActionQueue action_queue;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800342
343 // id for the first time run.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700344 uint32_t nop_actor_id = 0;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800345 // Check the internal state and write down id for later use.
346 bool sent_started, sent_cancel, interrupted;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800347 // id for the second run.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700348 uint32_t nop_actor2_id = 0;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800349
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800350 // Tick an empty queue and make sure it was not running.
351 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
352 action_queue.Tick();
353 EXPECT_FALSE(action_queue.Running());
354
355 // Enqueue action to be canceled.
356 {
357 UIntT uint;
358 uint.val = 0;
359 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
360 }
361 action_queue.Tick();
362
363 // Should still be running as the actor could not have signalled.
364 EXPECT_TRUE(action_queue.Running());
365
366 EXPECT_TRUE(action_queue.GetCurrentActionState(nullptr, &sent_started,
367 &sent_cancel, &interrupted,
368 &nop_actor_id, nullptr));
369 EXPECT_TRUE(sent_started);
370 EXPECT_FALSE(sent_cancel);
371 EXPECT_FALSE(interrupted);
372 ASSERT_NE(0u, nop_actor_id);
373
374 // Add the next action which should ensure the first stopped.
375 {
376 UIntT uint;
377 uint.val = 0;
378 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
379 }
380
381 // Check the internal state and write down id for later use.
382 EXPECT_TRUE(action_queue.GetNextActionState(nullptr, &sent_started,
383 &sent_cancel, &interrupted,
384 &nop_actor2_id, nullptr));
385 EXPECT_NE(nop_actor_id, nop_actor2_id);
386 EXPECT_FALSE(sent_started);
387 EXPECT_FALSE(sent_cancel);
388 EXPECT_FALSE(interrupted);
389 ASSERT_NE(0u, nop_actor2_id);
390
391 action_queue.Tick();
392 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800393
394 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800395 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
396 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800397
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800398 // Check the new action is the right one.
399 uint32_t test_id = 0;
400 EXPECT_TRUE(action_queue.GetCurrentActionState(
401 nullptr, &sent_started, &sent_cancel, &interrupted, &test_id, nullptr));
402 EXPECT_TRUE(sent_started);
403 EXPECT_FALSE(sent_cancel);
404 EXPECT_FALSE(interrupted);
405 EXPECT_EQ(nop_actor2_id, test_id);
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800406
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800407 // Make sure it is still going.
408 EXPECT_TRUE(action_queue.Running());
409 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800410
Austin Schuh1bf8a212019-05-26 22:13:14 -0700411 // Now let everything finish.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800412 RunAt(monotonic_clock::time_point(chrono::seconds(3)), [&]() {
413 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800414
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800415 // Make sure it stopped.
416 EXPECT_FALSE(action_queue.Running());
417 });
418
419 event_loop_factory_.RunFor(chrono::seconds(4));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800420}
421
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800422// Tests that we do get an index with our goal
423TEST_F(ActionTest, ActionIndex) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700424 TestActorIndex idx_actor(actor1_event_loop_.get());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800425
Austin Schuh1bf8a212019-05-26 22:13:14 -0700426 TestActorIndex::Factory test_actor_index_factory =
427 TestActorIndex::MakeFactory(test_event_loop_.get());
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800428 ::aos::Fetcher<actions::TestActionGoal> goal_fetcher_ =
429 test_event_loop_->MakeFetcher<actions::TestActionGoal>("/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -0700430
431 ActionQueue action_queue;
432 // Tick an empty queue and make sure it was not running. Also tick the
433 // factory to allow it to send out the initial cancel message.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800434 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
435 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700436
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800437 EXPECT_FALSE(action_queue.Running());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800438
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800439 // Enqueue action to post index.
440 {
441 UIntT uint;
442 uint.val = 5;
443 action_queue.EnqueueAction(test_actor_index_factory.Make(uint));
444 }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800445
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800446 ASSERT_TRUE(goal_fetcher_.Fetch());
447 EXPECT_EQ(5u, goal_fetcher_->params()->val());
448 EXPECT_EQ(0u, idx_actor.index);
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800449
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800450 action_queue.Tick();
451 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800452
453 // Run the next action so it can accomplish signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800454 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
455 action_queue.Tick();
456 EXPECT_EQ(5u, idx_actor.index);
Austin Schuh1bf8a212019-05-26 22:13:14 -0700457
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800458 // Enqueue action to post index.
459 {
460 UIntT uint;
461 uint.val = 3;
462 action_queue.EnqueueAction(test_actor_index_factory.Make(uint));
463 }
464 ASSERT_TRUE(goal_fetcher_.Fetch());
465 EXPECT_EQ(3u, goal_fetcher_->params()->val());
466 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800467
468 // Run the next action so it can accomplish signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800469 RunAt(monotonic_clock::time_point(chrono::seconds(3)), [&]() {
470 action_queue.Tick();
471 EXPECT_EQ(3u, idx_actor.index);
472 });
Austin Schuh1bf8a212019-05-26 22:13:14 -0700473
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800474 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800475}
476
477// Tests that an action with a structure params works.
478TEST_F(ActionTest, StructParamType) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700479 TestActor2Nop nop_actor(actor2_event_loop_.get());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800480
Austin Schuh1bf8a212019-05-26 22:13:14 -0700481 TestActor2Nop::Factory test_action_2_nop_factory =
482 TestActor2Nop::MakeFactory(test_event_loop_.get());
483
484 ActionQueue action_queue;
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800485
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800486 RunAt(monotonic_clock::time_point(chrono::seconds(0)), [&]() {
487 // Tick an empty queue and make sure it was not running.
488 action_queue.Tick();
489 EXPECT_FALSE(action_queue.Running());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800490
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800491 actions::MyParamsT p;
492 p.param1 = 5.0;
493 p.param2 = 7;
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800494
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800495 action_queue.EnqueueAction(test_action_2_nop_factory.Make(p));
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800496
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800497 // We started an action and it should be running.
498 EXPECT_TRUE(action_queue.Running());
499
500 // Tick it and make sure it is still running.
501 action_queue.Tick();
502 EXPECT_TRUE(action_queue.Running());
503 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800504
505 // Run the action so it can signal completion.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700506 // The actor takes no time, but running for a second is the best way to get it
507 // to go.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800508 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
509 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700510
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800511 // Make sure it stopped.
512 EXPECT_FALSE(action_queue.Running());
513 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800514
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800515 event_loop_factory_.RunFor(chrono::seconds(2));
Brian Silverman237a5542015-03-29 17:59:29 -0400516}
517
518} // namespace testing
519} // namespace actions
520} // namespace common
521} // namespace aos