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