blob: b373aa6b21c9772e906fa575f5c562066dadf71c [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 Schuh7d87b672019-12-01 20:23:49 -08006#include "aos/events/test_message_generated.h"
Neil Balchc8f41ed2018-01-20 22:06:53 -08007#include "gtest/gtest.h"
8
9namespace aos {
10namespace testing {
11
Austin Schuh7267c532019-05-19 19:55:53 -070012namespace chrono = ::std::chrono;
13
Neil Balchc8f41ed2018-01-20 22:06:53 -080014class SimulatedEventLoopTestFactory : public EventLoopTestFactory {
15 public:
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080016 ::std::unique_ptr<EventLoop> Make(std::string_view name) override {
Austin Schuh217a9782019-12-21 23:02:50 -080017 MaybeMake();
Austin Schuhac0771c2020-01-07 18:36:30 -080018 return event_loop_factory_->MakeEventLoop(name, my_node());
Neil Balchc8f41ed2018-01-20 22:06:53 -080019 }
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080020 ::std::unique_ptr<EventLoop> MakePrimary(std::string_view name) override {
Austin Schuh217a9782019-12-21 23:02:50 -080021 MaybeMake();
Austin Schuhac0771c2020-01-07 18:36:30 -080022 return event_loop_factory_->MakeEventLoop(name, my_node());
Austin Schuh44019f92019-05-19 19:58:27 -070023 }
24
Austin Schuh217a9782019-12-21 23:02:50 -080025 void Run() override { event_loop_factory_->Run(); }
26 void Exit() override { event_loop_factory_->Exit(); }
Austin Schuh44019f92019-05-19 19:58:27 -070027
Austin Schuh52d325c2019-06-23 18:59:06 -070028 // TODO(austin): Implement this. It's used currently for a phased loop test.
29 // I'm not sure how much that matters.
30 void SleepFor(::std::chrono::nanoseconds /*duration*/) override {}
31
Austin Schuh7d87b672019-12-01 20:23:49 -080032 void set_send_delay(std::chrono::nanoseconds send_delay) {
Austin Schuh217a9782019-12-21 23:02:50 -080033 MaybeMake();
34 event_loop_factory_->set_send_delay(send_delay);
Austin Schuh7d87b672019-12-01 20:23:49 -080035 }
36
Neil Balchc8f41ed2018-01-20 22:06:53 -080037 private:
Austin Schuh217a9782019-12-21 23:02:50 -080038 void MaybeMake() {
39 if (!event_loop_factory_) {
40 if (configuration()->has_nodes()) {
Austin Schuhac0771c2020-01-07 18:36:30 -080041 event_loop_factory_ =
42 std::make_unique<SimulatedEventLoopFactory>(configuration());
Austin Schuh217a9782019-12-21 23:02:50 -080043 } else {
44 event_loop_factory_ =
45 std::make_unique<SimulatedEventLoopFactory>(configuration());
46 }
47 }
48 }
49 std::unique_ptr<SimulatedEventLoopFactory> event_loop_factory_;
Neil Balchc8f41ed2018-01-20 22:06:53 -080050};
51
Austin Schuh6b6dfa52019-06-12 20:16:20 -070052INSTANTIATE_TEST_CASE_P(SimulatedEventLoopDeathTest, AbstractEventLoopDeathTest,
53 ::testing::Values([]() {
54 return new SimulatedEventLoopTestFactory();
55 }));
56
Neil Balchc8f41ed2018-01-20 22:06:53 -080057INSTANTIATE_TEST_CASE_P(SimulatedEventLoopTest, AbstractEventLoopTest,
58 ::testing::Values([]() {
59 return new SimulatedEventLoopTestFactory();
60 }));
61
62// Test that creating an event and running the scheduler runs the event.
63TEST(EventSchedulerTest, ScheduleEvent) {
64 int counter = 0;
65 EventScheduler scheduler;
66
Austin Schuhac0771c2020-01-07 18:36:30 -080067 scheduler.Schedule(distributed_clock::epoch() + chrono::seconds(1),
68 [&counter]() { counter += 1; });
Neil Balchc8f41ed2018-01-20 22:06:53 -080069 scheduler.Run();
70 EXPECT_EQ(counter, 1);
Austin Schuhac0771c2020-01-07 18:36:30 -080071 auto token =
72 scheduler.Schedule(distributed_clock::epoch() + chrono::seconds(2),
73 [&counter]() { counter += 1; });
Neil Balchc8f41ed2018-01-20 22:06:53 -080074 scheduler.Deschedule(token);
75 scheduler.Run();
76 EXPECT_EQ(counter, 1);
77}
78
79// Test that descheduling an already scheduled event doesn't run the event.
80TEST(EventSchedulerTest, DescheduleEvent) {
81 int counter = 0;
82 EventScheduler scheduler;
83
Austin Schuhac0771c2020-01-07 18:36:30 -080084 auto token =
85 scheduler.Schedule(distributed_clock::epoch() + chrono::seconds(1),
86 [&counter]() { counter += 1; });
Neil Balchc8f41ed2018-01-20 22:06:53 -080087 scheduler.Deschedule(token);
88 scheduler.Run();
89 EXPECT_EQ(counter, 0);
90}
Austin Schuh44019f92019-05-19 19:58:27 -070091
92// Test that running for a time period with no handlers causes time to progress
93// correctly.
94TEST(SimulatedEventLoopTest, RunForNoHandlers) {
Austin Schuh39788ff2019-12-01 18:22:57 -080095 SimulatedEventLoopTestFactory factory;
96
97 SimulatedEventLoopFactory simulated_event_loop_factory(
98 factory.configuration());
Austin Schuh44019f92019-05-19 19:58:27 -070099 ::std::unique_ptr<EventLoop> event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800100 simulated_event_loop_factory.MakeEventLoop("loop");
Austin Schuh44019f92019-05-19 19:58:27 -0700101
102 simulated_event_loop_factory.RunFor(chrono::seconds(1));
103
104 EXPECT_EQ(::aos::monotonic_clock::epoch() + chrono::seconds(1),
Austin Schuh44019f92019-05-19 19:58:27 -0700105 event_loop->monotonic_now());
106}
107
108// Test that running for a time with a periodic handler causes time to end
109// correctly.
110TEST(SimulatedEventLoopTest, RunForTimerHandler) {
Austin Schuh39788ff2019-12-01 18:22:57 -0800111 SimulatedEventLoopTestFactory factory;
112
113 SimulatedEventLoopFactory simulated_event_loop_factory(
114 factory.configuration());
Austin Schuh44019f92019-05-19 19:58:27 -0700115 ::std::unique_ptr<EventLoop> event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800116 simulated_event_loop_factory.MakeEventLoop("loop");
Austin Schuh44019f92019-05-19 19:58:27 -0700117
118 int counter = 0;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700119 auto timer = event_loop->AddTimer([&counter]() { ++counter; });
Austin Schuh44019f92019-05-19 19:58:27 -0700120 event_loop->OnRun([&event_loop, &timer] {
121 timer->Setup(event_loop->monotonic_now() + chrono::milliseconds(50),
122 chrono::milliseconds(100));
123 });
124
125 simulated_event_loop_factory.RunFor(chrono::seconds(1));
126
127 EXPECT_EQ(::aos::monotonic_clock::epoch() + chrono::seconds(1),
Austin Schuh44019f92019-05-19 19:58:27 -0700128 event_loop->monotonic_now());
129 EXPECT_EQ(counter, 10);
130}
131
Austin Schuh7d87b672019-12-01 20:23:49 -0800132// Tests that watchers have latency in simulation.
133TEST(SimulatedEventLoopTest, WatcherTimingReport) {
134 SimulatedEventLoopTestFactory factory;
135 factory.set_send_delay(std::chrono::microseconds(50));
136
137 FLAGS_timing_report_ms = 1000;
138 auto loop1 = factory.MakePrimary("primary");
139 loop1->MakeWatcher("/test", [](const TestMessage &) {});
140
141 auto loop2 = factory.Make("sender_loop");
142
143 auto loop3 = factory.Make("report_fetcher");
144
145 Fetcher<timing::Report> report_fetcher =
146 loop3->MakeFetcher<timing::Report>("/aos");
147 EXPECT_FALSE(report_fetcher.Fetch());
148
149 auto sender = loop2->MakeSender<TestMessage>("/test");
150
151 // Send 10 messages in the middle of a timing report period so we get
152 // something interesting back.
153 auto test_timer = loop2->AddTimer([&sender]() {
154 for (int i = 0; i < 10; ++i) {
155 aos::Sender<TestMessage>::Builder msg = sender.MakeBuilder();
156 TestMessage::Builder builder = msg.MakeBuilder<TestMessage>();
157 builder.add_value(200 + i);
158 ASSERT_TRUE(msg.Send(builder.Finish()));
159 }
160 });
161
162 // Quit after 1 timing report, mid way through the next cycle.
163 {
164 auto end_timer = loop1->AddTimer([&factory]() { factory.Exit(); });
165 end_timer->Setup(loop1->monotonic_now() + chrono::milliseconds(2500));
166 end_timer->set_name("end");
167 }
168
169 loop1->OnRun([&test_timer, &loop1]() {
170 test_timer->Setup(loop1->monotonic_now() + chrono::milliseconds(1500));
171 });
172
173 factory.Run();
174
175 // And, since we are here, check that the timing report makes sense.
176 // Start by looking for our event loop's timing.
177 FlatbufferDetachedBuffer<timing::Report> primary_report =
178 FlatbufferDetachedBuffer<timing::Report>::Empty();
179 while (report_fetcher.FetchNext()) {
180 LOG(INFO) << "Report " << FlatbufferToJson(report_fetcher.get());
181 if (report_fetcher->name()->string_view() == "primary") {
182 primary_report = CopyFlatBuffer(report_fetcher.get());
183 }
184 }
185
186 // Check the watcher report.
187 VLOG(1) << FlatbufferToJson(primary_report, true);
188
189 EXPECT_EQ(primary_report.message().name()->string_view(), "primary");
190
191 // Just the timing report timer.
192 ASSERT_NE(primary_report.message().timers(), nullptr);
193 EXPECT_EQ(primary_report.message().timers()->size(), 2);
194
195 // No phased loops
196 ASSERT_EQ(primary_report.message().phased_loops(), nullptr);
197
198 // And now confirm that the watcher received all 10 messages, and has latency.
199 ASSERT_NE(primary_report.message().watchers(), nullptr);
200 ASSERT_EQ(primary_report.message().watchers()->size(), 1);
201 EXPECT_EQ(primary_report.message().watchers()->Get(0)->count(), 10);
202 EXPECT_NEAR(
203 primary_report.message().watchers()->Get(0)->wakeup_latency()->average(),
204 0.00005, 1e-9);
205 EXPECT_NEAR(
206 primary_report.message().watchers()->Get(0)->wakeup_latency()->min(),
207 0.00005, 1e-9);
208 EXPECT_NEAR(
209 primary_report.message().watchers()->Get(0)->wakeup_latency()->max(),
210 0.00005, 1e-9);
211 EXPECT_EQ(primary_report.message()
212 .watchers()
213 ->Get(0)
214 ->wakeup_latency()
215 ->standard_deviation(),
216 0.0);
217
218 EXPECT_EQ(
219 primary_report.message().watchers()->Get(0)->handler_time()->average(),
220 0.0);
221 EXPECT_EQ(primary_report.message().watchers()->Get(0)->handler_time()->min(),
222 0.0);
223 EXPECT_EQ(primary_report.message().watchers()->Get(0)->handler_time()->max(),
224 0.0);
225 EXPECT_EQ(primary_report.message()
226 .watchers()
227 ->Get(0)
228 ->handler_time()
229 ->standard_deviation(),
230 0.0);
231}
232
Neil Balchc8f41ed2018-01-20 22:06:53 -0800233} // namespace testing
234} // namespace aos