blob: 9e69ae4a4442dab017a19713392c3679d8c6c02b [file] [log] [blame]
James Kuszmaul38735e82019-12-07 16:42:06 -08001#include "aos/events/logging/logger.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -08002
3#include "aos/events/event_loop.h"
4#include "aos/events/ping_lib.h"
5#include "aos/events/pong_lib.h"
6#include "aos/events/simulated_event_loop.h"
7#include "glog/logging.h"
Austin Schuh6f3babe2020-01-26 20:34:50 -08008#include "gmock/gmock.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -08009#include "gtest/gtest.h"
10
11namespace aos {
12namespace logger {
13namespace testing {
14
15namespace chrono = std::chrono;
16
17class LoggerTest : public ::testing::Test {
18 public:
19 LoggerTest()
20 : config_(
21 aos::configuration::ReadConfig("aos/events/pingpong_config.json")),
22 event_loop_factory_(&config_.message()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080023 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080024 ping_(ping_event_loop_.get()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080025 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080026 pong_(pong_event_loop_.get()) {}
27
28 // Config and factory.
29 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
30 SimulatedEventLoopFactory event_loop_factory_;
31
32 // Event loop and app for Ping
33 std::unique_ptr<EventLoop> ping_event_loop_;
34 Ping ping_;
35
36 // Event loop and app for Pong
37 std::unique_ptr<EventLoop> pong_event_loop_;
38 Pong pong_;
39};
40
41// Tests that we can startup at all. This confirms that the channels are all in
42// the config.
43TEST_F(LoggerTest, Starts) {
44 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
45 const ::std::string logfile = tmpdir + "/logfile.bfbs";
46 // Remove it.
47 unlink(logfile.c_str());
48
49 LOG(INFO) << "Logging data to " << logfile;
50
51 {
52 DetachedBufferWriter writer(logfile);
53 std::unique_ptr<EventLoop> logger_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080054 event_loop_factory_.MakeEventLoop("logger");
Austin Schuhe309d2a2019-11-29 13:25:21 -080055
56 event_loop_factory_.RunFor(chrono::milliseconds(95));
57
58 Logger logger(&writer, logger_event_loop.get(),
59 std::chrono::milliseconds(100));
60 event_loop_factory_.RunFor(chrono::milliseconds(20000));
61 }
62
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080063 // Even though it doesn't make any difference here, exercise the logic for
64 // passing in a separate config.
65 LogReader reader(logfile, &config_.message());
Austin Schuhe309d2a2019-11-29 13:25:21 -080066
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080067 // Confirm that we can remap logged channels to point to new buses.
68 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
Austin Schuhe309d2a2019-11-29 13:25:21 -080069
Austin Schuh15649d62019-12-28 16:36:38 -080070 // This sends out the fetched messages and advances time to the start of the
71 // log file.
James Kuszmaul84ff3e52020-01-03 19:48:53 -080072 reader.Register();
Austin Schuhe309d2a2019-11-29 13:25:21 -080073
Austin Schuh6f3babe2020-01-26 20:34:50 -080074 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
James Kuszmaul84ff3e52020-01-03 19:48:53 -080075
Austin Schuhe309d2a2019-11-29 13:25:21 -080076 std::unique_ptr<EventLoop> test_event_loop =
James Kuszmaul84ff3e52020-01-03 19:48:53 -080077 reader.event_loop_factory()->MakeEventLoop("log_reader");
Austin Schuhe309d2a2019-11-29 13:25:21 -080078
79 int ping_count = 10;
80 int pong_count = 10;
81
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080082 // Confirm that the ping value matches in the remapped channel location.
83 test_event_loop->MakeWatcher("/original/test",
Austin Schuhe309d2a2019-11-29 13:25:21 -080084 [&ping_count](const examples::Ping &ping) {
85 EXPECT_EQ(ping.value(), ping_count + 1);
86 ++ping_count;
87 });
88 // Confirm that the ping and pong counts both match, and the value also
89 // matches.
90 test_event_loop->MakeWatcher(
91 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
92 EXPECT_EQ(pong.value(), pong_count + 1);
93 ++pong_count;
94 EXPECT_EQ(ping_count, pong_count);
95 });
96
James Kuszmaul84ff3e52020-01-03 19:48:53 -080097 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
Austin Schuhe309d2a2019-11-29 13:25:21 -080098 EXPECT_EQ(ping_count, 2010);
Austin Schuhe309d2a2019-11-29 13:25:21 -080099}
100
Austin Schuhfa895892020-01-07 20:07:41 -0800101// Tests that we can read and write rotated log files.
102TEST_F(LoggerTest, RotatedLogFile) {
103 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
104 const ::std::string logfile0 = tmpdir + "/logfile0.bfbs";
105 const ::std::string logfile1 = tmpdir + "/logfile1.bfbs";
106 // Remove it.
107 unlink(logfile0.c_str());
108 unlink(logfile1.c_str());
109
110 LOG(INFO) << "Logging data to " << logfile0 << " and " << logfile1;
111
112 {
113 DetachedBufferWriter writer0(logfile0);
114 DetachedBufferWriter writer1(logfile1);
115 std::unique_ptr<EventLoop> logger_event_loop =
116 event_loop_factory_.MakeEventLoop("logger");
117
118 event_loop_factory_.RunFor(chrono::milliseconds(95));
119
120 Logger logger(&writer0, logger_event_loop.get(),
121 std::chrono::milliseconds(100));
122 event_loop_factory_.RunFor(chrono::milliseconds(10000));
123 logger.Rotate(&writer1);
124 event_loop_factory_.RunFor(chrono::milliseconds(10000));
125 }
126
127 // Even though it doesn't make any difference here, exercise the logic for
128 // passing in a separate config.
129 LogReader reader(std::vector<std::string>{logfile0, logfile1},
130 &config_.message());
131
132 // Confirm that we can remap logged channels to point to new buses.
133 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
134
135 // This sends out the fetched messages and advances time to the start of the
136 // log file.
137 reader.Register();
138
Austin Schuh6f3babe2020-01-26 20:34:50 -0800139 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
Austin Schuhfa895892020-01-07 20:07:41 -0800140
141 std::unique_ptr<EventLoop> test_event_loop =
142 reader.event_loop_factory()->MakeEventLoop("log_reader");
143
144 int ping_count = 10;
145 int pong_count = 10;
146
147 // Confirm that the ping value matches in the remapped channel location.
148 test_event_loop->MakeWatcher("/original/test",
149 [&ping_count](const examples::Ping &ping) {
150 EXPECT_EQ(ping.value(), ping_count + 1);
151 ++ping_count;
152 });
153 // Confirm that the ping and pong counts both match, and the value also
154 // matches.
155 test_event_loop->MakeWatcher(
156 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
157 EXPECT_EQ(pong.value(), pong_count + 1);
158 ++pong_count;
159 EXPECT_EQ(ping_count, pong_count);
160 });
161
162 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
163 EXPECT_EQ(ping_count, 2010);
164}
165
Austin Schuh4c4e0092019-12-22 16:18:03 -0800166// Tests that a large number of messages per second doesn't overwhelm writev.
167TEST_F(LoggerTest, ManyMessages) {
168 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
169 const ::std::string logfile = tmpdir + "/logfile.bfbs";
170 // Remove the log file.
171 unlink(logfile.c_str());
172
173 LOG(INFO) << "Logging data to " << logfile;
174
175 {
176 DetachedBufferWriter writer(logfile);
177 std::unique_ptr<EventLoop> logger_event_loop =
178 event_loop_factory_.MakeEventLoop("logger");
179
180 std::unique_ptr<EventLoop> ping_spammer_event_loop =
181 event_loop_factory_.MakeEventLoop("ping_spammer");
182 aos::Sender<examples::Ping> ping_sender =
183 ping_spammer_event_loop->MakeSender<examples::Ping>("/test");
184
185 aos::TimerHandler *timer_handler =
186 ping_spammer_event_loop->AddTimer([&ping_sender]() {
187 aos::Sender<examples::Ping>::Builder builder =
188 ping_sender.MakeBuilder();
189 examples::Ping::Builder ping_builder =
190 builder.MakeBuilder<examples::Ping>();
191 CHECK(builder.Send(ping_builder.Finish()));
192 });
193
194 // 100 ms / 0.05 ms -> 2000 messages. Should be enough to crash it.
195 ping_spammer_event_loop->OnRun([&ping_spammer_event_loop, timer_handler]() {
196 timer_handler->Setup(ping_spammer_event_loop->monotonic_now(),
197 chrono::microseconds(50));
198 });
199
200 Logger logger(&writer, logger_event_loop.get(),
201 std::chrono::milliseconds(100));
202
203 event_loop_factory_.RunFor(chrono::milliseconds(1000));
204 }
205}
206
Austin Schuh15649d62019-12-28 16:36:38 -0800207class MultinodeLoggerTest : public ::testing::Test {
208 public:
209 MultinodeLoggerTest()
210 : config_(aos::configuration::ReadConfig(
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800211 "aos/events/logging/multinode_pingpong_config.json")),
Austin Schuhac0771c2020-01-07 18:36:30 -0800212 event_loop_factory_(&config_.message()),
Austin Schuhcde938c2020-02-02 17:30:07 -0800213 pi1_(
214 configuration::GetNode(event_loop_factory_.configuration(), "pi1")),
215 pi2_(configuration::GetNode(event_loop_factory_.configuration(),
216 "pi2")) {}
Austin Schuh15649d62019-12-28 16:36:38 -0800217
218 // Config and factory.
219 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
220 SimulatedEventLoopFactory event_loop_factory_;
221
Austin Schuhcde938c2020-02-02 17:30:07 -0800222 const Node *pi1_;
223 const Node *pi2_;
Austin Schuh15649d62019-12-28 16:36:38 -0800224};
225
Austin Schuh6f3babe2020-01-26 20:34:50 -0800226// Counts the number of messages on a channel (returns channel, count) for every
227// message matching matcher()
228std::vector<std::pair<int, int>> CountChannelsMatching(
229 std::string_view filename,
230 std::function<bool(const MessageHeader *)> matcher) {
231 MessageReader message_reader(filename);
232 std::vector<int> counts(
233 message_reader.log_file_header()->configuration()->channels()->size(), 0);
Austin Schuh15649d62019-12-28 16:36:38 -0800234
Austin Schuh6f3babe2020-01-26 20:34:50 -0800235 while (true) {
236 std::optional<FlatbufferVector<MessageHeader>> msg =
237 message_reader.ReadMessage();
238 if (!msg) {
239 break;
240 }
241
242 if (matcher(&msg.value().message())) {
243 counts[msg.value().message().channel_index()]++;
244 }
245 }
246
247 std::vector<std::pair<int, int>> result;
248 int channel = 0;
249 for (size_t i = 0; i < counts.size(); ++i) {
250 if (counts[i] != 0) {
251 result.push_back(std::make_pair(channel, counts[i]));
252 }
253 ++channel;
254 }
255
256 return result;
257}
258
259// Counts the number of messages (channel, count) for all data messages.
260std::vector<std::pair<int, int>> CountChannelsData(std::string_view filename) {
261 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
262 if (msg->has_data()) {
263 CHECK(!msg->has_monotonic_remote_time());
264 CHECK(!msg->has_realtime_remote_time());
265 CHECK(!msg->has_remote_queue_index());
266 return true;
267 }
268 return false;
269 });
270}
271
272// Counts the number of messages (channel, count) for all timestamp messages.
273std::vector<std::pair<int, int>> CountChannelsTimestamp(
274 std::string_view filename) {
275 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
276 if (!msg->has_data()) {
277 CHECK(msg->has_monotonic_remote_time());
278 CHECK(msg->has_realtime_remote_time());
279 CHECK(msg->has_remote_queue_index());
280 return true;
281 }
282 return false;
283 });
284}
285
Austin Schuhcde938c2020-02-02 17:30:07 -0800286// Tests that we can write and read simple multi-node log files.
287TEST_F(MultinodeLoggerTest, SimpleMultiNode) {
Austin Schuh6f3babe2020-01-26 20:34:50 -0800288 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
289 const ::std::string logfile_base = tmpdir + "/multi_logfile";
290 const ::std::string logfile1 = logfile_base + "_pi1_data.bfbs";
291 const ::std::string logfile2 =
292 logfile_base + "_pi2_data/test/aos.examples.Pong.bfbs";
293 const ::std::string logfile3 = logfile_base + "_pi2_data.bfbs";
294
295 // Remove them.
296 unlink(logfile1.c_str());
297 unlink(logfile2.c_str());
298 unlink(logfile3.c_str());
299
300 LOG(INFO) << "Logging data to " << logfile1 << ", " << logfile2 << " and "
301 << logfile3;
Austin Schuh15649d62019-12-28 16:36:38 -0800302
303 {
Austin Schuhcde938c2020-02-02 17:30:07 -0800304 std::unique_ptr<EventLoop> ping_event_loop =
305 event_loop_factory_.MakeEventLoop("ping", pi1_);
306 Ping ping(ping_event_loop.get());
307 std::unique_ptr<EventLoop> pong_event_loop =
308 event_loop_factory_.MakeEventLoop("pong", pi2_);
309 Pong pong(pong_event_loop.get());
Austin Schuh15649d62019-12-28 16:36:38 -0800310
Austin Schuh6f3babe2020-01-26 20:34:50 -0800311 std::unique_ptr<EventLoop> pi1_logger_event_loop =
Austin Schuhcde938c2020-02-02 17:30:07 -0800312 event_loop_factory_.MakeEventLoop("logger", pi1_);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800313 std::unique_ptr<LogNamer> pi1_log_namer =
314 std::make_unique<MultiNodeLogNamer>(
315 logfile_base, pi1_logger_event_loop->configuration(),
316 pi1_logger_event_loop->node());
317
318 std::unique_ptr<EventLoop> pi2_logger_event_loop =
Austin Schuhcde938c2020-02-02 17:30:07 -0800319 event_loop_factory_.MakeEventLoop("logger", pi2_);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800320 std::unique_ptr<LogNamer> pi2_log_namer =
321 std::make_unique<MultiNodeLogNamer>(
322 logfile_base, pi2_logger_event_loop->configuration(),
323 pi2_logger_event_loop->node());
Austin Schuh15649d62019-12-28 16:36:38 -0800324
325 event_loop_factory_.RunFor(chrono::milliseconds(95));
326
Austin Schuh6f3babe2020-01-26 20:34:50 -0800327 Logger pi1_logger(std::move(pi1_log_namer), pi1_logger_event_loop.get(),
Austin Schuh8bd96322020-02-13 21:18:22 -0800328 chrono::milliseconds(100));
Austin Schuhcde938c2020-02-02 17:30:07 -0800329
Austin Schuh6f3babe2020-01-26 20:34:50 -0800330 Logger pi2_logger(std::move(pi2_log_namer), pi2_logger_event_loop.get(),
Austin Schuh8bd96322020-02-13 21:18:22 -0800331 chrono::milliseconds(100));
Austin Schuh15649d62019-12-28 16:36:38 -0800332 event_loop_factory_.RunFor(chrono::milliseconds(20000));
333 }
334
Austin Schuh6f3babe2020-01-26 20:34:50 -0800335 {
336 // Confirm that the headers are all for the correct nodes.
337 FlatbufferVector<LogFileHeader> logheader1 = ReadHeader(logfile1);
338 EXPECT_EQ(logheader1.message().node()->name()->string_view(), "pi1");
339 FlatbufferVector<LogFileHeader> logheader2 = ReadHeader(logfile2);
340 EXPECT_EQ(logheader2.message().node()->name()->string_view(), "pi2");
341 FlatbufferVector<LogFileHeader> logheader3 = ReadHeader(logfile3);
342 EXPECT_EQ(logheader3.message().node()->name()->string_view(), "pi2");
Austin Schuh15649d62019-12-28 16:36:38 -0800343
Austin Schuh6f3babe2020-01-26 20:34:50 -0800344 // Timing reports, pings
345 EXPECT_THAT(CountChannelsData(logfile1),
Austin Schuhcde938c2020-02-02 17:30:07 -0800346 ::testing::ElementsAre(::testing::Pair(1, 40),
Austin Schuh6f3babe2020-01-26 20:34:50 -0800347 ::testing::Pair(4, 2001)));
348 // Timestamps for pong
349 EXPECT_THAT(CountChannelsTimestamp(logfile1),
350 ::testing::ElementsAre(::testing::Pair(5, 2001)));
351
352 // Pong data.
353 EXPECT_THAT(CountChannelsData(logfile2),
354 ::testing::ElementsAre(::testing::Pair(5, 2001)));
355 // No timestamps
356 EXPECT_THAT(CountChannelsTimestamp(logfile2), ::testing::ElementsAre());
357
358 // Timing reports and pongs.
359 EXPECT_THAT(CountChannelsData(logfile3),
Austin Schuhcde938c2020-02-02 17:30:07 -0800360 ::testing::ElementsAre(::testing::Pair(3, 40),
Austin Schuh6f3babe2020-01-26 20:34:50 -0800361 ::testing::Pair(5, 2001)));
362 // And ping timestamps.
363 EXPECT_THAT(CountChannelsTimestamp(logfile3),
364 ::testing::ElementsAre(::testing::Pair(4, 2001)));
365 }
366
Austin Schuhcde938c2020-02-02 17:30:07 -0800367 LogReader reader(
368 {std::vector<std::string>{logfile1}, std::vector<std::string>{logfile3}});
Austin Schuh6f3babe2020-01-26 20:34:50 -0800369
Austin Schuhac0771c2020-01-07 18:36:30 -0800370 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
Austin Schuh6331ef92020-01-07 18:28:09 -0800371 log_reader_factory.set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800372
373 // This sends out the fetched messages and advances time to the start of the
374 // log file.
Austin Schuh6331ef92020-01-07 18:28:09 -0800375 reader.Register(&log_reader_factory);
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800376
Austin Schuhac0771c2020-01-07 18:36:30 -0800377 const Node *pi1 =
378 configuration::GetNode(log_reader_factory.configuration(), "pi1");
Austin Schuh6f3babe2020-01-26 20:34:50 -0800379 const Node *pi2 =
380 configuration::GetNode(log_reader_factory.configuration(), "pi2");
Austin Schuhac0771c2020-01-07 18:36:30 -0800381
Austin Schuh6f3babe2020-01-26 20:34:50 -0800382 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800383
384 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800385
Austin Schuh6f3babe2020-01-26 20:34:50 -0800386 std::unique_ptr<EventLoop> pi1_event_loop =
Austin Schuhac0771c2020-01-07 18:36:30 -0800387 log_reader_factory.MakeEventLoop("test", pi1);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800388 std::unique_ptr<EventLoop> pi2_event_loop =
389 log_reader_factory.MakeEventLoop("test", pi2);
Austin Schuh15649d62019-12-28 16:36:38 -0800390
Austin Schuh6f3babe2020-01-26 20:34:50 -0800391 int pi1_ping_count = 10;
392 int pi2_ping_count = 10;
393 int pi1_pong_count = 10;
394 int pi2_pong_count = 10;
Austin Schuh15649d62019-12-28 16:36:38 -0800395
396 // Confirm that the ping value matches.
Austin Schuh6f3babe2020-01-26 20:34:50 -0800397 pi1_event_loop->MakeWatcher(
398 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
399 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
400 << pi1_event_loop->context().monotonic_remote_time << " -> "
401 << pi1_event_loop->context().monotonic_event_time;
402 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
403 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
404 pi1_ping_count * chrono::milliseconds(10) +
405 monotonic_clock::epoch());
406 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
407 pi1_ping_count * chrono::milliseconds(10) +
408 realtime_clock::epoch());
409 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
410 pi1_event_loop->context().monotonic_event_time);
411 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
412 pi1_event_loop->context().realtime_event_time);
Austin Schuh15649d62019-12-28 16:36:38 -0800413
Austin Schuh6f3babe2020-01-26 20:34:50 -0800414 ++pi1_ping_count;
415 });
416 pi2_event_loop->MakeWatcher(
417 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
418 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
419 << pi2_event_loop->context().monotonic_remote_time << " -> "
420 << pi2_event_loop->context().monotonic_event_time;
421 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
422
423 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
424 pi2_ping_count * chrono::milliseconds(10) +
425 monotonic_clock::epoch());
426 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
427 pi2_ping_count * chrono::milliseconds(10) +
428 realtime_clock::epoch());
429 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time +
430 chrono::microseconds(150),
431 pi2_event_loop->context().monotonic_event_time);
432 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time +
433 chrono::microseconds(150),
434 pi2_event_loop->context().realtime_event_time);
435 ++pi2_ping_count;
Austin Schuh15649d62019-12-28 16:36:38 -0800436 });
437
Austin Schuh6f3babe2020-01-26 20:34:50 -0800438 constexpr ssize_t kQueueIndexOffset = 0;
439 // Confirm that the ping and pong counts both match, and the value also
440 // matches.
441 pi1_event_loop->MakeWatcher(
442 "/test", [&pi1_event_loop, &pi1_ping_count,
443 &pi1_pong_count](const examples::Pong &pong) {
444 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
445 << pi1_event_loop->context().monotonic_remote_time << " -> "
446 << pi1_event_loop->context().monotonic_event_time;
447
448 EXPECT_EQ(pi1_event_loop->context().remote_queue_index,
449 pi1_pong_count + kQueueIndexOffset);
450 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
451 chrono::microseconds(200) +
452 pi1_pong_count * chrono::milliseconds(10) +
453 monotonic_clock::epoch());
454 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
455 chrono::microseconds(200) +
456 pi1_pong_count * chrono::milliseconds(10) +
457 realtime_clock::epoch());
458
459 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time +
460 chrono::microseconds(150),
461 pi1_event_loop->context().monotonic_event_time);
462 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time +
463 chrono::microseconds(150),
464 pi1_event_loop->context().realtime_event_time);
465
466 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
467 ++pi1_pong_count;
468 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
469 });
470 pi2_event_loop->MakeWatcher(
471 "/test", [&pi2_event_loop, &pi2_ping_count,
472 &pi2_pong_count](const examples::Pong &pong) {
473 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
474 << pi2_event_loop->context().monotonic_remote_time << " -> "
475 << pi2_event_loop->context().monotonic_event_time;
476
477 EXPECT_EQ(pi2_event_loop->context().remote_queue_index,
478 pi2_pong_count + kQueueIndexOffset - 9);
479
480 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
481 chrono::microseconds(200) +
482 pi2_pong_count * chrono::milliseconds(10) +
483 monotonic_clock::epoch());
484 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
485 chrono::microseconds(200) +
486 pi2_pong_count * chrono::milliseconds(10) +
487 realtime_clock::epoch());
488
489 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
490 pi2_event_loop->context().monotonic_event_time);
491 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
492 pi2_event_loop->context().realtime_event_time);
493
494 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
495 ++pi2_pong_count;
496 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
497 });
498
499 log_reader_factory.Run();
500 EXPECT_EQ(pi1_ping_count, 2010);
501 EXPECT_EQ(pi2_ping_count, 2010);
502 EXPECT_EQ(pi1_pong_count, 2010);
503 EXPECT_EQ(pi2_pong_count, 2010);
Austin Schuh6331ef92020-01-07 18:28:09 -0800504
505 reader.Deregister();
Austin Schuh15649d62019-12-28 16:36:38 -0800506}
507
Austin Schuhcde938c2020-02-02 17:30:07 -0800508// Tests that we can read log files where they don't start at the same monotonic
509// time.
510TEST_F(MultinodeLoggerTest, StaggeredStart) {
511 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
512 const ::std::string logfile_base = tmpdir + "/multi_logfile";
513 const ::std::string logfile1 = logfile_base + "_pi1_data.bfbs";
514 const ::std::string logfile2 =
515 logfile_base + "_pi2_data/test/aos.examples.Pong.bfbs";
516 const ::std::string logfile3 = logfile_base + "_pi2_data.bfbs";
517
518 // Remove them.
519 unlink(logfile1.c_str());
520 unlink(logfile2.c_str());
521 unlink(logfile3.c_str());
522
523 LOG(INFO) << "Logging data to " << logfile1 << " and " << logfile3;
524
525 {
526 std::unique_ptr<EventLoop> ping_event_loop =
527 event_loop_factory_.MakeEventLoop("ping", pi1_);
528 Ping ping(ping_event_loop.get());
529 std::unique_ptr<EventLoop> pong_event_loop =
530 event_loop_factory_.MakeEventLoop("pong", pi2_);
531 Pong pong(pong_event_loop.get());
532
533 std::unique_ptr<EventLoop> pi1_logger_event_loop =
534 event_loop_factory_.MakeEventLoop("logger", pi1_);
535 std::unique_ptr<LogNamer> pi1_log_namer =
536 std::make_unique<MultiNodeLogNamer>(
537 logfile_base, pi1_logger_event_loop->configuration(),
538 pi1_logger_event_loop->node());
539
540 std::unique_ptr<EventLoop> pi2_logger_event_loop =
541 event_loop_factory_.MakeEventLoop("logger", pi2_);
542 std::unique_ptr<LogNamer> pi2_log_namer =
543 std::make_unique<MultiNodeLogNamer>(
544 logfile_base, pi2_logger_event_loop->configuration(),
545 pi2_logger_event_loop->node());
546
547 event_loop_factory_.RunFor(chrono::milliseconds(95));
548
549 Logger pi1_logger(std::move(pi1_log_namer), pi1_logger_event_loop.get(),
Austin Schuh8bd96322020-02-13 21:18:22 -0800550 chrono::milliseconds(100));
Austin Schuhcde938c2020-02-02 17:30:07 -0800551
552 event_loop_factory_.RunFor(chrono::milliseconds(200));
553
554 Logger pi2_logger(std::move(pi2_log_namer), pi2_logger_event_loop.get(),
Austin Schuh8bd96322020-02-13 21:18:22 -0800555 chrono::milliseconds(100));
Austin Schuhcde938c2020-02-02 17:30:07 -0800556 event_loop_factory_.RunFor(chrono::milliseconds(20000));
557 }
558
559 LogReader reader(
560 {std::vector<std::string>{logfile1}, std::vector<std::string>{logfile3}});
561
562 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
563 log_reader_factory.set_send_delay(chrono::microseconds(0));
564
565 // This sends out the fetched messages and advances time to the start of the
566 // log file.
567 reader.Register(&log_reader_factory);
568
569 const Node *pi1 =
570 configuration::GetNode(log_reader_factory.configuration(), "pi1");
571 const Node *pi2 =
572 configuration::GetNode(log_reader_factory.configuration(), "pi2");
573
574 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
575
576 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
577
578 std::unique_ptr<EventLoop> pi1_event_loop =
579 log_reader_factory.MakeEventLoop("test", pi1);
580 std::unique_ptr<EventLoop> pi2_event_loop =
581 log_reader_factory.MakeEventLoop("test", pi2);
582
583 int pi1_ping_count = 30;
584 int pi2_ping_count = 30;
585 int pi1_pong_count = 30;
586 int pi2_pong_count = 30;
587
588 // Confirm that the ping value matches.
589 pi1_event_loop->MakeWatcher(
590 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
591 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
592 << pi1_event_loop->context().monotonic_remote_time << " -> "
593 << pi1_event_loop->context().monotonic_event_time;
594 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
595
596 ++pi1_ping_count;
597 });
598 pi2_event_loop->MakeWatcher(
599 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
600 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
601 << pi2_event_loop->context().monotonic_remote_time << " -> "
602 << pi2_event_loop->context().monotonic_event_time;
603 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
604
605 ++pi2_ping_count;
606 });
607
608 // Confirm that the ping and pong counts both match, and the value also
609 // matches.
610 pi1_event_loop->MakeWatcher(
611 "/test", [&pi1_event_loop, &pi1_ping_count,
612 &pi1_pong_count](const examples::Pong &pong) {
613 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
614 << pi1_event_loop->context().monotonic_remote_time << " -> "
615 << pi1_event_loop->context().monotonic_event_time;
616
617 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
618 ++pi1_pong_count;
619 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
620 });
621 pi2_event_loop->MakeWatcher(
622 "/test", [&pi2_event_loop, &pi2_ping_count,
623 &pi2_pong_count](const examples::Pong &pong) {
624 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
625 << pi2_event_loop->context().monotonic_remote_time << " -> "
626 << pi2_event_loop->context().monotonic_event_time;
627
628 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
629 ++pi2_pong_count;
630 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
631 });
632
633 log_reader_factory.Run();
634 EXPECT_EQ(pi1_ping_count, 2030);
635 EXPECT_EQ(pi2_ping_count, 2030);
636 EXPECT_EQ(pi1_pong_count, 2030);
637 EXPECT_EQ(pi2_pong_count, 2030);
638
639 reader.Deregister();
640}
Austin Schuh6f3babe2020-01-26 20:34:50 -0800641
Austin Schuh8bd96322020-02-13 21:18:22 -0800642// Tests that we can read log files where the monotonic clocks drift and don't
643// match correctly. While we are here, also test that different ending times
644// also is readable.
645TEST_F(MultinodeLoggerTest, MismatchedClocks) {
Austin Schuhcde938c2020-02-02 17:30:07 -0800646 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
647 const ::std::string logfile_base = tmpdir + "/multi_logfile";
648 const ::std::string logfile1 = logfile_base + "_pi1_data.bfbs";
649 const ::std::string logfile2 =
650 logfile_base + "_pi2_data/test/aos.examples.Pong.bfbs";
651 const ::std::string logfile3 = logfile_base + "_pi2_data.bfbs";
652
653 // Remove them.
654 unlink(logfile1.c_str());
655 unlink(logfile2.c_str());
656 unlink(logfile3.c_str());
657
658 LOG(INFO) << "Logging data to " << logfile1 << " and " << logfile3;
659
660 {
Austin Schuh8bd96322020-02-13 21:18:22 -0800661 NodeEventLoopFactory *pi2 =
662 event_loop_factory_.GetNodeEventLoopFactory(pi2_);
663 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
664 << pi2->realtime_now() << " distributed "
665 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -0800666
Austin Schuh8bd96322020-02-13 21:18:22 -0800667 const chrono::nanoseconds initial_pi2_offset = -chrono::seconds(1000);
668 chrono::nanoseconds pi2_offset = initial_pi2_offset;
Austin Schuhcde938c2020-02-02 17:30:07 -0800669
Austin Schuh8bd96322020-02-13 21:18:22 -0800670 pi2->SetDistributedOffset(pi2_offset);
671 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
672 << pi2->realtime_now() << " distributed "
673 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -0800674
Austin Schuh8bd96322020-02-13 21:18:22 -0800675 std::unique_ptr<EventLoop> ping_event_loop =
676 event_loop_factory_.MakeEventLoop("ping", pi1_);
677 Ping ping(ping_event_loop.get());
678 std::unique_ptr<EventLoop> pong_event_loop =
679 event_loop_factory_.MakeEventLoop("pong", pi2_);
680 Pong pong(pong_event_loop.get());
Austin Schuhcde938c2020-02-02 17:30:07 -0800681
Austin Schuh8bd96322020-02-13 21:18:22 -0800682 std::unique_ptr<EventLoop> pi2_logger_event_loop =
683 event_loop_factory_.MakeEventLoop("logger", pi2_);
684 std::unique_ptr<LogNamer> pi2_log_namer =
685 std::make_unique<MultiNodeLogNamer>(
686 logfile_base, pi2_logger_event_loop->configuration(),
687 pi2_logger_event_loop->node());
Austin Schuhcde938c2020-02-02 17:30:07 -0800688
Austin Schuh8bd96322020-02-13 21:18:22 -0800689 for (int i = 0; i < 95; ++i) {
690 pi2_offset += chrono::nanoseconds(200);
691 pi2->SetDistributedOffset(pi2_offset);
692 event_loop_factory_.RunFor(chrono::milliseconds(1));
693 }
Austin Schuhcde938c2020-02-02 17:30:07 -0800694
Austin Schuh8bd96322020-02-13 21:18:22 -0800695 Logger pi2_logger(std::move(pi2_log_namer), pi2_logger_event_loop.get(),
696 chrono::milliseconds(100));
Austin Schuhcde938c2020-02-02 17:30:07 -0800697
Austin Schuh8bd96322020-02-13 21:18:22 -0800698 event_loop_factory_.RunFor(chrono::milliseconds(200));
Austin Schuhcde938c2020-02-02 17:30:07 -0800699
Austin Schuh8bd96322020-02-13 21:18:22 -0800700 {
701 // Run pi1's logger for only part of the time.
702 std::unique_ptr<EventLoop> pi1_logger_event_loop =
703 event_loop_factory_.MakeEventLoop("logger", pi1_);
704 std::unique_ptr<LogNamer> pi1_log_namer =
705 std::make_unique<MultiNodeLogNamer>(
706 logfile_base, pi1_logger_event_loop->configuration(),
707 pi1_logger_event_loop->node());
708
709 Logger pi1_logger(std::move(pi1_log_namer), pi1_logger_event_loop.get(),
710 chrono::milliseconds(100));
711
712 for (int i = 0; i < 20000; ++i) {
713 pi2_offset += chrono::nanoseconds(200);
714 pi2->SetDistributedOffset(pi2_offset);
715 event_loop_factory_.RunFor(chrono::milliseconds(1));
716 }
717
718 EXPECT_GT(pi2_offset - initial_pi2_offset,
719 event_loop_factory_.send_delay() +
720 event_loop_factory_.network_delay());
721
722 for (int i = 0; i < 40000; ++i) {
723 pi2_offset -= chrono::nanoseconds(200);
724 pi2->SetDistributedOffset(pi2_offset);
725 event_loop_factory_.RunFor(chrono::milliseconds(1));
726 }
727 }
728
729 // And log a bit more on pi2.
730 event_loop_factory_.RunFor(chrono::milliseconds(400));
Austin Schuhcde938c2020-02-02 17:30:07 -0800731 }
732
733 LogReader reader(
734 {std::vector<std::string>{logfile1}, std::vector<std::string>{logfile3}});
735
736 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
737 log_reader_factory.set_send_delay(chrono::microseconds(0));
738
739 // This sends out the fetched messages and advances time to the start of the
740 // log file.
741 reader.Register(&log_reader_factory);
742
743
744 const Node *pi1 =
745 configuration::GetNode(log_reader_factory.configuration(), "pi1");
746 const Node *pi2 =
747 configuration::GetNode(log_reader_factory.configuration(), "pi2");
748
749 LOG(INFO) << "Done registering (pi1) "
750 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now() << " "
751 << log_reader_factory.GetNodeEventLoopFactory(pi1)->realtime_now();
752 LOG(INFO) << "Done registering (pi2) "
753 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now() << " "
754 << log_reader_factory.GetNodeEventLoopFactory(pi2)->realtime_now();
755
756 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
757
758 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
759
760 std::unique_ptr<EventLoop> pi1_event_loop =
761 log_reader_factory.MakeEventLoop("test", pi1);
762 std::unique_ptr<EventLoop> pi2_event_loop =
763 log_reader_factory.MakeEventLoop("test", pi2);
764
765 int pi1_ping_count = 30;
766 int pi2_ping_count = 30;
767 int pi1_pong_count = 30;
768 int pi2_pong_count = 30;
769
770 // Confirm that the ping value matches.
771 pi1_event_loop->MakeWatcher(
772 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
773 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
774 << pi1_event_loop->context().monotonic_remote_time << " -> "
775 << pi1_event_loop->context().monotonic_event_time;
776 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
777
778 ++pi1_ping_count;
779 });
780 pi2_event_loop->MakeWatcher(
781 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
782 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
783 << pi2_event_loop->context().monotonic_remote_time << " -> "
784 << pi2_event_loop->context().monotonic_event_time;
785 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
786
787 ++pi2_ping_count;
788 });
789
790 // Confirm that the ping and pong counts both match, and the value also
791 // matches.
792 pi1_event_loop->MakeWatcher(
793 "/test", [&pi1_event_loop, &pi1_ping_count,
794 &pi1_pong_count](const examples::Pong &pong) {
795 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
796 << pi1_event_loop->context().monotonic_remote_time << " -> "
797 << pi1_event_loop->context().monotonic_event_time;
798
799 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
800 ++pi1_pong_count;
801 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
802 });
803 pi2_event_loop->MakeWatcher(
804 "/test", [&pi2_event_loop, &pi2_ping_count,
805 &pi2_pong_count](const examples::Pong &pong) {
806 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
807 << pi2_event_loop->context().monotonic_remote_time << " -> "
808 << pi2_event_loop->context().monotonic_event_time;
809
810 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
811 ++pi2_pong_count;
812 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
813 });
814
815 log_reader_factory.Run();
Austin Schuh8bd96322020-02-13 21:18:22 -0800816 EXPECT_EQ(pi1_ping_count, 6030);
817 EXPECT_EQ(pi2_ping_count, 6030);
818 EXPECT_EQ(pi1_pong_count, 6030);
819 EXPECT_EQ(pi2_pong_count, 6030);
Austin Schuhcde938c2020-02-02 17:30:07 -0800820
821 reader.Deregister();
822}
823
Austin Schuh8bd96322020-02-13 21:18:22 -0800824// TODO(austin): We can write a test which recreates a logfile and confirms that
825// we get it back. That is the ultimate test.
826
Austin Schuhe309d2a2019-11-29 13:25:21 -0800827} // namespace testing
828} // namespace logger
829} // namespace aos