blob: 2095529e89fc7c5d381fd336bb242da73c8c2ae3 [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"
Austin Schuh01b4c352020-09-21 23:09:39 -07004#include "aos/events/message_counter.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -08005#include "aos/events/ping_lib.h"
6#include "aos/events/pong_lib.h"
7#include "aos/events/simulated_event_loop.h"
Austin Schuh2f8fd752020-09-01 22:38:28 -07008#include "aos/util/file.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -08009#include "glog/logging.h"
Austin Schuh6f3babe2020-01-26 20:34:50 -080010#include "gmock/gmock.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -080011#include "gtest/gtest.h"
12
13namespace aos {
14namespace logger {
15namespace testing {
16
17namespace chrono = std::chrono;
Austin Schuh01b4c352020-09-21 23:09:39 -070018using aos::testing::MessageCounter;
Austin Schuhe309d2a2019-11-29 13:25:21 -080019
20class LoggerTest : public ::testing::Test {
21 public:
22 LoggerTest()
23 : config_(
24 aos::configuration::ReadConfig("aos/events/pingpong_config.json")),
25 event_loop_factory_(&config_.message()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080026 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080027 ping_(ping_event_loop_.get()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080028 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080029 pong_(pong_event_loop_.get()) {}
30
31 // Config and factory.
32 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
33 SimulatedEventLoopFactory event_loop_factory_;
34
35 // Event loop and app for Ping
36 std::unique_ptr<EventLoop> ping_event_loop_;
37 Ping ping_;
38
39 // Event loop and app for Pong
40 std::unique_ptr<EventLoop> pong_event_loop_;
41 Pong pong_;
42};
43
Brian Silverman1f345222020-09-24 21:14:48 -070044using LoggerDeathTest = LoggerTest;
45
Austin Schuhe309d2a2019-11-29 13:25:21 -080046// Tests that we can startup at all. This confirms that the channels are all in
47// the config.
48TEST_F(LoggerTest, Starts) {
49 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
Austin Schuh2f8fd752020-09-01 22:38:28 -070050 const ::std::string base_name = tmpdir + "/logfile";
51 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuhe309d2a2019-11-29 13:25:21 -080052 // Remove it.
53 unlink(logfile.c_str());
54
55 LOG(INFO) << "Logging data to " << logfile;
56
57 {
Austin Schuhe309d2a2019-11-29 13:25:21 -080058 std::unique_ptr<EventLoop> logger_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080059 event_loop_factory_.MakeEventLoop("logger");
Austin Schuhe309d2a2019-11-29 13:25:21 -080060
61 event_loop_factory_.RunFor(chrono::milliseconds(95));
62
Brian Silverman1f345222020-09-24 21:14:48 -070063 Logger logger(logger_event_loop.get());
64 logger.set_polling_period(std::chrono::milliseconds(100));
65 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuhe309d2a2019-11-29 13:25:21 -080066 event_loop_factory_.RunFor(chrono::milliseconds(20000));
67 }
68
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080069 // Even though it doesn't make any difference here, exercise the logic for
70 // passing in a separate config.
71 LogReader reader(logfile, &config_.message());
Austin Schuhe309d2a2019-11-29 13:25:21 -080072
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080073 // Confirm that we can remap logged channels to point to new buses.
74 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
Austin Schuhe309d2a2019-11-29 13:25:21 -080075
Austin Schuh15649d62019-12-28 16:36:38 -080076 // This sends out the fetched messages and advances time to the start of the
77 // log file.
James Kuszmaul84ff3e52020-01-03 19:48:53 -080078 reader.Register();
Austin Schuhe309d2a2019-11-29 13:25:21 -080079
Austin Schuh6f3babe2020-01-26 20:34:50 -080080 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
James Kuszmaul84ff3e52020-01-03 19:48:53 -080081
Austin Schuhe309d2a2019-11-29 13:25:21 -080082 std::unique_ptr<EventLoop> test_event_loop =
James Kuszmaul84ff3e52020-01-03 19:48:53 -080083 reader.event_loop_factory()->MakeEventLoop("log_reader");
Austin Schuhe309d2a2019-11-29 13:25:21 -080084
85 int ping_count = 10;
86 int pong_count = 10;
87
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080088 // Confirm that the ping value matches in the remapped channel location.
89 test_event_loop->MakeWatcher("/original/test",
Austin Schuhe309d2a2019-11-29 13:25:21 -080090 [&ping_count](const examples::Ping &ping) {
91 EXPECT_EQ(ping.value(), ping_count + 1);
92 ++ping_count;
93 });
94 // Confirm that the ping and pong counts both match, and the value also
95 // matches.
96 test_event_loop->MakeWatcher(
97 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
98 EXPECT_EQ(pong.value(), pong_count + 1);
99 ++pong_count;
100 EXPECT_EQ(ping_count, pong_count);
101 });
102
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800103 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
Austin Schuhe309d2a2019-11-29 13:25:21 -0800104 EXPECT_EQ(ping_count, 2010);
Austin Schuhe309d2a2019-11-29 13:25:21 -0800105}
106
Brian Silverman1f345222020-09-24 21:14:48 -0700107// Tests calling StartLogging twice.
108TEST_F(LoggerDeathTest, ExtraStart) {
109 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
110 const ::std::string base_name1 = tmpdir + "/logfile1";
111 const ::std::string logfile1 = base_name1 + ".part0.bfbs";
112 const ::std::string base_name2 = tmpdir + "/logfile2";
113 const ::std::string logfile2 = base_name2 + ".part0.bfbs";
114 unlink(logfile1.c_str());
115 unlink(logfile2.c_str());
116
117 LOG(INFO) << "Logging data to " << logfile1 << " then " << logfile2;
118
119 {
120 std::unique_ptr<EventLoop> logger_event_loop =
121 event_loop_factory_.MakeEventLoop("logger");
122
123 event_loop_factory_.RunFor(chrono::milliseconds(95));
124
125 Logger logger(logger_event_loop.get());
126 logger.set_polling_period(std::chrono::milliseconds(100));
127 logger_event_loop->OnRun(
128 [base_name1, base_name2, &logger_event_loop, &logger]() {
129 logger.StartLogging(std::make_unique<LocalLogNamer>(
130 base_name1, logger_event_loop->node()));
131 EXPECT_DEATH(logger.StartLogging(std::make_unique<LocalLogNamer>(
132 base_name2, logger_event_loop->node())),
133 "Already logging");
134 });
135 event_loop_factory_.RunFor(chrono::milliseconds(20000));
136 }
137}
138
139// Tests calling StopLogging twice.
140TEST_F(LoggerDeathTest, ExtraStop) {
141 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
142 const ::std::string base_name = tmpdir + "/logfile";
143 const ::std::string logfile = base_name + ".part0.bfbs";
144 // Remove it.
145 unlink(logfile.c_str());
146
147 LOG(INFO) << "Logging data to " << logfile;
148
149 {
150 std::unique_ptr<EventLoop> logger_event_loop =
151 event_loop_factory_.MakeEventLoop("logger");
152
153 event_loop_factory_.RunFor(chrono::milliseconds(95));
154
155 Logger logger(logger_event_loop.get());
156 logger.set_polling_period(std::chrono::milliseconds(100));
157 logger_event_loop->OnRun([base_name, &logger_event_loop, &logger]() {
158 logger.StartLogging(std::make_unique<LocalLogNamer>(
159 base_name, logger_event_loop->node()));
160 logger.StopLogging(aos::monotonic_clock::min_time);
161 EXPECT_DEATH(logger.StopLogging(aos::monotonic_clock::min_time),
162 "Not logging right now");
163 });
164 event_loop_factory_.RunFor(chrono::milliseconds(20000));
165 }
166}
167
168// Tests that we can startup twice.
169TEST_F(LoggerTest, StartsTwice) {
170 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
171 const ::std::string base_name1 = tmpdir + "/logfile1";
172 const ::std::string logfile1 = base_name1 + ".part0.bfbs";
173 const ::std::string base_name2 = tmpdir + "/logfile2";
174 const ::std::string logfile2 = base_name2 + ".part0.bfbs";
175 unlink(logfile1.c_str());
176 unlink(logfile2.c_str());
177
178 LOG(INFO) << "Logging data to " << logfile1 << " then " << logfile2;
179
180 {
181 std::unique_ptr<EventLoop> logger_event_loop =
182 event_loop_factory_.MakeEventLoop("logger");
183
184 event_loop_factory_.RunFor(chrono::milliseconds(95));
185
186 Logger logger(logger_event_loop.get());
187 logger.set_polling_period(std::chrono::milliseconds(100));
188 logger.StartLogging(
189 std::make_unique<LocalLogNamer>(base_name1, logger_event_loop->node()));
190 event_loop_factory_.RunFor(chrono::milliseconds(10000));
191 logger.StopLogging(logger_event_loop->monotonic_now());
192 event_loop_factory_.RunFor(chrono::milliseconds(10000));
193 logger.StartLogging(
194 std::make_unique<LocalLogNamer>(base_name2, logger_event_loop->node()));
195 event_loop_factory_.RunFor(chrono::milliseconds(10000));
196 }
197
198 for (const auto &logfile :
199 {std::make_tuple(logfile1, 10), std::make_tuple(logfile2, 2010)}) {
200 SCOPED_TRACE(std::get<0>(logfile));
201 LogReader reader(std::get<0>(logfile));
202 reader.Register();
203
204 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
205
206 std::unique_ptr<EventLoop> test_event_loop =
207 reader.event_loop_factory()->MakeEventLoop("log_reader");
208
209 int ping_count = std::get<1>(logfile);
210 int pong_count = std::get<1>(logfile);
211
212 // Confirm that the ping and pong counts both match, and the value also
213 // matches.
214 test_event_loop->MakeWatcher("/test",
215 [&ping_count](const examples::Ping &ping) {
216 EXPECT_EQ(ping.value(), ping_count + 1);
217 ++ping_count;
218 });
219 test_event_loop->MakeWatcher(
220 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
221 EXPECT_EQ(pong.value(), pong_count + 1);
222 ++pong_count;
223 EXPECT_EQ(ping_count, pong_count);
224 });
225
226 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
227 EXPECT_EQ(ping_count, std::get<1>(logfile) + 1000);
228 }
229}
230
Austin Schuhfa895892020-01-07 20:07:41 -0800231// Tests that we can read and write rotated log files.
232TEST_F(LoggerTest, RotatedLogFile) {
233 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
Austin Schuh2f8fd752020-09-01 22:38:28 -0700234 const ::std::string base_name = tmpdir + "/logfile";
235 const ::std::string logfile0 = base_name + ".part0.bfbs";
236 const ::std::string logfile1 = base_name + ".part1.bfbs";
Austin Schuhfa895892020-01-07 20:07:41 -0800237 // Remove it.
238 unlink(logfile0.c_str());
239 unlink(logfile1.c_str());
240
241 LOG(INFO) << "Logging data to " << logfile0 << " and " << logfile1;
242
243 {
Austin Schuhfa895892020-01-07 20:07:41 -0800244 std::unique_ptr<EventLoop> logger_event_loop =
245 event_loop_factory_.MakeEventLoop("logger");
246
247 event_loop_factory_.RunFor(chrono::milliseconds(95));
248
Brian Silverman1f345222020-09-24 21:14:48 -0700249 Logger logger(logger_event_loop.get());
250 logger.set_polling_period(std::chrono::milliseconds(100));
251 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuhfa895892020-01-07 20:07:41 -0800252 event_loop_factory_.RunFor(chrono::milliseconds(10000));
Austin Schuh2f8fd752020-09-01 22:38:28 -0700253 logger.Rotate();
Austin Schuhfa895892020-01-07 20:07:41 -0800254 event_loop_factory_.RunFor(chrono::milliseconds(10000));
255 }
256
Austin Schuh64fab802020-09-09 22:47:47 -0700257 {
258 // Confirm that the UUIDs match for both the parts and the logger, and the
259 // parts_index increments.
260 std::vector<FlatbufferVector<LogFileHeader>> log_header;
261 for (std::string_view f : {logfile0, logfile1}) {
262 log_header.emplace_back(ReadHeader(f));
263 }
264
265 EXPECT_EQ(log_header[0].message().logger_uuid()->string_view(),
266 log_header[1].message().logger_uuid()->string_view());
267 EXPECT_EQ(log_header[0].message().parts_uuid()->string_view(),
268 log_header[1].message().parts_uuid()->string_view());
269
270 EXPECT_EQ(log_header[0].message().parts_index(), 0);
271 EXPECT_EQ(log_header[1].message().parts_index(), 1);
272 }
273
Austin Schuhfa895892020-01-07 20:07:41 -0800274 // Even though it doesn't make any difference here, exercise the logic for
275 // passing in a separate config.
276 LogReader reader(std::vector<std::string>{logfile0, logfile1},
277 &config_.message());
278
279 // Confirm that we can remap logged channels to point to new buses.
280 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
281
282 // This sends out the fetched messages and advances time to the start of the
283 // log file.
284 reader.Register();
285
Austin Schuh6f3babe2020-01-26 20:34:50 -0800286 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
Austin Schuhfa895892020-01-07 20:07:41 -0800287
288 std::unique_ptr<EventLoop> test_event_loop =
289 reader.event_loop_factory()->MakeEventLoop("log_reader");
290
291 int ping_count = 10;
292 int pong_count = 10;
293
294 // Confirm that the ping value matches in the remapped channel location.
295 test_event_loop->MakeWatcher("/original/test",
296 [&ping_count](const examples::Ping &ping) {
297 EXPECT_EQ(ping.value(), ping_count + 1);
298 ++ping_count;
299 });
300 // Confirm that the ping and pong counts both match, and the value also
301 // matches.
302 test_event_loop->MakeWatcher(
303 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
304 EXPECT_EQ(pong.value(), pong_count + 1);
305 ++pong_count;
306 EXPECT_EQ(ping_count, pong_count);
307 });
308
309 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
310 EXPECT_EQ(ping_count, 2010);
311}
312
Austin Schuh4c4e0092019-12-22 16:18:03 -0800313// Tests that a large number of messages per second doesn't overwhelm writev.
314TEST_F(LoggerTest, ManyMessages) {
315 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
Austin Schuh2f8fd752020-09-01 22:38:28 -0700316 const ::std::string base_name = tmpdir + "/logfile";
317 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuh4c4e0092019-12-22 16:18:03 -0800318 // Remove the log file.
319 unlink(logfile.c_str());
320
321 LOG(INFO) << "Logging data to " << logfile;
Austin Schuh4c3b9702020-08-30 11:34:55 -0700322 ping_.set_quiet(true);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800323
324 {
Austin Schuh4c4e0092019-12-22 16:18:03 -0800325 std::unique_ptr<EventLoop> logger_event_loop =
326 event_loop_factory_.MakeEventLoop("logger");
327
328 std::unique_ptr<EventLoop> ping_spammer_event_loop =
329 event_loop_factory_.MakeEventLoop("ping_spammer");
330 aos::Sender<examples::Ping> ping_sender =
331 ping_spammer_event_loop->MakeSender<examples::Ping>("/test");
332
333 aos::TimerHandler *timer_handler =
334 ping_spammer_event_loop->AddTimer([&ping_sender]() {
335 aos::Sender<examples::Ping>::Builder builder =
336 ping_sender.MakeBuilder();
337 examples::Ping::Builder ping_builder =
338 builder.MakeBuilder<examples::Ping>();
339 CHECK(builder.Send(ping_builder.Finish()));
340 });
341
342 // 100 ms / 0.05 ms -> 2000 messages. Should be enough to crash it.
343 ping_spammer_event_loop->OnRun([&ping_spammer_event_loop, timer_handler]() {
344 timer_handler->Setup(ping_spammer_event_loop->monotonic_now(),
345 chrono::microseconds(50));
346 });
347
Brian Silverman1f345222020-09-24 21:14:48 -0700348 Logger logger(logger_event_loop.get());
349 logger.set_polling_period(std::chrono::milliseconds(100));
350 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800351
352 event_loop_factory_.RunFor(chrono::milliseconds(1000));
353 }
354}
355
Austin Schuh15649d62019-12-28 16:36:38 -0800356class MultinodeLoggerTest : public ::testing::Test {
357 public:
358 MultinodeLoggerTest()
359 : config_(aos::configuration::ReadConfig(
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800360 "aos/events/logging/multinode_pingpong_config.json")),
Austin Schuhac0771c2020-01-07 18:36:30 -0800361 event_loop_factory_(&config_.message()),
Austin Schuhcde938c2020-02-02 17:30:07 -0800362 pi1_(
363 configuration::GetNode(event_loop_factory_.configuration(), "pi1")),
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700364 pi2_(
365 configuration::GetNode(event_loop_factory_.configuration(), "pi2")),
366 tmp_dir_(getenv("TEST_TMPDIR")),
367 logfile_base_(tmp_dir_ + "/multi_logfile"),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700368 logfiles_(
369 {logfile_base_ + "_pi1_data.part0.bfbs",
370 logfile_base_ + "_pi2_data/test/aos.examples.Pong.part0.bfbs",
371 logfile_base_ + "_pi2_data/test/aos.examples.Pong.part1.bfbs",
372 logfile_base_ + "_pi2_data.part0.bfbs",
373 logfile_base_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
374 "aos.logger.MessageHeader.part0.bfbs",
375 logfile_base_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
376 "aos.logger.MessageHeader.part1.bfbs",
377 logfile_base_ + "_timestamps/pi2/aos/remote_timestamps/pi1/"
378 "aos.logger.MessageHeader.part0.bfbs",
379 logfile_base_ + "_timestamps/pi2/aos/remote_timestamps/pi1/"
380 "aos.logger.MessageHeader.part1.bfbs",
381 logfile_base_ +
382 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part0.bfbs",
383 logfile_base_ +
384 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part1.bfbs",
385 logfile_base_ +
386 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part0.bfbs",
387 logfile_base_ +
388 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part1.bfbs"}),
389 structured_logfiles_{
390 std::vector<std::string>{logfiles_[0]},
391 std::vector<std::string>{logfiles_[1], logfiles_[2]},
392 std::vector<std::string>{logfiles_[3]},
393 std::vector<std::string>{logfiles_[4], logfiles_[5]},
394 std::vector<std::string>{logfiles_[6], logfiles_[7]},
395 std::vector<std::string>{logfiles_[8], logfiles_[9]},
396 std::vector<std::string>{logfiles_[10], logfiles_[11]}},
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700397 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping", pi1_)),
398 ping_(ping_event_loop_.get()),
399 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong", pi2_)),
400 pong_(pong_event_loop_.get()) {
401 // Go through and remove the logfiles if they already exist.
402 for (const auto file : logfiles_) {
403 unlink(file.c_str());
404 }
405
406 LOG(INFO) << "Logging data to " << logfiles_[0] << ", " << logfiles_[1]
407 << " and " << logfiles_[2];
408 }
409
410 struct LoggerState {
411 std::unique_ptr<EventLoop> event_loop;
412 std::unique_ptr<Logger> logger;
413 };
414
415 LoggerState MakeLogger(const Node *node) {
416 return {event_loop_factory_.MakeEventLoop("logger", node), {}};
417 }
418
419 void StartLogger(LoggerState *logger) {
Brian Silverman1f345222020-09-24 21:14:48 -0700420 logger->logger = std::make_unique<Logger>(logger->event_loop.get());
421 logger->logger->set_polling_period(std::chrono::milliseconds(100));
422 logger->event_loop->OnRun([this, logger]() {
423 logger->logger->StartLogging(std::make_unique<MultiNodeLogNamer>(
424 logfile_base_, logger->event_loop->configuration(),
425 logger->event_loop->node()));
426 });
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700427 }
Austin Schuh15649d62019-12-28 16:36:38 -0800428
429 // Config and factory.
430 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
431 SimulatedEventLoopFactory event_loop_factory_;
432
Austin Schuhcde938c2020-02-02 17:30:07 -0800433 const Node *pi1_;
434 const Node *pi2_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700435
436 std::string tmp_dir_;
437 std::string logfile_base_;
Austin Schuh2f8fd752020-09-01 22:38:28 -0700438 std::vector<std::string> logfiles_;
439
440 std::vector<std::vector<std::string>> structured_logfiles_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700441
442 std::unique_ptr<EventLoop> ping_event_loop_;
443 Ping ping_;
444 std::unique_ptr<EventLoop> pong_event_loop_;
445 Pong pong_;
Austin Schuh15649d62019-12-28 16:36:38 -0800446};
447
Austin Schuh391e3172020-09-01 22:48:18 -0700448// Counts the number of messages on a channel. Returns (channel name, channel
449// type, count) for every message matching matcher()
450std::vector<std::tuple<std::string, std::string, int>> CountChannelsMatching(
Austin Schuh6f3babe2020-01-26 20:34:50 -0800451 std::string_view filename,
452 std::function<bool(const MessageHeader *)> matcher) {
453 MessageReader message_reader(filename);
454 std::vector<int> counts(
455 message_reader.log_file_header()->configuration()->channels()->size(), 0);
Austin Schuh15649d62019-12-28 16:36:38 -0800456
Austin Schuh6f3babe2020-01-26 20:34:50 -0800457 while (true) {
458 std::optional<FlatbufferVector<MessageHeader>> msg =
459 message_reader.ReadMessage();
460 if (!msg) {
461 break;
462 }
463
464 if (matcher(&msg.value().message())) {
465 counts[msg.value().message().channel_index()]++;
466 }
467 }
468
Austin Schuh391e3172020-09-01 22:48:18 -0700469 std::vector<std::tuple<std::string, std::string, int>> result;
Austin Schuh6f3babe2020-01-26 20:34:50 -0800470 int channel = 0;
471 for (size_t i = 0; i < counts.size(); ++i) {
472 if (counts[i] != 0) {
Austin Schuh391e3172020-09-01 22:48:18 -0700473 const Channel *channel =
474 message_reader.log_file_header()->configuration()->channels()->Get(i);
475 result.push_back(std::make_tuple(channel->name()->str(),
476 channel->type()->str(), counts[i]));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800477 }
478 ++channel;
479 }
480
481 return result;
482}
483
484// Counts the number of messages (channel, count) for all data messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700485std::vector<std::tuple<std::string, std::string, int>> CountChannelsData(
486 std::string_view filename) {
Austin Schuh6f3babe2020-01-26 20:34:50 -0800487 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
488 if (msg->has_data()) {
489 CHECK(!msg->has_monotonic_remote_time());
490 CHECK(!msg->has_realtime_remote_time());
491 CHECK(!msg->has_remote_queue_index());
492 return true;
493 }
494 return false;
495 });
496}
497
498// Counts the number of messages (channel, count) for all timestamp messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700499std::vector<std::tuple<std::string, std::string, int>> CountChannelsTimestamp(
Austin Schuh6f3babe2020-01-26 20:34:50 -0800500 std::string_view filename) {
501 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
502 if (!msg->has_data()) {
503 CHECK(msg->has_monotonic_remote_time());
504 CHECK(msg->has_realtime_remote_time());
505 CHECK(msg->has_remote_queue_index());
506 return true;
507 }
508 return false;
509 });
510}
511
Austin Schuhcde938c2020-02-02 17:30:07 -0800512// Tests that we can write and read simple multi-node log files.
513TEST_F(MultinodeLoggerTest, SimpleMultiNode) {
Austin Schuh15649d62019-12-28 16:36:38 -0800514 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700515 LoggerState pi1_logger = MakeLogger(pi1_);
516 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuh15649d62019-12-28 16:36:38 -0800517
518 event_loop_factory_.RunFor(chrono::milliseconds(95));
519
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700520 StartLogger(&pi1_logger);
521 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800522
Austin Schuh15649d62019-12-28 16:36:38 -0800523 event_loop_factory_.RunFor(chrono::milliseconds(20000));
524 }
525
Austin Schuh6f3babe2020-01-26 20:34:50 -0800526 {
Austin Schuh64fab802020-09-09 22:47:47 -0700527 std::set<std::string> logfile_uuids;
528 std::set<std::string> parts_uuids;
529 // Confirm that we have the expected number of UUIDs for both the logfile
530 // UUIDs and parts UUIDs.
531 std::vector<FlatbufferVector<LogFileHeader>> log_header;
532 for (std::string_view f : logfiles_) {
533 log_header.emplace_back(ReadHeader(f));
534 logfile_uuids.insert(log_header.back().message().logger_uuid()->str());
535 parts_uuids.insert(log_header.back().message().parts_uuid()->str());
536 }
Austin Schuh15649d62019-12-28 16:36:38 -0800537
Austin Schuh64fab802020-09-09 22:47:47 -0700538 EXPECT_EQ(logfile_uuids.size(), 2u);
539 EXPECT_EQ(parts_uuids.size(), 7u);
540
541 // And confirm everything is on the correct node.
542 EXPECT_EQ(log_header[0].message().node()->name()->string_view(), "pi1");
543 EXPECT_EQ(log_header[1].message().node()->name()->string_view(), "pi2");
544 EXPECT_EQ(log_header[2].message().node()->name()->string_view(), "pi2");
545 EXPECT_EQ(log_header[3].message().node()->name()->string_view(), "pi2");
546 EXPECT_EQ(log_header[4].message().node()->name()->string_view(), "pi2");
547 EXPECT_EQ(log_header[5].message().node()->name()->string_view(), "pi2");
548 EXPECT_EQ(log_header[6].message().node()->name()->string_view(), "pi1");
549 EXPECT_EQ(log_header[7].message().node()->name()->string_view(), "pi1");
550 EXPECT_EQ(log_header[8].message().node()->name()->string_view(), "pi1");
551 EXPECT_EQ(log_header[9].message().node()->name()->string_view(), "pi1");
552 EXPECT_EQ(log_header[10].message().node()->name()->string_view(), "pi2");
553 EXPECT_EQ(log_header[11].message().node()->name()->string_view(), "pi2");
554
555 // And the parts index matches.
556 EXPECT_EQ(log_header[0].message().parts_index(), 0);
557 EXPECT_EQ(log_header[1].message().parts_index(), 0);
558 EXPECT_EQ(log_header[2].message().parts_index(), 1);
559 EXPECT_EQ(log_header[3].message().parts_index(), 0);
560 EXPECT_EQ(log_header[4].message().parts_index(), 0);
561 EXPECT_EQ(log_header[5].message().parts_index(), 1);
562 EXPECT_EQ(log_header[6].message().parts_index(), 0);
563 EXPECT_EQ(log_header[7].message().parts_index(), 1);
564 EXPECT_EQ(log_header[8].message().parts_index(), 0);
565 EXPECT_EQ(log_header[9].message().parts_index(), 1);
566 EXPECT_EQ(log_header[10].message().parts_index(), 0);
567 EXPECT_EQ(log_header[11].message().parts_index(), 1);
568 }
569
570 {
Austin Schuh391e3172020-09-01 22:48:18 -0700571 using ::testing::UnorderedElementsAre;
572
Austin Schuh6f3babe2020-01-26 20:34:50 -0800573 // Timing reports, pings
Austin Schuh2f8fd752020-09-01 22:38:28 -0700574 EXPECT_THAT(
575 CountChannelsData(logfiles_[0]),
576 UnorderedElementsAre(
577 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200),
578 std::make_tuple("/pi1/aos", "aos.timing.Report", 40),
579 std::make_tuple("/test", "aos.examples.Ping", 2001)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800580 // Timestamps for pong
Austin Schuh2f8fd752020-09-01 22:38:28 -0700581 EXPECT_THAT(
582 CountChannelsTimestamp(logfiles_[0]),
583 UnorderedElementsAre(
584 std::make_tuple("/test", "aos.examples.Pong", 2001),
585 std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800586
587 // Pong data.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700588 EXPECT_THAT(CountChannelsData(logfiles_[1]),
Austin Schuh391e3172020-09-01 22:48:18 -0700589 UnorderedElementsAre(
Austin Schuh2f8fd752020-09-01 22:38:28 -0700590 std::make_tuple("/test", "aos.examples.Pong", 101)));
591 EXPECT_THAT(CountChannelsData(logfiles_[2]),
592 UnorderedElementsAre(
593 std::make_tuple("/test", "aos.examples.Pong", 1900)));
Austin Schuh391e3172020-09-01 22:48:18 -0700594
Austin Schuh6f3babe2020-01-26 20:34:50 -0800595 // No timestamps
Austin Schuh391e3172020-09-01 22:48:18 -0700596 EXPECT_THAT(CountChannelsTimestamp(logfiles_[1]), UnorderedElementsAre());
Austin Schuh2f8fd752020-09-01 22:38:28 -0700597 EXPECT_THAT(CountChannelsTimestamp(logfiles_[2]), UnorderedElementsAre());
Austin Schuh6f3babe2020-01-26 20:34:50 -0800598
599 // Timing reports and pongs.
Austin Schuh2f8fd752020-09-01 22:38:28 -0700600 EXPECT_THAT(
601 CountChannelsData(logfiles_[3]),
602 UnorderedElementsAre(
603 std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200),
604 std::make_tuple("/pi2/aos", "aos.timing.Report", 40),
605 std::make_tuple("/test", "aos.examples.Pong", 2001)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800606 // And ping timestamps.
Austin Schuh2f8fd752020-09-01 22:38:28 -0700607 EXPECT_THAT(
608 CountChannelsTimestamp(logfiles_[3]),
609 UnorderedElementsAre(
610 std::make_tuple("/test", "aos.examples.Ping", 2001),
611 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200)));
612
613 // Timestamps from pi2 on pi1, and the other way.
614 EXPECT_THAT(CountChannelsData(logfiles_[4]), UnorderedElementsAre());
615 EXPECT_THAT(CountChannelsData(logfiles_[5]), UnorderedElementsAre());
616 EXPECT_THAT(CountChannelsData(logfiles_[6]), UnorderedElementsAre());
617 EXPECT_THAT(CountChannelsData(logfiles_[7]), UnorderedElementsAre());
618 EXPECT_THAT(
619 CountChannelsTimestamp(logfiles_[4]),
620 UnorderedElementsAre(
621 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 10),
622 std::make_tuple("/test", "aos.examples.Ping", 101)));
623 EXPECT_THAT(
624 CountChannelsTimestamp(logfiles_[5]),
625 UnorderedElementsAre(
626 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 190),
627 std::make_tuple("/test", "aos.examples.Ping", 1900)));
628 EXPECT_THAT(CountChannelsTimestamp(logfiles_[6]),
629 UnorderedElementsAre(std::make_tuple(
630 "/pi2/aos", "aos.message_bridge.Timestamp", 10)));
631 EXPECT_THAT(CountChannelsTimestamp(logfiles_[7]),
632 UnorderedElementsAre(std::make_tuple(
633 "/pi2/aos", "aos.message_bridge.Timestamp", 190)));
634
635 // And then test that the remotely logged timestamp data files only have
636 // timestamps in them.
637 EXPECT_THAT(CountChannelsTimestamp(logfiles_[8]), UnorderedElementsAre());
638 EXPECT_THAT(CountChannelsTimestamp(logfiles_[9]), UnorderedElementsAre());
639 EXPECT_THAT(CountChannelsTimestamp(logfiles_[10]), UnorderedElementsAre());
640 EXPECT_THAT(CountChannelsTimestamp(logfiles_[11]), UnorderedElementsAre());
641
642 EXPECT_THAT(CountChannelsData(logfiles_[8]),
643 UnorderedElementsAre(std::make_tuple(
644 "/pi1/aos", "aos.message_bridge.Timestamp", 10)));
645 EXPECT_THAT(CountChannelsData(logfiles_[9]),
646 UnorderedElementsAre(std::make_tuple(
647 "/pi1/aos", "aos.message_bridge.Timestamp", 190)));
648
649 EXPECT_THAT(CountChannelsData(logfiles_[10]),
650 UnorderedElementsAre(std::make_tuple(
651 "/pi2/aos", "aos.message_bridge.Timestamp", 10)));
652 EXPECT_THAT(CountChannelsData(logfiles_[11]),
653 UnorderedElementsAre(std::make_tuple(
654 "/pi2/aos", "aos.message_bridge.Timestamp", 190)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800655 }
656
Austin Schuh2f8fd752020-09-01 22:38:28 -0700657 LogReader reader(structured_logfiles_);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800658
Austin Schuhac0771c2020-01-07 18:36:30 -0800659 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
Austin Schuh6331ef92020-01-07 18:28:09 -0800660 log_reader_factory.set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800661
662 // This sends out the fetched messages and advances time to the start of the
663 // log file.
Austin Schuh6331ef92020-01-07 18:28:09 -0800664 reader.Register(&log_reader_factory);
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800665
Austin Schuhac0771c2020-01-07 18:36:30 -0800666 const Node *pi1 =
667 configuration::GetNode(log_reader_factory.configuration(), "pi1");
Austin Schuh6f3babe2020-01-26 20:34:50 -0800668 const Node *pi2 =
669 configuration::GetNode(log_reader_factory.configuration(), "pi2");
Austin Schuhac0771c2020-01-07 18:36:30 -0800670
Austin Schuh2f8fd752020-09-01 22:38:28 -0700671 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
672 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
673 LOG(INFO) << "now pi1 "
674 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
675 LOG(INFO) << "now pi2 "
676 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
677
Austin Schuh6f3babe2020-01-26 20:34:50 -0800678 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800679
680 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800681
Austin Schuh6f3babe2020-01-26 20:34:50 -0800682 std::unique_ptr<EventLoop> pi1_event_loop =
Austin Schuhac0771c2020-01-07 18:36:30 -0800683 log_reader_factory.MakeEventLoop("test", pi1);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800684 std::unique_ptr<EventLoop> pi2_event_loop =
685 log_reader_factory.MakeEventLoop("test", pi2);
Austin Schuh15649d62019-12-28 16:36:38 -0800686
Austin Schuh6f3babe2020-01-26 20:34:50 -0800687 int pi1_ping_count = 10;
688 int pi2_ping_count = 10;
689 int pi1_pong_count = 10;
690 int pi2_pong_count = 10;
Austin Schuh15649d62019-12-28 16:36:38 -0800691
692 // Confirm that the ping value matches.
Austin Schuh6f3babe2020-01-26 20:34:50 -0800693 pi1_event_loop->MakeWatcher(
694 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
Austin Schuh2f8fd752020-09-01 22:38:28 -0700695 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping) << " at "
Austin Schuh6f3babe2020-01-26 20:34:50 -0800696 << pi1_event_loop->context().monotonic_remote_time << " -> "
697 << pi1_event_loop->context().monotonic_event_time;
698 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
699 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
700 pi1_ping_count * chrono::milliseconds(10) +
701 monotonic_clock::epoch());
702 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
703 pi1_ping_count * chrono::milliseconds(10) +
704 realtime_clock::epoch());
705 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
706 pi1_event_loop->context().monotonic_event_time);
707 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
708 pi1_event_loop->context().realtime_event_time);
Austin Schuh15649d62019-12-28 16:36:38 -0800709
Austin Schuh6f3babe2020-01-26 20:34:50 -0800710 ++pi1_ping_count;
711 });
712 pi2_event_loop->MakeWatcher(
713 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
Austin Schuh2f8fd752020-09-01 22:38:28 -0700714 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping) << " at "
Austin Schuh6f3babe2020-01-26 20:34:50 -0800715 << pi2_event_loop->context().monotonic_remote_time << " -> "
716 << pi2_event_loop->context().monotonic_event_time;
717 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
718
719 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
720 pi2_ping_count * chrono::milliseconds(10) +
721 monotonic_clock::epoch());
722 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
723 pi2_ping_count * chrono::milliseconds(10) +
724 realtime_clock::epoch());
725 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time +
726 chrono::microseconds(150),
727 pi2_event_loop->context().monotonic_event_time);
728 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time +
729 chrono::microseconds(150),
730 pi2_event_loop->context().realtime_event_time);
731 ++pi2_ping_count;
Austin Schuh15649d62019-12-28 16:36:38 -0800732 });
733
Austin Schuh6f3babe2020-01-26 20:34:50 -0800734 constexpr ssize_t kQueueIndexOffset = 0;
735 // Confirm that the ping and pong counts both match, and the value also
736 // matches.
737 pi1_event_loop->MakeWatcher(
738 "/test", [&pi1_event_loop, &pi1_ping_count,
739 &pi1_pong_count](const examples::Pong &pong) {
740 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
741 << pi1_event_loop->context().monotonic_remote_time << " -> "
742 << pi1_event_loop->context().monotonic_event_time;
743
744 EXPECT_EQ(pi1_event_loop->context().remote_queue_index,
745 pi1_pong_count + kQueueIndexOffset);
746 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
747 chrono::microseconds(200) +
748 pi1_pong_count * chrono::milliseconds(10) +
749 monotonic_clock::epoch());
750 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
751 chrono::microseconds(200) +
752 pi1_pong_count * chrono::milliseconds(10) +
753 realtime_clock::epoch());
754
755 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time +
756 chrono::microseconds(150),
757 pi1_event_loop->context().monotonic_event_time);
758 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time +
759 chrono::microseconds(150),
760 pi1_event_loop->context().realtime_event_time);
761
762 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
763 ++pi1_pong_count;
764 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
765 });
766 pi2_event_loop->MakeWatcher(
767 "/test", [&pi2_event_loop, &pi2_ping_count,
768 &pi2_pong_count](const examples::Pong &pong) {
769 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
770 << pi2_event_loop->context().monotonic_remote_time << " -> "
771 << pi2_event_loop->context().monotonic_event_time;
772
773 EXPECT_EQ(pi2_event_loop->context().remote_queue_index,
774 pi2_pong_count + kQueueIndexOffset - 9);
775
776 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
777 chrono::microseconds(200) +
778 pi2_pong_count * chrono::milliseconds(10) +
779 monotonic_clock::epoch());
780 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
781 chrono::microseconds(200) +
782 pi2_pong_count * chrono::milliseconds(10) +
783 realtime_clock::epoch());
784
785 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
786 pi2_event_loop->context().monotonic_event_time);
787 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
788 pi2_event_loop->context().realtime_event_time);
789
790 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
791 ++pi2_pong_count;
792 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
793 });
794
795 log_reader_factory.Run();
796 EXPECT_EQ(pi1_ping_count, 2010);
797 EXPECT_EQ(pi2_ping_count, 2010);
798 EXPECT_EQ(pi1_pong_count, 2010);
799 EXPECT_EQ(pi2_pong_count, 2010);
Austin Schuh6331ef92020-01-07 18:28:09 -0800800
801 reader.Deregister();
Austin Schuh15649d62019-12-28 16:36:38 -0800802}
803
James Kuszmaul46d82582020-05-09 19:50:09 -0700804typedef MultinodeLoggerTest MultinodeLoggerDeathTest;
805
806// Test that if we feed the replay with a mismatched node list that we die on
807// the LogReader constructor.
808TEST_F(MultinodeLoggerDeathTest, MultiNodeBadReplayConfig) {
James Kuszmaul46d82582020-05-09 19:50:09 -0700809 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700810 LoggerState pi1_logger = MakeLogger(pi1_);
811 LoggerState pi2_logger = MakeLogger(pi2_);
James Kuszmaul46d82582020-05-09 19:50:09 -0700812
813 event_loop_factory_.RunFor(chrono::milliseconds(95));
814
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700815 StartLogger(&pi1_logger);
816 StartLogger(&pi2_logger);
James Kuszmaul46d82582020-05-09 19:50:09 -0700817
James Kuszmaul46d82582020-05-09 19:50:09 -0700818 event_loop_factory_.RunFor(chrono::milliseconds(20000));
819 }
820
821 // Test that, if we add an additional node to the replay config that the
822 // logger complains about the mismatch in number of nodes.
823 FlatbufferDetachedBuffer<Configuration> extra_nodes_config =
824 configuration::MergeWithConfig(&config_.message(), R"({
825 "nodes": [
826 {
827 "name": "extra-node"
828 }
829 ]
830 }
831 )");
832
Austin Schuh2f8fd752020-09-01 22:38:28 -0700833 EXPECT_DEATH(LogReader(structured_logfiles_, &extra_nodes_config.message()),
James Kuszmaul46d82582020-05-09 19:50:09 -0700834 "Log file and replay config need to have matching nodes lists.");
James Kuszmaul46d82582020-05-09 19:50:09 -0700835}
836
Austin Schuhcde938c2020-02-02 17:30:07 -0800837// Tests that we can read log files where they don't start at the same monotonic
838// time.
839TEST_F(MultinodeLoggerTest, StaggeredStart) {
Austin Schuhcde938c2020-02-02 17:30:07 -0800840 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700841 LoggerState pi1_logger = MakeLogger(pi1_);
842 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuhcde938c2020-02-02 17:30:07 -0800843
844 event_loop_factory_.RunFor(chrono::milliseconds(95));
845
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700846 StartLogger(&pi1_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800847
848 event_loop_factory_.RunFor(chrono::milliseconds(200));
849
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700850 StartLogger(&pi2_logger);
851
Austin Schuhcde938c2020-02-02 17:30:07 -0800852 event_loop_factory_.RunFor(chrono::milliseconds(20000));
853 }
854
Austin Schuh2f8fd752020-09-01 22:38:28 -0700855 LogReader reader(structured_logfiles_);
Austin Schuhcde938c2020-02-02 17:30:07 -0800856
857 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
858 log_reader_factory.set_send_delay(chrono::microseconds(0));
859
860 // This sends out the fetched messages and advances time to the start of the
861 // log file.
862 reader.Register(&log_reader_factory);
863
864 const Node *pi1 =
865 configuration::GetNode(log_reader_factory.configuration(), "pi1");
866 const Node *pi2 =
867 configuration::GetNode(log_reader_factory.configuration(), "pi2");
868
869 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
870
871 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
872
873 std::unique_ptr<EventLoop> pi1_event_loop =
874 log_reader_factory.MakeEventLoop("test", pi1);
875 std::unique_ptr<EventLoop> pi2_event_loop =
876 log_reader_factory.MakeEventLoop("test", pi2);
877
878 int pi1_ping_count = 30;
879 int pi2_ping_count = 30;
880 int pi1_pong_count = 30;
881 int pi2_pong_count = 30;
882
883 // Confirm that the ping value matches.
884 pi1_event_loop->MakeWatcher(
885 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
886 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
887 << pi1_event_loop->context().monotonic_remote_time << " -> "
888 << pi1_event_loop->context().monotonic_event_time;
889 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
890
891 ++pi1_ping_count;
892 });
893 pi2_event_loop->MakeWatcher(
894 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
895 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
896 << pi2_event_loop->context().monotonic_remote_time << " -> "
897 << pi2_event_loop->context().monotonic_event_time;
898 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
899
900 ++pi2_ping_count;
901 });
902
903 // Confirm that the ping and pong counts both match, and the value also
904 // matches.
905 pi1_event_loop->MakeWatcher(
906 "/test", [&pi1_event_loop, &pi1_ping_count,
907 &pi1_pong_count](const examples::Pong &pong) {
908 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
909 << pi1_event_loop->context().monotonic_remote_time << " -> "
910 << pi1_event_loop->context().monotonic_event_time;
911
912 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
913 ++pi1_pong_count;
914 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
915 });
916 pi2_event_loop->MakeWatcher(
917 "/test", [&pi2_event_loop, &pi2_ping_count,
918 &pi2_pong_count](const examples::Pong &pong) {
919 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
920 << pi2_event_loop->context().monotonic_remote_time << " -> "
921 << pi2_event_loop->context().monotonic_event_time;
922
923 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
924 ++pi2_pong_count;
925 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
926 });
927
928 log_reader_factory.Run();
929 EXPECT_EQ(pi1_ping_count, 2030);
930 EXPECT_EQ(pi2_ping_count, 2030);
931 EXPECT_EQ(pi1_pong_count, 2030);
932 EXPECT_EQ(pi2_pong_count, 2030);
933
934 reader.Deregister();
935}
Austin Schuh6f3babe2020-01-26 20:34:50 -0800936
Austin Schuh8bd96322020-02-13 21:18:22 -0800937// Tests that we can read log files where the monotonic clocks drift and don't
938// match correctly. While we are here, also test that different ending times
939// also is readable.
940TEST_F(MultinodeLoggerTest, MismatchedClocks) {
Austin Schuhcde938c2020-02-02 17:30:07 -0800941 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700942 LoggerState pi2_logger = MakeLogger(pi2_);
943
Austin Schuh8bd96322020-02-13 21:18:22 -0800944 NodeEventLoopFactory *pi2 =
945 event_loop_factory_.GetNodeEventLoopFactory(pi2_);
946 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
947 << pi2->realtime_now() << " distributed "
948 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -0800949
Austin Schuh8bd96322020-02-13 21:18:22 -0800950 const chrono::nanoseconds initial_pi2_offset = -chrono::seconds(1000);
951 chrono::nanoseconds pi2_offset = initial_pi2_offset;
Austin Schuhcde938c2020-02-02 17:30:07 -0800952
Austin Schuhbe69cf32020-08-27 11:38:33 -0700953 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800954 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
955 << pi2->realtime_now() << " distributed "
956 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -0800957
Austin Schuh8bd96322020-02-13 21:18:22 -0800958 for (int i = 0; i < 95; ++i) {
959 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -0700960 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800961 event_loop_factory_.RunFor(chrono::milliseconds(1));
962 }
Austin Schuhcde938c2020-02-02 17:30:07 -0800963
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700964 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800965
Austin Schuh8bd96322020-02-13 21:18:22 -0800966 event_loop_factory_.RunFor(chrono::milliseconds(200));
Austin Schuhcde938c2020-02-02 17:30:07 -0800967
Austin Schuh8bd96322020-02-13 21:18:22 -0800968 {
969 // Run pi1's logger for only part of the time.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700970 LoggerState pi1_logger = MakeLogger(pi1_);
Austin Schuh8bd96322020-02-13 21:18:22 -0800971
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700972 StartLogger(&pi1_logger);
Austin Schuh8bd96322020-02-13 21:18:22 -0800973
974 for (int i = 0; i < 20000; ++i) {
975 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -0700976 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800977 event_loop_factory_.RunFor(chrono::milliseconds(1));
978 }
979
980 EXPECT_GT(pi2_offset - initial_pi2_offset,
981 event_loop_factory_.send_delay() +
982 event_loop_factory_.network_delay());
983
984 for (int i = 0; i < 40000; ++i) {
985 pi2_offset -= chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -0700986 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800987 event_loop_factory_.RunFor(chrono::milliseconds(1));
988 }
989 }
990
991 // And log a bit more on pi2.
992 event_loop_factory_.RunFor(chrono::milliseconds(400));
Austin Schuhcde938c2020-02-02 17:30:07 -0800993 }
994
Austin Schuh2f8fd752020-09-01 22:38:28 -0700995 LogReader reader(structured_logfiles_);
Austin Schuhcde938c2020-02-02 17:30:07 -0800996
997 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
998 log_reader_factory.set_send_delay(chrono::microseconds(0));
999
Austin Schuhcde938c2020-02-02 17:30:07 -08001000 const Node *pi1 =
1001 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1002 const Node *pi2 =
1003 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1004
Austin Schuh2f8fd752020-09-01 22:38:28 -07001005 // This sends out the fetched messages and advances time to the start of the
1006 // log file.
1007 reader.Register(&log_reader_factory);
1008
1009 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
1010 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
1011 LOG(INFO) << "now pi1 "
1012 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
1013 LOG(INFO) << "now pi2 "
1014 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
1015
Austin Schuhcde938c2020-02-02 17:30:07 -08001016 LOG(INFO) << "Done registering (pi1) "
Austin Schuh391e3172020-09-01 22:48:18 -07001017 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now()
1018 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -08001019 << log_reader_factory.GetNodeEventLoopFactory(pi1)->realtime_now();
1020 LOG(INFO) << "Done registering (pi2) "
Austin Schuh391e3172020-09-01 22:48:18 -07001021 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now()
1022 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -08001023 << log_reader_factory.GetNodeEventLoopFactory(pi2)->realtime_now();
1024
1025 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1026
1027 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1028
1029 std::unique_ptr<EventLoop> pi1_event_loop =
1030 log_reader_factory.MakeEventLoop("test", pi1);
1031 std::unique_ptr<EventLoop> pi2_event_loop =
1032 log_reader_factory.MakeEventLoop("test", pi2);
1033
1034 int pi1_ping_count = 30;
1035 int pi2_ping_count = 30;
1036 int pi1_pong_count = 30;
1037 int pi2_pong_count = 30;
1038
1039 // Confirm that the ping value matches.
1040 pi1_event_loop->MakeWatcher(
1041 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
1042 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
1043 << pi1_event_loop->context().monotonic_remote_time << " -> "
1044 << pi1_event_loop->context().monotonic_event_time;
1045 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
1046
1047 ++pi1_ping_count;
1048 });
1049 pi2_event_loop->MakeWatcher(
1050 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
1051 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
1052 << pi2_event_loop->context().monotonic_remote_time << " -> "
1053 << pi2_event_loop->context().monotonic_event_time;
1054 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
1055
1056 ++pi2_ping_count;
1057 });
1058
1059 // Confirm that the ping and pong counts both match, and the value also
1060 // matches.
1061 pi1_event_loop->MakeWatcher(
1062 "/test", [&pi1_event_loop, &pi1_ping_count,
1063 &pi1_pong_count](const examples::Pong &pong) {
1064 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
1065 << pi1_event_loop->context().monotonic_remote_time << " -> "
1066 << pi1_event_loop->context().monotonic_event_time;
1067
1068 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
1069 ++pi1_pong_count;
1070 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
1071 });
1072 pi2_event_loop->MakeWatcher(
1073 "/test", [&pi2_event_loop, &pi2_ping_count,
1074 &pi2_pong_count](const examples::Pong &pong) {
1075 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
1076 << pi2_event_loop->context().monotonic_remote_time << " -> "
1077 << pi2_event_loop->context().monotonic_event_time;
1078
1079 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1080 ++pi2_pong_count;
1081 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1082 });
1083
1084 log_reader_factory.Run();
Austin Schuh8bd96322020-02-13 21:18:22 -08001085 EXPECT_EQ(pi1_ping_count, 6030);
1086 EXPECT_EQ(pi2_ping_count, 6030);
1087 EXPECT_EQ(pi1_pong_count, 6030);
1088 EXPECT_EQ(pi2_pong_count, 6030);
Austin Schuhcde938c2020-02-02 17:30:07 -08001089
1090 reader.Deregister();
1091}
1092
Austin Schuh5212cad2020-09-09 23:12:09 -07001093// Tests that we can sort a bunch of parts into the pre-determined sorted parts.
1094TEST_F(MultinodeLoggerTest, SortParts) {
1095 // Make a bunch of parts.
1096 {
1097 LoggerState pi1_logger = MakeLogger(pi1_);
1098 LoggerState pi2_logger = MakeLogger(pi2_);
1099
1100 event_loop_factory_.RunFor(chrono::milliseconds(95));
1101
1102 StartLogger(&pi1_logger);
1103 StartLogger(&pi2_logger);
1104
1105 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1106 }
1107
Austin Schuh11d43732020-09-21 17:28:30 -07001108 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1109
1110 EXPECT_EQ(sorted_parts.size(), 2u);
1111
1112 // Count up the number of UUIDs and make sure they are what we expect as a
1113 // sanity check.
1114 std::set<std::string> logger_uuids;
1115 std::set<std::string> parts_uuids;
1116 std::set<std::string> both_uuids;
1117
1118 size_t missing_rt_count = 0;
1119
1120 for (const LogFile &log_file : sorted_parts) {
1121 EXPECT_FALSE(log_file.logger_uuid.empty());
1122 logger_uuids.insert(log_file.logger_uuid);
1123 both_uuids.insert(log_file.logger_uuid);
1124
1125 for (const LogParts &part : log_file.parts) {
1126 EXPECT_NE(part.monotonic_start_time, aos::monotonic_clock::min_time)
1127 << ": " << part;
Brian Silvermand90905f2020-09-23 14:42:56 -07001128 missing_rt_count +=
1129 part.realtime_start_time == aos::realtime_clock::min_time;
Austin Schuh11d43732020-09-21 17:28:30 -07001130
1131 EXPECT_TRUE(logger_uuids.find(part.logger_uuid) != logger_uuids.end());
1132 EXPECT_NE(part.node, "");
1133 parts_uuids.insert(part.parts_uuid);
1134 both_uuids.insert(part.parts_uuid);
1135 }
1136 }
1137
1138 // We won't have RT timestamps for 5 log files. We don't log the RT start
1139 // time on remote nodes because we don't know it and would be guessing. And
1140 // the log reader can actually do a better job.
1141 EXPECT_EQ(missing_rt_count, 5u);
1142
1143 EXPECT_EQ(logger_uuids.size(), 2u);
1144 EXPECT_EQ(parts_uuids.size(), ToLogReaderVector(sorted_parts).size());
1145 EXPECT_EQ(logger_uuids.size() + parts_uuids.size(), both_uuids.size());
Austin Schuh5212cad2020-09-09 23:12:09 -07001146
1147 // Test that each list of parts is in order. Don't worry about the ordering
1148 // between part file lists though.
1149 // (inner vectors all need to be in order, but outer one doesn't matter).
Austin Schuh11d43732020-09-21 17:28:30 -07001150 EXPECT_THAT(ToLogReaderVector(sorted_parts),
Austin Schuh5212cad2020-09-09 23:12:09 -07001151 ::testing::UnorderedElementsAreArray(structured_logfiles_));
1152}
1153
Austin Schuh01b4c352020-09-21 23:09:39 -07001154// Tests that if we remap a remapped channel, it shows up correctly.
1155TEST_F(MultinodeLoggerTest, RemapLoggedChannel) {
1156 {
1157 LoggerState pi1_logger = MakeLogger(pi1_);
1158 LoggerState pi2_logger = MakeLogger(pi2_);
1159
1160 event_loop_factory_.RunFor(chrono::milliseconds(95));
1161
1162 StartLogger(&pi1_logger);
1163 StartLogger(&pi2_logger);
1164
1165 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1166 }
1167
1168 LogReader reader(structured_logfiles_);
1169
1170 // Remap just on pi1.
1171 reader.RemapLoggedChannel<aos::timing::Report>(
1172 "/aos", configuration::GetNode(reader.configuration(), "pi1"));
1173
1174 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1175 log_reader_factory.set_send_delay(chrono::microseconds(0));
1176
1177 reader.Register(&log_reader_factory);
1178
1179 const Node *pi1 =
1180 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1181 const Node *pi2 =
1182 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1183
1184 // Confirm we can read the data on the remapped channel, just for pi1. Nothing
1185 // else should have moved.
1186 std::unique_ptr<EventLoop> pi1_event_loop =
1187 log_reader_factory.MakeEventLoop("test", pi1);
1188 pi1_event_loop->SkipTimingReport();
1189 std::unique_ptr<EventLoop> full_pi1_event_loop =
1190 log_reader_factory.MakeEventLoop("test", pi1);
1191 full_pi1_event_loop->SkipTimingReport();
1192 std::unique_ptr<EventLoop> pi2_event_loop =
1193 log_reader_factory.MakeEventLoop("test", pi2);
1194 pi2_event_loop->SkipTimingReport();
1195
1196 MessageCounter<aos::timing::Report> pi1_timing_report(pi1_event_loop.get(),
1197 "/aos");
1198 MessageCounter<aos::timing::Report> full_pi1_timing_report(
1199 full_pi1_event_loop.get(), "/pi1/aos");
1200 MessageCounter<aos::timing::Report> pi1_original_timing_report(
1201 pi1_event_loop.get(), "/original/aos");
1202 MessageCounter<aos::timing::Report> full_pi1_original_timing_report(
1203 full_pi1_event_loop.get(), "/original/pi1/aos");
1204 MessageCounter<aos::timing::Report> pi2_timing_report(pi2_event_loop.get(),
1205 "/aos");
1206
1207 log_reader_factory.Run();
1208
1209 EXPECT_EQ(pi1_timing_report.count(), 0u);
1210 EXPECT_EQ(full_pi1_timing_report.count(), 0u);
1211 EXPECT_NE(pi1_original_timing_report.count(), 0u);
1212 EXPECT_NE(full_pi1_original_timing_report.count(), 0u);
1213 EXPECT_NE(pi2_timing_report.count(), 0u);
1214
1215 reader.Deregister();
1216}
1217
Austin Schuh8bd96322020-02-13 21:18:22 -08001218// TODO(austin): We can write a test which recreates a logfile and confirms that
1219// we get it back. That is the ultimate test.
1220
Austin Schuhe309d2a2019-11-29 13:25:21 -08001221} // namespace testing
1222} // namespace logger
1223} // namespace aos