blob: c7ab942ffb0d55ff21c62e052aa8f8a6e61e38bf [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 Schuh2f8fd752020-09-01 22:38:28 -07006#include "aos/events/logging/logger_generated.h"
Austin Schuh01b4c352020-09-21 23:09:39 -07007#include "aos/events/message_counter.h"
Austin Schuh898f4972020-01-11 17:21:25 -08008#include "aos/events/ping_lib.h"
9#include "aos/events/pong_lib.h"
Austin Schuh7d87b672019-12-01 20:23:49 -080010#include "aos/events/test_message_generated.h"
Austin Schuh4c3b9702020-08-30 11:34:55 -070011#include "aos/network/message_bridge_client_generated.h"
12#include "aos/network/message_bridge_server_generated.h"
13#include "aos/network/timestamp_generated.h"
Neil Balchc8f41ed2018-01-20 22:06:53 -080014#include "gtest/gtest.h"
15
16namespace aos {
17namespace testing {
Brian Silverman28d14302020-09-18 15:26:17 -070018namespace {
19
20std::string ConfigPrefix() { return "aos/"; }
21
22} // namespace
Neil Balchc8f41ed2018-01-20 22:06:53 -080023
Austin Schuh7267c532019-05-19 19:55:53 -070024namespace chrono = ::std::chrono;
25
Neil Balchc8f41ed2018-01-20 22:06:53 -080026class SimulatedEventLoopTestFactory : public EventLoopTestFactory {
27 public:
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080028 ::std::unique_ptr<EventLoop> Make(std::string_view name) override {
Austin Schuh217a9782019-12-21 23:02:50 -080029 MaybeMake();
Austin Schuhac0771c2020-01-07 18:36:30 -080030 return event_loop_factory_->MakeEventLoop(name, my_node());
Neil Balchc8f41ed2018-01-20 22:06:53 -080031 }
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080032 ::std::unique_ptr<EventLoop> MakePrimary(std::string_view name) override {
Austin Schuh217a9782019-12-21 23:02:50 -080033 MaybeMake();
Austin Schuhac0771c2020-01-07 18:36:30 -080034 return event_loop_factory_->MakeEventLoop(name, my_node());
Austin Schuh44019f92019-05-19 19:58:27 -070035 }
36
Austin Schuh217a9782019-12-21 23:02:50 -080037 void Run() override { event_loop_factory_->Run(); }
38 void Exit() override { event_loop_factory_->Exit(); }
Austin Schuh44019f92019-05-19 19:58:27 -070039
Austin Schuh52d325c2019-06-23 18:59:06 -070040 // TODO(austin): Implement this. It's used currently for a phased loop test.
41 // I'm not sure how much that matters.
42 void SleepFor(::std::chrono::nanoseconds /*duration*/) override {}
43
Austin Schuh7d87b672019-12-01 20:23:49 -080044 void set_send_delay(std::chrono::nanoseconds send_delay) {
Austin Schuh217a9782019-12-21 23:02:50 -080045 MaybeMake();
46 event_loop_factory_->set_send_delay(send_delay);
Austin Schuh7d87b672019-12-01 20:23:49 -080047 }
48
Neil Balchc8f41ed2018-01-20 22:06:53 -080049 private:
Austin Schuh217a9782019-12-21 23:02:50 -080050 void MaybeMake() {
51 if (!event_loop_factory_) {
52 if (configuration()->has_nodes()) {
Austin Schuhac0771c2020-01-07 18:36:30 -080053 event_loop_factory_ =
54 std::make_unique<SimulatedEventLoopFactory>(configuration());
Austin Schuh217a9782019-12-21 23:02:50 -080055 } else {
56 event_loop_factory_ =
57 std::make_unique<SimulatedEventLoopFactory>(configuration());
58 }
59 }
60 }
61 std::unique_ptr<SimulatedEventLoopFactory> event_loop_factory_;
Neil Balchc8f41ed2018-01-20 22:06:53 -080062};
63
Brian Silverman77162972020-08-12 19:52:40 -070064INSTANTIATE_TEST_CASE_P(SimulatedEventLoopCopyTest, AbstractEventLoopTest,
65 ::testing::Values(std::make_tuple(
66 []() {
67 return new SimulatedEventLoopTestFactory();
68 },
69 ReadMethod::COPY)));
Austin Schuh6b6dfa52019-06-12 20:16:20 -070070
Brian Silverman77162972020-08-12 19:52:40 -070071INSTANTIATE_TEST_CASE_P(
72 SimulatedEventLoopCopyDeathTest, AbstractEventLoopDeathTest,
73 ::testing::Values(
74 std::make_tuple([]() { return new SimulatedEventLoopTestFactory(); },
75 ReadMethod::COPY)));
76
77INSTANTIATE_TEST_CASE_P(SimulatedEventLoopPinTest, AbstractEventLoopTest,
78 ::testing::Values(std::make_tuple(
79 []() {
80 return new SimulatedEventLoopTestFactory();
81 },
82 ReadMethod::PIN)));
83
84INSTANTIATE_TEST_CASE_P(
85 SimulatedEventLoopPinDeathTest, AbstractEventLoopDeathTest,
86 ::testing::Values(
87 std::make_tuple([]() { return new SimulatedEventLoopTestFactory(); },
88 ReadMethod::PIN)));
Neil Balchc8f41ed2018-01-20 22:06:53 -080089
90// Test that creating an event and running the scheduler runs the event.
91TEST(EventSchedulerTest, ScheduleEvent) {
92 int counter = 0;
Austin Schuh8bd96322020-02-13 21:18:22 -080093 EventSchedulerScheduler scheduler_scheduler;
Neil Balchc8f41ed2018-01-20 22:06:53 -080094 EventScheduler scheduler;
Austin Schuh8bd96322020-02-13 21:18:22 -080095 scheduler_scheduler.AddEventScheduler(&scheduler);
Neil Balchc8f41ed2018-01-20 22:06:53 -080096
Austin Schuh8bd96322020-02-13 21:18:22 -080097 scheduler.Schedule(monotonic_clock::epoch() + chrono::seconds(1),
Austin Schuhac0771c2020-01-07 18:36:30 -080098 [&counter]() { counter += 1; });
Austin Schuh8bd96322020-02-13 21:18:22 -080099 scheduler_scheduler.Run();
Neil Balchc8f41ed2018-01-20 22:06:53 -0800100 EXPECT_EQ(counter, 1);
Ravago Jonescf453ab2020-05-06 21:14:53 -0700101 auto token = scheduler.Schedule(monotonic_clock::epoch() + chrono::seconds(2),
102 [&counter]() { counter += 1; });
Neil Balchc8f41ed2018-01-20 22:06:53 -0800103 scheduler.Deschedule(token);
Austin Schuh8bd96322020-02-13 21:18:22 -0800104 scheduler_scheduler.Run();
Neil Balchc8f41ed2018-01-20 22:06:53 -0800105 EXPECT_EQ(counter, 1);
106}
107
108// Test that descheduling an already scheduled event doesn't run the event.
109TEST(EventSchedulerTest, DescheduleEvent) {
110 int counter = 0;
Austin Schuh8bd96322020-02-13 21:18:22 -0800111 EventSchedulerScheduler scheduler_scheduler;
Neil Balchc8f41ed2018-01-20 22:06:53 -0800112 EventScheduler scheduler;
Austin Schuh8bd96322020-02-13 21:18:22 -0800113 scheduler_scheduler.AddEventScheduler(&scheduler);
Neil Balchc8f41ed2018-01-20 22:06:53 -0800114
Austin Schuh8bd96322020-02-13 21:18:22 -0800115 auto token = scheduler.Schedule(monotonic_clock::epoch() + chrono::seconds(1),
116 [&counter]() { counter += 1; });
Neil Balchc8f41ed2018-01-20 22:06:53 -0800117 scheduler.Deschedule(token);
Austin Schuh8bd96322020-02-13 21:18:22 -0800118 scheduler_scheduler.Run();
Neil Balchc8f41ed2018-01-20 22:06:53 -0800119 EXPECT_EQ(counter, 0);
120}
Austin Schuh44019f92019-05-19 19:58:27 -0700121
122// Test that running for a time period with no handlers causes time to progress
123// correctly.
124TEST(SimulatedEventLoopTest, RunForNoHandlers) {
Austin Schuh39788ff2019-12-01 18:22:57 -0800125 SimulatedEventLoopTestFactory factory;
126
127 SimulatedEventLoopFactory simulated_event_loop_factory(
128 factory.configuration());
Austin Schuh44019f92019-05-19 19:58:27 -0700129 ::std::unique_ptr<EventLoop> event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800130 simulated_event_loop_factory.MakeEventLoop("loop");
Austin Schuh44019f92019-05-19 19:58:27 -0700131
132 simulated_event_loop_factory.RunFor(chrono::seconds(1));
133
134 EXPECT_EQ(::aos::monotonic_clock::epoch() + chrono::seconds(1),
Austin Schuh44019f92019-05-19 19:58:27 -0700135 event_loop->monotonic_now());
136}
137
138// Test that running for a time with a periodic handler causes time to end
139// correctly.
140TEST(SimulatedEventLoopTest, RunForTimerHandler) {
Austin Schuh39788ff2019-12-01 18:22:57 -0800141 SimulatedEventLoopTestFactory factory;
142
143 SimulatedEventLoopFactory simulated_event_loop_factory(
144 factory.configuration());
Austin Schuh44019f92019-05-19 19:58:27 -0700145 ::std::unique_ptr<EventLoop> event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800146 simulated_event_loop_factory.MakeEventLoop("loop");
Austin Schuh44019f92019-05-19 19:58:27 -0700147
148 int counter = 0;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700149 auto timer = event_loop->AddTimer([&counter]() { ++counter; });
Austin Schuh44019f92019-05-19 19:58:27 -0700150 event_loop->OnRun([&event_loop, &timer] {
151 timer->Setup(event_loop->monotonic_now() + chrono::milliseconds(50),
152 chrono::milliseconds(100));
153 });
154
155 simulated_event_loop_factory.RunFor(chrono::seconds(1));
156
157 EXPECT_EQ(::aos::monotonic_clock::epoch() + chrono::seconds(1),
Austin Schuh44019f92019-05-19 19:58:27 -0700158 event_loop->monotonic_now());
159 EXPECT_EQ(counter, 10);
160}
161
Austin Schuh7d87b672019-12-01 20:23:49 -0800162// Tests that watchers have latency in simulation.
163TEST(SimulatedEventLoopTest, WatcherTimingReport) {
164 SimulatedEventLoopTestFactory factory;
165 factory.set_send_delay(std::chrono::microseconds(50));
166
167 FLAGS_timing_report_ms = 1000;
168 auto loop1 = factory.MakePrimary("primary");
169 loop1->MakeWatcher("/test", [](const TestMessage &) {});
170
171 auto loop2 = factory.Make("sender_loop");
172
173 auto loop3 = factory.Make("report_fetcher");
174
175 Fetcher<timing::Report> report_fetcher =
176 loop3->MakeFetcher<timing::Report>("/aos");
177 EXPECT_FALSE(report_fetcher.Fetch());
178
179 auto sender = loop2->MakeSender<TestMessage>("/test");
180
181 // Send 10 messages in the middle of a timing report period so we get
182 // something interesting back.
183 auto test_timer = loop2->AddTimer([&sender]() {
184 for (int i = 0; i < 10; ++i) {
185 aos::Sender<TestMessage>::Builder msg = sender.MakeBuilder();
186 TestMessage::Builder builder = msg.MakeBuilder<TestMessage>();
187 builder.add_value(200 + i);
188 ASSERT_TRUE(msg.Send(builder.Finish()));
189 }
190 });
191
192 // Quit after 1 timing report, mid way through the next cycle.
193 {
194 auto end_timer = loop1->AddTimer([&factory]() { factory.Exit(); });
195 end_timer->Setup(loop1->monotonic_now() + chrono::milliseconds(2500));
196 end_timer->set_name("end");
197 }
198
199 loop1->OnRun([&test_timer, &loop1]() {
200 test_timer->Setup(loop1->monotonic_now() + chrono::milliseconds(1500));
201 });
202
203 factory.Run();
204
205 // And, since we are here, check that the timing report makes sense.
206 // Start by looking for our event loop's timing.
207 FlatbufferDetachedBuffer<timing::Report> primary_report =
208 FlatbufferDetachedBuffer<timing::Report>::Empty();
209 while (report_fetcher.FetchNext()) {
210 LOG(INFO) << "Report " << FlatbufferToJson(report_fetcher.get());
211 if (report_fetcher->name()->string_view() == "primary") {
212 primary_report = CopyFlatBuffer(report_fetcher.get());
213 }
214 }
215
216 // Check the watcher report.
Ravago Jonescf453ab2020-05-06 21:14:53 -0700217 VLOG(1) << FlatbufferToJson(primary_report, {.multi_line = true});
Austin Schuh7d87b672019-12-01 20:23:49 -0800218
219 EXPECT_EQ(primary_report.message().name()->string_view(), "primary");
220
221 // Just the timing report timer.
222 ASSERT_NE(primary_report.message().timers(), nullptr);
223 EXPECT_EQ(primary_report.message().timers()->size(), 2);
224
225 // No phased loops
226 ASSERT_EQ(primary_report.message().phased_loops(), nullptr);
227
228 // And now confirm that the watcher received all 10 messages, and has latency.
229 ASSERT_NE(primary_report.message().watchers(), nullptr);
230 ASSERT_EQ(primary_report.message().watchers()->size(), 1);
231 EXPECT_EQ(primary_report.message().watchers()->Get(0)->count(), 10);
232 EXPECT_NEAR(
233 primary_report.message().watchers()->Get(0)->wakeup_latency()->average(),
234 0.00005, 1e-9);
235 EXPECT_NEAR(
236 primary_report.message().watchers()->Get(0)->wakeup_latency()->min(),
237 0.00005, 1e-9);
238 EXPECT_NEAR(
239 primary_report.message().watchers()->Get(0)->wakeup_latency()->max(),
240 0.00005, 1e-9);
241 EXPECT_EQ(primary_report.message()
242 .watchers()
243 ->Get(0)
244 ->wakeup_latency()
245 ->standard_deviation(),
246 0.0);
247
248 EXPECT_EQ(
249 primary_report.message().watchers()->Get(0)->handler_time()->average(),
250 0.0);
251 EXPECT_EQ(primary_report.message().watchers()->Get(0)->handler_time()->min(),
252 0.0);
253 EXPECT_EQ(primary_report.message().watchers()->Get(0)->handler_time()->max(),
254 0.0);
255 EXPECT_EQ(primary_report.message()
256 .watchers()
257 ->Get(0)
258 ->handler_time()
259 ->standard_deviation(),
260 0.0);
261}
262
Austin Schuh4c3b9702020-08-30 11:34:55 -0700263// Tests that ping and pong work when on 2 different nodes, and the message
264// gateway messages are sent out as expected.
Austin Schuh898f4972020-01-11 17:21:25 -0800265TEST(SimulatedEventLoopTest, MultinodePingPong) {
266 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
Brian Silverman28d14302020-09-18 15:26:17 -0700267 aos::configuration::ReadConfig(ConfigPrefix() +
268 "events/multinode_pingpong_config.json");
Austin Schuh898f4972020-01-11 17:21:25 -0800269 const Node *pi1 = configuration::GetNode(&config.message(), "pi1");
270 const Node *pi2 = configuration::GetNode(&config.message(), "pi2");
Austin Schuh4c3b9702020-08-30 11:34:55 -0700271 const Node *pi3 = configuration::GetNode(&config.message(), "pi3");
Austin Schuh898f4972020-01-11 17:21:25 -0800272
273 SimulatedEventLoopFactory simulated_event_loop_factory(&config.message());
274
275 std::unique_ptr<EventLoop> ping_event_loop =
276 simulated_event_loop_factory.MakeEventLoop("ping", pi1);
277 Ping ping(ping_event_loop.get());
278
279 std::unique_ptr<EventLoop> pong_event_loop =
280 simulated_event_loop_factory.MakeEventLoop("pong", pi2);
281 Pong pong(pong_event_loop.get());
282
283 std::unique_ptr<EventLoop> pi2_pong_counter_event_loop =
284 simulated_event_loop_factory.MakeEventLoop("pi2_pong_counter", pi2);
Austin Schuh4c3b9702020-08-30 11:34:55 -0700285 MessageCounter<examples::Pong> pi2_pong_counter(
286 pi2_pong_counter_event_loop.get(), "/test");
Austin Schuh2f8fd752020-09-01 22:38:28 -0700287 aos::Fetcher<message_bridge::Timestamp> pi1_on_pi2_timestamp_fetcher =
288 pi2_pong_counter_event_loop->MakeFetcher<message_bridge::Timestamp>(
289 "/pi1/aos");
290 aos::Fetcher<examples::Ping> ping_on_pi2_fetcher =
291 pi2_pong_counter_event_loop->MakeFetcher<examples::Ping>("/test");
Austin Schuh898f4972020-01-11 17:21:25 -0800292
Austin Schuh4c3b9702020-08-30 11:34:55 -0700293 std::unique_ptr<EventLoop> pi3_pong_counter_event_loop =
294 simulated_event_loop_factory.MakeEventLoop("pi3_pong_counter", pi3);
Austin Schuh898f4972020-01-11 17:21:25 -0800295
296 std::unique_ptr<EventLoop> pi1_pong_counter_event_loop =
297 simulated_event_loop_factory.MakeEventLoop("pi1_pong_counter", pi1);
Austin Schuh4c3b9702020-08-30 11:34:55 -0700298 MessageCounter<examples::Pong> pi1_pong_counter(
299 pi1_pong_counter_event_loop.get(), "/test");
Austin Schuh2f8fd752020-09-01 22:38:28 -0700300 aos::Fetcher<examples::Ping> ping_on_pi1_fetcher =
301 pi1_pong_counter_event_loop->MakeFetcher<examples::Ping>("/test");
302 aos::Fetcher<message_bridge::Timestamp> pi1_on_pi1_timestamp_fetcher =
303 pi1_pong_counter_event_loop->MakeFetcher<message_bridge::Timestamp>(
304 "/aos");
305
306 std::unique_ptr<EventLoop> pi1_remote_timestamp =
307 simulated_event_loop_factory.MakeEventLoop("pi1_remote_timestamp", pi1);
Austin Schuh4c3b9702020-08-30 11:34:55 -0700308
309 // Count timestamps.
310 MessageCounter<message_bridge::Timestamp> pi1_on_pi1_timestamp_counter(
311 pi1_pong_counter_event_loop.get(), "/pi1/aos");
312 MessageCounter<message_bridge::Timestamp> pi1_on_pi2_timestamp_counter(
313 pi2_pong_counter_event_loop.get(), "/pi1/aos");
314 MessageCounter<message_bridge::Timestamp> pi1_on_pi3_timestamp_counter(
315 pi3_pong_counter_event_loop.get(), "/pi1/aos");
316 MessageCounter<message_bridge::Timestamp> pi2_on_pi1_timestamp_counter(
317 pi1_pong_counter_event_loop.get(), "/pi2/aos");
318 MessageCounter<message_bridge::Timestamp> pi2_on_pi2_timestamp_counter(
319 pi2_pong_counter_event_loop.get(), "/pi2/aos");
320 MessageCounter<message_bridge::Timestamp> pi3_on_pi1_timestamp_counter(
321 pi1_pong_counter_event_loop.get(), "/pi3/aos");
322 MessageCounter<message_bridge::Timestamp> pi3_on_pi3_timestamp_counter(
323 pi3_pong_counter_event_loop.get(), "/pi3/aos");
324
Austin Schuh2f8fd752020-09-01 22:38:28 -0700325 // Count remote timestamps
326 MessageCounter<logger::MessageHeader> remote_timestamps_pi2_on_pi1(
327 pi1_pong_counter_event_loop.get(), "/aos/remote_timestamps/pi2");
328 MessageCounter<logger::MessageHeader> remote_timestamps_pi1_on_pi2(
329 pi2_pong_counter_event_loop.get(), "/aos/remote_timestamps/pi1");
330
Austin Schuh4c3b9702020-08-30 11:34:55 -0700331 // Wait to let timestamp estimation start up before looking for the results.
332 simulated_event_loop_factory.RunFor(chrono::milliseconds(500));
333
334 int pi1_server_statistics_count = 0;
Austin Schuh898f4972020-01-11 17:21:25 -0800335 pi1_pong_counter_event_loop->MakeWatcher(
Austin Schuh4c3b9702020-08-30 11:34:55 -0700336 "/pi1/aos", [&pi1_server_statistics_count](
337 const message_bridge::ServerStatistics &stats) {
338 VLOG(1) << "pi1 ServerStatistics " << FlatbufferToJson(&stats);
339 EXPECT_EQ(stats.connections()->size(), 2u);
340 for (const message_bridge::ServerConnection *connection :
341 *stats.connections()) {
342 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
343 if (connection->node()->name()->string_view() == "pi2") {
344 EXPECT_GT(connection->sent_packets(), 50);
345 } else if (connection->node()->name()->string_view() == "pi3") {
346 EXPECT_GE(connection->sent_packets(), 5);
347 } else {
348 LOG(FATAL) << "Unknown connection";
349 }
350
351 EXPECT_TRUE(connection->has_monotonic_offset());
352 EXPECT_EQ(connection->monotonic_offset(), 0);
353 }
354 ++pi1_server_statistics_count;
355 });
356
357 int pi2_server_statistics_count = 0;
358 pi2_pong_counter_event_loop->MakeWatcher(
359 "/pi2/aos", [&pi2_server_statistics_count](
360 const message_bridge::ServerStatistics &stats) {
361 VLOG(1) << "pi2 ServerStatistics " << FlatbufferToJson(&stats);
362 EXPECT_EQ(stats.connections()->size(), 1u);
363
364 const message_bridge::ServerConnection *connection =
365 stats.connections()->Get(0);
366 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
367 EXPECT_GT(connection->sent_packets(), 50);
368 EXPECT_TRUE(connection->has_monotonic_offset());
369 EXPECT_EQ(connection->monotonic_offset(), 0);
370 ++pi2_server_statistics_count;
371 });
372
373 int pi3_server_statistics_count = 0;
374 pi3_pong_counter_event_loop->MakeWatcher(
375 "/pi3/aos", [&pi3_server_statistics_count](
376 const message_bridge::ServerStatistics &stats) {
377 VLOG(1) << "pi3 ServerStatistics " << FlatbufferToJson(&stats);
378 EXPECT_EQ(stats.connections()->size(), 1u);
379
380 const message_bridge::ServerConnection *connection =
381 stats.connections()->Get(0);
382 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
383 EXPECT_GE(connection->sent_packets(), 5);
384 EXPECT_TRUE(connection->has_monotonic_offset());
385 EXPECT_EQ(connection->monotonic_offset(), 0);
386 ++pi3_server_statistics_count;
387 });
388
389 int pi1_client_statistics_count = 0;
390 pi1_pong_counter_event_loop->MakeWatcher(
391 "/pi1/aos", [&pi1_client_statistics_count](
392 const message_bridge::ClientStatistics &stats) {
393 VLOG(1) << "pi1 ClientStatistics " << FlatbufferToJson(&stats);
394 EXPECT_EQ(stats.connections()->size(), 2u);
395
396 for (const message_bridge::ClientConnection *connection :
397 *stats.connections()) {
398 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
399 if (connection->node()->name()->string_view() == "pi2") {
400 EXPECT_GT(connection->received_packets(), 50);
401 } else if (connection->node()->name()->string_view() == "pi3") {
402 EXPECT_GE(connection->received_packets(), 5);
403 } else {
404 LOG(FATAL) << "Unknown connection";
405 }
406
407 EXPECT_TRUE(connection->has_monotonic_offset());
408 EXPECT_EQ(connection->monotonic_offset(), 150000);
409 }
410 ++pi1_client_statistics_count;
411 });
412
413 int pi2_client_statistics_count = 0;
414 pi2_pong_counter_event_loop->MakeWatcher(
415 "/pi2/aos", [&pi2_client_statistics_count](
416 const message_bridge::ClientStatistics &stats) {
417 VLOG(1) << "pi2 ClientStatistics " << FlatbufferToJson(&stats);
418 EXPECT_EQ(stats.connections()->size(), 1u);
419
420 const message_bridge::ClientConnection *connection =
421 stats.connections()->Get(0);
422 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
423 EXPECT_GT(connection->received_packets(), 50);
424 EXPECT_TRUE(connection->has_monotonic_offset());
425 EXPECT_EQ(connection->monotonic_offset(), 150000);
426 ++pi2_client_statistics_count;
427 });
428
429 int pi3_client_statistics_count = 0;
430 pi3_pong_counter_event_loop->MakeWatcher(
431 "/pi3/aos", [&pi3_client_statistics_count](
432 const message_bridge::ClientStatistics &stats) {
433 VLOG(1) << "pi3 ClientStatistics " << FlatbufferToJson(&stats);
434 EXPECT_EQ(stats.connections()->size(), 1u);
435
436 const message_bridge::ClientConnection *connection =
437 stats.connections()->Get(0);
438 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
439 EXPECT_GE(connection->received_packets(), 5);
440 EXPECT_TRUE(connection->has_monotonic_offset());
441 EXPECT_EQ(connection->monotonic_offset(), 150000);
442 ++pi3_client_statistics_count;
443 });
444
Austin Schuh2f8fd752020-09-01 22:38:28 -0700445 // Find the channel index for both the /pi1/aos Timestamp channel and Ping
446 // channel.
447 const size_t pi1_timestamp_channel =
448 configuration::ChannelIndex(pi1_pong_counter_event_loop->configuration(),
449 pi1_on_pi2_timestamp_fetcher.channel());
450 const size_t ping_timestamp_channel =
451 configuration::ChannelIndex(pi1_pong_counter_event_loop->configuration(),
452 ping_on_pi2_fetcher.channel());
453
454 for (const Channel *channel :
455 *pi1_pong_counter_event_loop->configuration()->channels()) {
456 VLOG(1) << "Channel "
457 << configuration::ChannelIndex(
458 pi1_pong_counter_event_loop->configuration(), channel)
459 << " " << configuration::CleanedChannelToString(channel);
460 }
461
462 // For each remote timestamp we get back, confirm that it is either a ping
463 // message, or a timestamp we sent out. Also confirm that the timestamps are
464 // correct.
465 pi1_remote_timestamp->MakeWatcher(
466 "/pi1/aos/remote_timestamps/pi2",
467 [pi1_timestamp_channel, ping_timestamp_channel, &ping_on_pi2_fetcher,
468 &ping_on_pi1_fetcher, &pi1_on_pi2_timestamp_fetcher,
469 &pi1_on_pi1_timestamp_fetcher](const logger::MessageHeader &header) {
470 VLOG(1) << aos::FlatbufferToJson(&header);
471
472 const aos::monotonic_clock::time_point header_monotonic_sent_time(
473 chrono::nanoseconds(header.monotonic_sent_time()));
474 const aos::realtime_clock::time_point header_realtime_sent_time(
475 chrono::nanoseconds(header.realtime_sent_time()));
476 const aos::monotonic_clock::time_point header_monotonic_remote_time(
477 chrono::nanoseconds(header.monotonic_remote_time()));
478 const aos::realtime_clock::time_point header_realtime_remote_time(
479 chrono::nanoseconds(header.realtime_remote_time()));
480
481 const Context *pi1_context = nullptr;
482 const Context *pi2_context = nullptr;
483
484 if (header.channel_index() == pi1_timestamp_channel) {
485 // Find the forwarded message.
486 while (pi1_on_pi2_timestamp_fetcher.context().monotonic_event_time <
487 header_monotonic_sent_time) {
488 ASSERT_TRUE(pi1_on_pi2_timestamp_fetcher.FetchNext());
489 }
490
491 // And the source message.
492 while (pi1_on_pi1_timestamp_fetcher.context().monotonic_event_time <
493 header_monotonic_remote_time) {
494 ASSERT_TRUE(pi1_on_pi1_timestamp_fetcher.FetchNext());
495 }
496
497 pi1_context = &pi1_on_pi1_timestamp_fetcher.context();
498 pi2_context = &pi1_on_pi2_timestamp_fetcher.context();
499 } else if (header.channel_index() == ping_timestamp_channel) {
500 // Find the forwarded message.
501 while (ping_on_pi2_fetcher.context().monotonic_event_time <
502 header_monotonic_sent_time) {
503 ASSERT_TRUE(ping_on_pi2_fetcher.FetchNext());
504 }
505
506 // And the source message.
507 while (ping_on_pi1_fetcher.context().monotonic_event_time <
508 header_monotonic_remote_time) {
509 ASSERT_TRUE(ping_on_pi1_fetcher.FetchNext());
510 }
511
512 pi1_context = &ping_on_pi1_fetcher.context();
513 pi2_context = &ping_on_pi2_fetcher.context();
514 } else {
515 LOG(FATAL) << "Unknown channel";
516 }
517
518 // Confirm the forwarded message has matching timestamps to the
519 // timestamps we got back.
520 EXPECT_EQ(pi2_context->queue_index, header.queue_index());
521 EXPECT_EQ(pi2_context->monotonic_event_time,
522 header_monotonic_sent_time);
523 EXPECT_EQ(pi2_context->realtime_event_time, header_realtime_sent_time);
524 EXPECT_EQ(pi2_context->realtime_remote_time,
525 header_realtime_remote_time);
526 EXPECT_EQ(pi2_context->monotonic_remote_time,
527 header_monotonic_remote_time);
528
529 // Confirm the forwarded message also matches the source message.
530 EXPECT_EQ(pi1_context->queue_index, header.queue_index());
531 EXPECT_EQ(pi1_context->monotonic_event_time,
532 header_monotonic_remote_time);
533 EXPECT_EQ(pi1_context->realtime_event_time,
534 header_realtime_remote_time);
535 });
536
Austin Schuh4c3b9702020-08-30 11:34:55 -0700537 simulated_event_loop_factory.RunFor(chrono::seconds(10) -
538 chrono::milliseconds(500) +
539 chrono::milliseconds(5));
540
541 EXPECT_EQ(pi1_pong_counter.count(), 1001);
542 EXPECT_EQ(pi2_pong_counter.count(), 1001);
543
544 EXPECT_EQ(pi1_on_pi1_timestamp_counter.count(), 100);
545 EXPECT_EQ(pi1_on_pi2_timestamp_counter.count(), 100);
546 EXPECT_EQ(pi1_on_pi3_timestamp_counter.count(), 100);
547 EXPECT_EQ(pi2_on_pi1_timestamp_counter.count(), 100);
548 EXPECT_EQ(pi2_on_pi2_timestamp_counter.count(), 100);
549 EXPECT_EQ(pi3_on_pi1_timestamp_counter.count(), 100);
550 EXPECT_EQ(pi3_on_pi3_timestamp_counter.count(), 100);
551
552 EXPECT_EQ(pi1_server_statistics_count, 9);
553 EXPECT_EQ(pi2_server_statistics_count, 9);
554 EXPECT_EQ(pi3_server_statistics_count, 9);
555
556 EXPECT_EQ(pi1_client_statistics_count, 95);
557 EXPECT_EQ(pi2_client_statistics_count, 95);
558 EXPECT_EQ(pi3_client_statistics_count, 95);
Austin Schuh2f8fd752020-09-01 22:38:28 -0700559
560 // Also confirm that remote timestamps are being forwarded correctly.
561 EXPECT_EQ(remote_timestamps_pi2_on_pi1.count(), 1101);
562 EXPECT_EQ(remote_timestamps_pi1_on_pi2.count(), 1101);
Austin Schuh4c3b9702020-08-30 11:34:55 -0700563}
564
565// Tests that an offset between nodes can be recovered and shows up in
566// ServerStatistics correctly.
567TEST(SimulatedEventLoopTest, MultinodePingPongWithOffset) {
568 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
Brian Silverman28d14302020-09-18 15:26:17 -0700569 aos::configuration::ReadConfig(ConfigPrefix() +
570 "events/multinode_pingpong_config.json");
Austin Schuh4c3b9702020-08-30 11:34:55 -0700571 const Node *pi1 = configuration::GetNode(&config.message(), "pi1");
572 const Node *pi2 = configuration::GetNode(&config.message(), "pi2");
573 const Node *pi3 = configuration::GetNode(&config.message(), "pi3");
574
575 SimulatedEventLoopFactory simulated_event_loop_factory(&config.message());
576 NodeEventLoopFactory *pi2_factory =
577 simulated_event_loop_factory.GetNodeEventLoopFactory(pi2);
578
579 constexpr chrono::milliseconds kOffset{1501};
580 pi2_factory->SetDistributedOffset(kOffset, 1.0);
581
582 std::unique_ptr<EventLoop> ping_event_loop =
583 simulated_event_loop_factory.MakeEventLoop("ping", pi1);
584 Ping ping(ping_event_loop.get());
585
586 std::unique_ptr<EventLoop> pong_event_loop =
587 simulated_event_loop_factory.MakeEventLoop("pong", pi2);
588 Pong pong(pong_event_loop.get());
589
590 std::unique_ptr<EventLoop> pi2_pong_counter_event_loop =
591 simulated_event_loop_factory.MakeEventLoop("pi2_pong_counter", pi2);
592
593 std::unique_ptr<EventLoop> pi3_pong_counter_event_loop =
594 simulated_event_loop_factory.MakeEventLoop("pi3_pong_counter", pi3);
595
596 std::unique_ptr<EventLoop> pi1_pong_counter_event_loop =
597 simulated_event_loop_factory.MakeEventLoop("pi1_pong_counter", pi1);
598
599 // Wait to let timestamp estimation start up before looking for the results.
600 simulated_event_loop_factory.RunFor(chrono::milliseconds(500));
601
602 // Confirm the offsets are being recovered correctly.
603 int pi1_server_statistics_count = 0;
604 pi1_pong_counter_event_loop->MakeWatcher(
605 "/pi1/aos", [&pi1_server_statistics_count,
606 kOffset](const message_bridge::ServerStatistics &stats) {
607 VLOG(1) << "pi1 ServerStatistics " << FlatbufferToJson(&stats);
608 EXPECT_EQ(stats.connections()->size(), 2u);
609 for (const message_bridge::ServerConnection *connection :
610 *stats.connections()) {
611 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
612 if (connection->node()->name()->string_view() == "pi2") {
613 EXPECT_EQ(connection->monotonic_offset(),
614 chrono::nanoseconds(kOffset).count());
615 } else if (connection->node()->name()->string_view() == "pi3") {
616 EXPECT_EQ(connection->monotonic_offset(), 0);
617 } else {
618 LOG(FATAL) << "Unknown connection";
619 }
620
621 EXPECT_TRUE(connection->has_monotonic_offset());
622 }
623 ++pi1_server_statistics_count;
624 });
625
626 int pi2_server_statistics_count = 0;
627 pi2_pong_counter_event_loop->MakeWatcher(
628 "/pi2/aos", [&pi2_server_statistics_count,
629 kOffset](const message_bridge::ServerStatistics &stats) {
630 VLOG(1) << "pi2 ServerStatistics " << FlatbufferToJson(&stats);
631 EXPECT_EQ(stats.connections()->size(), 1u);
632
633 const message_bridge::ServerConnection *connection =
634 stats.connections()->Get(0);
635 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
636 EXPECT_TRUE(connection->has_monotonic_offset());
637 EXPECT_EQ(connection->monotonic_offset(),
638 -chrono::nanoseconds(kOffset).count());
639 ++pi2_server_statistics_count;
640 });
641
642 int pi3_server_statistics_count = 0;
643 pi3_pong_counter_event_loop->MakeWatcher(
644 "/pi3/aos", [&pi3_server_statistics_count](
645 const message_bridge::ServerStatistics &stats) {
646 VLOG(1) << "pi3 ServerStatistics " << FlatbufferToJson(&stats);
647 EXPECT_EQ(stats.connections()->size(), 1u);
648
649 const message_bridge::ServerConnection *connection =
650 stats.connections()->Get(0);
651 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
652 EXPECT_TRUE(connection->has_monotonic_offset());
653 EXPECT_EQ(connection->monotonic_offset(), 0);
654 ++pi3_server_statistics_count;
655 });
656
657 simulated_event_loop_factory.RunFor(chrono::seconds(10) -
658 chrono::milliseconds(500) +
659 chrono::milliseconds(5));
660
661 EXPECT_EQ(pi1_server_statistics_count, 9);
662 EXPECT_EQ(pi2_server_statistics_count, 9);
663 EXPECT_EQ(pi3_server_statistics_count, 9);
664}
665
666// Test that disabling statistics actually disables them.
667TEST(SimulatedEventLoopTest, MultinodeWithoutStatistics) {
668 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
Brian Silverman28d14302020-09-18 15:26:17 -0700669 aos::configuration::ReadConfig(ConfigPrefix() +
670 "events/multinode_pingpong_config.json");
Austin Schuh4c3b9702020-08-30 11:34:55 -0700671 const Node *pi1 = configuration::GetNode(&config.message(), "pi1");
672 const Node *pi2 = configuration::GetNode(&config.message(), "pi2");
673 const Node *pi3 = configuration::GetNode(&config.message(), "pi3");
674
675 SimulatedEventLoopFactory simulated_event_loop_factory(&config.message());
676 simulated_event_loop_factory.DisableStatistics();
677
678 std::unique_ptr<EventLoop> ping_event_loop =
679 simulated_event_loop_factory.MakeEventLoop("ping", pi1);
680 Ping ping(ping_event_loop.get());
681
682 std::unique_ptr<EventLoop> pong_event_loop =
683 simulated_event_loop_factory.MakeEventLoop("pong", pi2);
684 Pong pong(pong_event_loop.get());
685
686 std::unique_ptr<EventLoop> pi2_pong_counter_event_loop =
687 simulated_event_loop_factory.MakeEventLoop("pi2_pong_counter", pi2);
688
689 MessageCounter<examples::Pong> pi2_pong_counter(
690 pi2_pong_counter_event_loop.get(), "/test");
691
692 std::unique_ptr<EventLoop> pi3_pong_counter_event_loop =
693 simulated_event_loop_factory.MakeEventLoop("pi3_pong_counter", pi3);
694
695 std::unique_ptr<EventLoop> pi1_pong_counter_event_loop =
696 simulated_event_loop_factory.MakeEventLoop("pi1_pong_counter", pi1);
697
698 MessageCounter<examples::Pong> pi1_pong_counter(
699 pi1_pong_counter_event_loop.get(), "/test");
700
701 // Count timestamps.
702 MessageCounter<message_bridge::Timestamp> pi1_on_pi1_timestamp_counter(
703 pi1_pong_counter_event_loop.get(), "/pi1/aos");
704 MessageCounter<message_bridge::Timestamp> pi1_on_pi2_timestamp_counter(
705 pi2_pong_counter_event_loop.get(), "/pi1/aos");
706 MessageCounter<message_bridge::Timestamp> pi1_on_pi3_timestamp_counter(
707 pi3_pong_counter_event_loop.get(), "/pi1/aos");
708 MessageCounter<message_bridge::Timestamp> pi2_on_pi1_timestamp_counter(
709 pi1_pong_counter_event_loop.get(), "/pi2/aos");
710 MessageCounter<message_bridge::Timestamp> pi2_on_pi2_timestamp_counter(
711 pi2_pong_counter_event_loop.get(), "/pi2/aos");
712 MessageCounter<message_bridge::Timestamp> pi3_on_pi1_timestamp_counter(
713 pi1_pong_counter_event_loop.get(), "/pi3/aos");
714 MessageCounter<message_bridge::Timestamp> pi3_on_pi3_timestamp_counter(
715 pi3_pong_counter_event_loop.get(), "/pi3/aos");
716
Austin Schuh2f8fd752020-09-01 22:38:28 -0700717 // Count remote timestamps
718 MessageCounter<logger::MessageHeader> remote_timestamps_pi2_on_pi1(
719 pi1_pong_counter_event_loop.get(), "/aos/remote_timestamps/pi2");
720 MessageCounter<logger::MessageHeader> remote_timestamps_pi1_on_pi2(
721 pi2_pong_counter_event_loop.get(), "/aos/remote_timestamps/pi1");
722
Austin Schuh4c3b9702020-08-30 11:34:55 -0700723 MessageCounter<message_bridge::ServerStatistics>
724 pi1_server_statistics_counter(pi1_pong_counter_event_loop.get(),
725 "/pi1/aos");
726 MessageCounter<message_bridge::ServerStatistics>
727 pi2_server_statistics_counter(pi2_pong_counter_event_loop.get(),
728 "/pi2/aos");
729 MessageCounter<message_bridge::ServerStatistics>
730 pi3_server_statistics_counter(pi3_pong_counter_event_loop.get(),
731 "/pi3/aos");
732
733 MessageCounter<message_bridge::ClientStatistics>
734 pi1_client_statistics_counter(pi1_pong_counter_event_loop.get(),
735 "/pi1/aos");
736 MessageCounter<message_bridge::ClientStatistics>
737 pi2_client_statistics_counter(pi2_pong_counter_event_loop.get(),
738 "/pi2/aos");
739 MessageCounter<message_bridge::ClientStatistics>
740 pi3_client_statistics_counter(pi3_pong_counter_event_loop.get(),
741 "/pi3/aos");
Austin Schuh898f4972020-01-11 17:21:25 -0800742
743 simulated_event_loop_factory.RunFor(chrono::seconds(10) +
744 chrono::milliseconds(5));
745
Austin Schuh4c3b9702020-08-30 11:34:55 -0700746 EXPECT_EQ(pi1_pong_counter.count(), 1001u);
747 EXPECT_EQ(pi2_pong_counter.count(), 1001u);
748
749 EXPECT_EQ(pi1_on_pi1_timestamp_counter.count(), 0u);
750 EXPECT_EQ(pi1_on_pi2_timestamp_counter.count(), 0u);
751 EXPECT_EQ(pi1_on_pi3_timestamp_counter.count(), 0u);
752 EXPECT_EQ(pi2_on_pi1_timestamp_counter.count(), 0u);
753 EXPECT_EQ(pi2_on_pi2_timestamp_counter.count(), 0u);
754 EXPECT_EQ(pi3_on_pi1_timestamp_counter.count(), 0u);
755 EXPECT_EQ(pi3_on_pi3_timestamp_counter.count(), 0u);
756
757 EXPECT_EQ(pi1_server_statistics_counter.count(), 0u);
758 EXPECT_EQ(pi2_server_statistics_counter.count(), 0u);
759 EXPECT_EQ(pi3_server_statistics_counter.count(), 0u);
760
761 EXPECT_EQ(pi1_client_statistics_counter.count(), 0u);
762 EXPECT_EQ(pi2_client_statistics_counter.count(), 0u);
763 EXPECT_EQ(pi3_client_statistics_counter.count(), 0u);
Austin Schuh2f8fd752020-09-01 22:38:28 -0700764
765 // Also confirm that remote timestamps are being forwarded correctly.
766 EXPECT_EQ(remote_timestamps_pi2_on_pi1.count(), 1001);
767 EXPECT_EQ(remote_timestamps_pi1_on_pi2.count(), 1001);
Austin Schuh898f4972020-01-11 17:21:25 -0800768}
769
Neil Balchc8f41ed2018-01-20 22:06:53 -0800770} // namespace testing
771} // namespace aos