blob: 3923297601becfc66cbcd439078d3780a9af3c10 [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());
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700521 EXPECT_EQ(pi2_context->remote_queue_index, header.remote_queue_index());
Austin Schuh2f8fd752020-09-01 22:38:28 -0700522 EXPECT_EQ(pi2_context->monotonic_event_time,
523 header_monotonic_sent_time);
524 EXPECT_EQ(pi2_context->realtime_event_time, header_realtime_sent_time);
525 EXPECT_EQ(pi2_context->realtime_remote_time,
526 header_realtime_remote_time);
527 EXPECT_EQ(pi2_context->monotonic_remote_time,
528 header_monotonic_remote_time);
529
530 // Confirm the forwarded message also matches the source message.
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700531 EXPECT_EQ(pi1_context->queue_index, header.remote_queue_index());
Austin Schuh2f8fd752020-09-01 22:38:28 -0700532 EXPECT_EQ(pi1_context->monotonic_event_time,
533 header_monotonic_remote_time);
534 EXPECT_EQ(pi1_context->realtime_event_time,
535 header_realtime_remote_time);
536 });
537
Austin Schuh4c3b9702020-08-30 11:34:55 -0700538 simulated_event_loop_factory.RunFor(chrono::seconds(10) -
539 chrono::milliseconds(500) +
540 chrono::milliseconds(5));
541
542 EXPECT_EQ(pi1_pong_counter.count(), 1001);
543 EXPECT_EQ(pi2_pong_counter.count(), 1001);
544
545 EXPECT_EQ(pi1_on_pi1_timestamp_counter.count(), 100);
546 EXPECT_EQ(pi1_on_pi2_timestamp_counter.count(), 100);
547 EXPECT_EQ(pi1_on_pi3_timestamp_counter.count(), 100);
548 EXPECT_EQ(pi2_on_pi1_timestamp_counter.count(), 100);
549 EXPECT_EQ(pi2_on_pi2_timestamp_counter.count(), 100);
550 EXPECT_EQ(pi3_on_pi1_timestamp_counter.count(), 100);
551 EXPECT_EQ(pi3_on_pi3_timestamp_counter.count(), 100);
552
553 EXPECT_EQ(pi1_server_statistics_count, 9);
554 EXPECT_EQ(pi2_server_statistics_count, 9);
555 EXPECT_EQ(pi3_server_statistics_count, 9);
556
557 EXPECT_EQ(pi1_client_statistics_count, 95);
558 EXPECT_EQ(pi2_client_statistics_count, 95);
559 EXPECT_EQ(pi3_client_statistics_count, 95);
Austin Schuh2f8fd752020-09-01 22:38:28 -0700560
561 // Also confirm that remote timestamps are being forwarded correctly.
562 EXPECT_EQ(remote_timestamps_pi2_on_pi1.count(), 1101);
563 EXPECT_EQ(remote_timestamps_pi1_on_pi2.count(), 1101);
Austin Schuh4c3b9702020-08-30 11:34:55 -0700564}
565
566// Tests that an offset between nodes can be recovered and shows up in
567// ServerStatistics correctly.
568TEST(SimulatedEventLoopTest, MultinodePingPongWithOffset) {
569 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
Brian Silverman28d14302020-09-18 15:26:17 -0700570 aos::configuration::ReadConfig(ConfigPrefix() +
571 "events/multinode_pingpong_config.json");
Austin Schuh4c3b9702020-08-30 11:34:55 -0700572 const Node *pi1 = configuration::GetNode(&config.message(), "pi1");
573 const Node *pi2 = configuration::GetNode(&config.message(), "pi2");
574 const Node *pi3 = configuration::GetNode(&config.message(), "pi3");
575
576 SimulatedEventLoopFactory simulated_event_loop_factory(&config.message());
577 NodeEventLoopFactory *pi2_factory =
578 simulated_event_loop_factory.GetNodeEventLoopFactory(pi2);
579
580 constexpr chrono::milliseconds kOffset{1501};
581 pi2_factory->SetDistributedOffset(kOffset, 1.0);
582
583 std::unique_ptr<EventLoop> ping_event_loop =
584 simulated_event_loop_factory.MakeEventLoop("ping", pi1);
585 Ping ping(ping_event_loop.get());
586
587 std::unique_ptr<EventLoop> pong_event_loop =
588 simulated_event_loop_factory.MakeEventLoop("pong", pi2);
589 Pong pong(pong_event_loop.get());
590
591 std::unique_ptr<EventLoop> pi2_pong_counter_event_loop =
592 simulated_event_loop_factory.MakeEventLoop("pi2_pong_counter", pi2);
593
594 std::unique_ptr<EventLoop> pi3_pong_counter_event_loop =
595 simulated_event_loop_factory.MakeEventLoop("pi3_pong_counter", pi3);
596
597 std::unique_ptr<EventLoop> pi1_pong_counter_event_loop =
598 simulated_event_loop_factory.MakeEventLoop("pi1_pong_counter", pi1);
599
600 // Wait to let timestamp estimation start up before looking for the results.
601 simulated_event_loop_factory.RunFor(chrono::milliseconds(500));
602
603 // Confirm the offsets are being recovered correctly.
604 int pi1_server_statistics_count = 0;
605 pi1_pong_counter_event_loop->MakeWatcher(
606 "/pi1/aos", [&pi1_server_statistics_count,
607 kOffset](const message_bridge::ServerStatistics &stats) {
608 VLOG(1) << "pi1 ServerStatistics " << FlatbufferToJson(&stats);
609 EXPECT_EQ(stats.connections()->size(), 2u);
610 for (const message_bridge::ServerConnection *connection :
611 *stats.connections()) {
612 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
613 if (connection->node()->name()->string_view() == "pi2") {
614 EXPECT_EQ(connection->monotonic_offset(),
615 chrono::nanoseconds(kOffset).count());
616 } else if (connection->node()->name()->string_view() == "pi3") {
617 EXPECT_EQ(connection->monotonic_offset(), 0);
618 } else {
619 LOG(FATAL) << "Unknown connection";
620 }
621
622 EXPECT_TRUE(connection->has_monotonic_offset());
623 }
624 ++pi1_server_statistics_count;
625 });
626
627 int pi2_server_statistics_count = 0;
628 pi2_pong_counter_event_loop->MakeWatcher(
629 "/pi2/aos", [&pi2_server_statistics_count,
630 kOffset](const message_bridge::ServerStatistics &stats) {
631 VLOG(1) << "pi2 ServerStatistics " << FlatbufferToJson(&stats);
632 EXPECT_EQ(stats.connections()->size(), 1u);
633
634 const message_bridge::ServerConnection *connection =
635 stats.connections()->Get(0);
636 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
637 EXPECT_TRUE(connection->has_monotonic_offset());
638 EXPECT_EQ(connection->monotonic_offset(),
639 -chrono::nanoseconds(kOffset).count());
640 ++pi2_server_statistics_count;
641 });
642
643 int pi3_server_statistics_count = 0;
644 pi3_pong_counter_event_loop->MakeWatcher(
645 "/pi3/aos", [&pi3_server_statistics_count](
646 const message_bridge::ServerStatistics &stats) {
647 VLOG(1) << "pi3 ServerStatistics " << FlatbufferToJson(&stats);
648 EXPECT_EQ(stats.connections()->size(), 1u);
649
650 const message_bridge::ServerConnection *connection =
651 stats.connections()->Get(0);
652 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
653 EXPECT_TRUE(connection->has_monotonic_offset());
654 EXPECT_EQ(connection->monotonic_offset(), 0);
655 ++pi3_server_statistics_count;
656 });
657
658 simulated_event_loop_factory.RunFor(chrono::seconds(10) -
659 chrono::milliseconds(500) +
660 chrono::milliseconds(5));
661
662 EXPECT_EQ(pi1_server_statistics_count, 9);
663 EXPECT_EQ(pi2_server_statistics_count, 9);
664 EXPECT_EQ(pi3_server_statistics_count, 9);
665}
666
667// Test that disabling statistics actually disables them.
668TEST(SimulatedEventLoopTest, MultinodeWithoutStatistics) {
669 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
Brian Silverman28d14302020-09-18 15:26:17 -0700670 aos::configuration::ReadConfig(ConfigPrefix() +
671 "events/multinode_pingpong_config.json");
Austin Schuh4c3b9702020-08-30 11:34:55 -0700672 const Node *pi1 = configuration::GetNode(&config.message(), "pi1");
673 const Node *pi2 = configuration::GetNode(&config.message(), "pi2");
674 const Node *pi3 = configuration::GetNode(&config.message(), "pi3");
675
676 SimulatedEventLoopFactory simulated_event_loop_factory(&config.message());
677 simulated_event_loop_factory.DisableStatistics();
678
679 std::unique_ptr<EventLoop> ping_event_loop =
680 simulated_event_loop_factory.MakeEventLoop("ping", pi1);
681 Ping ping(ping_event_loop.get());
682
683 std::unique_ptr<EventLoop> pong_event_loop =
684 simulated_event_loop_factory.MakeEventLoop("pong", pi2);
685 Pong pong(pong_event_loop.get());
686
687 std::unique_ptr<EventLoop> pi2_pong_counter_event_loop =
688 simulated_event_loop_factory.MakeEventLoop("pi2_pong_counter", pi2);
689
690 MessageCounter<examples::Pong> pi2_pong_counter(
691 pi2_pong_counter_event_loop.get(), "/test");
692
693 std::unique_ptr<EventLoop> pi3_pong_counter_event_loop =
694 simulated_event_loop_factory.MakeEventLoop("pi3_pong_counter", pi3);
695
696 std::unique_ptr<EventLoop> pi1_pong_counter_event_loop =
697 simulated_event_loop_factory.MakeEventLoop("pi1_pong_counter", pi1);
698
699 MessageCounter<examples::Pong> pi1_pong_counter(
700 pi1_pong_counter_event_loop.get(), "/test");
701
702 // Count timestamps.
703 MessageCounter<message_bridge::Timestamp> pi1_on_pi1_timestamp_counter(
704 pi1_pong_counter_event_loop.get(), "/pi1/aos");
705 MessageCounter<message_bridge::Timestamp> pi1_on_pi2_timestamp_counter(
706 pi2_pong_counter_event_loop.get(), "/pi1/aos");
707 MessageCounter<message_bridge::Timestamp> pi1_on_pi3_timestamp_counter(
708 pi3_pong_counter_event_loop.get(), "/pi1/aos");
709 MessageCounter<message_bridge::Timestamp> pi2_on_pi1_timestamp_counter(
710 pi1_pong_counter_event_loop.get(), "/pi2/aos");
711 MessageCounter<message_bridge::Timestamp> pi2_on_pi2_timestamp_counter(
712 pi2_pong_counter_event_loop.get(), "/pi2/aos");
713 MessageCounter<message_bridge::Timestamp> pi3_on_pi1_timestamp_counter(
714 pi1_pong_counter_event_loop.get(), "/pi3/aos");
715 MessageCounter<message_bridge::Timestamp> pi3_on_pi3_timestamp_counter(
716 pi3_pong_counter_event_loop.get(), "/pi3/aos");
717
Austin Schuh2f8fd752020-09-01 22:38:28 -0700718 // Count remote timestamps
719 MessageCounter<logger::MessageHeader> remote_timestamps_pi2_on_pi1(
720 pi1_pong_counter_event_loop.get(), "/aos/remote_timestamps/pi2");
721 MessageCounter<logger::MessageHeader> remote_timestamps_pi1_on_pi2(
722 pi2_pong_counter_event_loop.get(), "/aos/remote_timestamps/pi1");
723
Austin Schuh4c3b9702020-08-30 11:34:55 -0700724 MessageCounter<message_bridge::ServerStatistics>
725 pi1_server_statistics_counter(pi1_pong_counter_event_loop.get(),
726 "/pi1/aos");
727 MessageCounter<message_bridge::ServerStatistics>
728 pi2_server_statistics_counter(pi2_pong_counter_event_loop.get(),
729 "/pi2/aos");
730 MessageCounter<message_bridge::ServerStatistics>
731 pi3_server_statistics_counter(pi3_pong_counter_event_loop.get(),
732 "/pi3/aos");
733
734 MessageCounter<message_bridge::ClientStatistics>
735 pi1_client_statistics_counter(pi1_pong_counter_event_loop.get(),
736 "/pi1/aos");
737 MessageCounter<message_bridge::ClientStatistics>
738 pi2_client_statistics_counter(pi2_pong_counter_event_loop.get(),
739 "/pi2/aos");
740 MessageCounter<message_bridge::ClientStatistics>
741 pi3_client_statistics_counter(pi3_pong_counter_event_loop.get(),
742 "/pi3/aos");
Austin Schuh898f4972020-01-11 17:21:25 -0800743
744 simulated_event_loop_factory.RunFor(chrono::seconds(10) +
745 chrono::milliseconds(5));
746
Austin Schuh4c3b9702020-08-30 11:34:55 -0700747 EXPECT_EQ(pi1_pong_counter.count(), 1001u);
748 EXPECT_EQ(pi2_pong_counter.count(), 1001u);
749
750 EXPECT_EQ(pi1_on_pi1_timestamp_counter.count(), 0u);
751 EXPECT_EQ(pi1_on_pi2_timestamp_counter.count(), 0u);
752 EXPECT_EQ(pi1_on_pi3_timestamp_counter.count(), 0u);
753 EXPECT_EQ(pi2_on_pi1_timestamp_counter.count(), 0u);
754 EXPECT_EQ(pi2_on_pi2_timestamp_counter.count(), 0u);
755 EXPECT_EQ(pi3_on_pi1_timestamp_counter.count(), 0u);
756 EXPECT_EQ(pi3_on_pi3_timestamp_counter.count(), 0u);
757
758 EXPECT_EQ(pi1_server_statistics_counter.count(), 0u);
759 EXPECT_EQ(pi2_server_statistics_counter.count(), 0u);
760 EXPECT_EQ(pi3_server_statistics_counter.count(), 0u);
761
762 EXPECT_EQ(pi1_client_statistics_counter.count(), 0u);
763 EXPECT_EQ(pi2_client_statistics_counter.count(), 0u);
764 EXPECT_EQ(pi3_client_statistics_counter.count(), 0u);
Austin Schuh2f8fd752020-09-01 22:38:28 -0700765
766 // Also confirm that remote timestamps are being forwarded correctly.
767 EXPECT_EQ(remote_timestamps_pi2_on_pi1.count(), 1001);
768 EXPECT_EQ(remote_timestamps_pi1_on_pi2.count(), 1001);
Austin Schuh898f4972020-01-11 17:21:25 -0800769}
770
Austin Schuh2febf0d2020-09-21 22:24:30 -0700771// Tests that the time offset having a slope doesn't break the world.
772// SimulatedMessageBridge has enough self consistency CHECK statements to
773// confirm, and we can can also check a message in each direction to make sure
774// it gets delivered as expected.
775TEST(SimulatedEventLoopTest, MultinodePingPongWithOffsetAndSlope) {
776 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
777 aos::configuration::ReadConfig(ConfigPrefix() +
778 "events/multinode_pingpong_config.json");
779 const Node *pi1 = configuration::GetNode(&config.message(), "pi1");
780 const Node *pi2 = configuration::GetNode(&config.message(), "pi2");
781
782 SimulatedEventLoopFactory simulated_event_loop_factory(&config.message());
783 NodeEventLoopFactory *pi2_factory =
784 simulated_event_loop_factory.GetNodeEventLoopFactory(pi2);
785
786 // Move the pi far into the future so the slope is significant. And set it to
787 // something reasonable.
788 constexpr chrono::milliseconds kOffset{150100};
789 pi2_factory->SetDistributedOffset(kOffset, 1.0001);
790
791 std::unique_ptr<EventLoop> ping_event_loop =
792 simulated_event_loop_factory.MakeEventLoop("ping", pi1);
793 Ping ping(ping_event_loop.get());
794
795 std::unique_ptr<EventLoop> pong_event_loop =
796 simulated_event_loop_factory.MakeEventLoop("pong", pi2);
797 Pong pong(pong_event_loop.get());
798
799 std::unique_ptr<EventLoop> pi1_counter_event_loop =
800 simulated_event_loop_factory.MakeEventLoop("pi1_counter", pi1);
801 std::unique_ptr<EventLoop> pi2_counter_event_loop =
802 simulated_event_loop_factory.MakeEventLoop("pi2_counter", pi2);
803
804 aos::Fetcher<examples::Ping> ping_on_pi1_fetcher =
805 pi1_counter_event_loop->MakeFetcher<examples::Ping>("/test");
806 aos::Fetcher<examples::Ping> ping_on_pi2_fetcher =
807 pi2_counter_event_loop->MakeFetcher<examples::Ping>("/test");
808
809 aos::Fetcher<examples::Pong> pong_on_pi2_fetcher =
810 pi2_counter_event_loop->MakeFetcher<examples::Pong>("/test");
811 aos::Fetcher<examples::Pong> pong_on_pi1_fetcher =
812 pi1_counter_event_loop->MakeFetcher<examples::Pong>("/test");
813
814 // End after a pong message comes back. This will leave the latest messages
815 // on all channels so we can look at timestamps easily and check they make
816 // sense.
817 std::unique_ptr<EventLoop> pi1_pong_ender =
818 simulated_event_loop_factory.MakeEventLoop("pi2_counter", pi1);
819 int count = 0;
820 pi1_pong_ender->MakeWatcher(
821 "/test", [&simulated_event_loop_factory, &count](const examples::Pong &) {
822 if (++count == 100) {
823 simulated_event_loop_factory.Exit();
824 }
825 });
826
827 // Run enough that messages should be delivered.
828 simulated_event_loop_factory.Run();
829
830 // Grab the latest messages.
831 EXPECT_TRUE(ping_on_pi1_fetcher.Fetch());
832 EXPECT_TRUE(ping_on_pi2_fetcher.Fetch());
833 EXPECT_TRUE(pong_on_pi1_fetcher.Fetch());
834 EXPECT_TRUE(pong_on_pi2_fetcher.Fetch());
835
836 // Compute their time on the global distributed clock so we can compute
837 // distance betwen them.
838 const distributed_clock::time_point pi1_ping_time =
839 simulated_event_loop_factory.GetNodeEventLoopFactory(pi1)
840 ->ToDistributedClock(
841 ping_on_pi1_fetcher.context().monotonic_event_time);
842 const distributed_clock::time_point pi2_ping_time =
843 simulated_event_loop_factory.GetNodeEventLoopFactory(pi2)
844 ->ToDistributedClock(
845 ping_on_pi2_fetcher.context().monotonic_event_time);
846 const distributed_clock::time_point pi1_pong_time =
847 simulated_event_loop_factory.GetNodeEventLoopFactory(pi1)
848 ->ToDistributedClock(
849 pong_on_pi1_fetcher.context().monotonic_event_time);
850 const distributed_clock::time_point pi2_pong_time =
851 simulated_event_loop_factory.GetNodeEventLoopFactory(pi2)
852 ->ToDistributedClock(
853 pong_on_pi2_fetcher.context().monotonic_event_time);
854
855 // And confirm the delivery delay is just about exactly 150 uS for both
856 // directions like expected. There will be a couple ns of rounding errors in
857 // the conversion functions that aren't worth accounting for right now. This
858 // will either be really close, or really far.
859 EXPECT_GE(pi2_ping_time, chrono::microseconds(150) - chrono::nanoseconds(10) +
860 pi1_ping_time);
861 EXPECT_LE(pi2_ping_time, chrono::microseconds(150) + chrono::nanoseconds(10) +
862 pi1_ping_time);
863
864 EXPECT_GE(pi1_pong_time, chrono::microseconds(150) - chrono::nanoseconds(10) +
865 pi2_pong_time);
866 EXPECT_LE(pi1_pong_time, chrono::microseconds(150) + chrono::nanoseconds(10) +
867 pi2_pong_time);
868}
869
Neil Balchc8f41ed2018-01-20 22:06:53 -0800870} // namespace testing
871} // namespace aos