blob: c7c3c482c2969d89ca56b278d4712dd542580ffe [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
Philipp Schrader790cb542023-07-05 21:06:52 -07007#include "gtest/gtest.h"
8
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
Stephan Pleinesf63bde82024-01-13 15:59:33 -080016namespace aos::common::actions::testing {
Ben Fredricksond69f38b2015-01-28 20:06:15 -080017
Austin Schuhf2a50ba2016-12-24 16:16:26 -080018namespace chrono = ::std::chrono;
19
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080020class TestActorIndex
Alex Perrycb7da4b2019-08-28 19:35:56 -070021 : public aos::common::actions::ActorBase<actions::TestActionGoal> {
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080022 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070023 typedef TypedActionFactory<actions::TestActionGoal> Factory;
Austin Schuh1bf8a212019-05-26 22:13:14 -070024
25 explicit TestActorIndex(::aos::EventLoop *event_loop)
Alex Perrycb7da4b2019-08-28 19:35:56 -070026 : aos::common::actions::ActorBase<actions::TestActionGoal>(
27 event_loop, "/test_action") {}
Austin Schuh1bf8a212019-05-26 22:13:14 -070028
29 static Factory MakeFactory(::aos::EventLoop *event_loop) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070030 return Factory(event_loop, "/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -070031 }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080032
Alex Perrycb7da4b2019-08-28 19:35:56 -070033 bool RunAction(const UInt *new_index) override {
34 VLOG(1) << "New index " << FlatbufferToJson(new_index);
35 index = new_index->val();
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080036 return true;
37 }
38
39 uint32_t index = 0;
40};
41
Ben Fredricksond69f38b2015-01-28 20:06:15 -080042class TestActorNOP
Alex Perrycb7da4b2019-08-28 19:35:56 -070043 : public aos::common::actions::ActorBase<actions::TestActionGoal> {
Ben Fredricksond69f38b2015-01-28 20:06:15 -080044 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070045 typedef TypedActionFactory<actions::TestActionGoal> Factory;
Austin Schuh1bf8a212019-05-26 22:13:14 -070046
47 explicit TestActorNOP(::aos::EventLoop *event_loop)
milind1f1dca32021-07-03 13:50:07 -070048 : actions::ActorBase<actions::TestActionGoal>(event_loop,
49 "/test_action") {}
Austin Schuh1bf8a212019-05-26 22:13:14 -070050
51 static Factory MakeFactory(::aos::EventLoop *event_loop) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070052 return Factory(event_loop, "/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -070053 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -080054
Alex Perrycb7da4b2019-08-28 19:35:56 -070055 bool RunAction(const UInt *) override { return true; }
Ben Fredricksond69f38b2015-01-28 20:06:15 -080056};
57
Ben Fredricksond69f38b2015-01-28 20:06:15 -080058class TestActorShouldCancel
Alex Perrycb7da4b2019-08-28 19:35:56 -070059 : public aos::common::actions::ActorBase<actions::TestActionGoal> {
Ben Fredricksond69f38b2015-01-28 20:06:15 -080060 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070061 typedef TypedActionFactory<actions::TestActionGoal> Factory;
Austin Schuh1bf8a212019-05-26 22:13:14 -070062
63 explicit TestActorShouldCancel(::aos::EventLoop *event_loop)
Alex Perrycb7da4b2019-08-28 19:35:56 -070064 : aos::common::actions::ActorBase<actions::TestActionGoal>(
65 event_loop, "/test_action") {}
Austin Schuh1bf8a212019-05-26 22:13:14 -070066
67 static Factory MakeFactory(::aos::EventLoop *event_loop) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070068 return Factory(event_loop, "/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -070069 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -080070
Alex Perrycb7da4b2019-08-28 19:35:56 -070071 bool RunAction(const UInt *) override {
Ben Fredricksond69f38b2015-01-28 20:06:15 -080072 while (!ShouldCancel()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070073 AOS_LOG(FATAL, "NOT CANCELED!!\n");
Ben Fredricksond69f38b2015-01-28 20:06:15 -080074 }
Daniel Petti3b1e48f2015-02-15 15:57:53 -080075 return true;
Ben Fredricksond69f38b2015-01-28 20:06:15 -080076 }
77};
78
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080079class TestActor2Nop
Alex Perrycb7da4b2019-08-28 19:35:56 -070080 : public aos::common::actions::ActorBase<actions::TestAction2Goal> {
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080081 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070082 typedef TypedActionFactory<actions::TestAction2Goal> Factory;
Austin Schuh1bf8a212019-05-26 22:13:14 -070083
84 explicit TestActor2Nop(::aos::EventLoop *event_loop)
milind1f1dca32021-07-03 13:50:07 -070085 : actions::ActorBase<actions::TestAction2Goal>(event_loop,
86 "/test_action2") {}
Austin Schuh1bf8a212019-05-26 22:13:14 -070087
88 static Factory MakeFactory(::aos::EventLoop *event_loop) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070089 return Factory(event_loop, "/test_action2");
Austin Schuh1bf8a212019-05-26 22:13:14 -070090 }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080091
Alex Perrycb7da4b2019-08-28 19:35:56 -070092 bool RunAction(const actions::MyParams *) { return true; }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080093};
94
Ben Fredricksond69f38b2015-01-28 20:06:15 -080095class ActionTest : public ::testing::Test {
96 protected:
Austin Schuh1bf8a212019-05-26 22:13:14 -070097 ActionTest()
Austin Schuh373f1762021-06-02 21:07:09 -070098 : configuration_(configuration::ReadConfig(
99 aos::testing::ArtifactPath("aos/actions/action_test_config.json"))),
Alex Perrycb7da4b2019-08-28 19:35:56 -0700100 event_loop_factory_(&configuration_.message()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800101 actor1_event_loop_(event_loop_factory_.MakeEventLoop("actor1")),
102 actor2_event_loop_(event_loop_factory_.MakeEventLoop("actor2")),
Brian Silverman13065ed2020-12-16 15:15:27 -0800103 test_event_loop_(event_loop_factory_.MakeEventLoop("test")) {}
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800104
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800105 void RunAt(monotonic_clock::time_point exec_time, std::function<void()> fn) {
106 TimerHandler *timer = test_event_loop_->AddTimer(fn);
Philipp Schradera6712522023-07-05 20:25:11 -0700107 test_event_loop_->OnRun(
108 [timer, exec_time]() { timer->Schedule(exec_time); });
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800109 }
110
Alex Perrycb7da4b2019-08-28 19:35:56 -0700111 FlatbufferDetachedBuffer<Configuration> configuration_;
112
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800113 // Bring up and down Core.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700114 ::aos::SimulatedEventLoopFactory event_loop_factory_;
115
116 ::std::unique_ptr<::aos::EventLoop> actor1_event_loop_;
117 ::std::unique_ptr<::aos::EventLoop> actor2_event_loop_;
118 ::std::unique_ptr<::aos::EventLoop> test_event_loop_;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800119};
120
121// Tests that the the actions exist in a safe state at startup.
122TEST_F(ActionTest, DoesNothing) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700123 ActionQueue action_queue;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800124 // Tick an empty queue and make sure it was not running.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700125 EXPECT_FALSE(action_queue.Running());
126 action_queue.Tick();
127 EXPECT_FALSE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800128}
129
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700130// Tests that starting with an old run message in the goal queue actually works.
131// This used to result in the client hanging, waiting for a response to its
132// cancel message.
133TEST_F(ActionTest, StartWithOldGoal) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700134 ::std::unique_ptr<::aos::EventLoop> test2_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800135 event_loop_factory_.MakeEventLoop("test2");
Alex Perrycb7da4b2019-08-28 19:35:56 -0700136 ::aos::Sender<TestActionGoal> goal_sender =
137 test2_event_loop->MakeSender<TestActionGoal>("/test_action");
138 ::aos::Fetcher<Status> status_fetcher =
139 test2_event_loop->MakeFetcher<Status>("/test_action");
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700140
Austin Schuh1bf8a212019-05-26 22:13:14 -0700141 TestActorIndex::Factory nop_actor_factory =
142 TestActorNOP::MakeFactory(test_event_loop_.get());
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700143
Austin Schuh1bf8a212019-05-26 22:13:14 -0700144 ActionQueue action_queue;
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700145
Austin Schuh1bf8a212019-05-26 22:13:14 -0700146 {
milind1f1dca32021-07-03 13:50:07 -0700147 ::aos::Sender<TestActionGoal>::Builder builder = goal_sender.MakeBuilder();
Alex Perrycb7da4b2019-08-28 19:35:56 -0700148
149 TestActionGoal::Builder goal_builder =
150 builder.MakeBuilder<TestActionGoal>();
151
152 goal_builder.add_run(971);
milind1f1dca32021-07-03 13:50:07 -0700153 builder.CheckOk(builder.Send(goal_builder.Finish()));
Austin Schuh1bf8a212019-05-26 22:13:14 -0700154 }
155
156 TestActorNOP nop_act(actor1_event_loop_.get());
157
158 ASSERT_FALSE(status_fetcher.Fetch());
159
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800160 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
161 ASSERT_TRUE(status_fetcher.Fetch());
162 EXPECT_EQ(0u, status_fetcher->running());
163 EXPECT_EQ(0u, status_fetcher->last_running());
Austin Schuh1bf8a212019-05-26 22:13:14 -0700164
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800165 {
166 UIntT uint;
167 uint.val = 0;
168 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
169 }
Austin Schuh1bf8a212019-05-26 22:13:14 -0700170
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800171 // We started an action and it should be running.
172 EXPECT_TRUE(action_queue.Running());
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700173
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800174 action_queue.CancelAllActions();
175 action_queue.Tick();
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700176
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800177 EXPECT_TRUE(action_queue.Running());
178 });
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700179
180 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800181 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
182 action_queue.Tick();
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700183
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800184 // Make sure it stopped.
185 EXPECT_FALSE(action_queue.Running());
186 });
187
188 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800189}
190
191// Tests that an action starts and stops.
192TEST_F(ActionTest, ActionQueueWasRunning) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700193 TestActorNOP nop_act(actor1_event_loop_.get());
194
195 TestActorIndex::Factory nop_actor_factory =
196 TestActorNOP::MakeFactory(test_event_loop_.get());
197
198 ActionQueue action_queue;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800199
200 // Tick an empty queue and make sure it was not running.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800201 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
202 action_queue.Tick();
203 EXPECT_FALSE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800204
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800205 {
206 UIntT uint;
207 uint.val = 0;
208 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
209 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800210
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800211 // We started an action and it should be running.
212 EXPECT_TRUE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800213
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800214 // Tick it and make sure it is still running.
215 action_queue.Tick();
216 EXPECT_TRUE(action_queue.Running());
217 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800218
219 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800220 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
221 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800222
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800223 // Make sure it stopped.
224 EXPECT_FALSE(action_queue.Running());
225 });
226
227 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800228}
229
230// Tests that we can cancel two actions and have them both stop.
231TEST_F(ActionTest, ActionQueueCancelAll) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700232 TestActorNOP nop_act(actor1_event_loop_.get());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800233
Austin Schuh1bf8a212019-05-26 22:13:14 -0700234 TestActorIndex::Factory nop_actor_factory =
235 TestActorNOP::MakeFactory(test_event_loop_.get());
236
237 ActionQueue action_queue;
238
239 // Let the actor and action queue start up and confirm nothing is running.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800240 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
241 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700242
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800243 EXPECT_FALSE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800244
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800245 // Enqueue two actions to test both cancel. We can have an action and a next
246 // action so we want to test that.
247 {
248 UIntT uint;
249 uint.val = 0;
250 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
251 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
252 }
Austin Schuh1bf8a212019-05-26 22:13:14 -0700253
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800254 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800255
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800256 // Check that current and next exist.
257 EXPECT_TRUE(action_queue.GetCurrentActionState(nullptr, nullptr, nullptr,
258 nullptr, nullptr, nullptr));
259 EXPECT_TRUE(action_queue.GetNextActionState(nullptr, nullptr, nullptr,
260 nullptr, nullptr, nullptr));
261
262 action_queue.CancelAllActions();
263 action_queue.Tick();
264
265 // It should still be running as the actor could not have signaled.
266 EXPECT_TRUE(action_queue.Running());
267
268 bool sent_started, sent_cancel, interrupted;
269 EXPECT_TRUE(action_queue.GetCurrentActionState(
270 nullptr, &sent_started, &sent_cancel, &interrupted, nullptr, nullptr));
271 EXPECT_TRUE(sent_started);
272 EXPECT_TRUE(sent_cancel);
273 EXPECT_FALSE(interrupted);
274
275 EXPECT_FALSE(action_queue.GetNextActionState(nullptr, nullptr, nullptr,
Austin Schuh1bf8a212019-05-26 22:13:14 -0700276 nullptr, nullptr, nullptr));
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800277 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800278
279 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800280 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
281 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700282
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800283 // Make sure it stopped.
284 EXPECT_FALSE(action_queue.Running());
285 EXPECT_EQ(1, nop_act.running_count());
286 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800287
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800288 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800289}
290
291// Tests that an action that would block forever stops when canceled.
292TEST_F(ActionTest, ActionQueueCancelOne) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700293 TestActorShouldCancel cancel_act(actor1_event_loop_.get());
294
295 TestActorShouldCancel::Factory cancel_action_factory =
296 TestActorShouldCancel::MakeFactory(test_event_loop_.get());
297
298 ActionQueue action_queue;
299
300 // Let the actor and action queue start up.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800301 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
302 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800303
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800304 // Enqueue blocking action.
305 {
306 UIntT uint;
307 uint.val = 0;
308 action_queue.EnqueueAction(cancel_action_factory.Make(uint));
309 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800310
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800311 action_queue.Tick();
312 EXPECT_TRUE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800313
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800314 // Tell action to cancel.
315 action_queue.CancelCurrentAction();
316 action_queue.Tick();
317 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800318
319 // This will block forever on failure.
320 // TODO(ben): prolly a bad way to fail
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800321 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
322 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800323
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800324 // It should still be running as the actor could not have signalled.
325 EXPECT_FALSE(action_queue.Running());
326 });
327
328 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800329}
330
Austin Schuh1bf8a212019-05-26 22:13:14 -0700331// Tests that 2 actions in a row causes the second one to cancel the first one.
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800332TEST_F(ActionTest, ActionQueueTwoActions) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700333 TestActorNOP nop_actor(actor1_event_loop_.get());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800334
Austin Schuh1bf8a212019-05-26 22:13:14 -0700335 TestActorIndex::Factory nop_actor_factory =
336 TestActorNOP::MakeFactory(test_event_loop_.get());
337
338 ActionQueue action_queue;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800339
340 // id for the first time run.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700341 uint32_t nop_actor_id = 0;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800342 // Check the internal state and write down id for later use.
343 bool sent_started, sent_cancel, interrupted;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800344 // id for the second run.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700345 uint32_t nop_actor2_id = 0;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800346
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800347 // Tick an empty queue and make sure it was not running.
348 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
349 action_queue.Tick();
350 EXPECT_FALSE(action_queue.Running());
351
352 // Enqueue action to be canceled.
353 {
354 UIntT uint;
355 uint.val = 0;
356 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
357 }
358 action_queue.Tick();
359
360 // Should still be running as the actor could not have signalled.
361 EXPECT_TRUE(action_queue.Running());
362
363 EXPECT_TRUE(action_queue.GetCurrentActionState(nullptr, &sent_started,
364 &sent_cancel, &interrupted,
365 &nop_actor_id, nullptr));
366 EXPECT_TRUE(sent_started);
367 EXPECT_FALSE(sent_cancel);
368 EXPECT_FALSE(interrupted);
369 ASSERT_NE(0u, nop_actor_id);
370
371 // Add the next action which should ensure the first stopped.
372 {
373 UIntT uint;
374 uint.val = 0;
375 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
376 }
377
378 // Check the internal state and write down id for later use.
379 EXPECT_TRUE(action_queue.GetNextActionState(nullptr, &sent_started,
380 &sent_cancel, &interrupted,
381 &nop_actor2_id, nullptr));
382 EXPECT_NE(nop_actor_id, nop_actor2_id);
383 EXPECT_FALSE(sent_started);
384 EXPECT_FALSE(sent_cancel);
385 EXPECT_FALSE(interrupted);
386 ASSERT_NE(0u, nop_actor2_id);
387
388 action_queue.Tick();
389 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800390
391 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800392 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
393 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800394
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800395 // Check the new action is the right one.
396 uint32_t test_id = 0;
397 EXPECT_TRUE(action_queue.GetCurrentActionState(
398 nullptr, &sent_started, &sent_cancel, &interrupted, &test_id, nullptr));
399 EXPECT_TRUE(sent_started);
400 EXPECT_FALSE(sent_cancel);
401 EXPECT_FALSE(interrupted);
402 EXPECT_EQ(nop_actor2_id, test_id);
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800403
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800404 // Make sure it is still going.
405 EXPECT_TRUE(action_queue.Running());
406 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800407
Austin Schuh1bf8a212019-05-26 22:13:14 -0700408 // Now let everything finish.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800409 RunAt(monotonic_clock::time_point(chrono::seconds(3)), [&]() {
410 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800411
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800412 // Make sure it stopped.
413 EXPECT_FALSE(action_queue.Running());
414 });
415
416 event_loop_factory_.RunFor(chrono::seconds(4));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800417}
418
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800419// Tests that we do get an index with our goal
420TEST_F(ActionTest, ActionIndex) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700421 TestActorIndex idx_actor(actor1_event_loop_.get());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800422
Austin Schuh1bf8a212019-05-26 22:13:14 -0700423 TestActorIndex::Factory test_actor_index_factory =
424 TestActorIndex::MakeFactory(test_event_loop_.get());
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800425 ::aos::Fetcher<actions::TestActionGoal> goal_fetcher_ =
426 test_event_loop_->MakeFetcher<actions::TestActionGoal>("/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -0700427
428 ActionQueue action_queue;
429 // Tick an empty queue and make sure it was not running. Also tick the
430 // factory to allow it to send out the initial cancel message.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800431 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
432 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700433
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800434 EXPECT_FALSE(action_queue.Running());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800435
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800436 // Enqueue action to post index.
437 {
438 UIntT uint;
439 uint.val = 5;
440 action_queue.EnqueueAction(test_actor_index_factory.Make(uint));
441 }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800442
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800443 ASSERT_TRUE(goal_fetcher_.Fetch());
444 EXPECT_EQ(5u, goal_fetcher_->params()->val());
445 EXPECT_EQ(0u, idx_actor.index);
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800446
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800447 action_queue.Tick();
448 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800449
450 // Run the next action so it can accomplish signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800451 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
452 action_queue.Tick();
453 EXPECT_EQ(5u, idx_actor.index);
Austin Schuh1bf8a212019-05-26 22:13:14 -0700454
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800455 // Enqueue action to post index.
456 {
457 UIntT uint;
458 uint.val = 3;
459 action_queue.EnqueueAction(test_actor_index_factory.Make(uint));
460 }
461 ASSERT_TRUE(goal_fetcher_.Fetch());
462 EXPECT_EQ(3u, goal_fetcher_->params()->val());
463 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800464
465 // Run the next action so it can accomplish signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800466 RunAt(monotonic_clock::time_point(chrono::seconds(3)), [&]() {
467 action_queue.Tick();
468 EXPECT_EQ(3u, idx_actor.index);
469 });
Austin Schuh1bf8a212019-05-26 22:13:14 -0700470
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800471 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800472}
473
474// Tests that an action with a structure params works.
475TEST_F(ActionTest, StructParamType) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700476 TestActor2Nop nop_actor(actor2_event_loop_.get());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800477
Austin Schuh1bf8a212019-05-26 22:13:14 -0700478 TestActor2Nop::Factory test_action_2_nop_factory =
479 TestActor2Nop::MakeFactory(test_event_loop_.get());
480
481 ActionQueue action_queue;
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800482
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800483 RunAt(monotonic_clock::time_point(chrono::seconds(0)), [&]() {
484 // Tick an empty queue and make sure it was not running.
485 action_queue.Tick();
486 EXPECT_FALSE(action_queue.Running());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800487
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800488 actions::MyParamsT p;
489 p.param1 = 5.0;
490 p.param2 = 7;
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800491
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800492 action_queue.EnqueueAction(test_action_2_nop_factory.Make(p));
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800493
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800494 // We started an action and it should be running.
495 EXPECT_TRUE(action_queue.Running());
496
497 // Tick it and make sure it is still running.
498 action_queue.Tick();
499 EXPECT_TRUE(action_queue.Running());
500 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800501
502 // Run the action so it can signal completion.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700503 // The actor takes no time, but running for a second is the best way to get it
504 // to go.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800505 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
506 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700507
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800508 // Make sure it stopped.
509 EXPECT_FALSE(action_queue.Running());
510 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800511
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800512 event_loop_factory_.RunFor(chrono::seconds(2));
Brian Silverman237a5542015-03-29 17:59:29 -0400513}
514
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800515} // namespace aos::common::actions::testing