blob: 375b8fd24851a1b0e4c940467a9323eb1dd5bacb [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 Schuh898f4972020-01-11 17:21:25 -08007#include "aos/events/ping_lib.h"
8#include "aos/events/pong_lib.h"
Austin Schuh7d87b672019-12-01 20:23:49 -08009#include "aos/events/test_message_generated.h"
Austin Schuh4c3b9702020-08-30 11:34:55 -070010#include "aos/network/message_bridge_client_generated.h"
11#include "aos/network/message_bridge_server_generated.h"
12#include "aos/network/timestamp_generated.h"
Neil Balchc8f41ed2018-01-20 22:06:53 -080013#include "gtest/gtest.h"
14
15namespace aos {
16namespace testing {
Brian Silverman28d14302020-09-18 15:26:17 -070017namespace {
18
19std::string ConfigPrefix() { return "aos/"; }
20
21} // namespace
Neil Balchc8f41ed2018-01-20 22:06:53 -080022
Austin Schuh7267c532019-05-19 19:55:53 -070023namespace chrono = ::std::chrono;
24
Neil Balchc8f41ed2018-01-20 22:06:53 -080025class SimulatedEventLoopTestFactory : public EventLoopTestFactory {
26 public:
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080027 ::std::unique_ptr<EventLoop> Make(std::string_view name) override {
Austin Schuh217a9782019-12-21 23:02:50 -080028 MaybeMake();
Austin Schuhac0771c2020-01-07 18:36:30 -080029 return event_loop_factory_->MakeEventLoop(name, my_node());
Neil Balchc8f41ed2018-01-20 22:06:53 -080030 }
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080031 ::std::unique_ptr<EventLoop> MakePrimary(std::string_view name) override {
Austin Schuh217a9782019-12-21 23:02:50 -080032 MaybeMake();
Austin Schuhac0771c2020-01-07 18:36:30 -080033 return event_loop_factory_->MakeEventLoop(name, my_node());
Austin Schuh44019f92019-05-19 19:58:27 -070034 }
35
Austin Schuh217a9782019-12-21 23:02:50 -080036 void Run() override { event_loop_factory_->Run(); }
37 void Exit() override { event_loop_factory_->Exit(); }
Austin Schuh44019f92019-05-19 19:58:27 -070038
Austin Schuh52d325c2019-06-23 18:59:06 -070039 // TODO(austin): Implement this. It's used currently for a phased loop test.
40 // I'm not sure how much that matters.
41 void SleepFor(::std::chrono::nanoseconds /*duration*/) override {}
42
Austin Schuh7d87b672019-12-01 20:23:49 -080043 void set_send_delay(std::chrono::nanoseconds send_delay) {
Austin Schuh217a9782019-12-21 23:02:50 -080044 MaybeMake();
45 event_loop_factory_->set_send_delay(send_delay);
Austin Schuh7d87b672019-12-01 20:23:49 -080046 }
47
Neil Balchc8f41ed2018-01-20 22:06:53 -080048 private:
Austin Schuh217a9782019-12-21 23:02:50 -080049 void MaybeMake() {
50 if (!event_loop_factory_) {
51 if (configuration()->has_nodes()) {
Austin Schuhac0771c2020-01-07 18:36:30 -080052 event_loop_factory_ =
53 std::make_unique<SimulatedEventLoopFactory>(configuration());
Austin Schuh217a9782019-12-21 23:02:50 -080054 } else {
55 event_loop_factory_ =
56 std::make_unique<SimulatedEventLoopFactory>(configuration());
57 }
58 }
59 }
60 std::unique_ptr<SimulatedEventLoopFactory> event_loop_factory_;
Neil Balchc8f41ed2018-01-20 22:06:53 -080061};
62
Brian Silverman77162972020-08-12 19:52:40 -070063INSTANTIATE_TEST_CASE_P(SimulatedEventLoopCopyTest, AbstractEventLoopTest,
64 ::testing::Values(std::make_tuple(
65 []() {
66 return new SimulatedEventLoopTestFactory();
67 },
68 ReadMethod::COPY)));
Austin Schuh6b6dfa52019-06-12 20:16:20 -070069
Brian Silverman77162972020-08-12 19:52:40 -070070INSTANTIATE_TEST_CASE_P(
71 SimulatedEventLoopCopyDeathTest, AbstractEventLoopDeathTest,
72 ::testing::Values(
73 std::make_tuple([]() { return new SimulatedEventLoopTestFactory(); },
74 ReadMethod::COPY)));
75
76INSTANTIATE_TEST_CASE_P(SimulatedEventLoopPinTest, AbstractEventLoopTest,
77 ::testing::Values(std::make_tuple(
78 []() {
79 return new SimulatedEventLoopTestFactory();
80 },
81 ReadMethod::PIN)));
82
83INSTANTIATE_TEST_CASE_P(
84 SimulatedEventLoopPinDeathTest, AbstractEventLoopDeathTest,
85 ::testing::Values(
86 std::make_tuple([]() { return new SimulatedEventLoopTestFactory(); },
87 ReadMethod::PIN)));
Neil Balchc8f41ed2018-01-20 22:06:53 -080088
89// Test that creating an event and running the scheduler runs the event.
90TEST(EventSchedulerTest, ScheduleEvent) {
91 int counter = 0;
Austin Schuh8bd96322020-02-13 21:18:22 -080092 EventSchedulerScheduler scheduler_scheduler;
Neil Balchc8f41ed2018-01-20 22:06:53 -080093 EventScheduler scheduler;
Austin Schuh8bd96322020-02-13 21:18:22 -080094 scheduler_scheduler.AddEventScheduler(&scheduler);
Neil Balchc8f41ed2018-01-20 22:06:53 -080095
Austin Schuh8bd96322020-02-13 21:18:22 -080096 scheduler.Schedule(monotonic_clock::epoch() + chrono::seconds(1),
Austin Schuhac0771c2020-01-07 18:36:30 -080097 [&counter]() { counter += 1; });
Austin Schuh8bd96322020-02-13 21:18:22 -080098 scheduler_scheduler.Run();
Neil Balchc8f41ed2018-01-20 22:06:53 -080099 EXPECT_EQ(counter, 1);
Ravago Jonescf453ab2020-05-06 21:14:53 -0700100 auto token = scheduler.Schedule(monotonic_clock::epoch() + chrono::seconds(2),
101 [&counter]() { counter += 1; });
Neil Balchc8f41ed2018-01-20 22:06:53 -0800102 scheduler.Deschedule(token);
Austin Schuh8bd96322020-02-13 21:18:22 -0800103 scheduler_scheduler.Run();
Neil Balchc8f41ed2018-01-20 22:06:53 -0800104 EXPECT_EQ(counter, 1);
105}
106
107// Test that descheduling an already scheduled event doesn't run the event.
108TEST(EventSchedulerTest, DescheduleEvent) {
109 int counter = 0;
Austin Schuh8bd96322020-02-13 21:18:22 -0800110 EventSchedulerScheduler scheduler_scheduler;
Neil Balchc8f41ed2018-01-20 22:06:53 -0800111 EventScheduler scheduler;
Austin Schuh8bd96322020-02-13 21:18:22 -0800112 scheduler_scheduler.AddEventScheduler(&scheduler);
Neil Balchc8f41ed2018-01-20 22:06:53 -0800113
Austin Schuh8bd96322020-02-13 21:18:22 -0800114 auto token = scheduler.Schedule(monotonic_clock::epoch() + chrono::seconds(1),
115 [&counter]() { counter += 1; });
Neil Balchc8f41ed2018-01-20 22:06:53 -0800116 scheduler.Deschedule(token);
Austin Schuh8bd96322020-02-13 21:18:22 -0800117 scheduler_scheduler.Run();
Neil Balchc8f41ed2018-01-20 22:06:53 -0800118 EXPECT_EQ(counter, 0);
119}
Austin Schuh44019f92019-05-19 19:58:27 -0700120
121// Test that running for a time period with no handlers causes time to progress
122// correctly.
123TEST(SimulatedEventLoopTest, RunForNoHandlers) {
Austin Schuh39788ff2019-12-01 18:22:57 -0800124 SimulatedEventLoopTestFactory factory;
125
126 SimulatedEventLoopFactory simulated_event_loop_factory(
127 factory.configuration());
Austin Schuh44019f92019-05-19 19:58:27 -0700128 ::std::unique_ptr<EventLoop> event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800129 simulated_event_loop_factory.MakeEventLoop("loop");
Austin Schuh44019f92019-05-19 19:58:27 -0700130
131 simulated_event_loop_factory.RunFor(chrono::seconds(1));
132
133 EXPECT_EQ(::aos::monotonic_clock::epoch() + chrono::seconds(1),
Austin Schuh44019f92019-05-19 19:58:27 -0700134 event_loop->monotonic_now());
135}
136
137// Test that running for a time with a periodic handler causes time to end
138// correctly.
139TEST(SimulatedEventLoopTest, RunForTimerHandler) {
Austin Schuh39788ff2019-12-01 18:22:57 -0800140 SimulatedEventLoopTestFactory factory;
141
142 SimulatedEventLoopFactory simulated_event_loop_factory(
143 factory.configuration());
Austin Schuh44019f92019-05-19 19:58:27 -0700144 ::std::unique_ptr<EventLoop> event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -0800145 simulated_event_loop_factory.MakeEventLoop("loop");
Austin Schuh44019f92019-05-19 19:58:27 -0700146
147 int counter = 0;
Alex Perrycb7da4b2019-08-28 19:35:56 -0700148 auto timer = event_loop->AddTimer([&counter]() { ++counter; });
Austin Schuh44019f92019-05-19 19:58:27 -0700149 event_loop->OnRun([&event_loop, &timer] {
150 timer->Setup(event_loop->monotonic_now() + chrono::milliseconds(50),
151 chrono::milliseconds(100));
152 });
153
154 simulated_event_loop_factory.RunFor(chrono::seconds(1));
155
156 EXPECT_EQ(::aos::monotonic_clock::epoch() + chrono::seconds(1),
Austin Schuh44019f92019-05-19 19:58:27 -0700157 event_loop->monotonic_now());
158 EXPECT_EQ(counter, 10);
159}
160
Austin Schuh7d87b672019-12-01 20:23:49 -0800161// Tests that watchers have latency in simulation.
162TEST(SimulatedEventLoopTest, WatcherTimingReport) {
163 SimulatedEventLoopTestFactory factory;
164 factory.set_send_delay(std::chrono::microseconds(50));
165
166 FLAGS_timing_report_ms = 1000;
167 auto loop1 = factory.MakePrimary("primary");
168 loop1->MakeWatcher("/test", [](const TestMessage &) {});
169
170 auto loop2 = factory.Make("sender_loop");
171
172 auto loop3 = factory.Make("report_fetcher");
173
174 Fetcher<timing::Report> report_fetcher =
175 loop3->MakeFetcher<timing::Report>("/aos");
176 EXPECT_FALSE(report_fetcher.Fetch());
177
178 auto sender = loop2->MakeSender<TestMessage>("/test");
179
180 // Send 10 messages in the middle of a timing report period so we get
181 // something interesting back.
182 auto test_timer = loop2->AddTimer([&sender]() {
183 for (int i = 0; i < 10; ++i) {
184 aos::Sender<TestMessage>::Builder msg = sender.MakeBuilder();
185 TestMessage::Builder builder = msg.MakeBuilder<TestMessage>();
186 builder.add_value(200 + i);
187 ASSERT_TRUE(msg.Send(builder.Finish()));
188 }
189 });
190
191 // Quit after 1 timing report, mid way through the next cycle.
192 {
193 auto end_timer = loop1->AddTimer([&factory]() { factory.Exit(); });
194 end_timer->Setup(loop1->monotonic_now() + chrono::milliseconds(2500));
195 end_timer->set_name("end");
196 }
197
198 loop1->OnRun([&test_timer, &loop1]() {
199 test_timer->Setup(loop1->monotonic_now() + chrono::milliseconds(1500));
200 });
201
202 factory.Run();
203
204 // And, since we are here, check that the timing report makes sense.
205 // Start by looking for our event loop's timing.
206 FlatbufferDetachedBuffer<timing::Report> primary_report =
207 FlatbufferDetachedBuffer<timing::Report>::Empty();
208 while (report_fetcher.FetchNext()) {
209 LOG(INFO) << "Report " << FlatbufferToJson(report_fetcher.get());
210 if (report_fetcher->name()->string_view() == "primary") {
211 primary_report = CopyFlatBuffer(report_fetcher.get());
212 }
213 }
214
215 // Check the watcher report.
Ravago Jonescf453ab2020-05-06 21:14:53 -0700216 VLOG(1) << FlatbufferToJson(primary_report, {.multi_line = true});
Austin Schuh7d87b672019-12-01 20:23:49 -0800217
218 EXPECT_EQ(primary_report.message().name()->string_view(), "primary");
219
220 // Just the timing report timer.
221 ASSERT_NE(primary_report.message().timers(), nullptr);
222 EXPECT_EQ(primary_report.message().timers()->size(), 2);
223
224 // No phased loops
225 ASSERT_EQ(primary_report.message().phased_loops(), nullptr);
226
227 // And now confirm that the watcher received all 10 messages, and has latency.
228 ASSERT_NE(primary_report.message().watchers(), nullptr);
229 ASSERT_EQ(primary_report.message().watchers()->size(), 1);
230 EXPECT_EQ(primary_report.message().watchers()->Get(0)->count(), 10);
231 EXPECT_NEAR(
232 primary_report.message().watchers()->Get(0)->wakeup_latency()->average(),
233 0.00005, 1e-9);
234 EXPECT_NEAR(
235 primary_report.message().watchers()->Get(0)->wakeup_latency()->min(),
236 0.00005, 1e-9);
237 EXPECT_NEAR(
238 primary_report.message().watchers()->Get(0)->wakeup_latency()->max(),
239 0.00005, 1e-9);
240 EXPECT_EQ(primary_report.message()
241 .watchers()
242 ->Get(0)
243 ->wakeup_latency()
244 ->standard_deviation(),
245 0.0);
246
247 EXPECT_EQ(
248 primary_report.message().watchers()->Get(0)->handler_time()->average(),
249 0.0);
250 EXPECT_EQ(primary_report.message().watchers()->Get(0)->handler_time()->min(),
251 0.0);
252 EXPECT_EQ(primary_report.message().watchers()->Get(0)->handler_time()->max(),
253 0.0);
254 EXPECT_EQ(primary_report.message()
255 .watchers()
256 ->Get(0)
257 ->handler_time()
258 ->standard_deviation(),
259 0.0);
260}
261
Austin Schuh4c3b9702020-08-30 11:34:55 -0700262template <typename T>
263class MessageCounter {
264 public:
265 MessageCounter(aos::EventLoop *event_loop, std::string_view name) {
266 event_loop->MakeNoArgWatcher<T>(name, [this]() { ++count_; });
267 }
268
269 size_t count() const { return count_; }
270
271 private:
272 size_t count_ = 0;
273};
274
275// Tests that ping and pong work when on 2 different nodes, and the message
276// gateway messages are sent out as expected.
Austin Schuh898f4972020-01-11 17:21:25 -0800277TEST(SimulatedEventLoopTest, MultinodePingPong) {
278 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
Brian Silverman28d14302020-09-18 15:26:17 -0700279 aos::configuration::ReadConfig(ConfigPrefix() +
280 "events/multinode_pingpong_config.json");
Austin Schuh898f4972020-01-11 17:21:25 -0800281 const Node *pi1 = configuration::GetNode(&config.message(), "pi1");
282 const Node *pi2 = configuration::GetNode(&config.message(), "pi2");
Austin Schuh4c3b9702020-08-30 11:34:55 -0700283 const Node *pi3 = configuration::GetNode(&config.message(), "pi3");
Austin Schuh898f4972020-01-11 17:21:25 -0800284
285 SimulatedEventLoopFactory simulated_event_loop_factory(&config.message());
286
287 std::unique_ptr<EventLoop> ping_event_loop =
288 simulated_event_loop_factory.MakeEventLoop("ping", pi1);
289 Ping ping(ping_event_loop.get());
290
291 std::unique_ptr<EventLoop> pong_event_loop =
292 simulated_event_loop_factory.MakeEventLoop("pong", pi2);
293 Pong pong(pong_event_loop.get());
294
295 std::unique_ptr<EventLoop> pi2_pong_counter_event_loop =
296 simulated_event_loop_factory.MakeEventLoop("pi2_pong_counter", pi2);
Austin Schuh4c3b9702020-08-30 11:34:55 -0700297 MessageCounter<examples::Pong> pi2_pong_counter(
298 pi2_pong_counter_event_loop.get(), "/test");
Austin Schuh2f8fd752020-09-01 22:38:28 -0700299 aos::Fetcher<message_bridge::Timestamp> pi1_on_pi2_timestamp_fetcher =
300 pi2_pong_counter_event_loop->MakeFetcher<message_bridge::Timestamp>(
301 "/pi1/aos");
302 aos::Fetcher<examples::Ping> ping_on_pi2_fetcher =
303 pi2_pong_counter_event_loop->MakeFetcher<examples::Ping>("/test");
Austin Schuh898f4972020-01-11 17:21:25 -0800304
Austin Schuh4c3b9702020-08-30 11:34:55 -0700305 std::unique_ptr<EventLoop> pi3_pong_counter_event_loop =
306 simulated_event_loop_factory.MakeEventLoop("pi3_pong_counter", pi3);
Austin Schuh898f4972020-01-11 17:21:25 -0800307
308 std::unique_ptr<EventLoop> pi1_pong_counter_event_loop =
309 simulated_event_loop_factory.MakeEventLoop("pi1_pong_counter", pi1);
Austin Schuh4c3b9702020-08-30 11:34:55 -0700310 MessageCounter<examples::Pong> pi1_pong_counter(
311 pi1_pong_counter_event_loop.get(), "/test");
Austin Schuh2f8fd752020-09-01 22:38:28 -0700312 aos::Fetcher<examples::Ping> ping_on_pi1_fetcher =
313 pi1_pong_counter_event_loop->MakeFetcher<examples::Ping>("/test");
314 aos::Fetcher<message_bridge::Timestamp> pi1_on_pi1_timestamp_fetcher =
315 pi1_pong_counter_event_loop->MakeFetcher<message_bridge::Timestamp>(
316 "/aos");
317
318 std::unique_ptr<EventLoop> pi1_remote_timestamp =
319 simulated_event_loop_factory.MakeEventLoop("pi1_remote_timestamp", pi1);
Austin Schuh4c3b9702020-08-30 11:34:55 -0700320
321 // Count timestamps.
322 MessageCounter<message_bridge::Timestamp> pi1_on_pi1_timestamp_counter(
323 pi1_pong_counter_event_loop.get(), "/pi1/aos");
324 MessageCounter<message_bridge::Timestamp> pi1_on_pi2_timestamp_counter(
325 pi2_pong_counter_event_loop.get(), "/pi1/aos");
326 MessageCounter<message_bridge::Timestamp> pi1_on_pi3_timestamp_counter(
327 pi3_pong_counter_event_loop.get(), "/pi1/aos");
328 MessageCounter<message_bridge::Timestamp> pi2_on_pi1_timestamp_counter(
329 pi1_pong_counter_event_loop.get(), "/pi2/aos");
330 MessageCounter<message_bridge::Timestamp> pi2_on_pi2_timestamp_counter(
331 pi2_pong_counter_event_loop.get(), "/pi2/aos");
332 MessageCounter<message_bridge::Timestamp> pi3_on_pi1_timestamp_counter(
333 pi1_pong_counter_event_loop.get(), "/pi3/aos");
334 MessageCounter<message_bridge::Timestamp> pi3_on_pi3_timestamp_counter(
335 pi3_pong_counter_event_loop.get(), "/pi3/aos");
336
Austin Schuh2f8fd752020-09-01 22:38:28 -0700337 // Count remote timestamps
338 MessageCounter<logger::MessageHeader> remote_timestamps_pi2_on_pi1(
339 pi1_pong_counter_event_loop.get(), "/aos/remote_timestamps/pi2");
340 MessageCounter<logger::MessageHeader> remote_timestamps_pi1_on_pi2(
341 pi2_pong_counter_event_loop.get(), "/aos/remote_timestamps/pi1");
342
Austin Schuh4c3b9702020-08-30 11:34:55 -0700343 // Wait to let timestamp estimation start up before looking for the results.
344 simulated_event_loop_factory.RunFor(chrono::milliseconds(500));
345
346 int pi1_server_statistics_count = 0;
Austin Schuh898f4972020-01-11 17:21:25 -0800347 pi1_pong_counter_event_loop->MakeWatcher(
Austin Schuh4c3b9702020-08-30 11:34:55 -0700348 "/pi1/aos", [&pi1_server_statistics_count](
349 const message_bridge::ServerStatistics &stats) {
350 VLOG(1) << "pi1 ServerStatistics " << FlatbufferToJson(&stats);
351 EXPECT_EQ(stats.connections()->size(), 2u);
352 for (const message_bridge::ServerConnection *connection :
353 *stats.connections()) {
354 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
355 if (connection->node()->name()->string_view() == "pi2") {
356 EXPECT_GT(connection->sent_packets(), 50);
357 } else if (connection->node()->name()->string_view() == "pi3") {
358 EXPECT_GE(connection->sent_packets(), 5);
359 } else {
360 LOG(FATAL) << "Unknown connection";
361 }
362
363 EXPECT_TRUE(connection->has_monotonic_offset());
364 EXPECT_EQ(connection->monotonic_offset(), 0);
365 }
366 ++pi1_server_statistics_count;
367 });
368
369 int pi2_server_statistics_count = 0;
370 pi2_pong_counter_event_loop->MakeWatcher(
371 "/pi2/aos", [&pi2_server_statistics_count](
372 const message_bridge::ServerStatistics &stats) {
373 VLOG(1) << "pi2 ServerStatistics " << FlatbufferToJson(&stats);
374 EXPECT_EQ(stats.connections()->size(), 1u);
375
376 const message_bridge::ServerConnection *connection =
377 stats.connections()->Get(0);
378 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
379 EXPECT_GT(connection->sent_packets(), 50);
380 EXPECT_TRUE(connection->has_monotonic_offset());
381 EXPECT_EQ(connection->monotonic_offset(), 0);
382 ++pi2_server_statistics_count;
383 });
384
385 int pi3_server_statistics_count = 0;
386 pi3_pong_counter_event_loop->MakeWatcher(
387 "/pi3/aos", [&pi3_server_statistics_count](
388 const message_bridge::ServerStatistics &stats) {
389 VLOG(1) << "pi3 ServerStatistics " << FlatbufferToJson(&stats);
390 EXPECT_EQ(stats.connections()->size(), 1u);
391
392 const message_bridge::ServerConnection *connection =
393 stats.connections()->Get(0);
394 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
395 EXPECT_GE(connection->sent_packets(), 5);
396 EXPECT_TRUE(connection->has_monotonic_offset());
397 EXPECT_EQ(connection->monotonic_offset(), 0);
398 ++pi3_server_statistics_count;
399 });
400
401 int pi1_client_statistics_count = 0;
402 pi1_pong_counter_event_loop->MakeWatcher(
403 "/pi1/aos", [&pi1_client_statistics_count](
404 const message_bridge::ClientStatistics &stats) {
405 VLOG(1) << "pi1 ClientStatistics " << FlatbufferToJson(&stats);
406 EXPECT_EQ(stats.connections()->size(), 2u);
407
408 for (const message_bridge::ClientConnection *connection :
409 *stats.connections()) {
410 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
411 if (connection->node()->name()->string_view() == "pi2") {
412 EXPECT_GT(connection->received_packets(), 50);
413 } else if (connection->node()->name()->string_view() == "pi3") {
414 EXPECT_GE(connection->received_packets(), 5);
415 } else {
416 LOG(FATAL) << "Unknown connection";
417 }
418
419 EXPECT_TRUE(connection->has_monotonic_offset());
420 EXPECT_EQ(connection->monotonic_offset(), 150000);
421 }
422 ++pi1_client_statistics_count;
423 });
424
425 int pi2_client_statistics_count = 0;
426 pi2_pong_counter_event_loop->MakeWatcher(
427 "/pi2/aos", [&pi2_client_statistics_count](
428 const message_bridge::ClientStatistics &stats) {
429 VLOG(1) << "pi2 ClientStatistics " << FlatbufferToJson(&stats);
430 EXPECT_EQ(stats.connections()->size(), 1u);
431
432 const message_bridge::ClientConnection *connection =
433 stats.connections()->Get(0);
434 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
435 EXPECT_GT(connection->received_packets(), 50);
436 EXPECT_TRUE(connection->has_monotonic_offset());
437 EXPECT_EQ(connection->monotonic_offset(), 150000);
438 ++pi2_client_statistics_count;
439 });
440
441 int pi3_client_statistics_count = 0;
442 pi3_pong_counter_event_loop->MakeWatcher(
443 "/pi3/aos", [&pi3_client_statistics_count](
444 const message_bridge::ClientStatistics &stats) {
445 VLOG(1) << "pi3 ClientStatistics " << FlatbufferToJson(&stats);
446 EXPECT_EQ(stats.connections()->size(), 1u);
447
448 const message_bridge::ClientConnection *connection =
449 stats.connections()->Get(0);
450 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
451 EXPECT_GE(connection->received_packets(), 5);
452 EXPECT_TRUE(connection->has_monotonic_offset());
453 EXPECT_EQ(connection->monotonic_offset(), 150000);
454 ++pi3_client_statistics_count;
455 });
456
Austin Schuh2f8fd752020-09-01 22:38:28 -0700457 // Find the channel index for both the /pi1/aos Timestamp channel and Ping
458 // channel.
459 const size_t pi1_timestamp_channel =
460 configuration::ChannelIndex(pi1_pong_counter_event_loop->configuration(),
461 pi1_on_pi2_timestamp_fetcher.channel());
462 const size_t ping_timestamp_channel =
463 configuration::ChannelIndex(pi1_pong_counter_event_loop->configuration(),
464 ping_on_pi2_fetcher.channel());
465
466 for (const Channel *channel :
467 *pi1_pong_counter_event_loop->configuration()->channels()) {
468 VLOG(1) << "Channel "
469 << configuration::ChannelIndex(
470 pi1_pong_counter_event_loop->configuration(), channel)
471 << " " << configuration::CleanedChannelToString(channel);
472 }
473
474 // For each remote timestamp we get back, confirm that it is either a ping
475 // message, or a timestamp we sent out. Also confirm that the timestamps are
476 // correct.
477 pi1_remote_timestamp->MakeWatcher(
478 "/pi1/aos/remote_timestamps/pi2",
479 [pi1_timestamp_channel, ping_timestamp_channel, &ping_on_pi2_fetcher,
480 &ping_on_pi1_fetcher, &pi1_on_pi2_timestamp_fetcher,
481 &pi1_on_pi1_timestamp_fetcher](const logger::MessageHeader &header) {
482 VLOG(1) << aos::FlatbufferToJson(&header);
483
484 const aos::monotonic_clock::time_point header_monotonic_sent_time(
485 chrono::nanoseconds(header.monotonic_sent_time()));
486 const aos::realtime_clock::time_point header_realtime_sent_time(
487 chrono::nanoseconds(header.realtime_sent_time()));
488 const aos::monotonic_clock::time_point header_monotonic_remote_time(
489 chrono::nanoseconds(header.monotonic_remote_time()));
490 const aos::realtime_clock::time_point header_realtime_remote_time(
491 chrono::nanoseconds(header.realtime_remote_time()));
492
493 const Context *pi1_context = nullptr;
494 const Context *pi2_context = nullptr;
495
496 if (header.channel_index() == pi1_timestamp_channel) {
497 // Find the forwarded message.
498 while (pi1_on_pi2_timestamp_fetcher.context().monotonic_event_time <
499 header_monotonic_sent_time) {
500 ASSERT_TRUE(pi1_on_pi2_timestamp_fetcher.FetchNext());
501 }
502
503 // And the source message.
504 while (pi1_on_pi1_timestamp_fetcher.context().monotonic_event_time <
505 header_monotonic_remote_time) {
506 ASSERT_TRUE(pi1_on_pi1_timestamp_fetcher.FetchNext());
507 }
508
509 pi1_context = &pi1_on_pi1_timestamp_fetcher.context();
510 pi2_context = &pi1_on_pi2_timestamp_fetcher.context();
511 } else if (header.channel_index() == ping_timestamp_channel) {
512 // Find the forwarded message.
513 while (ping_on_pi2_fetcher.context().monotonic_event_time <
514 header_monotonic_sent_time) {
515 ASSERT_TRUE(ping_on_pi2_fetcher.FetchNext());
516 }
517
518 // And the source message.
519 while (ping_on_pi1_fetcher.context().monotonic_event_time <
520 header_monotonic_remote_time) {
521 ASSERT_TRUE(ping_on_pi1_fetcher.FetchNext());
522 }
523
524 pi1_context = &ping_on_pi1_fetcher.context();
525 pi2_context = &ping_on_pi2_fetcher.context();
526 } else {
527 LOG(FATAL) << "Unknown channel";
528 }
529
530 // Confirm the forwarded message has matching timestamps to the
531 // timestamps we got back.
532 EXPECT_EQ(pi2_context->queue_index, header.queue_index());
533 EXPECT_EQ(pi2_context->monotonic_event_time,
534 header_monotonic_sent_time);
535 EXPECT_EQ(pi2_context->realtime_event_time, header_realtime_sent_time);
536 EXPECT_EQ(pi2_context->realtime_remote_time,
537 header_realtime_remote_time);
538 EXPECT_EQ(pi2_context->monotonic_remote_time,
539 header_monotonic_remote_time);
540
541 // Confirm the forwarded message also matches the source message.
542 EXPECT_EQ(pi1_context->queue_index, header.queue_index());
543 EXPECT_EQ(pi1_context->monotonic_event_time,
544 header_monotonic_remote_time);
545 EXPECT_EQ(pi1_context->realtime_event_time,
546 header_realtime_remote_time);
547 });
548
Austin Schuh4c3b9702020-08-30 11:34:55 -0700549 simulated_event_loop_factory.RunFor(chrono::seconds(10) -
550 chrono::milliseconds(500) +
551 chrono::milliseconds(5));
552
553 EXPECT_EQ(pi1_pong_counter.count(), 1001);
554 EXPECT_EQ(pi2_pong_counter.count(), 1001);
555
556 EXPECT_EQ(pi1_on_pi1_timestamp_counter.count(), 100);
557 EXPECT_EQ(pi1_on_pi2_timestamp_counter.count(), 100);
558 EXPECT_EQ(pi1_on_pi3_timestamp_counter.count(), 100);
559 EXPECT_EQ(pi2_on_pi1_timestamp_counter.count(), 100);
560 EXPECT_EQ(pi2_on_pi2_timestamp_counter.count(), 100);
561 EXPECT_EQ(pi3_on_pi1_timestamp_counter.count(), 100);
562 EXPECT_EQ(pi3_on_pi3_timestamp_counter.count(), 100);
563
564 EXPECT_EQ(pi1_server_statistics_count, 9);
565 EXPECT_EQ(pi2_server_statistics_count, 9);
566 EXPECT_EQ(pi3_server_statistics_count, 9);
567
568 EXPECT_EQ(pi1_client_statistics_count, 95);
569 EXPECT_EQ(pi2_client_statistics_count, 95);
570 EXPECT_EQ(pi3_client_statistics_count, 95);
Austin Schuh2f8fd752020-09-01 22:38:28 -0700571
572 // Also confirm that remote timestamps are being forwarded correctly.
573 EXPECT_EQ(remote_timestamps_pi2_on_pi1.count(), 1101);
574 EXPECT_EQ(remote_timestamps_pi1_on_pi2.count(), 1101);
Austin Schuh4c3b9702020-08-30 11:34:55 -0700575}
576
577// Tests that an offset between nodes can be recovered and shows up in
578// ServerStatistics correctly.
579TEST(SimulatedEventLoopTest, MultinodePingPongWithOffset) {
580 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
Brian Silverman28d14302020-09-18 15:26:17 -0700581 aos::configuration::ReadConfig(ConfigPrefix() +
582 "events/multinode_pingpong_config.json");
Austin Schuh4c3b9702020-08-30 11:34:55 -0700583 const Node *pi1 = configuration::GetNode(&config.message(), "pi1");
584 const Node *pi2 = configuration::GetNode(&config.message(), "pi2");
585 const Node *pi3 = configuration::GetNode(&config.message(), "pi3");
586
587 SimulatedEventLoopFactory simulated_event_loop_factory(&config.message());
588 NodeEventLoopFactory *pi2_factory =
589 simulated_event_loop_factory.GetNodeEventLoopFactory(pi2);
590
591 constexpr chrono::milliseconds kOffset{1501};
592 pi2_factory->SetDistributedOffset(kOffset, 1.0);
593
594 std::unique_ptr<EventLoop> ping_event_loop =
595 simulated_event_loop_factory.MakeEventLoop("ping", pi1);
596 Ping ping(ping_event_loop.get());
597
598 std::unique_ptr<EventLoop> pong_event_loop =
599 simulated_event_loop_factory.MakeEventLoop("pong", pi2);
600 Pong pong(pong_event_loop.get());
601
602 std::unique_ptr<EventLoop> pi2_pong_counter_event_loop =
603 simulated_event_loop_factory.MakeEventLoop("pi2_pong_counter", pi2);
604
605 std::unique_ptr<EventLoop> pi3_pong_counter_event_loop =
606 simulated_event_loop_factory.MakeEventLoop("pi3_pong_counter", pi3);
607
608 std::unique_ptr<EventLoop> pi1_pong_counter_event_loop =
609 simulated_event_loop_factory.MakeEventLoop("pi1_pong_counter", pi1);
610
611 // Wait to let timestamp estimation start up before looking for the results.
612 simulated_event_loop_factory.RunFor(chrono::milliseconds(500));
613
614 // Confirm the offsets are being recovered correctly.
615 int pi1_server_statistics_count = 0;
616 pi1_pong_counter_event_loop->MakeWatcher(
617 "/pi1/aos", [&pi1_server_statistics_count,
618 kOffset](const message_bridge::ServerStatistics &stats) {
619 VLOG(1) << "pi1 ServerStatistics " << FlatbufferToJson(&stats);
620 EXPECT_EQ(stats.connections()->size(), 2u);
621 for (const message_bridge::ServerConnection *connection :
622 *stats.connections()) {
623 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
624 if (connection->node()->name()->string_view() == "pi2") {
625 EXPECT_EQ(connection->monotonic_offset(),
626 chrono::nanoseconds(kOffset).count());
627 } else if (connection->node()->name()->string_view() == "pi3") {
628 EXPECT_EQ(connection->monotonic_offset(), 0);
629 } else {
630 LOG(FATAL) << "Unknown connection";
631 }
632
633 EXPECT_TRUE(connection->has_monotonic_offset());
634 }
635 ++pi1_server_statistics_count;
636 });
637
638 int pi2_server_statistics_count = 0;
639 pi2_pong_counter_event_loop->MakeWatcher(
640 "/pi2/aos", [&pi2_server_statistics_count,
641 kOffset](const message_bridge::ServerStatistics &stats) {
642 VLOG(1) << "pi2 ServerStatistics " << FlatbufferToJson(&stats);
643 EXPECT_EQ(stats.connections()->size(), 1u);
644
645 const message_bridge::ServerConnection *connection =
646 stats.connections()->Get(0);
647 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
648 EXPECT_TRUE(connection->has_monotonic_offset());
649 EXPECT_EQ(connection->monotonic_offset(),
650 -chrono::nanoseconds(kOffset).count());
651 ++pi2_server_statistics_count;
652 });
653
654 int pi3_server_statistics_count = 0;
655 pi3_pong_counter_event_loop->MakeWatcher(
656 "/pi3/aos", [&pi3_server_statistics_count](
657 const message_bridge::ServerStatistics &stats) {
658 VLOG(1) << "pi3 ServerStatistics " << FlatbufferToJson(&stats);
659 EXPECT_EQ(stats.connections()->size(), 1u);
660
661 const message_bridge::ServerConnection *connection =
662 stats.connections()->Get(0);
663 EXPECT_EQ(connection->state(), message_bridge::State::CONNECTED);
664 EXPECT_TRUE(connection->has_monotonic_offset());
665 EXPECT_EQ(connection->monotonic_offset(), 0);
666 ++pi3_server_statistics_count;
667 });
668
669 simulated_event_loop_factory.RunFor(chrono::seconds(10) -
670 chrono::milliseconds(500) +
671 chrono::milliseconds(5));
672
673 EXPECT_EQ(pi1_server_statistics_count, 9);
674 EXPECT_EQ(pi2_server_statistics_count, 9);
675 EXPECT_EQ(pi3_server_statistics_count, 9);
676}
677
678// Test that disabling statistics actually disables them.
679TEST(SimulatedEventLoopTest, MultinodeWithoutStatistics) {
680 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
Brian Silverman28d14302020-09-18 15:26:17 -0700681 aos::configuration::ReadConfig(ConfigPrefix() +
682 "events/multinode_pingpong_config.json");
Austin Schuh4c3b9702020-08-30 11:34:55 -0700683 const Node *pi1 = configuration::GetNode(&config.message(), "pi1");
684 const Node *pi2 = configuration::GetNode(&config.message(), "pi2");
685 const Node *pi3 = configuration::GetNode(&config.message(), "pi3");
686
687 SimulatedEventLoopFactory simulated_event_loop_factory(&config.message());
688 simulated_event_loop_factory.DisableStatistics();
689
690 std::unique_ptr<EventLoop> ping_event_loop =
691 simulated_event_loop_factory.MakeEventLoop("ping", pi1);
692 Ping ping(ping_event_loop.get());
693
694 std::unique_ptr<EventLoop> pong_event_loop =
695 simulated_event_loop_factory.MakeEventLoop("pong", pi2);
696 Pong pong(pong_event_loop.get());
697
698 std::unique_ptr<EventLoop> pi2_pong_counter_event_loop =
699 simulated_event_loop_factory.MakeEventLoop("pi2_pong_counter", pi2);
700
701 MessageCounter<examples::Pong> pi2_pong_counter(
702 pi2_pong_counter_event_loop.get(), "/test");
703
704 std::unique_ptr<EventLoop> pi3_pong_counter_event_loop =
705 simulated_event_loop_factory.MakeEventLoop("pi3_pong_counter", pi3);
706
707 std::unique_ptr<EventLoop> pi1_pong_counter_event_loop =
708 simulated_event_loop_factory.MakeEventLoop("pi1_pong_counter", pi1);
709
710 MessageCounter<examples::Pong> pi1_pong_counter(
711 pi1_pong_counter_event_loop.get(), "/test");
712
713 // Count timestamps.
714 MessageCounter<message_bridge::Timestamp> pi1_on_pi1_timestamp_counter(
715 pi1_pong_counter_event_loop.get(), "/pi1/aos");
716 MessageCounter<message_bridge::Timestamp> pi1_on_pi2_timestamp_counter(
717 pi2_pong_counter_event_loop.get(), "/pi1/aos");
718 MessageCounter<message_bridge::Timestamp> pi1_on_pi3_timestamp_counter(
719 pi3_pong_counter_event_loop.get(), "/pi1/aos");
720 MessageCounter<message_bridge::Timestamp> pi2_on_pi1_timestamp_counter(
721 pi1_pong_counter_event_loop.get(), "/pi2/aos");
722 MessageCounter<message_bridge::Timestamp> pi2_on_pi2_timestamp_counter(
723 pi2_pong_counter_event_loop.get(), "/pi2/aos");
724 MessageCounter<message_bridge::Timestamp> pi3_on_pi1_timestamp_counter(
725 pi1_pong_counter_event_loop.get(), "/pi3/aos");
726 MessageCounter<message_bridge::Timestamp> pi3_on_pi3_timestamp_counter(
727 pi3_pong_counter_event_loop.get(), "/pi3/aos");
728
Austin Schuh2f8fd752020-09-01 22:38:28 -0700729 // Count remote timestamps
730 MessageCounter<logger::MessageHeader> remote_timestamps_pi2_on_pi1(
731 pi1_pong_counter_event_loop.get(), "/aos/remote_timestamps/pi2");
732 MessageCounter<logger::MessageHeader> remote_timestamps_pi1_on_pi2(
733 pi2_pong_counter_event_loop.get(), "/aos/remote_timestamps/pi1");
734
Austin Schuh4c3b9702020-08-30 11:34:55 -0700735 MessageCounter<message_bridge::ServerStatistics>
736 pi1_server_statistics_counter(pi1_pong_counter_event_loop.get(),
737 "/pi1/aos");
738 MessageCounter<message_bridge::ServerStatistics>
739 pi2_server_statistics_counter(pi2_pong_counter_event_loop.get(),
740 "/pi2/aos");
741 MessageCounter<message_bridge::ServerStatistics>
742 pi3_server_statistics_counter(pi3_pong_counter_event_loop.get(),
743 "/pi3/aos");
744
745 MessageCounter<message_bridge::ClientStatistics>
746 pi1_client_statistics_counter(pi1_pong_counter_event_loop.get(),
747 "/pi1/aos");
748 MessageCounter<message_bridge::ClientStatistics>
749 pi2_client_statistics_counter(pi2_pong_counter_event_loop.get(),
750 "/pi2/aos");
751 MessageCounter<message_bridge::ClientStatistics>
752 pi3_client_statistics_counter(pi3_pong_counter_event_loop.get(),
753 "/pi3/aos");
Austin Schuh898f4972020-01-11 17:21:25 -0800754
755 simulated_event_loop_factory.RunFor(chrono::seconds(10) +
756 chrono::milliseconds(5));
757
Austin Schuh4c3b9702020-08-30 11:34:55 -0700758 EXPECT_EQ(pi1_pong_counter.count(), 1001u);
759 EXPECT_EQ(pi2_pong_counter.count(), 1001u);
760
761 EXPECT_EQ(pi1_on_pi1_timestamp_counter.count(), 0u);
762 EXPECT_EQ(pi1_on_pi2_timestamp_counter.count(), 0u);
763 EXPECT_EQ(pi1_on_pi3_timestamp_counter.count(), 0u);
764 EXPECT_EQ(pi2_on_pi1_timestamp_counter.count(), 0u);
765 EXPECT_EQ(pi2_on_pi2_timestamp_counter.count(), 0u);
766 EXPECT_EQ(pi3_on_pi1_timestamp_counter.count(), 0u);
767 EXPECT_EQ(pi3_on_pi3_timestamp_counter.count(), 0u);
768
769 EXPECT_EQ(pi1_server_statistics_counter.count(), 0u);
770 EXPECT_EQ(pi2_server_statistics_counter.count(), 0u);
771 EXPECT_EQ(pi3_server_statistics_counter.count(), 0u);
772
773 EXPECT_EQ(pi1_client_statistics_counter.count(), 0u);
774 EXPECT_EQ(pi2_client_statistics_counter.count(), 0u);
775 EXPECT_EQ(pi3_client_statistics_counter.count(), 0u);
Austin Schuh2f8fd752020-09-01 22:38:28 -0700776
777 // Also confirm that remote timestamps are being forwarded correctly.
778 EXPECT_EQ(remote_timestamps_pi2_on_pi1.count(), 1001);
779 EXPECT_EQ(remote_timestamps_pi1_on_pi2.count(), 1001);
Austin Schuh898f4972020-01-11 17:21:25 -0800780}
781
Austin Schuh2febf0d2020-09-21 22:24:30 -0700782// Tests that the time offset having a slope doesn't break the world.
783// SimulatedMessageBridge has enough self consistency CHECK statements to
784// confirm, and we can can also check a message in each direction to make sure
785// it gets delivered as expected.
786TEST(SimulatedEventLoopTest, MultinodePingPongWithOffsetAndSlope) {
787 aos::FlatbufferDetachedBuffer<aos::Configuration> config =
788 aos::configuration::ReadConfig(ConfigPrefix() +
789 "events/multinode_pingpong_config.json");
790 const Node *pi1 = configuration::GetNode(&config.message(), "pi1");
791 const Node *pi2 = configuration::GetNode(&config.message(), "pi2");
792
793 SimulatedEventLoopFactory simulated_event_loop_factory(&config.message());
794 NodeEventLoopFactory *pi2_factory =
795 simulated_event_loop_factory.GetNodeEventLoopFactory(pi2);
796
797 // Move the pi far into the future so the slope is significant. And set it to
798 // something reasonable.
799 constexpr chrono::milliseconds kOffset{150100};
800 pi2_factory->SetDistributedOffset(kOffset, 1.0001);
801
802 std::unique_ptr<EventLoop> ping_event_loop =
803 simulated_event_loop_factory.MakeEventLoop("ping", pi1);
804 Ping ping(ping_event_loop.get());
805
806 std::unique_ptr<EventLoop> pong_event_loop =
807 simulated_event_loop_factory.MakeEventLoop("pong", pi2);
808 Pong pong(pong_event_loop.get());
809
810 std::unique_ptr<EventLoop> pi1_counter_event_loop =
811 simulated_event_loop_factory.MakeEventLoop("pi1_counter", pi1);
812 std::unique_ptr<EventLoop> pi2_counter_event_loop =
813 simulated_event_loop_factory.MakeEventLoop("pi2_counter", pi2);
814
815 aos::Fetcher<examples::Ping> ping_on_pi1_fetcher =
816 pi1_counter_event_loop->MakeFetcher<examples::Ping>("/test");
817 aos::Fetcher<examples::Ping> ping_on_pi2_fetcher =
818 pi2_counter_event_loop->MakeFetcher<examples::Ping>("/test");
819
820 aos::Fetcher<examples::Pong> pong_on_pi2_fetcher =
821 pi2_counter_event_loop->MakeFetcher<examples::Pong>("/test");
822 aos::Fetcher<examples::Pong> pong_on_pi1_fetcher =
823 pi1_counter_event_loop->MakeFetcher<examples::Pong>("/test");
824
825 // End after a pong message comes back. This will leave the latest messages
826 // on all channels so we can look at timestamps easily and check they make
827 // sense.
828 std::unique_ptr<EventLoop> pi1_pong_ender =
829 simulated_event_loop_factory.MakeEventLoop("pi2_counter", pi1);
830 int count = 0;
831 pi1_pong_ender->MakeWatcher(
832 "/test", [&simulated_event_loop_factory, &count](const examples::Pong &) {
833 if (++count == 100) {
834 simulated_event_loop_factory.Exit();
835 }
836 });
837
838 // Run enough that messages should be delivered.
839 simulated_event_loop_factory.Run();
840
841 // Grab the latest messages.
842 EXPECT_TRUE(ping_on_pi1_fetcher.Fetch());
843 EXPECT_TRUE(ping_on_pi2_fetcher.Fetch());
844 EXPECT_TRUE(pong_on_pi1_fetcher.Fetch());
845 EXPECT_TRUE(pong_on_pi2_fetcher.Fetch());
846
847 // Compute their time on the global distributed clock so we can compute
848 // distance betwen them.
849 const distributed_clock::time_point pi1_ping_time =
850 simulated_event_loop_factory.GetNodeEventLoopFactory(pi1)
851 ->ToDistributedClock(
852 ping_on_pi1_fetcher.context().monotonic_event_time);
853 const distributed_clock::time_point pi2_ping_time =
854 simulated_event_loop_factory.GetNodeEventLoopFactory(pi2)
855 ->ToDistributedClock(
856 ping_on_pi2_fetcher.context().monotonic_event_time);
857 const distributed_clock::time_point pi1_pong_time =
858 simulated_event_loop_factory.GetNodeEventLoopFactory(pi1)
859 ->ToDistributedClock(
860 pong_on_pi1_fetcher.context().monotonic_event_time);
861 const distributed_clock::time_point pi2_pong_time =
862 simulated_event_loop_factory.GetNodeEventLoopFactory(pi2)
863 ->ToDistributedClock(
864 pong_on_pi2_fetcher.context().monotonic_event_time);
865
866 // And confirm the delivery delay is just about exactly 150 uS for both
867 // directions like expected. There will be a couple ns of rounding errors in
868 // the conversion functions that aren't worth accounting for right now. This
869 // will either be really close, or really far.
870 EXPECT_GE(pi2_ping_time, chrono::microseconds(150) - chrono::nanoseconds(10) +
871 pi1_ping_time);
872 EXPECT_LE(pi2_ping_time, chrono::microseconds(150) + chrono::nanoseconds(10) +
873 pi1_ping_time);
874
875 EXPECT_GE(pi1_pong_time, chrono::microseconds(150) - chrono::nanoseconds(10) +
876 pi2_pong_time);
877 EXPECT_LE(pi1_pong_time, chrono::microseconds(150) + chrono::nanoseconds(10) +
878 pi2_pong_time);
879}
880
Neil Balchc8f41ed2018-01-20 22:06:53 -0800881} // namespace testing
882} // namespace aos