blob: 3d6a199605d0416ad66a2eac489d73a3ebc25162 [file] [log] [blame]
Stephan Pleinesbad70072024-05-22 16:48:01 -07001#include <stdint.h>
Ben Fredricksond69f38b2015-01-28 20:06:15 -08002
milind1f1dca32021-07-03 13:50:07 -07003#include <chrono>
Stephan Pleinesbad70072024-05-22 16:48:01 -07004#include <functional>
Ben Fredricksond69f38b2015-01-28 20:06:15 -08005#include <memory>
Stephan Pleinesbad70072024-05-22 16:48:01 -07006#include <ostream>
7#include <string>
Ben Fredricksond69f38b2015-01-28 20:06:15 -08008
Austin Schuh99f7c6a2024-06-25 22:07:44 -07009#include "absl/log/check.h"
10#include "absl/log/log.h"
Stephan Pleinesbad70072024-05-22 16:48:01 -070011#include "flatbuffers/buffer.h"
Philipp Schrader790cb542023-07-05 21:06:52 -070012#include "gtest/gtest.h"
13
John Park33858a32018-09-28 23:05:48 -070014#include "aos/actions/actions.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070015#include "aos/actions/actions_generated.h"
Austin Schuh1bf8a212019-05-26 22:13:14 -070016#include "aos/actions/actor.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070017#include "aos/actions/test_action_generated.h"
Stephan Pleinesbad70072024-05-22 16:48:01 -070018#include "aos/configuration.h"
19#include "aos/events/event_loop.h"
Alex Perrycb7da4b2019-08-28 19:35:56 -070020#include "aos/events/simulated_event_loop.h"
Stephan Pleinesbad70072024-05-22 16:48:01 -070021#include "aos/flatbuffers.h"
22#include "aos/json_to_flatbuffer.h"
23#include "aos/logging/implementations.h"
Austin Schuh373f1762021-06-02 21:07:09 -070024#include "aos/testing/path.h"
Stephan Pleinesbad70072024-05-22 16:48:01 -070025#include "aos/time/time.h"
Ben Fredricksond69f38b2015-01-28 20:06:15 -080026
Stephan Pleinesf63bde82024-01-13 15:59:33 -080027namespace aos::common::actions::testing {
Ben Fredricksond69f38b2015-01-28 20:06:15 -080028
Austin Schuhf2a50ba2016-12-24 16:16:26 -080029namespace chrono = ::std::chrono;
30
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080031class TestActorIndex
Alex Perrycb7da4b2019-08-28 19:35:56 -070032 : public aos::common::actions::ActorBase<actions::TestActionGoal> {
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080033 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070034 typedef TypedActionFactory<actions::TestActionGoal> Factory;
Austin Schuh1bf8a212019-05-26 22:13:14 -070035
36 explicit TestActorIndex(::aos::EventLoop *event_loop)
Alex Perrycb7da4b2019-08-28 19:35:56 -070037 : aos::common::actions::ActorBase<actions::TestActionGoal>(
38 event_loop, "/test_action") {}
Austin Schuh1bf8a212019-05-26 22:13:14 -070039
40 static Factory MakeFactory(::aos::EventLoop *event_loop) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070041 return Factory(event_loop, "/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -070042 }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080043
Alex Perrycb7da4b2019-08-28 19:35:56 -070044 bool RunAction(const UInt *new_index) override {
45 VLOG(1) << "New index " << FlatbufferToJson(new_index);
46 index = new_index->val();
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080047 return true;
48 }
49
50 uint32_t index = 0;
51};
52
Ben Fredricksond69f38b2015-01-28 20:06:15 -080053class TestActorNOP
Alex Perrycb7da4b2019-08-28 19:35:56 -070054 : public aos::common::actions::ActorBase<actions::TestActionGoal> {
Ben Fredricksond69f38b2015-01-28 20:06:15 -080055 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070056 typedef TypedActionFactory<actions::TestActionGoal> Factory;
Austin Schuh1bf8a212019-05-26 22:13:14 -070057
58 explicit TestActorNOP(::aos::EventLoop *event_loop)
milind1f1dca32021-07-03 13:50:07 -070059 : actions::ActorBase<actions::TestActionGoal>(event_loop,
60 "/test_action") {}
Austin Schuh1bf8a212019-05-26 22:13:14 -070061
62 static Factory MakeFactory(::aos::EventLoop *event_loop) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070063 return Factory(event_loop, "/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -070064 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -080065
Alex Perrycb7da4b2019-08-28 19:35:56 -070066 bool RunAction(const UInt *) override { return true; }
Ben Fredricksond69f38b2015-01-28 20:06:15 -080067};
68
Ben Fredricksond69f38b2015-01-28 20:06:15 -080069class TestActorShouldCancel
Alex Perrycb7da4b2019-08-28 19:35:56 -070070 : public aos::common::actions::ActorBase<actions::TestActionGoal> {
Ben Fredricksond69f38b2015-01-28 20:06:15 -080071 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070072 typedef TypedActionFactory<actions::TestActionGoal> Factory;
Austin Schuh1bf8a212019-05-26 22:13:14 -070073
74 explicit TestActorShouldCancel(::aos::EventLoop *event_loop)
Alex Perrycb7da4b2019-08-28 19:35:56 -070075 : aos::common::actions::ActorBase<actions::TestActionGoal>(
76 event_loop, "/test_action") {}
Austin Schuh1bf8a212019-05-26 22:13:14 -070077
78 static Factory MakeFactory(::aos::EventLoop *event_loop) {
Alex Perrycb7da4b2019-08-28 19:35:56 -070079 return Factory(event_loop, "/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -070080 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -080081
Alex Perrycb7da4b2019-08-28 19:35:56 -070082 bool RunAction(const UInt *) override {
Ben Fredricksond69f38b2015-01-28 20:06:15 -080083 while (!ShouldCancel()) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070084 AOS_LOG(FATAL, "NOT CANCELED!!\n");
Ben Fredricksond69f38b2015-01-28 20:06:15 -080085 }
Daniel Petti3b1e48f2015-02-15 15:57:53 -080086 return true;
Ben Fredricksond69f38b2015-01-28 20:06:15 -080087 }
88};
89
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080090class TestActor2Nop
Alex Perrycb7da4b2019-08-28 19:35:56 -070091 : public aos::common::actions::ActorBase<actions::TestAction2Goal> {
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -080092 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070093 typedef TypedActionFactory<actions::TestAction2Goal> Factory;
Austin Schuh1bf8a212019-05-26 22:13:14 -070094
95 explicit TestActor2Nop(::aos::EventLoop *event_loop)
milind1f1dca32021-07-03 13:50:07 -070096 : actions::ActorBase<actions::TestAction2Goal>(event_loop,
97 "/test_action2") {}
Austin Schuh1bf8a212019-05-26 22:13:14 -070098
99 static Factory MakeFactory(::aos::EventLoop *event_loop) {
Alex Perrycb7da4b2019-08-28 19:35:56 -0700100 return Factory(event_loop, "/test_action2");
Austin Schuh1bf8a212019-05-26 22:13:14 -0700101 }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800102
Alex Perrycb7da4b2019-08-28 19:35:56 -0700103 bool RunAction(const actions::MyParams *) { return true; }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800104};
105
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800106class ActionTest : public ::testing::Test {
107 protected:
Austin Schuh1bf8a212019-05-26 22:13:14 -0700108 ActionTest()
Austin Schuh373f1762021-06-02 21:07:09 -0700109 : configuration_(configuration::ReadConfig(
110 aos::testing::ArtifactPath("aos/actions/action_test_config.json"))),
Alex Perrycb7da4b2019-08-28 19:35:56 -0700111 event_loop_factory_(&configuration_.message()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800112 actor1_event_loop_(event_loop_factory_.MakeEventLoop("actor1")),
113 actor2_event_loop_(event_loop_factory_.MakeEventLoop("actor2")),
Brian Silverman13065ed2020-12-16 15:15:27 -0800114 test_event_loop_(event_loop_factory_.MakeEventLoop("test")) {}
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800115
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800116 void RunAt(monotonic_clock::time_point exec_time, std::function<void()> fn) {
117 TimerHandler *timer = test_event_loop_->AddTimer(fn);
Philipp Schradera6712522023-07-05 20:25:11 -0700118 test_event_loop_->OnRun(
119 [timer, exec_time]() { timer->Schedule(exec_time); });
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800120 }
121
Alex Perrycb7da4b2019-08-28 19:35:56 -0700122 FlatbufferDetachedBuffer<Configuration> configuration_;
123
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800124 // Bring up and down Core.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700125 ::aos::SimulatedEventLoopFactory event_loop_factory_;
126
127 ::std::unique_ptr<::aos::EventLoop> actor1_event_loop_;
128 ::std::unique_ptr<::aos::EventLoop> actor2_event_loop_;
129 ::std::unique_ptr<::aos::EventLoop> test_event_loop_;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800130};
131
132// Tests that the the actions exist in a safe state at startup.
133TEST_F(ActionTest, DoesNothing) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700134 ActionQueue action_queue;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800135 // Tick an empty queue and make sure it was not running.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700136 EXPECT_FALSE(action_queue.Running());
137 action_queue.Tick();
138 EXPECT_FALSE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800139}
140
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700141// Tests that starting with an old run message in the goal queue actually works.
142// This used to result in the client hanging, waiting for a response to its
143// cancel message.
144TEST_F(ActionTest, StartWithOldGoal) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700145 ::std::unique_ptr<::aos::EventLoop> test2_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800146 event_loop_factory_.MakeEventLoop("test2");
Alex Perrycb7da4b2019-08-28 19:35:56 -0700147 ::aos::Sender<TestActionGoal> goal_sender =
148 test2_event_loop->MakeSender<TestActionGoal>("/test_action");
149 ::aos::Fetcher<Status> status_fetcher =
150 test2_event_loop->MakeFetcher<Status>("/test_action");
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700151
Austin Schuh1bf8a212019-05-26 22:13:14 -0700152 TestActorIndex::Factory nop_actor_factory =
153 TestActorNOP::MakeFactory(test_event_loop_.get());
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700154
Austin Schuh1bf8a212019-05-26 22:13:14 -0700155 ActionQueue action_queue;
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700156
Austin Schuh1bf8a212019-05-26 22:13:14 -0700157 {
milind1f1dca32021-07-03 13:50:07 -0700158 ::aos::Sender<TestActionGoal>::Builder builder = goal_sender.MakeBuilder();
Alex Perrycb7da4b2019-08-28 19:35:56 -0700159
160 TestActionGoal::Builder goal_builder =
161 builder.MakeBuilder<TestActionGoal>();
162
163 goal_builder.add_run(971);
milind1f1dca32021-07-03 13:50:07 -0700164 builder.CheckOk(builder.Send(goal_builder.Finish()));
Austin Schuh1bf8a212019-05-26 22:13:14 -0700165 }
166
167 TestActorNOP nop_act(actor1_event_loop_.get());
168
169 ASSERT_FALSE(status_fetcher.Fetch());
170
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800171 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
172 ASSERT_TRUE(status_fetcher.Fetch());
173 EXPECT_EQ(0u, status_fetcher->running());
174 EXPECT_EQ(0u, status_fetcher->last_running());
Austin Schuh1bf8a212019-05-26 22:13:14 -0700175
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800176 {
177 UIntT uint;
178 uint.val = 0;
179 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
180 }
Austin Schuh1bf8a212019-05-26 22:13:14 -0700181
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800182 // We started an action and it should be running.
183 EXPECT_TRUE(action_queue.Running());
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700184
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800185 action_queue.CancelAllActions();
186 action_queue.Tick();
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700187
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800188 EXPECT_TRUE(action_queue.Running());
189 });
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700190
191 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800192 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
193 action_queue.Tick();
Brian Silvermana2ae62d2015-03-15 15:55:22 -0700194
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800195 // Make sure it stopped.
196 EXPECT_FALSE(action_queue.Running());
197 });
198
199 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800200}
201
202// Tests that an action starts and stops.
203TEST_F(ActionTest, ActionQueueWasRunning) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700204 TestActorNOP nop_act(actor1_event_loop_.get());
205
206 TestActorIndex::Factory nop_actor_factory =
207 TestActorNOP::MakeFactory(test_event_loop_.get());
208
209 ActionQueue action_queue;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800210
211 // Tick an empty queue and make sure it was not running.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800212 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
213 action_queue.Tick();
214 EXPECT_FALSE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800215
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800216 {
217 UIntT uint;
218 uint.val = 0;
219 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
220 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800221
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800222 // We started an action and it should be running.
223 EXPECT_TRUE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800224
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800225 // Tick it and make sure it is still running.
226 action_queue.Tick();
227 EXPECT_TRUE(action_queue.Running());
228 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800229
230 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800231 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
232 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800233
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800234 // Make sure it stopped.
235 EXPECT_FALSE(action_queue.Running());
236 });
237
238 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800239}
240
241// Tests that we can cancel two actions and have them both stop.
242TEST_F(ActionTest, ActionQueueCancelAll) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700243 TestActorNOP nop_act(actor1_event_loop_.get());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800244
Austin Schuh1bf8a212019-05-26 22:13:14 -0700245 TestActorIndex::Factory nop_actor_factory =
246 TestActorNOP::MakeFactory(test_event_loop_.get());
247
248 ActionQueue action_queue;
249
250 // Let the actor and action queue start up and confirm nothing is running.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800251 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
252 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700253
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800254 EXPECT_FALSE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800255
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800256 // Enqueue two actions to test both cancel. We can have an action and a next
257 // action so we want to test that.
258 {
259 UIntT uint;
260 uint.val = 0;
261 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
262 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
263 }
Austin Schuh1bf8a212019-05-26 22:13:14 -0700264
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800265 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800266
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800267 // Check that current and next exist.
268 EXPECT_TRUE(action_queue.GetCurrentActionState(nullptr, nullptr, nullptr,
269 nullptr, nullptr, nullptr));
270 EXPECT_TRUE(action_queue.GetNextActionState(nullptr, nullptr, nullptr,
271 nullptr, nullptr, nullptr));
272
273 action_queue.CancelAllActions();
274 action_queue.Tick();
275
276 // It should still be running as the actor could not have signaled.
277 EXPECT_TRUE(action_queue.Running());
278
279 bool sent_started, sent_cancel, interrupted;
280 EXPECT_TRUE(action_queue.GetCurrentActionState(
281 nullptr, &sent_started, &sent_cancel, &interrupted, nullptr, nullptr));
282 EXPECT_TRUE(sent_started);
283 EXPECT_TRUE(sent_cancel);
284 EXPECT_FALSE(interrupted);
285
286 EXPECT_FALSE(action_queue.GetNextActionState(nullptr, nullptr, nullptr,
Austin Schuh1bf8a212019-05-26 22:13:14 -0700287 nullptr, nullptr, nullptr));
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800288 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800289
290 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800291 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
292 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700293
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800294 // Make sure it stopped.
295 EXPECT_FALSE(action_queue.Running());
296 EXPECT_EQ(1, nop_act.running_count());
297 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800298
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800299 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800300}
301
302// Tests that an action that would block forever stops when canceled.
303TEST_F(ActionTest, ActionQueueCancelOne) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700304 TestActorShouldCancel cancel_act(actor1_event_loop_.get());
305
306 TestActorShouldCancel::Factory cancel_action_factory =
307 TestActorShouldCancel::MakeFactory(test_event_loop_.get());
308
309 ActionQueue action_queue;
310
311 // Let the actor and action queue start up.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800312 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
313 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800314
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800315 // Enqueue blocking action.
316 {
317 UIntT uint;
318 uint.val = 0;
319 action_queue.EnqueueAction(cancel_action_factory.Make(uint));
320 }
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800321
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800322 action_queue.Tick();
323 EXPECT_TRUE(action_queue.Running());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800324
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800325 // Tell action to cancel.
326 action_queue.CancelCurrentAction();
327 action_queue.Tick();
328 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800329
330 // This will block forever on failure.
331 // TODO(ben): prolly a bad way to fail
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800332 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
333 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800334
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800335 // It should still be running as the actor could not have signalled.
336 EXPECT_FALSE(action_queue.Running());
337 });
338
339 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800340}
341
Austin Schuh1bf8a212019-05-26 22:13:14 -0700342// Tests that 2 actions in a row causes the second one to cancel the first one.
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800343TEST_F(ActionTest, ActionQueueTwoActions) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700344 TestActorNOP nop_actor(actor1_event_loop_.get());
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800345
Austin Schuh1bf8a212019-05-26 22:13:14 -0700346 TestActorIndex::Factory nop_actor_factory =
347 TestActorNOP::MakeFactory(test_event_loop_.get());
348
349 ActionQueue action_queue;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800350
351 // id for the first time run.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700352 uint32_t nop_actor_id = 0;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800353 // Check the internal state and write down id for later use.
354 bool sent_started, sent_cancel, interrupted;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800355 // id for the second run.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700356 uint32_t nop_actor2_id = 0;
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800357
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800358 // Tick an empty queue and make sure it was not running.
359 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
360 action_queue.Tick();
361 EXPECT_FALSE(action_queue.Running());
362
363 // Enqueue action to be canceled.
364 {
365 UIntT uint;
366 uint.val = 0;
367 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
368 }
369 action_queue.Tick();
370
371 // Should still be running as the actor could not have signalled.
372 EXPECT_TRUE(action_queue.Running());
373
374 EXPECT_TRUE(action_queue.GetCurrentActionState(nullptr, &sent_started,
375 &sent_cancel, &interrupted,
376 &nop_actor_id, nullptr));
377 EXPECT_TRUE(sent_started);
378 EXPECT_FALSE(sent_cancel);
379 EXPECT_FALSE(interrupted);
380 ASSERT_NE(0u, nop_actor_id);
381
382 // Add the next action which should ensure the first stopped.
383 {
384 UIntT uint;
385 uint.val = 0;
386 action_queue.EnqueueAction(nop_actor_factory.Make(uint));
387 }
388
389 // Check the internal state and write down id for later use.
390 EXPECT_TRUE(action_queue.GetNextActionState(nullptr, &sent_started,
391 &sent_cancel, &interrupted,
392 &nop_actor2_id, nullptr));
393 EXPECT_NE(nop_actor_id, nop_actor2_id);
394 EXPECT_FALSE(sent_started);
395 EXPECT_FALSE(sent_cancel);
396 EXPECT_FALSE(interrupted);
397 ASSERT_NE(0u, nop_actor2_id);
398
399 action_queue.Tick();
400 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800401
402 // Run the action so it can signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800403 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
404 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800405
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800406 // Check the new action is the right one.
407 uint32_t test_id = 0;
408 EXPECT_TRUE(action_queue.GetCurrentActionState(
409 nullptr, &sent_started, &sent_cancel, &interrupted, &test_id, nullptr));
410 EXPECT_TRUE(sent_started);
411 EXPECT_FALSE(sent_cancel);
412 EXPECT_FALSE(interrupted);
413 EXPECT_EQ(nop_actor2_id, test_id);
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800414
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800415 // Make sure it is still going.
416 EXPECT_TRUE(action_queue.Running());
417 });
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800418
Austin Schuh1bf8a212019-05-26 22:13:14 -0700419 // Now let everything finish.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800420 RunAt(monotonic_clock::time_point(chrono::seconds(3)), [&]() {
421 action_queue.Tick();
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800422
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800423 // Make sure it stopped.
424 EXPECT_FALSE(action_queue.Running());
425 });
426
427 event_loop_factory_.RunFor(chrono::seconds(4));
Ben Fredricksond69f38b2015-01-28 20:06:15 -0800428}
429
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800430// Tests that we do get an index with our goal
431TEST_F(ActionTest, ActionIndex) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700432 TestActorIndex idx_actor(actor1_event_loop_.get());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800433
Austin Schuh1bf8a212019-05-26 22:13:14 -0700434 TestActorIndex::Factory test_actor_index_factory =
435 TestActorIndex::MakeFactory(test_event_loop_.get());
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800436 ::aos::Fetcher<actions::TestActionGoal> goal_fetcher_ =
437 test_event_loop_->MakeFetcher<actions::TestActionGoal>("/test_action");
Austin Schuh1bf8a212019-05-26 22:13:14 -0700438
439 ActionQueue action_queue;
440 // Tick an empty queue and make sure it was not running. Also tick the
441 // factory to allow it to send out the initial cancel message.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800442 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
443 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700444
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800445 EXPECT_FALSE(action_queue.Running());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800446
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800447 // Enqueue action to post index.
448 {
449 UIntT uint;
450 uint.val = 5;
451 action_queue.EnqueueAction(test_actor_index_factory.Make(uint));
452 }
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800453
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800454 ASSERT_TRUE(goal_fetcher_.Fetch());
455 EXPECT_EQ(5u, goal_fetcher_->params()->val());
456 EXPECT_EQ(0u, idx_actor.index);
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800457
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800458 action_queue.Tick();
459 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800460
461 // Run the next action so it can accomplish signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800462 RunAt(monotonic_clock::time_point(chrono::seconds(2)), [&]() {
463 action_queue.Tick();
464 EXPECT_EQ(5u, idx_actor.index);
Austin Schuh1bf8a212019-05-26 22:13:14 -0700465
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800466 // Enqueue action to post index.
467 {
468 UIntT uint;
469 uint.val = 3;
470 action_queue.EnqueueAction(test_actor_index_factory.Make(uint));
471 }
472 ASSERT_TRUE(goal_fetcher_.Fetch());
473 EXPECT_EQ(3u, goal_fetcher_->params()->val());
474 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800475
476 // Run the next action so it can accomplish signal completion.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800477 RunAt(monotonic_clock::time_point(chrono::seconds(3)), [&]() {
478 action_queue.Tick();
479 EXPECT_EQ(3u, idx_actor.index);
480 });
Austin Schuh1bf8a212019-05-26 22:13:14 -0700481
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800482 event_loop_factory_.RunFor(chrono::seconds(3));
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800483}
484
485// Tests that an action with a structure params works.
486TEST_F(ActionTest, StructParamType) {
Austin Schuh1bf8a212019-05-26 22:13:14 -0700487 TestActor2Nop nop_actor(actor2_event_loop_.get());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800488
Austin Schuh1bf8a212019-05-26 22:13:14 -0700489 TestActor2Nop::Factory test_action_2_nop_factory =
490 TestActor2Nop::MakeFactory(test_event_loop_.get());
491
492 ActionQueue action_queue;
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800493
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800494 RunAt(monotonic_clock::time_point(chrono::seconds(0)), [&]() {
495 // Tick an empty queue and make sure it was not running.
496 action_queue.Tick();
497 EXPECT_FALSE(action_queue.Running());
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800498
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800499 actions::MyParamsT p;
500 p.param1 = 5.0;
501 p.param2 = 7;
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800502
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800503 action_queue.EnqueueAction(test_action_2_nop_factory.Make(p));
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800504
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800505 // We started an action and it should be running.
506 EXPECT_TRUE(action_queue.Running());
507
508 // Tick it and make sure it is still running.
509 action_queue.Tick();
510 EXPECT_TRUE(action_queue.Running());
511 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800512
513 // Run the action so it can signal completion.
Austin Schuh1bf8a212019-05-26 22:13:14 -0700514 // The actor takes no time, but running for a second is the best way to get it
515 // to go.
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800516 RunAt(monotonic_clock::time_point(chrono::seconds(1)), [&]() {
517 action_queue.Tick();
Austin Schuh1bf8a212019-05-26 22:13:14 -0700518
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800519 // Make sure it stopped.
520 EXPECT_FALSE(action_queue.Running());
521 });
Ben Fredrickson9fb2ab12015-02-16 16:42:08 -0800522
Austin Schuh02e2aeb2020-02-10 21:51:30 -0800523 event_loop_factory_.RunFor(chrono::seconds(2));
Brian Silverman237a5542015-03-29 17:59:29 -0400524}
525
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800526} // namespace aos::common::actions::testing