blob: 78c0d44bc3884c787fb96aa818ceeecdd9169528 [file] [log] [blame]
Alex Perrycb7da4b2019-08-28 19:35:56 -07001#include "aos/events/simulated_event_loop.h"
2
Austin Schuh5f1cc5c2019-12-01 18:01:11 -08003#include <string_view>
4
Alex Perrycb7da4b2019-08-28 19:35:56 -07005#include "aos/events/event_loop_param_test.h"
Austin Schuh898f4972020-01-11 17:21:25 -08006#include "aos/events/ping_lib.h"
7#include "aos/events/pong_lib.h"
Austin Schuh7d87b672019-12-01 20:23:49 -08008#include "aos/events/test_message_generated.h"
Neil Balchc8f41ed2018-01-20 22:06:53 -08009#include "gtest/gtest.h"
10
11namespace aos {
12namespace testing {
13
Austin Schuh7267c532019-05-19 19:55:53 -070014namespace chrono = ::std::chrono;
15
Neil Balchc8f41ed2018-01-20 22:06:53 -080016class SimulatedEventLoopTestFactory : public EventLoopTestFactory {
17 public:
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080018 ::std::unique_ptr<EventLoop> Make(std::string_view name) override {
Austin Schuh217a9782019-12-21 23:02:50 -080019 MaybeMake();
Austin Schuhac0771c2020-01-07 18:36:30 -080020 return event_loop_factory_->MakeEventLoop(name, my_node());
Neil Balchc8f41ed2018-01-20 22:06:53 -080021 }
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080022 ::std::unique_ptr<EventLoop> MakePrimary(std::string_view name) override {
Austin Schuh217a9782019-12-21 23:02:50 -080023 MaybeMake();
Austin Schuhac0771c2020-01-07 18:36:30 -080024 return event_loop_factory_->MakeEventLoop(name, my_node());
Austin Schuh44019f92019-05-19 19:58:27 -070025 }
26
Austin Schuh217a9782019-12-21 23:02:50 -080027 void Run() override { event_loop_factory_->Run(); }
28 void Exit() override { event_loop_factory_->Exit(); }
Austin Schuh44019f92019-05-19 19:58:27 -070029
Austin Schuh52d325c2019-06-23 18:59:06 -070030 // TODO(austin): Implement this. It's used currently for a phased loop test.
31 // I'm not sure how much that matters.
32 void SleepFor(::std::chrono::nanoseconds /*duration*/) override {}
33
Austin Schuh7d87b672019-12-01 20:23:49 -080034 void set_send_delay(std::chrono::nanoseconds send_delay) {
Austin Schuh217a9782019-12-21 23:02:50 -080035 MaybeMake();
36 event_loop_factory_->set_send_delay(send_delay);
Austin Schuh7d87b672019-12-01 20:23:49 -080037 }
38
Neil Balchc8f41ed2018-01-20 22:06:53 -080039 private:
Austin Schuh217a9782019-12-21 23:02:50 -080040 void MaybeMake() {
41 if (!event_loop_factory_) {
42 if (configuration()->has_nodes()) {
Austin Schuhac0771c2020-01-07 18:36:30 -080043 event_loop_factory_ =
44 std::make_unique<SimulatedEventLoopFactory>(configuration());
Austin Schuh217a9782019-12-21 23:02:50 -080045 } else {
46 event_loop_factory_ =
47 std::make_unique<SimulatedEventLoopFactory>(configuration());
48 }
49 }
50 }
51 std::unique_ptr<SimulatedEventLoopFactory> event_loop_factory_;
Neil Balchc8f41ed2018-01-20 22:06:53 -080052};
53
Brian Silverman77162972020-08-12 19:52:40 -070054INSTANTIATE_TEST_CASE_P(SimulatedEventLoopCopyTest, AbstractEventLoopTest,
55 ::testing::Values(std::make_tuple(
56 []() {
57 return new SimulatedEventLoopTestFactory();
58 },
59 ReadMethod::COPY)));
Austin Schuh6b6dfa52019-06-12 20:16:20 -070060
Brian Silverman77162972020-08-12 19:52:40 -070061INSTANTIATE_TEST_CASE_P(
62 SimulatedEventLoopCopyDeathTest, AbstractEventLoopDeathTest,
63 ::testing::Values(
64 std::make_tuple([]() { return new SimulatedEventLoopTestFactory(); },
65 ReadMethod::COPY)));
66
67INSTANTIATE_TEST_CASE_P(SimulatedEventLoopPinTest, AbstractEventLoopTest,
68 ::testing::Values(std::make_tuple(
69 []() {
70 return new SimulatedEventLoopTestFactory();
71 },
72 ReadMethod::PIN)));
73
74INSTANTIATE_TEST_CASE_P(
75 SimulatedEventLoopPinDeathTest, AbstractEventLoopDeathTest,
76 ::testing::Values(
77 std::make_tuple([]() { return new SimulatedEventLoopTestFactory(); },
78 ReadMethod::PIN)));
Neil Balchc8f41ed2018-01-20 22:06:53 -080079
80// Test that creating an event and running the scheduler runs the event.
81TEST(EventSchedulerTest, ScheduleEvent) {
82 int counter = 0;
Austin Schuh8bd96322020-02-13 21:18:22 -080083 EventSchedulerScheduler scheduler_scheduler;
Neil Balchc8f41ed2018-01-20 22:06:53 -080084 EventScheduler scheduler;
Austin Schuh8bd96322020-02-13 21:18:22 -080085 scheduler_scheduler.AddEventScheduler(&scheduler);
Neil Balchc8f41ed2018-01-20 22:06:53 -080086
Austin Schuh8bd96322020-02-13 21:18:22 -080087 scheduler.Schedule(monotonic_clock::epoch() + chrono::seconds(1),
Austin Schuhac0771c2020-01-07 18:36:30 -080088 [&counter]() { counter += 1; });
Austin Schuh8bd96322020-02-13 21:18:22 -080089 scheduler_scheduler.Run();
Neil Balchc8f41ed2018-01-20 22:06:53 -080090 EXPECT_EQ(counter, 1);
Ravago Jonescf453ab2020-05-06 21:14:53 -070091 auto token = scheduler.Schedule(monotonic_clock::epoch() + chrono::seconds(2),
92 [&counter]() { counter += 1; });
Neil Balchc8f41ed2018-01-20 22:06:53 -080093 scheduler.Deschedule(token);
Austin Schuh8bd96322020-02-13 21:18:22 -080094 scheduler_scheduler.Run();
Neil Balchc8f41ed2018-01-20 22:06:53 -080095 EXPECT_EQ(counter, 1);
96}
97
98// Test that descheduling an already scheduled event doesn't run the event.
99TEST(EventSchedulerTest, DescheduleEvent) {
100 int counter = 0;
Austin Schuh8bd96322020-02-13 21:18:22 -0800101 EventSchedulerScheduler scheduler_scheduler;
Neil Balchc8f41ed2018-01-20 22:06:53 -0800102 EventScheduler scheduler;
Austin Schuh8bd96322020-02-13 21:18:22 -0800103 scheduler_scheduler.AddEventScheduler(&scheduler);
Neil Balchc8f41ed2018-01-20 22:06:53 -0800104
Austin Schuh8bd96322020-02-13 21:18:22 -0800105 auto token = scheduler.Schedule(monotonic_clock::epoch() + chrono::seconds(1),
106 [&counter]() { counter += 1; });
Neil Balchc8f41ed2018-01-20 22:06:53 -0800107 scheduler.Deschedule(token);
Austin Schuh8bd96322020-02-13 21:18:22 -0800108 scheduler_scheduler.Run();
Neil Balchc8f41ed2018-01-20 22:06:53 -0800109 EXPECT_EQ(counter, 0);
110}
Austin Schuh44019f92019-05-19 19:58:27 -0700111
112// Test that running for a time period with no handlers causes time to progress
113// correctly.
114TEST(SimulatedEventLoopTest, RunForNoHandlers) {
Austin Schuh39788ff2019-12-01 18:22:57 -0800115 SimulatedEventLoopTestFactory factory;
116
117 SimulatedEventLoopFactory simulated_event_loop_factory(
118 factory.configuration());
Austin Schuh44019f92019-05-19 19:58:27 -0700119 ::std::unique_ptr<EventLoop> event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800120 simulated_event_loop_factory.MakeEventLoop("loop");
Austin Schuh44019f92019-05-19 19:58:27 -0700121
122 simulated_event_loop_factory.RunFor(chrono::seconds(1));
123
124 EXPECT_EQ(::aos::monotonic_clock::epoch() + chrono::seconds(1),
Austin Schuh44019f92019-05-19 19:58:27 -0700125 event_loop->monotonic_now());
126}
127
128// Test that running for a time with a periodic handler causes time to end
129// correctly.
130TEST(SimulatedEventLoopTest, RunForTimerHandler) {
Austin Schuh39788ff2019-12-01 18:22:57 -0800131 SimulatedEventLoopTestFactory factory;
132
133 SimulatedEventLoopFactory simulated_event_loop_factory(
134 factory.configuration());
Austin Schuh44019f92019-05-19 19:58:27 -0700135 ::std::unique_ptr<EventLoop> event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800136 simulated_event_loop_factory.MakeEventLoop("loop");
Austin Schuh44019f92019-05-19 19:58:27 -0700137
138 int counter = 0;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700139 auto timer = event_loop->AddTimer([&counter]() { ++counter; });
Austin Schuh44019f92019-05-19 19:58:27 -0700140 event_loop->OnRun([&event_loop, &timer] {
141 timer->Setup(event_loop->monotonic_now() + chrono::milliseconds(50),
142 chrono::milliseconds(100));
143 });
144
145 simulated_event_loop_factory.RunFor(chrono::seconds(1));
146
147 EXPECT_EQ(::aos::monotonic_clock::epoch() + chrono::seconds(1),
Austin Schuh44019f92019-05-19 19:58:27 -0700148 event_loop->monotonic_now());
149 EXPECT_EQ(counter, 10);
150}
151
Austin Schuh7d87b672019-12-01 20:23:49 -0800152// Tests that watchers have latency in simulation.
153TEST(SimulatedEventLoopTest, WatcherTimingReport) {
154 SimulatedEventLoopTestFactory factory;
155 factory.set_send_delay(std::chrono::microseconds(50));
156
157 FLAGS_timing_report_ms = 1000;
158 auto loop1 = factory.MakePrimary("primary");
159 loop1->MakeWatcher("/test", [](const TestMessage &) {});
160
161 auto loop2 = factory.Make("sender_loop");
162
163 auto loop3 = factory.Make("report_fetcher");
164
165 Fetcher<timing::Report> report_fetcher =
166 loop3->MakeFetcher<timing::Report>("/aos");
167 EXPECT_FALSE(report_fetcher.Fetch());
168
169 auto sender = loop2->MakeSender<TestMessage>("/test");
170
171 // Send 10 messages in the middle of a timing report period so we get
172 // something interesting back.
173 auto test_timer = loop2->AddTimer([&sender]() {
174 for (int i = 0; i < 10; ++i) {
175 aos::Sender<TestMessage>::Builder msg = sender.MakeBuilder();
176 TestMessage::Builder builder = msg.MakeBuilder<TestMessage>();
177 builder.add_value(200 + i);
178 ASSERT_TRUE(msg.Send(builder.Finish()));
179 }
180 });
181
182 // Quit after 1 timing report, mid way through the next cycle.
183 {
184 auto end_timer = loop1->AddTimer([&factory]() { factory.Exit(); });
185 end_timer->Setup(loop1->monotonic_now() + chrono::milliseconds(2500));
186 end_timer->set_name("end");
187 }
188
189 loop1->OnRun([&test_timer, &loop1]() {
190 test_timer->Setup(loop1->monotonic_now() + chrono::milliseconds(1500));
191 });
192
193 factory.Run();
194
195 // And, since we are here, check that the timing report makes sense.
196 // Start by looking for our event loop's timing.
197 FlatbufferDetachedBuffer<timing::Report> primary_report =
198 FlatbufferDetachedBuffer<timing::Report>::Empty();
199 while (report_fetcher.FetchNext()) {
200 LOG(INFO) << "Report " << FlatbufferToJson(report_fetcher.get());
201 if (report_fetcher->name()->string_view() == "primary") {
202 primary_report = CopyFlatBuffer(report_fetcher.get());
203 }
204 }
205
206 // Check the watcher report.
Ravago Jonescf453ab2020-05-06 21:14:53 -0700207 VLOG(1) << FlatbufferToJson(primary_report, {.multi_line = true});
Austin Schuh7d87b672019-12-01 20:23:49 -0800208
209 EXPECT_EQ(primary_report.message().name()->string_view(), "primary");
210
211 // Just the timing report timer.
212 ASSERT_NE(primary_report.message().timers(), nullptr);
213 EXPECT_EQ(primary_report.message().timers()->size(), 2);
214
215 // No phased loops
216 ASSERT_EQ(primary_report.message().phased_loops(), nullptr);
217
218 // And now confirm that the watcher received all 10 messages, and has latency.
219 ASSERT_NE(primary_report.message().watchers(), nullptr);
220 ASSERT_EQ(primary_report.message().watchers()->size(), 1);
221 EXPECT_EQ(primary_report.message().watchers()->Get(0)->count(), 10);
222 EXPECT_NEAR(
223 primary_report.message().watchers()->Get(0)->wakeup_latency()->average(),
224 0.00005, 1e-9);
225 EXPECT_NEAR(
226 primary_report.message().watchers()->Get(0)->wakeup_latency()->min(),
227 0.00005, 1e-9);
228 EXPECT_NEAR(
229 primary_report.message().watchers()->Get(0)->wakeup_latency()->max(),
230 0.00005, 1e-9);
231 EXPECT_EQ(primary_report.message()
232 .watchers()
233 ->Get(0)
234 ->wakeup_latency()
235 ->standard_deviation(),
236 0.0);
237
238 EXPECT_EQ(
239 primary_report.message().watchers()->Get(0)->handler_time()->average(),
240 0.0);
241 EXPECT_EQ(primary_report.message().watchers()->Get(0)->handler_time()->min(),
242 0.0);
243 EXPECT_EQ(primary_report.message().watchers()->Get(0)->handler_time()->max(),
244 0.0);
245 EXPECT_EQ(primary_report.message()
246 .watchers()
247 ->Get(0)
248 ->handler_time()
249 ->standard_deviation(),
250 0.0);
251}
252
Austin Schuh898f4972020-01-11 17:21:25 -0800253// Tests that ping and pong work when on 2 different nodes.
254TEST(SimulatedEventLoopTest, MultinodePingPong) {
255 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
256 aos::configuration::ReadConfig(
257 "aos/events/multinode_pingpong_config.json");
258 const Node *pi1 = configuration::GetNode(&config.message(), "pi1");
259 const Node *pi2 = configuration::GetNode(&config.message(), "pi2");
260
261 SimulatedEventLoopFactory simulated_event_loop_factory(&config.message());
262
263 std::unique_ptr<EventLoop> ping_event_loop =
264 simulated_event_loop_factory.MakeEventLoop("ping", pi1);
265 Ping ping(ping_event_loop.get());
266
267 std::unique_ptr<EventLoop> pong_event_loop =
268 simulated_event_loop_factory.MakeEventLoop("pong", pi2);
269 Pong pong(pong_event_loop.get());
270
271 std::unique_ptr<EventLoop> pi2_pong_counter_event_loop =
272 simulated_event_loop_factory.MakeEventLoop("pi2_pong_counter", pi2);
273
274 int pi2_pong_count = 0;
275 pi2_pong_counter_event_loop->MakeWatcher(
276 "/test",
277 [&pi2_pong_count](const examples::Pong & /*pong*/) { ++pi2_pong_count; });
278
279 std::unique_ptr<EventLoop> pi1_pong_counter_event_loop =
280 simulated_event_loop_factory.MakeEventLoop("pi1_pong_counter", pi1);
281 int pi1_pong_count = 0;
282 pi1_pong_counter_event_loop->MakeWatcher(
283 "/test",
284 [&pi1_pong_count](const examples::Pong & /*pong*/) { ++pi1_pong_count; });
285
286 simulated_event_loop_factory.RunFor(chrono::seconds(10) +
287 chrono::milliseconds(5));
288
289 EXPECT_EQ(pi1_pong_count, 1001);
290 EXPECT_EQ(pi2_pong_count, 1001);
291}
292
Neil Balchc8f41ed2018-01-20 22:06:53 -0800293} // namespace testing
294} // namespace aos