blob: 44be58103c7d2a1f98029f6f1c0c0c2e72ee3624 [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:
Alex Perrycb7da4b2019-08-28 19:35:56 -070016 SimulatedEventLoopTestFactory() : event_loop_factory_(configuration()) {}
17
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080018 ::std::unique_ptr<EventLoop> Make(std::string_view name) override {
19 return event_loop_factory_.MakeEventLoop(name);
Neil Balchc8f41ed2018-01-20 22:06:53 -080020 }
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080021 ::std::unique_ptr<EventLoop> MakePrimary(std::string_view name) override {
22 return event_loop_factory_.MakeEventLoop(name);
Austin Schuh44019f92019-05-19 19:58:27 -070023 }
24
25 void Run() override { event_loop_factory_.Run(); }
Austin Schuh9fe68f72019-08-10 19:32:03 -070026 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) {
33 event_loop_factory_.set_send_delay(send_delay);
34 }
35
Neil Balchc8f41ed2018-01-20 22:06:53 -080036 private:
Austin Schuh44019f92019-05-19 19:58:27 -070037 SimulatedEventLoopFactory event_loop_factory_;
Neil Balchc8f41ed2018-01-20 22:06:53 -080038};
39
Austin Schuh6b6dfa52019-06-12 20:16:20 -070040INSTANTIATE_TEST_CASE_P(SimulatedEventLoopDeathTest, AbstractEventLoopDeathTest,
41 ::testing::Values([]() {
42 return new SimulatedEventLoopTestFactory();
43 }));
44
Neil Balchc8f41ed2018-01-20 22:06:53 -080045INSTANTIATE_TEST_CASE_P(SimulatedEventLoopTest, AbstractEventLoopTest,
46 ::testing::Values([]() {
47 return new SimulatedEventLoopTestFactory();
48 }));
49
50// Test that creating an event and running the scheduler runs the event.
51TEST(EventSchedulerTest, ScheduleEvent) {
52 int counter = 0;
53 EventScheduler scheduler;
54
55 scheduler.Schedule(::aos::monotonic_clock::now(),
56 [&counter]() { counter += 1; });
57 scheduler.Run();
58 EXPECT_EQ(counter, 1);
59 auto token = scheduler.Schedule(::aos::monotonic_clock::now(),
60 [&counter]() { counter += 1; });
61 scheduler.Deschedule(token);
62 scheduler.Run();
63 EXPECT_EQ(counter, 1);
64}
65
66// Test that descheduling an already scheduled event doesn't run the event.
67TEST(EventSchedulerTest, DescheduleEvent) {
68 int counter = 0;
69 EventScheduler scheduler;
70
71 auto token = scheduler.Schedule(::aos::monotonic_clock::now(),
72 [&counter]() { counter += 1; });
73 scheduler.Deschedule(token);
74 scheduler.Run();
75 EXPECT_EQ(counter, 0);
76}
Austin Schuh44019f92019-05-19 19:58:27 -070077
78// Test that running for a time period with no handlers causes time to progress
79// correctly.
80TEST(SimulatedEventLoopTest, RunForNoHandlers) {
Austin Schuh39788ff2019-12-01 18:22:57 -080081 SimulatedEventLoopTestFactory factory;
82
83 SimulatedEventLoopFactory simulated_event_loop_factory(
84 factory.configuration());
Austin Schuh44019f92019-05-19 19:58:27 -070085 ::std::unique_ptr<EventLoop> event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080086 simulated_event_loop_factory.MakeEventLoop("loop");
Austin Schuh44019f92019-05-19 19:58:27 -070087
88 simulated_event_loop_factory.RunFor(chrono::seconds(1));
89
90 EXPECT_EQ(::aos::monotonic_clock::epoch() + chrono::seconds(1),
91 simulated_event_loop_factory.monotonic_now());
92 EXPECT_EQ(::aos::monotonic_clock::epoch() + chrono::seconds(1),
93 event_loop->monotonic_now());
94}
95
96// Test that running for a time with a periodic handler causes time to end
97// correctly.
98TEST(SimulatedEventLoopTest, RunForTimerHandler) {
Austin Schuh39788ff2019-12-01 18:22:57 -080099 SimulatedEventLoopTestFactory factory;
100
101 SimulatedEventLoopFactory simulated_event_loop_factory(
102 factory.configuration());
Austin Schuh44019f92019-05-19 19:58:27 -0700103 ::std::unique_ptr<EventLoop> event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800104 simulated_event_loop_factory.MakeEventLoop("loop");
Austin Schuh44019f92019-05-19 19:58:27 -0700105
106 int counter = 0;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700107 auto timer = event_loop->AddTimer([&counter]() { ++counter; });
Austin Schuh44019f92019-05-19 19:58:27 -0700108 event_loop->OnRun([&event_loop, &timer] {
109 timer->Setup(event_loop->monotonic_now() + chrono::milliseconds(50),
110 chrono::milliseconds(100));
111 });
112
113 simulated_event_loop_factory.RunFor(chrono::seconds(1));
114
115 EXPECT_EQ(::aos::monotonic_clock::epoch() + chrono::seconds(1),
116 simulated_event_loop_factory.monotonic_now());
117 EXPECT_EQ(::aos::monotonic_clock::epoch() + chrono::seconds(1),
118 event_loop->monotonic_now());
119 EXPECT_EQ(counter, 10);
120}
121
Austin Schuh7d87b672019-12-01 20:23:49 -0800122// Tests that watchers have latency in simulation.
123TEST(SimulatedEventLoopTest, WatcherTimingReport) {
124 SimulatedEventLoopTestFactory factory;
125 factory.set_send_delay(std::chrono::microseconds(50));
126
127 FLAGS_timing_report_ms = 1000;
128 auto loop1 = factory.MakePrimary("primary");
129 loop1->MakeWatcher("/test", [](const TestMessage &) {});
130
131 auto loop2 = factory.Make("sender_loop");
132
133 auto loop3 = factory.Make("report_fetcher");
134
135 Fetcher<timing::Report> report_fetcher =
136 loop3->MakeFetcher<timing::Report>("/aos");
137 EXPECT_FALSE(report_fetcher.Fetch());
138
139 auto sender = loop2->MakeSender<TestMessage>("/test");
140
141 // Send 10 messages in the middle of a timing report period so we get
142 // something interesting back.
143 auto test_timer = loop2->AddTimer([&sender]() {
144 for (int i = 0; i < 10; ++i) {
145 aos::Sender<TestMessage>::Builder msg = sender.MakeBuilder();
146 TestMessage::Builder builder = msg.MakeBuilder<TestMessage>();
147 builder.add_value(200 + i);
148 ASSERT_TRUE(msg.Send(builder.Finish()));
149 }
150 });
151
152 // Quit after 1 timing report, mid way through the next cycle.
153 {
154 auto end_timer = loop1->AddTimer([&factory]() { factory.Exit(); });
155 end_timer->Setup(loop1->monotonic_now() + chrono::milliseconds(2500));
156 end_timer->set_name("end");
157 }
158
159 loop1->OnRun([&test_timer, &loop1]() {
160 test_timer->Setup(loop1->monotonic_now() + chrono::milliseconds(1500));
161 });
162
163 factory.Run();
164
165 // And, since we are here, check that the timing report makes sense.
166 // Start by looking for our event loop's timing.
167 FlatbufferDetachedBuffer<timing::Report> primary_report =
168 FlatbufferDetachedBuffer<timing::Report>::Empty();
169 while (report_fetcher.FetchNext()) {
170 LOG(INFO) << "Report " << FlatbufferToJson(report_fetcher.get());
171 if (report_fetcher->name()->string_view() == "primary") {
172 primary_report = CopyFlatBuffer(report_fetcher.get());
173 }
174 }
175
176 // Check the watcher report.
177 VLOG(1) << FlatbufferToJson(primary_report, true);
178
179 EXPECT_EQ(primary_report.message().name()->string_view(), "primary");
180
181 // Just the timing report timer.
182 ASSERT_NE(primary_report.message().timers(), nullptr);
183 EXPECT_EQ(primary_report.message().timers()->size(), 2);
184
185 // No phased loops
186 ASSERT_EQ(primary_report.message().phased_loops(), nullptr);
187
188 // And now confirm that the watcher received all 10 messages, and has latency.
189 ASSERT_NE(primary_report.message().watchers(), nullptr);
190 ASSERT_EQ(primary_report.message().watchers()->size(), 1);
191 EXPECT_EQ(primary_report.message().watchers()->Get(0)->count(), 10);
192 EXPECT_NEAR(
193 primary_report.message().watchers()->Get(0)->wakeup_latency()->average(),
194 0.00005, 1e-9);
195 EXPECT_NEAR(
196 primary_report.message().watchers()->Get(0)->wakeup_latency()->min(),
197 0.00005, 1e-9);
198 EXPECT_NEAR(
199 primary_report.message().watchers()->Get(0)->wakeup_latency()->max(),
200 0.00005, 1e-9);
201 EXPECT_EQ(primary_report.message()
202 .watchers()
203 ->Get(0)
204 ->wakeup_latency()
205 ->standard_deviation(),
206 0.0);
207
208 EXPECT_EQ(
209 primary_report.message().watchers()->Get(0)->handler_time()->average(),
210 0.0);
211 EXPECT_EQ(primary_report.message().watchers()->Get(0)->handler_time()->min(),
212 0.0);
213 EXPECT_EQ(primary_report.message().watchers()->Get(0)->handler_time()->max(),
214 0.0);
215 EXPECT_EQ(primary_report.message()
216 .watchers()
217 ->Get(0)
218 ->handler_time()
219 ->standard_deviation(),
220 0.0);
221}
222
Neil Balchc8f41ed2018-01-20 22:06:53 -0800223} // namespace testing
224} // namespace aos