blob: 7dbbb8e51787a1946f7dc1849a4eddb20521af53 [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;
Austin Schuh4c3b9702020-08-30 11:34:55 -0700174 ping_.set_quiet(true);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800175
176 {
177 DetachedBufferWriter writer(logfile);
178 std::unique_ptr<EventLoop> logger_event_loop =
179 event_loop_factory_.MakeEventLoop("logger");
180
181 std::unique_ptr<EventLoop> ping_spammer_event_loop =
182 event_loop_factory_.MakeEventLoop("ping_spammer");
183 aos::Sender<examples::Ping> ping_sender =
184 ping_spammer_event_loop->MakeSender<examples::Ping>("/test");
185
186 aos::TimerHandler *timer_handler =
187 ping_spammer_event_loop->AddTimer([&ping_sender]() {
188 aos::Sender<examples::Ping>::Builder builder =
189 ping_sender.MakeBuilder();
190 examples::Ping::Builder ping_builder =
191 builder.MakeBuilder<examples::Ping>();
192 CHECK(builder.Send(ping_builder.Finish()));
193 });
194
195 // 100 ms / 0.05 ms -> 2000 messages. Should be enough to crash it.
196 ping_spammer_event_loop->OnRun([&ping_spammer_event_loop, timer_handler]() {
197 timer_handler->Setup(ping_spammer_event_loop->monotonic_now(),
198 chrono::microseconds(50));
199 });
200
201 Logger logger(&writer, logger_event_loop.get(),
202 std::chrono::milliseconds(100));
203
204 event_loop_factory_.RunFor(chrono::milliseconds(1000));
205 }
206}
207
Austin Schuh15649d62019-12-28 16:36:38 -0800208class MultinodeLoggerTest : public ::testing::Test {
209 public:
210 MultinodeLoggerTest()
211 : config_(aos::configuration::ReadConfig(
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800212 "aos/events/logging/multinode_pingpong_config.json")),
Austin Schuhac0771c2020-01-07 18:36:30 -0800213 event_loop_factory_(&config_.message()),
Austin Schuhcde938c2020-02-02 17:30:07 -0800214 pi1_(
215 configuration::GetNode(event_loop_factory_.configuration(), "pi1")),
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700216 pi2_(
217 configuration::GetNode(event_loop_factory_.configuration(), "pi2")),
218 tmp_dir_(getenv("TEST_TMPDIR")),
219 logfile_base_(tmp_dir_ + "/multi_logfile"),
220 logfiles_({logfile_base_ + "_pi1_data.bfbs",
221 logfile_base_ + "_pi2_data/test/aos.examples.Pong.bfbs",
222 logfile_base_ + "_pi2_data.bfbs"}),
223 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping", pi1_)),
224 ping_(ping_event_loop_.get()),
225 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong", pi2_)),
226 pong_(pong_event_loop_.get()) {
227 // Go through and remove the logfiles if they already exist.
228 for (const auto file : logfiles_) {
229 unlink(file.c_str());
230 }
231
232 LOG(INFO) << "Logging data to " << logfiles_[0] << ", " << logfiles_[1]
233 << " and " << logfiles_[2];
234 }
235
236 struct LoggerState {
237 std::unique_ptr<EventLoop> event_loop;
238 std::unique_ptr<Logger> logger;
239 };
240
241 LoggerState MakeLogger(const Node *node) {
242 return {event_loop_factory_.MakeEventLoop("logger", node), {}};
243 }
244
245 void StartLogger(LoggerState *logger) {
246 logger->logger = std::make_unique<Logger>(
247 std::make_unique<MultiNodeLogNamer>(logfile_base_,
248 logger->event_loop->configuration(),
249 logger->event_loop->node()),
250 logger->event_loop.get(), chrono::milliseconds(100));
251 }
Austin Schuh15649d62019-12-28 16:36:38 -0800252
253 // Config and factory.
254 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
255 SimulatedEventLoopFactory event_loop_factory_;
256
Austin Schuhcde938c2020-02-02 17:30:07 -0800257 const Node *pi1_;
258 const Node *pi2_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700259
260 std::string tmp_dir_;
261 std::string logfile_base_;
262 std::array<std::string, 3> logfiles_;
263
264 std::unique_ptr<EventLoop> ping_event_loop_;
265 Ping ping_;
266 std::unique_ptr<EventLoop> pong_event_loop_;
267 Pong pong_;
Austin Schuh15649d62019-12-28 16:36:38 -0800268};
269
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700270
Austin Schuh6f3babe2020-01-26 20:34:50 -0800271// Counts the number of messages on a channel (returns channel, count) for every
272// message matching matcher()
273std::vector<std::pair<int, int>> CountChannelsMatching(
274 std::string_view filename,
275 std::function<bool(const MessageHeader *)> matcher) {
276 MessageReader message_reader(filename);
277 std::vector<int> counts(
278 message_reader.log_file_header()->configuration()->channels()->size(), 0);
Austin Schuh15649d62019-12-28 16:36:38 -0800279
Austin Schuh6f3babe2020-01-26 20:34:50 -0800280 while (true) {
281 std::optional<FlatbufferVector<MessageHeader>> msg =
282 message_reader.ReadMessage();
283 if (!msg) {
284 break;
285 }
286
287 if (matcher(&msg.value().message())) {
288 counts[msg.value().message().channel_index()]++;
289 }
290 }
291
292 std::vector<std::pair<int, int>> result;
293 int channel = 0;
294 for (size_t i = 0; i < counts.size(); ++i) {
295 if (counts[i] != 0) {
296 result.push_back(std::make_pair(channel, counts[i]));
297 }
298 ++channel;
299 }
300
301 return result;
302}
303
304// Counts the number of messages (channel, count) for all data messages.
305std::vector<std::pair<int, int>> CountChannelsData(std::string_view filename) {
306 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
307 if (msg->has_data()) {
308 CHECK(!msg->has_monotonic_remote_time());
309 CHECK(!msg->has_realtime_remote_time());
310 CHECK(!msg->has_remote_queue_index());
311 return true;
312 }
313 return false;
314 });
315}
316
317// Counts the number of messages (channel, count) for all timestamp messages.
318std::vector<std::pair<int, int>> CountChannelsTimestamp(
319 std::string_view filename) {
320 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
321 if (!msg->has_data()) {
322 CHECK(msg->has_monotonic_remote_time());
323 CHECK(msg->has_realtime_remote_time());
324 CHECK(msg->has_remote_queue_index());
325 return true;
326 }
327 return false;
328 });
329}
330
Austin Schuhcde938c2020-02-02 17:30:07 -0800331// Tests that we can write and read simple multi-node log files.
332TEST_F(MultinodeLoggerTest, SimpleMultiNode) {
Austin Schuh15649d62019-12-28 16:36:38 -0800333 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700334 LoggerState pi1_logger = MakeLogger(pi1_);
335 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuh15649d62019-12-28 16:36:38 -0800336
337 event_loop_factory_.RunFor(chrono::milliseconds(95));
338
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700339 StartLogger(&pi1_logger);
340 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800341
Austin Schuh15649d62019-12-28 16:36:38 -0800342 event_loop_factory_.RunFor(chrono::milliseconds(20000));
343 }
344
Austin Schuh6f3babe2020-01-26 20:34:50 -0800345 {
346 // Confirm that the headers are all for the correct nodes.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700347 FlatbufferVector<LogFileHeader> logheader1 = ReadHeader(logfiles_[0]);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800348 EXPECT_EQ(logheader1.message().node()->name()->string_view(), "pi1");
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700349 FlatbufferVector<LogFileHeader> logheader2 = ReadHeader(logfiles_[1]);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800350 EXPECT_EQ(logheader2.message().node()->name()->string_view(), "pi2");
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700351 FlatbufferVector<LogFileHeader> logheader3 = ReadHeader(logfiles_[2]);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800352 EXPECT_EQ(logheader3.message().node()->name()->string_view(), "pi2");
Austin Schuh15649d62019-12-28 16:36:38 -0800353
Austin Schuh6f3babe2020-01-26 20:34:50 -0800354 // Timing reports, pings
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700355 EXPECT_THAT(CountChannelsData(logfiles_[0]),
Austin Schuh4c3b9702020-08-30 11:34:55 -0700356 ::testing::ElementsAre(::testing::Pair(4, 40),
357 ::testing::Pair(10, 2001)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800358 // Timestamps for pong
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700359 EXPECT_THAT(CountChannelsTimestamp(logfiles_[0]),
Austin Schuh4c3b9702020-08-30 11:34:55 -0700360 ::testing::ElementsAre(::testing::Pair(11, 2001)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800361
362 // Pong data.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700363 EXPECT_THAT(CountChannelsData(logfiles_[1]),
Austin Schuh4c3b9702020-08-30 11:34:55 -0700364 ::testing::ElementsAre(::testing::Pair(11, 2001)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800365 // No timestamps
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700366 EXPECT_THAT(CountChannelsTimestamp(logfiles_[1]), ::testing::ElementsAre());
Austin Schuh6f3babe2020-01-26 20:34:50 -0800367
368 // Timing reports and pongs.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700369 EXPECT_THAT(CountChannelsData(logfiles_[2]),
Austin Schuh4c3b9702020-08-30 11:34:55 -0700370 ::testing::ElementsAre(::testing::Pair(9, 40),
371 ::testing::Pair(11, 2001)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800372 // And ping timestamps.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700373 EXPECT_THAT(CountChannelsTimestamp(logfiles_[2]),
Austin Schuh4c3b9702020-08-30 11:34:55 -0700374 ::testing::ElementsAre(::testing::Pair(10, 2001)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800375 }
376
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700377 LogReader reader({std::vector<std::string>{logfiles_[0]},
378 std::vector<std::string>{logfiles_[2]}});
Austin Schuh6f3babe2020-01-26 20:34:50 -0800379
Austin Schuhac0771c2020-01-07 18:36:30 -0800380 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
Austin Schuh6331ef92020-01-07 18:28:09 -0800381 log_reader_factory.set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800382
383 // This sends out the fetched messages and advances time to the start of the
384 // log file.
Austin Schuh6331ef92020-01-07 18:28:09 -0800385 reader.Register(&log_reader_factory);
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800386
Austin Schuhac0771c2020-01-07 18:36:30 -0800387 const Node *pi1 =
388 configuration::GetNode(log_reader_factory.configuration(), "pi1");
Austin Schuh6f3babe2020-01-26 20:34:50 -0800389 const Node *pi2 =
390 configuration::GetNode(log_reader_factory.configuration(), "pi2");
Austin Schuhac0771c2020-01-07 18:36:30 -0800391
Austin Schuh6f3babe2020-01-26 20:34:50 -0800392 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800393
394 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800395
Austin Schuh6f3babe2020-01-26 20:34:50 -0800396 std::unique_ptr<EventLoop> pi1_event_loop =
Austin Schuhac0771c2020-01-07 18:36:30 -0800397 log_reader_factory.MakeEventLoop("test", pi1);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800398 std::unique_ptr<EventLoop> pi2_event_loop =
399 log_reader_factory.MakeEventLoop("test", pi2);
Austin Schuh15649d62019-12-28 16:36:38 -0800400
Austin Schuh6f3babe2020-01-26 20:34:50 -0800401 int pi1_ping_count = 10;
402 int pi2_ping_count = 10;
403 int pi1_pong_count = 10;
404 int pi2_pong_count = 10;
Austin Schuh15649d62019-12-28 16:36:38 -0800405
406 // Confirm that the ping value matches.
Austin Schuh6f3babe2020-01-26 20:34:50 -0800407 pi1_event_loop->MakeWatcher(
408 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
409 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
410 << pi1_event_loop->context().monotonic_remote_time << " -> "
411 << pi1_event_loop->context().monotonic_event_time;
412 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
413 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
414 pi1_ping_count * chrono::milliseconds(10) +
415 monotonic_clock::epoch());
416 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
417 pi1_ping_count * chrono::milliseconds(10) +
418 realtime_clock::epoch());
419 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
420 pi1_event_loop->context().monotonic_event_time);
421 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
422 pi1_event_loop->context().realtime_event_time);
Austin Schuh15649d62019-12-28 16:36:38 -0800423
Austin Schuh6f3babe2020-01-26 20:34:50 -0800424 ++pi1_ping_count;
425 });
426 pi2_event_loop->MakeWatcher(
427 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
428 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
429 << pi2_event_loop->context().monotonic_remote_time << " -> "
430 << pi2_event_loop->context().monotonic_event_time;
431 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
432
433 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
434 pi2_ping_count * chrono::milliseconds(10) +
435 monotonic_clock::epoch());
436 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
437 pi2_ping_count * chrono::milliseconds(10) +
438 realtime_clock::epoch());
439 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time +
440 chrono::microseconds(150),
441 pi2_event_loop->context().monotonic_event_time);
442 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time +
443 chrono::microseconds(150),
444 pi2_event_loop->context().realtime_event_time);
445 ++pi2_ping_count;
Austin Schuh15649d62019-12-28 16:36:38 -0800446 });
447
Austin Schuh6f3babe2020-01-26 20:34:50 -0800448 constexpr ssize_t kQueueIndexOffset = 0;
449 // Confirm that the ping and pong counts both match, and the value also
450 // matches.
451 pi1_event_loop->MakeWatcher(
452 "/test", [&pi1_event_loop, &pi1_ping_count,
453 &pi1_pong_count](const examples::Pong &pong) {
454 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
455 << pi1_event_loop->context().monotonic_remote_time << " -> "
456 << pi1_event_loop->context().monotonic_event_time;
457
458 EXPECT_EQ(pi1_event_loop->context().remote_queue_index,
459 pi1_pong_count + kQueueIndexOffset);
460 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
461 chrono::microseconds(200) +
462 pi1_pong_count * chrono::milliseconds(10) +
463 monotonic_clock::epoch());
464 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
465 chrono::microseconds(200) +
466 pi1_pong_count * chrono::milliseconds(10) +
467 realtime_clock::epoch());
468
469 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time +
470 chrono::microseconds(150),
471 pi1_event_loop->context().monotonic_event_time);
472 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time +
473 chrono::microseconds(150),
474 pi1_event_loop->context().realtime_event_time);
475
476 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
477 ++pi1_pong_count;
478 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
479 });
480 pi2_event_loop->MakeWatcher(
481 "/test", [&pi2_event_loop, &pi2_ping_count,
482 &pi2_pong_count](const examples::Pong &pong) {
483 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
484 << pi2_event_loop->context().monotonic_remote_time << " -> "
485 << pi2_event_loop->context().monotonic_event_time;
486
487 EXPECT_EQ(pi2_event_loop->context().remote_queue_index,
488 pi2_pong_count + kQueueIndexOffset - 9);
489
490 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
491 chrono::microseconds(200) +
492 pi2_pong_count * chrono::milliseconds(10) +
493 monotonic_clock::epoch());
494 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
495 chrono::microseconds(200) +
496 pi2_pong_count * chrono::milliseconds(10) +
497 realtime_clock::epoch());
498
499 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
500 pi2_event_loop->context().monotonic_event_time);
501 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
502 pi2_event_loop->context().realtime_event_time);
503
504 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
505 ++pi2_pong_count;
506 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
507 });
508
509 log_reader_factory.Run();
510 EXPECT_EQ(pi1_ping_count, 2010);
511 EXPECT_EQ(pi2_ping_count, 2010);
512 EXPECT_EQ(pi1_pong_count, 2010);
513 EXPECT_EQ(pi2_pong_count, 2010);
Austin Schuh6331ef92020-01-07 18:28:09 -0800514
515 reader.Deregister();
Austin Schuh15649d62019-12-28 16:36:38 -0800516}
517
James Kuszmaul46d82582020-05-09 19:50:09 -0700518typedef MultinodeLoggerTest MultinodeLoggerDeathTest;
519
520// Test that if we feed the replay with a mismatched node list that we die on
521// the LogReader constructor.
522TEST_F(MultinodeLoggerDeathTest, MultiNodeBadReplayConfig) {
James Kuszmaul46d82582020-05-09 19:50:09 -0700523 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700524 LoggerState pi1_logger = MakeLogger(pi1_);
525 LoggerState pi2_logger = MakeLogger(pi2_);
James Kuszmaul46d82582020-05-09 19:50:09 -0700526
527 event_loop_factory_.RunFor(chrono::milliseconds(95));
528
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700529 StartLogger(&pi1_logger);
530 StartLogger(&pi2_logger);
James Kuszmaul46d82582020-05-09 19:50:09 -0700531
James Kuszmaul46d82582020-05-09 19:50:09 -0700532 event_loop_factory_.RunFor(chrono::milliseconds(20000));
533 }
534
535 // Test that, if we add an additional node to the replay config that the
536 // logger complains about the mismatch in number of nodes.
537 FlatbufferDetachedBuffer<Configuration> extra_nodes_config =
538 configuration::MergeWithConfig(&config_.message(), R"({
539 "nodes": [
540 {
541 "name": "extra-node"
542 }
543 ]
544 }
545 )");
546
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700547 EXPECT_DEATH(LogReader({std::vector<std::string>{logfiles_[0]},
548 std::vector<std::string>{logfiles_[2]}},
James Kuszmaul46d82582020-05-09 19:50:09 -0700549 &extra_nodes_config.message()),
550 "Log file and replay config need to have matching nodes lists.");
551 ;
552}
553
Austin Schuhcde938c2020-02-02 17:30:07 -0800554// Tests that we can read log files where they don't start at the same monotonic
555// time.
556TEST_F(MultinodeLoggerTest, StaggeredStart) {
Austin Schuhcde938c2020-02-02 17:30:07 -0800557 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700558 LoggerState pi1_logger = MakeLogger(pi1_);
559 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuhcde938c2020-02-02 17:30:07 -0800560
561 event_loop_factory_.RunFor(chrono::milliseconds(95));
562
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700563 StartLogger(&pi1_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800564
565 event_loop_factory_.RunFor(chrono::milliseconds(200));
566
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700567 StartLogger(&pi2_logger);
568
Austin Schuhcde938c2020-02-02 17:30:07 -0800569 event_loop_factory_.RunFor(chrono::milliseconds(20000));
570 }
571
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700572 LogReader reader({std::vector<std::string>{logfiles_[0]},
573 std::vector<std::string>{logfiles_[2]}});
Austin Schuhcde938c2020-02-02 17:30:07 -0800574
575 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
576 log_reader_factory.set_send_delay(chrono::microseconds(0));
577
578 // This sends out the fetched messages and advances time to the start of the
579 // log file.
580 reader.Register(&log_reader_factory);
581
582 const Node *pi1 =
583 configuration::GetNode(log_reader_factory.configuration(), "pi1");
584 const Node *pi2 =
585 configuration::GetNode(log_reader_factory.configuration(), "pi2");
586
587 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
588
589 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
590
591 std::unique_ptr<EventLoop> pi1_event_loop =
592 log_reader_factory.MakeEventLoop("test", pi1);
593 std::unique_ptr<EventLoop> pi2_event_loop =
594 log_reader_factory.MakeEventLoop("test", pi2);
595
596 int pi1_ping_count = 30;
597 int pi2_ping_count = 30;
598 int pi1_pong_count = 30;
599 int pi2_pong_count = 30;
600
601 // Confirm that the ping value matches.
602 pi1_event_loop->MakeWatcher(
603 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
604 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
605 << pi1_event_loop->context().monotonic_remote_time << " -> "
606 << pi1_event_loop->context().monotonic_event_time;
607 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
608
609 ++pi1_ping_count;
610 });
611 pi2_event_loop->MakeWatcher(
612 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
613 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
614 << pi2_event_loop->context().monotonic_remote_time << " -> "
615 << pi2_event_loop->context().monotonic_event_time;
616 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
617
618 ++pi2_ping_count;
619 });
620
621 // Confirm that the ping and pong counts both match, and the value also
622 // matches.
623 pi1_event_loop->MakeWatcher(
624 "/test", [&pi1_event_loop, &pi1_ping_count,
625 &pi1_pong_count](const examples::Pong &pong) {
626 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
627 << pi1_event_loop->context().monotonic_remote_time << " -> "
628 << pi1_event_loop->context().monotonic_event_time;
629
630 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
631 ++pi1_pong_count;
632 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
633 });
634 pi2_event_loop->MakeWatcher(
635 "/test", [&pi2_event_loop, &pi2_ping_count,
636 &pi2_pong_count](const examples::Pong &pong) {
637 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
638 << pi2_event_loop->context().monotonic_remote_time << " -> "
639 << pi2_event_loop->context().monotonic_event_time;
640
641 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
642 ++pi2_pong_count;
643 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
644 });
645
646 log_reader_factory.Run();
647 EXPECT_EQ(pi1_ping_count, 2030);
648 EXPECT_EQ(pi2_ping_count, 2030);
649 EXPECT_EQ(pi1_pong_count, 2030);
650 EXPECT_EQ(pi2_pong_count, 2030);
651
652 reader.Deregister();
653}
Austin Schuh6f3babe2020-01-26 20:34:50 -0800654
Austin Schuh8bd96322020-02-13 21:18:22 -0800655// Tests that we can read log files where the monotonic clocks drift and don't
656// match correctly. While we are here, also test that different ending times
657// also is readable.
658TEST_F(MultinodeLoggerTest, MismatchedClocks) {
Austin Schuhcde938c2020-02-02 17:30:07 -0800659 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700660 LoggerState pi2_logger = MakeLogger(pi2_);
661
Austin Schuh8bd96322020-02-13 21:18:22 -0800662 NodeEventLoopFactory *pi2 =
663 event_loop_factory_.GetNodeEventLoopFactory(pi2_);
664 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
665 << pi2->realtime_now() << " distributed "
666 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -0800667
Austin Schuh8bd96322020-02-13 21:18:22 -0800668 const chrono::nanoseconds initial_pi2_offset = -chrono::seconds(1000);
669 chrono::nanoseconds pi2_offset = initial_pi2_offset;
Austin Schuhcde938c2020-02-02 17:30:07 -0800670
Austin Schuhbe69cf32020-08-27 11:38:33 -0700671 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800672 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
673 << pi2->realtime_now() << " distributed "
674 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -0800675
Austin Schuhcde938c2020-02-02 17:30:07 -0800676
Austin Schuh8bd96322020-02-13 21:18:22 -0800677 for (int i = 0; i < 95; ++i) {
678 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -0700679 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800680 event_loop_factory_.RunFor(chrono::milliseconds(1));
681 }
Austin Schuhcde938c2020-02-02 17:30:07 -0800682
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700683
684 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800685
Austin Schuh8bd96322020-02-13 21:18:22 -0800686 event_loop_factory_.RunFor(chrono::milliseconds(200));
Austin Schuhcde938c2020-02-02 17:30:07 -0800687
Austin Schuh8bd96322020-02-13 21:18:22 -0800688 {
689 // Run pi1's logger for only part of the time.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700690 LoggerState pi1_logger = MakeLogger(pi1_);
Austin Schuh8bd96322020-02-13 21:18:22 -0800691
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700692 StartLogger(&pi1_logger);
Austin Schuh8bd96322020-02-13 21:18:22 -0800693
694 for (int i = 0; i < 20000; ++i) {
695 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -0700696 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800697 event_loop_factory_.RunFor(chrono::milliseconds(1));
698 }
699
700 EXPECT_GT(pi2_offset - initial_pi2_offset,
701 event_loop_factory_.send_delay() +
702 event_loop_factory_.network_delay());
703
704 for (int i = 0; i < 40000; ++i) {
705 pi2_offset -= chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -0700706 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800707 event_loop_factory_.RunFor(chrono::milliseconds(1));
708 }
709 }
710
711 // And log a bit more on pi2.
712 event_loop_factory_.RunFor(chrono::milliseconds(400));
Austin Schuhcde938c2020-02-02 17:30:07 -0800713 }
714
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700715 LogReader reader({std::vector<std::string>{logfiles_[0]},
716 std::vector<std::string>{logfiles_[2]}});
Austin Schuhcde938c2020-02-02 17:30:07 -0800717
718 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
719 log_reader_factory.set_send_delay(chrono::microseconds(0));
720
721 // This sends out the fetched messages and advances time to the start of the
722 // log file.
723 reader.Register(&log_reader_factory);
724
725
726 const Node *pi1 =
727 configuration::GetNode(log_reader_factory.configuration(), "pi1");
728 const Node *pi2 =
729 configuration::GetNode(log_reader_factory.configuration(), "pi2");
730
731 LOG(INFO) << "Done registering (pi1) "
732 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now() << " "
733 << log_reader_factory.GetNodeEventLoopFactory(pi1)->realtime_now();
734 LOG(INFO) << "Done registering (pi2) "
735 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now() << " "
736 << log_reader_factory.GetNodeEventLoopFactory(pi2)->realtime_now();
737
738 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
739
740 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
741
742 std::unique_ptr<EventLoop> pi1_event_loop =
743 log_reader_factory.MakeEventLoop("test", pi1);
744 std::unique_ptr<EventLoop> pi2_event_loop =
745 log_reader_factory.MakeEventLoop("test", pi2);
746
747 int pi1_ping_count = 30;
748 int pi2_ping_count = 30;
749 int pi1_pong_count = 30;
750 int pi2_pong_count = 30;
751
752 // Confirm that the ping value matches.
753 pi1_event_loop->MakeWatcher(
754 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
755 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
756 << pi1_event_loop->context().monotonic_remote_time << " -> "
757 << pi1_event_loop->context().monotonic_event_time;
758 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
759
760 ++pi1_ping_count;
761 });
762 pi2_event_loop->MakeWatcher(
763 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
764 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
765 << pi2_event_loop->context().monotonic_remote_time << " -> "
766 << pi2_event_loop->context().monotonic_event_time;
767 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
768
769 ++pi2_ping_count;
770 });
771
772 // Confirm that the ping and pong counts both match, and the value also
773 // matches.
774 pi1_event_loop->MakeWatcher(
775 "/test", [&pi1_event_loop, &pi1_ping_count,
776 &pi1_pong_count](const examples::Pong &pong) {
777 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
778 << pi1_event_loop->context().monotonic_remote_time << " -> "
779 << pi1_event_loop->context().monotonic_event_time;
780
781 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
782 ++pi1_pong_count;
783 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
784 });
785 pi2_event_loop->MakeWatcher(
786 "/test", [&pi2_event_loop, &pi2_ping_count,
787 &pi2_pong_count](const examples::Pong &pong) {
788 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
789 << pi2_event_loop->context().monotonic_remote_time << " -> "
790 << pi2_event_loop->context().monotonic_event_time;
791
792 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
793 ++pi2_pong_count;
794 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
795 });
796
797 log_reader_factory.Run();
Austin Schuh8bd96322020-02-13 21:18:22 -0800798 EXPECT_EQ(pi1_ping_count, 6030);
799 EXPECT_EQ(pi2_ping_count, 6030);
800 EXPECT_EQ(pi1_pong_count, 6030);
801 EXPECT_EQ(pi2_pong_count, 6030);
Austin Schuhcde938c2020-02-02 17:30:07 -0800802
803 reader.Deregister();
804}
805
Austin Schuh8bd96322020-02-13 21:18:22 -0800806// TODO(austin): We can write a test which recreates a logfile and confirms that
807// we get it back. That is the ultimate test.
808
Austin Schuhe309d2a2019-11-29 13:25:21 -0800809} // namespace testing
810} // namespace logger
811} // namespace aos