blob: dbc8a784f83cb558c231c47e34ed1e9e07e43b67 [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 Schuh8d7e0bb2020-10-02 17:57:00 -07008#include "aos/network/timestamp_generated.h"
Austin Schuhc243b422020-10-11 15:35:08 -07009#include "aos/testing/tmpdir.h"
Austin Schuh2f8fd752020-09-01 22:38:28 -070010#include "aos/util/file.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -080011#include "glog/logging.h"
Austin Schuh6f3babe2020-01-26 20:34:50 -080012#include "gmock/gmock.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -080013#include "gtest/gtest.h"
14
Austin Schuh3bd4c402020-11-06 18:19:06 -080015#ifdef LZMA
16#include "aos/events/logging/lzma_encoder.h"
17#endif
18
Austin Schuhe309d2a2019-11-29 13:25:21 -080019namespace aos {
20namespace logger {
21namespace testing {
22
23namespace chrono = std::chrono;
Austin Schuh01b4c352020-09-21 23:09:39 -070024using aos::testing::MessageCounter;
Austin Schuhe309d2a2019-11-29 13:25:21 -080025
26class LoggerTest : public ::testing::Test {
27 public:
28 LoggerTest()
29 : config_(
30 aos::configuration::ReadConfig("aos/events/pingpong_config.json")),
31 event_loop_factory_(&config_.message()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080032 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080033 ping_(ping_event_loop_.get()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080034 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080035 pong_(pong_event_loop_.get()) {}
36
37 // Config and factory.
38 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
39 SimulatedEventLoopFactory event_loop_factory_;
40
41 // Event loop and app for Ping
42 std::unique_ptr<EventLoop> ping_event_loop_;
43 Ping ping_;
44
45 // Event loop and app for Pong
46 std::unique_ptr<EventLoop> pong_event_loop_;
47 Pong pong_;
48};
49
Brian Silverman1f345222020-09-24 21:14:48 -070050using LoggerDeathTest = LoggerTest;
51
Austin Schuhe309d2a2019-11-29 13:25:21 -080052// Tests that we can startup at all. This confirms that the channels are all in
53// the config.
54TEST_F(LoggerTest, Starts) {
Austin Schuhc243b422020-10-11 15:35:08 -070055 const ::std::string tmpdir = aos::testing::TestTmpDir();
Austin Schuh2f8fd752020-09-01 22:38:28 -070056 const ::std::string base_name = tmpdir + "/logfile";
57 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuhe309d2a2019-11-29 13:25:21 -080058 // Remove it.
59 unlink(logfile.c_str());
60
61 LOG(INFO) << "Logging data to " << logfile;
62
63 {
Austin Schuhe309d2a2019-11-29 13:25:21 -080064 std::unique_ptr<EventLoop> logger_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080065 event_loop_factory_.MakeEventLoop("logger");
Austin Schuhe309d2a2019-11-29 13:25:21 -080066
67 event_loop_factory_.RunFor(chrono::milliseconds(95));
68
Brian Silverman1f345222020-09-24 21:14:48 -070069 Logger logger(logger_event_loop.get());
70 logger.set_polling_period(std::chrono::milliseconds(100));
71 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuhe309d2a2019-11-29 13:25:21 -080072 event_loop_factory_.RunFor(chrono::milliseconds(20000));
73 }
74
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080075 // Even though it doesn't make any difference here, exercise the logic for
76 // passing in a separate config.
77 LogReader reader(logfile, &config_.message());
Austin Schuhe309d2a2019-11-29 13:25:21 -080078
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080079 // Confirm that we can remap logged channels to point to new buses.
80 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
Austin Schuhe309d2a2019-11-29 13:25:21 -080081
Austin Schuh15649d62019-12-28 16:36:38 -080082 // This sends out the fetched messages and advances time to the start of the
83 // log file.
James Kuszmaul84ff3e52020-01-03 19:48:53 -080084 reader.Register();
Austin Schuhe309d2a2019-11-29 13:25:21 -080085
Austin Schuh6f3babe2020-01-26 20:34:50 -080086 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
James Kuszmaul84ff3e52020-01-03 19:48:53 -080087
Austin Schuhe309d2a2019-11-29 13:25:21 -080088 std::unique_ptr<EventLoop> test_event_loop =
James Kuszmaul84ff3e52020-01-03 19:48:53 -080089 reader.event_loop_factory()->MakeEventLoop("log_reader");
Austin Schuhe309d2a2019-11-29 13:25:21 -080090
91 int ping_count = 10;
92 int pong_count = 10;
93
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080094 // Confirm that the ping value matches in the remapped channel location.
95 test_event_loop->MakeWatcher("/original/test",
Austin Schuhe309d2a2019-11-29 13:25:21 -080096 [&ping_count](const examples::Ping &ping) {
97 EXPECT_EQ(ping.value(), ping_count + 1);
98 ++ping_count;
99 });
100 // Confirm that the ping and pong counts both match, and the value also
101 // matches.
102 test_event_loop->MakeWatcher(
103 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
104 EXPECT_EQ(pong.value(), pong_count + 1);
105 ++pong_count;
106 EXPECT_EQ(ping_count, pong_count);
107 });
108
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800109 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
Austin Schuhe309d2a2019-11-29 13:25:21 -0800110 EXPECT_EQ(ping_count, 2010);
Austin Schuhe309d2a2019-11-29 13:25:21 -0800111}
112
Brian Silverman1f345222020-09-24 21:14:48 -0700113// Tests calling StartLogging twice.
114TEST_F(LoggerDeathTest, ExtraStart) {
115 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
116 const ::std::string base_name1 = tmpdir + "/logfile1";
117 const ::std::string logfile1 = base_name1 + ".part0.bfbs";
118 const ::std::string base_name2 = tmpdir + "/logfile2";
119 const ::std::string logfile2 = base_name2 + ".part0.bfbs";
120 unlink(logfile1.c_str());
121 unlink(logfile2.c_str());
122
123 LOG(INFO) << "Logging data to " << logfile1 << " then " << logfile2;
124
125 {
126 std::unique_ptr<EventLoop> logger_event_loop =
127 event_loop_factory_.MakeEventLoop("logger");
128
129 event_loop_factory_.RunFor(chrono::milliseconds(95));
130
131 Logger logger(logger_event_loop.get());
132 logger.set_polling_period(std::chrono::milliseconds(100));
133 logger_event_loop->OnRun(
134 [base_name1, base_name2, &logger_event_loop, &logger]() {
135 logger.StartLogging(std::make_unique<LocalLogNamer>(
136 base_name1, logger_event_loop->node()));
137 EXPECT_DEATH(logger.StartLogging(std::make_unique<LocalLogNamer>(
138 base_name2, logger_event_loop->node())),
139 "Already logging");
140 });
141 event_loop_factory_.RunFor(chrono::milliseconds(20000));
142 }
143}
144
145// Tests calling StopLogging twice.
146TEST_F(LoggerDeathTest, ExtraStop) {
147 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
148 const ::std::string base_name = tmpdir + "/logfile";
149 const ::std::string logfile = base_name + ".part0.bfbs";
150 // Remove it.
151 unlink(logfile.c_str());
152
153 LOG(INFO) << "Logging data to " << logfile;
154
155 {
156 std::unique_ptr<EventLoop> logger_event_loop =
157 event_loop_factory_.MakeEventLoop("logger");
158
159 event_loop_factory_.RunFor(chrono::milliseconds(95));
160
161 Logger logger(logger_event_loop.get());
162 logger.set_polling_period(std::chrono::milliseconds(100));
163 logger_event_loop->OnRun([base_name, &logger_event_loop, &logger]() {
164 logger.StartLogging(std::make_unique<LocalLogNamer>(
165 base_name, logger_event_loop->node()));
166 logger.StopLogging(aos::monotonic_clock::min_time);
167 EXPECT_DEATH(logger.StopLogging(aos::monotonic_clock::min_time),
168 "Not logging right now");
169 });
170 event_loop_factory_.RunFor(chrono::milliseconds(20000));
171 }
172}
173
174// Tests that we can startup twice.
175TEST_F(LoggerTest, StartsTwice) {
176 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
177 const ::std::string base_name1 = tmpdir + "/logfile1";
178 const ::std::string logfile1 = base_name1 + ".part0.bfbs";
179 const ::std::string base_name2 = tmpdir + "/logfile2";
180 const ::std::string logfile2 = base_name2 + ".part0.bfbs";
181 unlink(logfile1.c_str());
182 unlink(logfile2.c_str());
183
184 LOG(INFO) << "Logging data to " << logfile1 << " then " << logfile2;
185
186 {
187 std::unique_ptr<EventLoop> logger_event_loop =
188 event_loop_factory_.MakeEventLoop("logger");
189
190 event_loop_factory_.RunFor(chrono::milliseconds(95));
191
192 Logger logger(logger_event_loop.get());
193 logger.set_polling_period(std::chrono::milliseconds(100));
194 logger.StartLogging(
195 std::make_unique<LocalLogNamer>(base_name1, logger_event_loop->node()));
196 event_loop_factory_.RunFor(chrono::milliseconds(10000));
197 logger.StopLogging(logger_event_loop->monotonic_now());
198 event_loop_factory_.RunFor(chrono::milliseconds(10000));
199 logger.StartLogging(
200 std::make_unique<LocalLogNamer>(base_name2, logger_event_loop->node()));
201 event_loop_factory_.RunFor(chrono::milliseconds(10000));
202 }
203
204 for (const auto &logfile :
205 {std::make_tuple(logfile1, 10), std::make_tuple(logfile2, 2010)}) {
206 SCOPED_TRACE(std::get<0>(logfile));
207 LogReader reader(std::get<0>(logfile));
208 reader.Register();
209
210 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
211
212 std::unique_ptr<EventLoop> test_event_loop =
213 reader.event_loop_factory()->MakeEventLoop("log_reader");
214
215 int ping_count = std::get<1>(logfile);
216 int pong_count = std::get<1>(logfile);
217
218 // Confirm that the ping and pong counts both match, and the value also
219 // matches.
220 test_event_loop->MakeWatcher("/test",
221 [&ping_count](const examples::Ping &ping) {
222 EXPECT_EQ(ping.value(), ping_count + 1);
223 ++ping_count;
224 });
225 test_event_loop->MakeWatcher(
226 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
227 EXPECT_EQ(pong.value(), pong_count + 1);
228 ++pong_count;
229 EXPECT_EQ(ping_count, pong_count);
230 });
231
232 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
233 EXPECT_EQ(ping_count, std::get<1>(logfile) + 1000);
234 }
235}
236
Austin Schuhfa895892020-01-07 20:07:41 -0800237// Tests that we can read and write rotated log files.
238TEST_F(LoggerTest, RotatedLogFile) {
239 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
Austin Schuh2f8fd752020-09-01 22:38:28 -0700240 const ::std::string base_name = tmpdir + "/logfile";
241 const ::std::string logfile0 = base_name + ".part0.bfbs";
242 const ::std::string logfile1 = base_name + ".part1.bfbs";
Austin Schuhfa895892020-01-07 20:07:41 -0800243 // Remove it.
244 unlink(logfile0.c_str());
245 unlink(logfile1.c_str());
246
247 LOG(INFO) << "Logging data to " << logfile0 << " and " << logfile1;
248
249 {
Austin Schuhfa895892020-01-07 20:07:41 -0800250 std::unique_ptr<EventLoop> logger_event_loop =
251 event_loop_factory_.MakeEventLoop("logger");
252
253 event_loop_factory_.RunFor(chrono::milliseconds(95));
254
Brian Silverman1f345222020-09-24 21:14:48 -0700255 Logger logger(logger_event_loop.get());
256 logger.set_polling_period(std::chrono::milliseconds(100));
257 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuhfa895892020-01-07 20:07:41 -0800258 event_loop_factory_.RunFor(chrono::milliseconds(10000));
Austin Schuh2f8fd752020-09-01 22:38:28 -0700259 logger.Rotate();
Austin Schuhfa895892020-01-07 20:07:41 -0800260 event_loop_factory_.RunFor(chrono::milliseconds(10000));
261 }
262
Austin Schuh64fab802020-09-09 22:47:47 -0700263 {
264 // Confirm that the UUIDs match for both the parts and the logger, and the
265 // parts_index increments.
Austin Schuhadd6eb32020-11-09 21:24:26 -0800266 std::vector<SizePrefixedFlatbufferVector<LogFileHeader>> log_header;
Austin Schuh64fab802020-09-09 22:47:47 -0700267 for (std::string_view f : {logfile0, logfile1}) {
Austin Schuh3bd4c402020-11-06 18:19:06 -0800268 log_header.emplace_back(ReadHeader(f).value());
Austin Schuh64fab802020-09-09 22:47:47 -0700269 }
270
Brian Silvermanae7c0332020-09-30 16:58:23 -0700271 EXPECT_EQ(log_header[0].message().log_event_uuid()->string_view(),
272 log_header[1].message().log_event_uuid()->string_view());
Austin Schuh64fab802020-09-09 22:47:47 -0700273 EXPECT_EQ(log_header[0].message().parts_uuid()->string_view(),
274 log_header[1].message().parts_uuid()->string_view());
275
276 EXPECT_EQ(log_header[0].message().parts_index(), 0);
277 EXPECT_EQ(log_header[1].message().parts_index(), 1);
278 }
279
Austin Schuhfa895892020-01-07 20:07:41 -0800280 // Even though it doesn't make any difference here, exercise the logic for
281 // passing in a separate config.
282 LogReader reader(std::vector<std::string>{logfile0, logfile1},
283 &config_.message());
284
285 // Confirm that we can remap logged channels to point to new buses.
286 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
287
288 // This sends out the fetched messages and advances time to the start of the
289 // log file.
290 reader.Register();
291
Austin Schuh6f3babe2020-01-26 20:34:50 -0800292 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
Austin Schuhfa895892020-01-07 20:07:41 -0800293
294 std::unique_ptr<EventLoop> test_event_loop =
295 reader.event_loop_factory()->MakeEventLoop("log_reader");
296
297 int ping_count = 10;
298 int pong_count = 10;
299
300 // Confirm that the ping value matches in the remapped channel location.
301 test_event_loop->MakeWatcher("/original/test",
302 [&ping_count](const examples::Ping &ping) {
303 EXPECT_EQ(ping.value(), ping_count + 1);
304 ++ping_count;
305 });
306 // Confirm that the ping and pong counts both match, and the value also
307 // matches.
308 test_event_loop->MakeWatcher(
309 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
310 EXPECT_EQ(pong.value(), pong_count + 1);
311 ++pong_count;
312 EXPECT_EQ(ping_count, pong_count);
313 });
314
315 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
316 EXPECT_EQ(ping_count, 2010);
317}
318
Austin Schuh4c4e0092019-12-22 16:18:03 -0800319// Tests that a large number of messages per second doesn't overwhelm writev.
320TEST_F(LoggerTest, ManyMessages) {
321 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
Austin Schuh2f8fd752020-09-01 22:38:28 -0700322 const ::std::string base_name = tmpdir + "/logfile";
323 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuh4c4e0092019-12-22 16:18:03 -0800324 // Remove the log file.
325 unlink(logfile.c_str());
326
327 LOG(INFO) << "Logging data to " << logfile;
Austin Schuh4c3b9702020-08-30 11:34:55 -0700328 ping_.set_quiet(true);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800329
330 {
Austin Schuh4c4e0092019-12-22 16:18:03 -0800331 std::unique_ptr<EventLoop> logger_event_loop =
332 event_loop_factory_.MakeEventLoop("logger");
333
334 std::unique_ptr<EventLoop> ping_spammer_event_loop =
335 event_loop_factory_.MakeEventLoop("ping_spammer");
336 aos::Sender<examples::Ping> ping_sender =
337 ping_spammer_event_loop->MakeSender<examples::Ping>("/test");
338
339 aos::TimerHandler *timer_handler =
340 ping_spammer_event_loop->AddTimer([&ping_sender]() {
341 aos::Sender<examples::Ping>::Builder builder =
342 ping_sender.MakeBuilder();
343 examples::Ping::Builder ping_builder =
344 builder.MakeBuilder<examples::Ping>();
345 CHECK(builder.Send(ping_builder.Finish()));
346 });
347
348 // 100 ms / 0.05 ms -> 2000 messages. Should be enough to crash it.
349 ping_spammer_event_loop->OnRun([&ping_spammer_event_loop, timer_handler]() {
350 timer_handler->Setup(ping_spammer_event_loop->monotonic_now(),
351 chrono::microseconds(50));
352 });
353
Brian Silverman1f345222020-09-24 21:14:48 -0700354 Logger logger(logger_event_loop.get());
355 logger.set_polling_period(std::chrono::milliseconds(100));
356 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800357
358 event_loop_factory_.RunFor(chrono::milliseconds(1000));
359 }
360}
361
Austin Schuh15649d62019-12-28 16:36:38 -0800362class MultinodeLoggerTest : public ::testing::Test {
363 public:
364 MultinodeLoggerTest()
365 : config_(aos::configuration::ReadConfig(
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800366 "aos/events/logging/multinode_pingpong_config.json")),
Austin Schuhac0771c2020-01-07 18:36:30 -0800367 event_loop_factory_(&config_.message()),
Austin Schuhcde938c2020-02-02 17:30:07 -0800368 pi1_(
369 configuration::GetNode(event_loop_factory_.configuration(), "pi1")),
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700370 pi2_(
371 configuration::GetNode(event_loop_factory_.configuration(), "pi2")),
372 tmp_dir_(getenv("TEST_TMPDIR")),
373 logfile_base_(tmp_dir_ + "/multi_logfile"),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700374 logfiles_(
375 {logfile_base_ + "_pi1_data.part0.bfbs",
376 logfile_base_ + "_pi2_data/test/aos.examples.Pong.part0.bfbs",
377 logfile_base_ + "_pi2_data/test/aos.examples.Pong.part1.bfbs",
378 logfile_base_ + "_pi2_data.part0.bfbs",
379 logfile_base_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
380 "aos.logger.MessageHeader.part0.bfbs",
381 logfile_base_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
382 "aos.logger.MessageHeader.part1.bfbs",
383 logfile_base_ + "_timestamps/pi2/aos/remote_timestamps/pi1/"
384 "aos.logger.MessageHeader.part0.bfbs",
385 logfile_base_ + "_timestamps/pi2/aos/remote_timestamps/pi1/"
386 "aos.logger.MessageHeader.part1.bfbs",
387 logfile_base_ +
388 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part0.bfbs",
389 logfile_base_ +
390 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part1.bfbs",
391 logfile_base_ +
392 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part0.bfbs",
393 logfile_base_ +
394 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part1.bfbs"}),
395 structured_logfiles_{
396 std::vector<std::string>{logfiles_[0]},
397 std::vector<std::string>{logfiles_[1], logfiles_[2]},
398 std::vector<std::string>{logfiles_[3]},
399 std::vector<std::string>{logfiles_[4], logfiles_[5]},
400 std::vector<std::string>{logfiles_[6], logfiles_[7]},
401 std::vector<std::string>{logfiles_[8], logfiles_[9]},
402 std::vector<std::string>{logfiles_[10], logfiles_[11]}},
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700403 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping", pi1_)),
404 ping_(ping_event_loop_.get()),
405 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong", pi2_)),
406 pong_(pong_event_loop_.get()) {
407 // Go through and remove the logfiles if they already exist.
408 for (const auto file : logfiles_) {
409 unlink(file.c_str());
410 }
411
412 LOG(INFO) << "Logging data to " << logfiles_[0] << ", " << logfiles_[1]
413 << " and " << logfiles_[2];
414 }
415
416 struct LoggerState {
417 std::unique_ptr<EventLoop> event_loop;
418 std::unique_ptr<Logger> logger;
419 };
420
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700421 LoggerState MakeLogger(const Node *node,
422 SimulatedEventLoopFactory *factory = nullptr) {
423 if (factory == nullptr) {
424 factory = &event_loop_factory_;
425 }
426 return {factory->MakeEventLoop("logger", node), {}};
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700427 }
428
Austin Schuh3bd4c402020-11-06 18:19:06 -0800429 void StartLogger(LoggerState *logger, std::string logfile_base = "",
430 bool compress = false) {
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700431 if (logfile_base.empty()) {
432 logfile_base = logfile_base_;
433 }
434
Brian Silverman1f345222020-09-24 21:14:48 -0700435 logger->logger = std::make_unique<Logger>(logger->event_loop.get());
436 logger->logger->set_polling_period(std::chrono::milliseconds(100));
Austin Schuh3bd4c402020-11-06 18:19:06 -0800437 logger->event_loop->OnRun([logger, logfile_base, compress]() {
438 std::unique_ptr<MultiNodeLogNamer> namer =
439 std::make_unique<MultiNodeLogNamer>(
440 logfile_base, logger->event_loop->configuration(),
441 logger->event_loop->node());
442 if (compress) {
443#ifdef LZMA
444 namer->set_extension(".xz");
445 namer->set_encoder_factory(
446 []() { return std::make_unique<aos::logger::LzmaEncoder>(3); });
447#else
448 LOG(FATAL) << "Compression unsupported";
449#endif
450 }
451
452 logger->logger->StartLogging(std::move(namer));
Brian Silverman1f345222020-09-24 21:14:48 -0700453 });
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700454 }
Austin Schuh15649d62019-12-28 16:36:38 -0800455
Austin Schuh3bd4c402020-11-06 18:19:06 -0800456 void VerifyParts(const std::vector<LogFile> &sorted_parts,
457 const std::vector<std::string> &corrupted_parts = {}) {
458 EXPECT_EQ(sorted_parts.size(), 2u);
459
460 // Count up the number of UUIDs and make sure they are what we expect as a
461 // sanity check.
462 std::set<std::string> log_event_uuids;
463 std::set<std::string> parts_uuids;
464 std::set<std::string> both_uuids;
465
466 size_t missing_rt_count = 0;
467
468 std::vector<std::string> logger_nodes;
469 for (const LogFile &log_file : sorted_parts) {
470 EXPECT_FALSE(log_file.log_event_uuid.empty());
471 log_event_uuids.insert(log_file.log_event_uuid);
472 logger_nodes.emplace_back(log_file.logger_node);
473 both_uuids.insert(log_file.log_event_uuid);
474
475 for (const LogParts &part : log_file.parts) {
476 EXPECT_NE(part.monotonic_start_time, aos::monotonic_clock::min_time)
477 << ": " << part;
478 missing_rt_count +=
479 part.realtime_start_time == aos::realtime_clock::min_time;
480
481 EXPECT_TRUE(log_event_uuids.find(part.log_event_uuid) !=
482 log_event_uuids.end());
483 EXPECT_NE(part.node, "");
484 parts_uuids.insert(part.parts_uuid);
485 both_uuids.insert(part.parts_uuid);
486 }
487 }
488
489 // We won't have RT timestamps for 5 log files. We don't log the RT start
490 // time on remote nodes because we don't know it and would be guessing. And
491 // the log reader can actually do a better job.
492 EXPECT_EQ(missing_rt_count, 5u);
493
494 EXPECT_EQ(log_event_uuids.size(), 2u);
495 EXPECT_EQ(parts_uuids.size(), ToLogReaderVector(sorted_parts).size());
496 EXPECT_EQ(log_event_uuids.size() + parts_uuids.size(), both_uuids.size());
497
498 // Test that each list of parts is in order. Don't worry about the ordering
499 // between part file lists though.
500 // (inner vectors all need to be in order, but outer one doesn't matter).
501 EXPECT_THAT(ToLogReaderVector(sorted_parts),
502 ::testing::UnorderedElementsAreArray(structured_logfiles_));
503
504 EXPECT_THAT(logger_nodes, ::testing::UnorderedElementsAre("pi1", "pi2"));
505
506 EXPECT_NE(sorted_parts[0].realtime_start_time,
507 aos::realtime_clock::min_time);
508 EXPECT_NE(sorted_parts[1].realtime_start_time,
509 aos::realtime_clock::min_time);
510
511 EXPECT_NE(sorted_parts[0].monotonic_start_time,
512 aos::monotonic_clock::min_time);
513 EXPECT_NE(sorted_parts[1].monotonic_start_time,
514 aos::monotonic_clock::min_time);
515
516 EXPECT_THAT(sorted_parts[0].corrupted, ::testing::Eq(corrupted_parts));
517 EXPECT_THAT(sorted_parts[1].corrupted, ::testing::Eq(corrupted_parts));
518 }
519
520 void AddExtension(std::string_view extension) {
521 std::transform(logfiles_.begin(), logfiles_.end(), logfiles_.begin(),
522 [extension](const std::string &in) {
523 return absl::StrCat(in, extension);
524 });
525
526 std::transform(structured_logfiles_.begin(), structured_logfiles_.end(),
527 structured_logfiles_.begin(),
528 [extension](std::vector<std::string> in) {
529 std::transform(in.begin(), in.end(), in.begin(),
530 [extension](const std::string &in_str) {
531 return absl::StrCat(in_str, extension);
532 });
533 return in;
534 });
535 }
536
Austin Schuh15649d62019-12-28 16:36:38 -0800537 // Config and factory.
538 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
539 SimulatedEventLoopFactory event_loop_factory_;
540
Austin Schuhcde938c2020-02-02 17:30:07 -0800541 const Node *pi1_;
542 const Node *pi2_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700543
544 std::string tmp_dir_;
545 std::string logfile_base_;
Austin Schuh2f8fd752020-09-01 22:38:28 -0700546 std::vector<std::string> logfiles_;
547
548 std::vector<std::vector<std::string>> structured_logfiles_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700549
550 std::unique_ptr<EventLoop> ping_event_loop_;
551 Ping ping_;
552 std::unique_ptr<EventLoop> pong_event_loop_;
553 Pong pong_;
Austin Schuh15649d62019-12-28 16:36:38 -0800554};
555
Austin Schuh391e3172020-09-01 22:48:18 -0700556// Counts the number of messages on a channel. Returns (channel name, channel
557// type, count) for every message matching matcher()
558std::vector<std::tuple<std::string, std::string, int>> CountChannelsMatching(
Austin Schuh6f3babe2020-01-26 20:34:50 -0800559 std::string_view filename,
560 std::function<bool(const MessageHeader *)> matcher) {
561 MessageReader message_reader(filename);
562 std::vector<int> counts(
563 message_reader.log_file_header()->configuration()->channels()->size(), 0);
Austin Schuh15649d62019-12-28 16:36:38 -0800564
Austin Schuh6f3babe2020-01-26 20:34:50 -0800565 while (true) {
Austin Schuhadd6eb32020-11-09 21:24:26 -0800566 std::optional<SizePrefixedFlatbufferVector<MessageHeader>> msg =
Austin Schuh6f3babe2020-01-26 20:34:50 -0800567 message_reader.ReadMessage();
568 if (!msg) {
569 break;
570 }
571
572 if (matcher(&msg.value().message())) {
573 counts[msg.value().message().channel_index()]++;
574 }
575 }
576
Austin Schuh391e3172020-09-01 22:48:18 -0700577 std::vector<std::tuple<std::string, std::string, int>> result;
Austin Schuh6f3babe2020-01-26 20:34:50 -0800578 int channel = 0;
579 for (size_t i = 0; i < counts.size(); ++i) {
580 if (counts[i] != 0) {
Austin Schuh391e3172020-09-01 22:48:18 -0700581 const Channel *channel =
582 message_reader.log_file_header()->configuration()->channels()->Get(i);
583 result.push_back(std::make_tuple(channel->name()->str(),
584 channel->type()->str(), counts[i]));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800585 }
586 ++channel;
587 }
588
589 return result;
590}
591
592// Counts the number of messages (channel, count) for all data messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700593std::vector<std::tuple<std::string, std::string, int>> CountChannelsData(
594 std::string_view filename) {
Austin Schuh6f3babe2020-01-26 20:34:50 -0800595 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
596 if (msg->has_data()) {
597 CHECK(!msg->has_monotonic_remote_time());
598 CHECK(!msg->has_realtime_remote_time());
599 CHECK(!msg->has_remote_queue_index());
600 return true;
601 }
602 return false;
603 });
604}
605
606// Counts the number of messages (channel, count) for all timestamp messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700607std::vector<std::tuple<std::string, std::string, int>> CountChannelsTimestamp(
Austin Schuh6f3babe2020-01-26 20:34:50 -0800608 std::string_view filename) {
609 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
610 if (!msg->has_data()) {
611 CHECK(msg->has_monotonic_remote_time());
612 CHECK(msg->has_realtime_remote_time());
613 CHECK(msg->has_remote_queue_index());
614 return true;
615 }
616 return false;
617 });
618}
619
Austin Schuhcde938c2020-02-02 17:30:07 -0800620// Tests that we can write and read simple multi-node log files.
621TEST_F(MultinodeLoggerTest, SimpleMultiNode) {
Austin Schuh15649d62019-12-28 16:36:38 -0800622 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700623 LoggerState pi1_logger = MakeLogger(pi1_);
624 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuh15649d62019-12-28 16:36:38 -0800625
626 event_loop_factory_.RunFor(chrono::milliseconds(95));
627
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700628 StartLogger(&pi1_logger);
629 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800630
Austin Schuh15649d62019-12-28 16:36:38 -0800631 event_loop_factory_.RunFor(chrono::milliseconds(20000));
632 }
633
Austin Schuh6f3babe2020-01-26 20:34:50 -0800634 {
Austin Schuh64fab802020-09-09 22:47:47 -0700635 std::set<std::string> logfile_uuids;
636 std::set<std::string> parts_uuids;
637 // Confirm that we have the expected number of UUIDs for both the logfile
638 // UUIDs and parts UUIDs.
Austin Schuhadd6eb32020-11-09 21:24:26 -0800639 std::vector<SizePrefixedFlatbufferVector<LogFileHeader>> log_header;
Austin Schuh64fab802020-09-09 22:47:47 -0700640 for (std::string_view f : logfiles_) {
Austin Schuh3bd4c402020-11-06 18:19:06 -0800641 log_header.emplace_back(ReadHeader(f).value());
Brian Silvermanae7c0332020-09-30 16:58:23 -0700642 logfile_uuids.insert(log_header.back().message().log_event_uuid()->str());
Austin Schuh64fab802020-09-09 22:47:47 -0700643 parts_uuids.insert(log_header.back().message().parts_uuid()->str());
644 }
Austin Schuh15649d62019-12-28 16:36:38 -0800645
Austin Schuh64fab802020-09-09 22:47:47 -0700646 EXPECT_EQ(logfile_uuids.size(), 2u);
647 EXPECT_EQ(parts_uuids.size(), 7u);
648
649 // And confirm everything is on the correct node.
650 EXPECT_EQ(log_header[0].message().node()->name()->string_view(), "pi1");
651 EXPECT_EQ(log_header[1].message().node()->name()->string_view(), "pi2");
652 EXPECT_EQ(log_header[2].message().node()->name()->string_view(), "pi2");
653 EXPECT_EQ(log_header[3].message().node()->name()->string_view(), "pi2");
654 EXPECT_EQ(log_header[4].message().node()->name()->string_view(), "pi2");
655 EXPECT_EQ(log_header[5].message().node()->name()->string_view(), "pi2");
656 EXPECT_EQ(log_header[6].message().node()->name()->string_view(), "pi1");
657 EXPECT_EQ(log_header[7].message().node()->name()->string_view(), "pi1");
658 EXPECT_EQ(log_header[8].message().node()->name()->string_view(), "pi1");
659 EXPECT_EQ(log_header[9].message().node()->name()->string_view(), "pi1");
660 EXPECT_EQ(log_header[10].message().node()->name()->string_view(), "pi2");
661 EXPECT_EQ(log_header[11].message().node()->name()->string_view(), "pi2");
662
663 // And the parts index matches.
664 EXPECT_EQ(log_header[0].message().parts_index(), 0);
665 EXPECT_EQ(log_header[1].message().parts_index(), 0);
666 EXPECT_EQ(log_header[2].message().parts_index(), 1);
667 EXPECT_EQ(log_header[3].message().parts_index(), 0);
668 EXPECT_EQ(log_header[4].message().parts_index(), 0);
669 EXPECT_EQ(log_header[5].message().parts_index(), 1);
670 EXPECT_EQ(log_header[6].message().parts_index(), 0);
671 EXPECT_EQ(log_header[7].message().parts_index(), 1);
672 EXPECT_EQ(log_header[8].message().parts_index(), 0);
673 EXPECT_EQ(log_header[9].message().parts_index(), 1);
674 EXPECT_EQ(log_header[10].message().parts_index(), 0);
675 EXPECT_EQ(log_header[11].message().parts_index(), 1);
676 }
677
678 {
Austin Schuh391e3172020-09-01 22:48:18 -0700679 using ::testing::UnorderedElementsAre;
680
Austin Schuh6f3babe2020-01-26 20:34:50 -0800681 // Timing reports, pings
Austin Schuh2f8fd752020-09-01 22:38:28 -0700682 EXPECT_THAT(
683 CountChannelsData(logfiles_[0]),
684 UnorderedElementsAre(
685 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200),
686 std::make_tuple("/pi1/aos", "aos.timing.Report", 40),
687 std::make_tuple("/test", "aos.examples.Ping", 2001)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800688 // Timestamps for pong
Austin Schuh2f8fd752020-09-01 22:38:28 -0700689 EXPECT_THAT(
690 CountChannelsTimestamp(logfiles_[0]),
691 UnorderedElementsAre(
692 std::make_tuple("/test", "aos.examples.Pong", 2001),
693 std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800694
695 // Pong data.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700696 EXPECT_THAT(CountChannelsData(logfiles_[1]),
Austin Schuh391e3172020-09-01 22:48:18 -0700697 UnorderedElementsAre(
Austin Schuh2f8fd752020-09-01 22:38:28 -0700698 std::make_tuple("/test", "aos.examples.Pong", 101)));
699 EXPECT_THAT(CountChannelsData(logfiles_[2]),
700 UnorderedElementsAre(
701 std::make_tuple("/test", "aos.examples.Pong", 1900)));
Austin Schuh391e3172020-09-01 22:48:18 -0700702
Austin Schuh6f3babe2020-01-26 20:34:50 -0800703 // No timestamps
Austin Schuh391e3172020-09-01 22:48:18 -0700704 EXPECT_THAT(CountChannelsTimestamp(logfiles_[1]), UnorderedElementsAre());
Austin Schuh2f8fd752020-09-01 22:38:28 -0700705 EXPECT_THAT(CountChannelsTimestamp(logfiles_[2]), UnorderedElementsAre());
Austin Schuh6f3babe2020-01-26 20:34:50 -0800706
707 // Timing reports and pongs.
Austin Schuh2f8fd752020-09-01 22:38:28 -0700708 EXPECT_THAT(
709 CountChannelsData(logfiles_[3]),
710 UnorderedElementsAre(
711 std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200),
712 std::make_tuple("/pi2/aos", "aos.timing.Report", 40),
713 std::make_tuple("/test", "aos.examples.Pong", 2001)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800714 // And ping timestamps.
Austin Schuh2f8fd752020-09-01 22:38:28 -0700715 EXPECT_THAT(
716 CountChannelsTimestamp(logfiles_[3]),
717 UnorderedElementsAre(
718 std::make_tuple("/test", "aos.examples.Ping", 2001),
719 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200)));
720
721 // Timestamps from pi2 on pi1, and the other way.
722 EXPECT_THAT(CountChannelsData(logfiles_[4]), UnorderedElementsAre());
723 EXPECT_THAT(CountChannelsData(logfiles_[5]), UnorderedElementsAre());
724 EXPECT_THAT(CountChannelsData(logfiles_[6]), UnorderedElementsAre());
725 EXPECT_THAT(CountChannelsData(logfiles_[7]), UnorderedElementsAre());
726 EXPECT_THAT(
727 CountChannelsTimestamp(logfiles_[4]),
728 UnorderedElementsAre(
729 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 10),
730 std::make_tuple("/test", "aos.examples.Ping", 101)));
731 EXPECT_THAT(
732 CountChannelsTimestamp(logfiles_[5]),
733 UnorderedElementsAre(
734 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 190),
735 std::make_tuple("/test", "aos.examples.Ping", 1900)));
736 EXPECT_THAT(CountChannelsTimestamp(logfiles_[6]),
737 UnorderedElementsAre(std::make_tuple(
738 "/pi2/aos", "aos.message_bridge.Timestamp", 10)));
739 EXPECT_THAT(CountChannelsTimestamp(logfiles_[7]),
740 UnorderedElementsAre(std::make_tuple(
741 "/pi2/aos", "aos.message_bridge.Timestamp", 190)));
742
743 // And then test that the remotely logged timestamp data files only have
744 // timestamps in them.
745 EXPECT_THAT(CountChannelsTimestamp(logfiles_[8]), UnorderedElementsAre());
746 EXPECT_THAT(CountChannelsTimestamp(logfiles_[9]), UnorderedElementsAre());
747 EXPECT_THAT(CountChannelsTimestamp(logfiles_[10]), UnorderedElementsAre());
748 EXPECT_THAT(CountChannelsTimestamp(logfiles_[11]), UnorderedElementsAre());
749
750 EXPECT_THAT(CountChannelsData(logfiles_[8]),
751 UnorderedElementsAre(std::make_tuple(
752 "/pi1/aos", "aos.message_bridge.Timestamp", 10)));
753 EXPECT_THAT(CountChannelsData(logfiles_[9]),
754 UnorderedElementsAre(std::make_tuple(
755 "/pi1/aos", "aos.message_bridge.Timestamp", 190)));
756
757 EXPECT_THAT(CountChannelsData(logfiles_[10]),
758 UnorderedElementsAre(std::make_tuple(
759 "/pi2/aos", "aos.message_bridge.Timestamp", 10)));
760 EXPECT_THAT(CountChannelsData(logfiles_[11]),
761 UnorderedElementsAre(std::make_tuple(
762 "/pi2/aos", "aos.message_bridge.Timestamp", 190)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800763 }
764
Austin Schuh2f8fd752020-09-01 22:38:28 -0700765 LogReader reader(structured_logfiles_);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800766
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700767 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuh6331ef92020-01-07 18:28:09 -0800768 log_reader_factory.set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800769
770 // This sends out the fetched messages and advances time to the start of the
771 // log file.
Austin Schuh6331ef92020-01-07 18:28:09 -0800772 reader.Register(&log_reader_factory);
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800773
Austin Schuhac0771c2020-01-07 18:36:30 -0800774 const Node *pi1 =
775 configuration::GetNode(log_reader_factory.configuration(), "pi1");
Austin Schuh6f3babe2020-01-26 20:34:50 -0800776 const Node *pi2 =
777 configuration::GetNode(log_reader_factory.configuration(), "pi2");
Austin Schuhac0771c2020-01-07 18:36:30 -0800778
Austin Schuh2f8fd752020-09-01 22:38:28 -0700779 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
780 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
781 LOG(INFO) << "now pi1 "
782 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
783 LOG(INFO) << "now pi2 "
784 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
785
Austin Schuh6f3babe2020-01-26 20:34:50 -0800786 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800787
788 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800789
Austin Schuh6f3babe2020-01-26 20:34:50 -0800790 std::unique_ptr<EventLoop> pi1_event_loop =
Austin Schuhac0771c2020-01-07 18:36:30 -0800791 log_reader_factory.MakeEventLoop("test", pi1);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800792 std::unique_ptr<EventLoop> pi2_event_loop =
793 log_reader_factory.MakeEventLoop("test", pi2);
Austin Schuh15649d62019-12-28 16:36:38 -0800794
Austin Schuh6f3babe2020-01-26 20:34:50 -0800795 int pi1_ping_count = 10;
796 int pi2_ping_count = 10;
797 int pi1_pong_count = 10;
798 int pi2_pong_count = 10;
Austin Schuh15649d62019-12-28 16:36:38 -0800799
800 // Confirm that the ping value matches.
Austin Schuh6f3babe2020-01-26 20:34:50 -0800801 pi1_event_loop->MakeWatcher(
802 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
Austin Schuh2f8fd752020-09-01 22:38:28 -0700803 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping) << " at "
Austin Schuh6f3babe2020-01-26 20:34:50 -0800804 << pi1_event_loop->context().monotonic_remote_time << " -> "
805 << pi1_event_loop->context().monotonic_event_time;
806 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
807 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
808 pi1_ping_count * chrono::milliseconds(10) +
809 monotonic_clock::epoch());
810 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
811 pi1_ping_count * chrono::milliseconds(10) +
812 realtime_clock::epoch());
813 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
814 pi1_event_loop->context().monotonic_event_time);
815 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
816 pi1_event_loop->context().realtime_event_time);
Austin Schuh15649d62019-12-28 16:36:38 -0800817
Austin Schuh6f3babe2020-01-26 20:34:50 -0800818 ++pi1_ping_count;
819 });
820 pi2_event_loop->MakeWatcher(
821 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
Austin Schuh2f8fd752020-09-01 22:38:28 -0700822 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping) << " at "
Austin Schuh6f3babe2020-01-26 20:34:50 -0800823 << pi2_event_loop->context().monotonic_remote_time << " -> "
824 << pi2_event_loop->context().monotonic_event_time;
825 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
826
827 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
828 pi2_ping_count * chrono::milliseconds(10) +
829 monotonic_clock::epoch());
830 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
831 pi2_ping_count * chrono::milliseconds(10) +
832 realtime_clock::epoch());
833 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time +
834 chrono::microseconds(150),
835 pi2_event_loop->context().monotonic_event_time);
836 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time +
837 chrono::microseconds(150),
838 pi2_event_loop->context().realtime_event_time);
839 ++pi2_ping_count;
Austin Schuh15649d62019-12-28 16:36:38 -0800840 });
841
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700842 constexpr ssize_t kQueueIndexOffset = -9;
Austin Schuh6f3babe2020-01-26 20:34:50 -0800843 // Confirm that the ping and pong counts both match, and the value also
844 // matches.
845 pi1_event_loop->MakeWatcher(
846 "/test", [&pi1_event_loop, &pi1_ping_count,
847 &pi1_pong_count](const examples::Pong &pong) {
848 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
849 << pi1_event_loop->context().monotonic_remote_time << " -> "
850 << pi1_event_loop->context().monotonic_event_time;
851
852 EXPECT_EQ(pi1_event_loop->context().remote_queue_index,
853 pi1_pong_count + kQueueIndexOffset);
854 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
855 chrono::microseconds(200) +
856 pi1_pong_count * chrono::milliseconds(10) +
857 monotonic_clock::epoch());
858 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
859 chrono::microseconds(200) +
860 pi1_pong_count * chrono::milliseconds(10) +
861 realtime_clock::epoch());
862
863 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time +
864 chrono::microseconds(150),
865 pi1_event_loop->context().monotonic_event_time);
866 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time +
867 chrono::microseconds(150),
868 pi1_event_loop->context().realtime_event_time);
869
870 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
871 ++pi1_pong_count;
872 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
873 });
874 pi2_event_loop->MakeWatcher(
875 "/test", [&pi2_event_loop, &pi2_ping_count,
876 &pi2_pong_count](const examples::Pong &pong) {
877 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
878 << pi2_event_loop->context().monotonic_remote_time << " -> "
879 << pi2_event_loop->context().monotonic_event_time;
880
881 EXPECT_EQ(pi2_event_loop->context().remote_queue_index,
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700882 pi2_pong_count + kQueueIndexOffset);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800883
884 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
885 chrono::microseconds(200) +
886 pi2_pong_count * chrono::milliseconds(10) +
887 monotonic_clock::epoch());
888 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
889 chrono::microseconds(200) +
890 pi2_pong_count * chrono::milliseconds(10) +
891 realtime_clock::epoch());
892
893 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
894 pi2_event_loop->context().monotonic_event_time);
895 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
896 pi2_event_loop->context().realtime_event_time);
897
898 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
899 ++pi2_pong_count;
900 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
901 });
902
903 log_reader_factory.Run();
904 EXPECT_EQ(pi1_ping_count, 2010);
905 EXPECT_EQ(pi2_ping_count, 2010);
906 EXPECT_EQ(pi1_pong_count, 2010);
907 EXPECT_EQ(pi2_pong_count, 2010);
Austin Schuh6331ef92020-01-07 18:28:09 -0800908
909 reader.Deregister();
Austin Schuh15649d62019-12-28 16:36:38 -0800910}
911
James Kuszmaul46d82582020-05-09 19:50:09 -0700912typedef MultinodeLoggerTest MultinodeLoggerDeathTest;
913
914// Test that if we feed the replay with a mismatched node list that we die on
915// the LogReader constructor.
916TEST_F(MultinodeLoggerDeathTest, MultiNodeBadReplayConfig) {
James Kuszmaul46d82582020-05-09 19:50:09 -0700917 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700918 LoggerState pi1_logger = MakeLogger(pi1_);
919 LoggerState pi2_logger = MakeLogger(pi2_);
James Kuszmaul46d82582020-05-09 19:50:09 -0700920
921 event_loop_factory_.RunFor(chrono::milliseconds(95));
922
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700923 StartLogger(&pi1_logger);
924 StartLogger(&pi2_logger);
James Kuszmaul46d82582020-05-09 19:50:09 -0700925
James Kuszmaul46d82582020-05-09 19:50:09 -0700926 event_loop_factory_.RunFor(chrono::milliseconds(20000));
927 }
928
929 // Test that, if we add an additional node to the replay config that the
930 // logger complains about the mismatch in number of nodes.
931 FlatbufferDetachedBuffer<Configuration> extra_nodes_config =
932 configuration::MergeWithConfig(&config_.message(), R"({
933 "nodes": [
934 {
935 "name": "extra-node"
936 }
937 ]
938 }
939 )");
940
Austin Schuh2f8fd752020-09-01 22:38:28 -0700941 EXPECT_DEATH(LogReader(structured_logfiles_, &extra_nodes_config.message()),
James Kuszmaul46d82582020-05-09 19:50:09 -0700942 "Log file and replay config need to have matching nodes lists.");
James Kuszmaul46d82582020-05-09 19:50:09 -0700943}
944
Austin Schuhcde938c2020-02-02 17:30:07 -0800945// Tests that we can read log files where they don't start at the same monotonic
946// time.
947TEST_F(MultinodeLoggerTest, StaggeredStart) {
Austin Schuhcde938c2020-02-02 17:30:07 -0800948 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700949 LoggerState pi1_logger = MakeLogger(pi1_);
950 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuhcde938c2020-02-02 17:30:07 -0800951
952 event_loop_factory_.RunFor(chrono::milliseconds(95));
953
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700954 StartLogger(&pi1_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800955
956 event_loop_factory_.RunFor(chrono::milliseconds(200));
957
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700958 StartLogger(&pi2_logger);
959
Austin Schuhcde938c2020-02-02 17:30:07 -0800960 event_loop_factory_.RunFor(chrono::milliseconds(20000));
961 }
962
Austin Schuh2f8fd752020-09-01 22:38:28 -0700963 LogReader reader(structured_logfiles_);
Austin Schuhcde938c2020-02-02 17:30:07 -0800964
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700965 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuhcde938c2020-02-02 17:30:07 -0800966 log_reader_factory.set_send_delay(chrono::microseconds(0));
967
968 // This sends out the fetched messages and advances time to the start of the
969 // log file.
970 reader.Register(&log_reader_factory);
971
972 const Node *pi1 =
973 configuration::GetNode(log_reader_factory.configuration(), "pi1");
974 const Node *pi2 =
975 configuration::GetNode(log_reader_factory.configuration(), "pi2");
976
977 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
978
979 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
980
981 std::unique_ptr<EventLoop> pi1_event_loop =
982 log_reader_factory.MakeEventLoop("test", pi1);
983 std::unique_ptr<EventLoop> pi2_event_loop =
984 log_reader_factory.MakeEventLoop("test", pi2);
985
986 int pi1_ping_count = 30;
987 int pi2_ping_count = 30;
988 int pi1_pong_count = 30;
989 int pi2_pong_count = 30;
990
991 // Confirm that the ping value matches.
992 pi1_event_loop->MakeWatcher(
993 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
994 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
995 << pi1_event_loop->context().monotonic_remote_time << " -> "
996 << pi1_event_loop->context().monotonic_event_time;
997 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
998
999 ++pi1_ping_count;
1000 });
1001 pi2_event_loop->MakeWatcher(
1002 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
1003 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
1004 << pi2_event_loop->context().monotonic_remote_time << " -> "
1005 << pi2_event_loop->context().monotonic_event_time;
1006 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
1007
1008 ++pi2_ping_count;
1009 });
1010
1011 // Confirm that the ping and pong counts both match, and the value also
1012 // matches.
1013 pi1_event_loop->MakeWatcher(
1014 "/test", [&pi1_event_loop, &pi1_ping_count,
1015 &pi1_pong_count](const examples::Pong &pong) {
1016 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
1017 << pi1_event_loop->context().monotonic_remote_time << " -> "
1018 << pi1_event_loop->context().monotonic_event_time;
1019
1020 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
1021 ++pi1_pong_count;
1022 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
1023 });
1024 pi2_event_loop->MakeWatcher(
1025 "/test", [&pi2_event_loop, &pi2_ping_count,
1026 &pi2_pong_count](const examples::Pong &pong) {
1027 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
1028 << pi2_event_loop->context().monotonic_remote_time << " -> "
1029 << pi2_event_loop->context().monotonic_event_time;
1030
1031 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1032 ++pi2_pong_count;
1033 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1034 });
1035
1036 log_reader_factory.Run();
1037 EXPECT_EQ(pi1_ping_count, 2030);
1038 EXPECT_EQ(pi2_ping_count, 2030);
1039 EXPECT_EQ(pi1_pong_count, 2030);
1040 EXPECT_EQ(pi2_pong_count, 2030);
1041
1042 reader.Deregister();
1043}
Austin Schuh6f3babe2020-01-26 20:34:50 -08001044
Austin Schuh8bd96322020-02-13 21:18:22 -08001045// Tests that we can read log files where the monotonic clocks drift and don't
1046// match correctly. While we are here, also test that different ending times
1047// also is readable.
1048TEST_F(MultinodeLoggerTest, MismatchedClocks) {
Austin Schuhcde938c2020-02-02 17:30:07 -08001049 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001050 LoggerState pi2_logger = MakeLogger(pi2_);
1051
Austin Schuh8bd96322020-02-13 21:18:22 -08001052 NodeEventLoopFactory *pi2 =
1053 event_loop_factory_.GetNodeEventLoopFactory(pi2_);
1054 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
1055 << pi2->realtime_now() << " distributed "
1056 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -08001057
Austin Schuh8bd96322020-02-13 21:18:22 -08001058 const chrono::nanoseconds initial_pi2_offset = -chrono::seconds(1000);
1059 chrono::nanoseconds pi2_offset = initial_pi2_offset;
Austin Schuhcde938c2020-02-02 17:30:07 -08001060
Austin Schuhbe69cf32020-08-27 11:38:33 -07001061 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -08001062 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
1063 << pi2->realtime_now() << " distributed "
1064 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -08001065
Austin Schuh8bd96322020-02-13 21:18:22 -08001066 for (int i = 0; i < 95; ++i) {
1067 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -07001068 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -08001069 event_loop_factory_.RunFor(chrono::milliseconds(1));
1070 }
Austin Schuhcde938c2020-02-02 17:30:07 -08001071
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001072 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -08001073
Austin Schuh8bd96322020-02-13 21:18:22 -08001074 event_loop_factory_.RunFor(chrono::milliseconds(200));
Austin Schuhcde938c2020-02-02 17:30:07 -08001075
Austin Schuh8bd96322020-02-13 21:18:22 -08001076 {
1077 // Run pi1's logger for only part of the time.
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001078 LoggerState pi1_logger = MakeLogger(pi1_);
Austin Schuh8bd96322020-02-13 21:18:22 -08001079
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001080 StartLogger(&pi1_logger);
Austin Schuh8bd96322020-02-13 21:18:22 -08001081
1082 for (int i = 0; i < 20000; ++i) {
1083 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -07001084 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -08001085 event_loop_factory_.RunFor(chrono::milliseconds(1));
1086 }
1087
1088 EXPECT_GT(pi2_offset - initial_pi2_offset,
1089 event_loop_factory_.send_delay() +
1090 event_loop_factory_.network_delay());
1091
1092 for (int i = 0; i < 40000; ++i) {
1093 pi2_offset -= chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -07001094 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -08001095 event_loop_factory_.RunFor(chrono::milliseconds(1));
1096 }
1097 }
1098
1099 // And log a bit more on pi2.
1100 event_loop_factory_.RunFor(chrono::milliseconds(400));
Austin Schuhcde938c2020-02-02 17:30:07 -08001101 }
1102
Austin Schuh2f8fd752020-09-01 22:38:28 -07001103 LogReader reader(structured_logfiles_);
Austin Schuhcde938c2020-02-02 17:30:07 -08001104
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001105 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuhcde938c2020-02-02 17:30:07 -08001106 log_reader_factory.set_send_delay(chrono::microseconds(0));
1107
Austin Schuhcde938c2020-02-02 17:30:07 -08001108 const Node *pi1 =
1109 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1110 const Node *pi2 =
1111 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1112
Austin Schuh2f8fd752020-09-01 22:38:28 -07001113 // This sends out the fetched messages and advances time to the start of the
1114 // log file.
1115 reader.Register(&log_reader_factory);
1116
1117 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
1118 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
1119 LOG(INFO) << "now pi1 "
1120 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
1121 LOG(INFO) << "now pi2 "
1122 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
1123
Austin Schuhcde938c2020-02-02 17:30:07 -08001124 LOG(INFO) << "Done registering (pi1) "
Austin Schuh391e3172020-09-01 22:48:18 -07001125 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now()
1126 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -08001127 << log_reader_factory.GetNodeEventLoopFactory(pi1)->realtime_now();
1128 LOG(INFO) << "Done registering (pi2) "
Austin Schuh391e3172020-09-01 22:48:18 -07001129 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now()
1130 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -08001131 << log_reader_factory.GetNodeEventLoopFactory(pi2)->realtime_now();
1132
1133 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1134
1135 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1136
1137 std::unique_ptr<EventLoop> pi1_event_loop =
1138 log_reader_factory.MakeEventLoop("test", pi1);
1139 std::unique_ptr<EventLoop> pi2_event_loop =
1140 log_reader_factory.MakeEventLoop("test", pi2);
1141
1142 int pi1_ping_count = 30;
1143 int pi2_ping_count = 30;
1144 int pi1_pong_count = 30;
1145 int pi2_pong_count = 30;
1146
1147 // Confirm that the ping value matches.
1148 pi1_event_loop->MakeWatcher(
1149 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
1150 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
1151 << pi1_event_loop->context().monotonic_remote_time << " -> "
1152 << pi1_event_loop->context().monotonic_event_time;
1153 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
1154
1155 ++pi1_ping_count;
1156 });
1157 pi2_event_loop->MakeWatcher(
1158 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
1159 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
1160 << pi2_event_loop->context().monotonic_remote_time << " -> "
1161 << pi2_event_loop->context().monotonic_event_time;
1162 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
1163
1164 ++pi2_ping_count;
1165 });
1166
1167 // Confirm that the ping and pong counts both match, and the value also
1168 // matches.
1169 pi1_event_loop->MakeWatcher(
1170 "/test", [&pi1_event_loop, &pi1_ping_count,
1171 &pi1_pong_count](const examples::Pong &pong) {
1172 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
1173 << pi1_event_loop->context().monotonic_remote_time << " -> "
1174 << pi1_event_loop->context().monotonic_event_time;
1175
1176 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
1177 ++pi1_pong_count;
1178 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
1179 });
1180 pi2_event_loop->MakeWatcher(
1181 "/test", [&pi2_event_loop, &pi2_ping_count,
1182 &pi2_pong_count](const examples::Pong &pong) {
1183 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
1184 << pi2_event_loop->context().monotonic_remote_time << " -> "
1185 << pi2_event_loop->context().monotonic_event_time;
1186
1187 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1188 ++pi2_pong_count;
1189 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1190 });
1191
1192 log_reader_factory.Run();
Austin Schuh8bd96322020-02-13 21:18:22 -08001193 EXPECT_EQ(pi1_ping_count, 6030);
1194 EXPECT_EQ(pi2_ping_count, 6030);
1195 EXPECT_EQ(pi1_pong_count, 6030);
1196 EXPECT_EQ(pi2_pong_count, 6030);
Austin Schuhcde938c2020-02-02 17:30:07 -08001197
1198 reader.Deregister();
1199}
1200
Austin Schuh5212cad2020-09-09 23:12:09 -07001201// Tests that we can sort a bunch of parts into the pre-determined sorted parts.
1202TEST_F(MultinodeLoggerTest, SortParts) {
1203 // Make a bunch of parts.
1204 {
1205 LoggerState pi1_logger = MakeLogger(pi1_);
1206 LoggerState pi2_logger = MakeLogger(pi2_);
1207
1208 event_loop_factory_.RunFor(chrono::milliseconds(95));
1209
1210 StartLogger(&pi1_logger);
1211 StartLogger(&pi2_logger);
1212
1213 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1214 }
1215
Austin Schuh11d43732020-09-21 17:28:30 -07001216 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
Austin Schuh3bd4c402020-11-06 18:19:06 -08001217 VerifyParts(sorted_parts);
1218}
Austin Schuh11d43732020-09-21 17:28:30 -07001219
Austin Schuh3bd4c402020-11-06 18:19:06 -08001220// Tests that we can sort a bunch of parts with an empty part. We should ignore
1221// it and remove it from the sorted list.
1222TEST_F(MultinodeLoggerTest, SortEmptyParts) {
1223 // Make a bunch of parts.
1224 {
1225 LoggerState pi1_logger = MakeLogger(pi1_);
1226 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuh11d43732020-09-21 17:28:30 -07001227
Austin Schuh3bd4c402020-11-06 18:19:06 -08001228 event_loop_factory_.RunFor(chrono::milliseconds(95));
Austin Schuh11d43732020-09-21 17:28:30 -07001229
Austin Schuh3bd4c402020-11-06 18:19:06 -08001230 StartLogger(&pi1_logger);
1231 StartLogger(&pi2_logger);
Austin Schuh11d43732020-09-21 17:28:30 -07001232
Austin Schuh3bd4c402020-11-06 18:19:06 -08001233 event_loop_factory_.RunFor(chrono::milliseconds(2000));
Austin Schuh11d43732020-09-21 17:28:30 -07001234 }
1235
Austin Schuh3bd4c402020-11-06 18:19:06 -08001236 // TODO(austin): Should we flip out if the file can't open?
1237 const std::string kEmptyFile("foobarinvalidfiledoesnotexist.bfbs");
Austin Schuh11d43732020-09-21 17:28:30 -07001238
Austin Schuh3bd4c402020-11-06 18:19:06 -08001239 aos::util::WriteStringToFileOrDie(kEmptyFile, "");
1240 logfiles_.emplace_back(kEmptyFile);
Austin Schuh5212cad2020-09-09 23:12:09 -07001241
Austin Schuh3bd4c402020-11-06 18:19:06 -08001242 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1243 VerifyParts(sorted_parts, {kEmptyFile});
Austin Schuh5212cad2020-09-09 23:12:09 -07001244}
1245
Austin Schuh3bd4c402020-11-06 18:19:06 -08001246#ifdef LZMA
1247// Tests that we can sort a bunch of parts with an empty .xz file in there. The
1248// empty file should be ignored.
1249TEST_F(MultinodeLoggerTest, SortEmptyCompressedParts) {
1250 // Make a bunch of parts.
1251 {
1252 LoggerState pi1_logger = MakeLogger(pi1_);
1253 LoggerState pi2_logger = MakeLogger(pi2_);
1254
1255 event_loop_factory_.RunFor(chrono::milliseconds(95));
1256
1257 StartLogger(&pi1_logger, "", true);
1258 StartLogger(&pi2_logger, "", true);
1259
1260 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1261 }
1262
1263 // TODO(austin): Should we flip out if the file can't open?
1264 const std::string kEmptyFile("foobarinvalidfiledoesnotexist.bfbs.xz");
1265
1266 AddExtension(".xz");
1267
1268 aos::util::WriteStringToFileOrDie(kEmptyFile, "");
1269 logfiles_.emplace_back(kEmptyFile);
1270
1271 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1272 VerifyParts(sorted_parts, {kEmptyFile});
1273}
1274
1275// Tests that we can sort a bunch of parts with the end missing off a compressed
1276// file. We should use the part we can read.
1277TEST_F(MultinodeLoggerTest, SortTruncatedCompressedParts) {
1278 // Make a bunch of parts.
1279 {
1280 LoggerState pi1_logger = MakeLogger(pi1_);
1281 LoggerState pi2_logger = MakeLogger(pi2_);
1282
1283 event_loop_factory_.RunFor(chrono::milliseconds(95));
1284
1285 StartLogger(&pi1_logger, "", true);
1286 StartLogger(&pi2_logger, "", true);
1287
1288 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1289 }
1290
1291 // Append everything with .xz.
1292 AddExtension(".xz");
1293
1294 // Strip off the end of one of the files. Pick one with a lot of data.
1295 ::std::string compressed_contents =
1296 aos::util::ReadFileToStringOrDie(logfiles_[0]);
1297
1298 aos::util::WriteStringToFileOrDie(
1299 logfiles_[0],
1300 compressed_contents.substr(0, compressed_contents.size() - 100));
1301
1302 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1303 VerifyParts(sorted_parts);
1304}
1305#endif
1306
Austin Schuh01b4c352020-09-21 23:09:39 -07001307// Tests that if we remap a remapped channel, it shows up correctly.
1308TEST_F(MultinodeLoggerTest, RemapLoggedChannel) {
1309 {
1310 LoggerState pi1_logger = MakeLogger(pi1_);
1311 LoggerState pi2_logger = MakeLogger(pi2_);
1312
1313 event_loop_factory_.RunFor(chrono::milliseconds(95));
1314
1315 StartLogger(&pi1_logger);
1316 StartLogger(&pi2_logger);
1317
1318 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1319 }
1320
1321 LogReader reader(structured_logfiles_);
1322
1323 // Remap just on pi1.
1324 reader.RemapLoggedChannel<aos::timing::Report>(
1325 "/aos", configuration::GetNode(reader.configuration(), "pi1"));
1326
1327 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1328 log_reader_factory.set_send_delay(chrono::microseconds(0));
1329
1330 reader.Register(&log_reader_factory);
1331
1332 const Node *pi1 =
1333 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1334 const Node *pi2 =
1335 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1336
1337 // Confirm we can read the data on the remapped channel, just for pi1. Nothing
1338 // else should have moved.
1339 std::unique_ptr<EventLoop> pi1_event_loop =
1340 log_reader_factory.MakeEventLoop("test", pi1);
1341 pi1_event_loop->SkipTimingReport();
1342 std::unique_ptr<EventLoop> full_pi1_event_loop =
1343 log_reader_factory.MakeEventLoop("test", pi1);
1344 full_pi1_event_loop->SkipTimingReport();
1345 std::unique_ptr<EventLoop> pi2_event_loop =
1346 log_reader_factory.MakeEventLoop("test", pi2);
1347 pi2_event_loop->SkipTimingReport();
1348
1349 MessageCounter<aos::timing::Report> pi1_timing_report(pi1_event_loop.get(),
1350 "/aos");
1351 MessageCounter<aos::timing::Report> full_pi1_timing_report(
1352 full_pi1_event_loop.get(), "/pi1/aos");
1353 MessageCounter<aos::timing::Report> pi1_original_timing_report(
1354 pi1_event_loop.get(), "/original/aos");
1355 MessageCounter<aos::timing::Report> full_pi1_original_timing_report(
1356 full_pi1_event_loop.get(), "/original/pi1/aos");
1357 MessageCounter<aos::timing::Report> pi2_timing_report(pi2_event_loop.get(),
1358 "/aos");
1359
1360 log_reader_factory.Run();
1361
1362 EXPECT_EQ(pi1_timing_report.count(), 0u);
1363 EXPECT_EQ(full_pi1_timing_report.count(), 0u);
1364 EXPECT_NE(pi1_original_timing_report.count(), 0u);
1365 EXPECT_NE(full_pi1_original_timing_report.count(), 0u);
1366 EXPECT_NE(pi2_timing_report.count(), 0u);
1367
1368 reader.Deregister();
1369}
1370
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001371// Tests that we properly recreate forwarded timestamps when replaying a log.
1372// This should be enough that we can then re-run the logger and get a valid log
1373// back.
1374TEST_F(MultinodeLoggerTest, MessageHeader) {
1375 {
1376 LoggerState pi1_logger = MakeLogger(pi1_);
1377 LoggerState pi2_logger = MakeLogger(pi2_);
1378
1379 event_loop_factory_.RunFor(chrono::milliseconds(95));
1380
1381 StartLogger(&pi1_logger);
1382 StartLogger(&pi2_logger);
1383
1384 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1385 }
1386
1387 LogReader reader(structured_logfiles_);
1388
1389 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1390 log_reader_factory.set_send_delay(chrono::microseconds(0));
1391
1392 // This sends out the fetched messages and advances time to the start of the
1393 // log file.
1394 reader.Register(&log_reader_factory);
1395
1396 const Node *pi1 =
1397 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1398 const Node *pi2 =
1399 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1400
1401 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
1402 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
1403 LOG(INFO) << "now pi1 "
1404 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
1405 LOG(INFO) << "now pi2 "
1406 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
1407
1408 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1409
1410 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1411
1412 std::unique_ptr<EventLoop> pi1_event_loop =
1413 log_reader_factory.MakeEventLoop("test", pi1);
1414 std::unique_ptr<EventLoop> pi2_event_loop =
1415 log_reader_factory.MakeEventLoop("test", pi2);
1416
1417 MessageCounter<MessageHeader> pi1_original_message_header_counter(
1418 pi1_event_loop.get(), "/original/aos/remote_timestamps/pi2");
1419 MessageCounter<MessageHeader> pi2_original_message_header_counter(
1420 pi2_event_loop.get(), "/original/aos/remote_timestamps/pi1");
1421
1422 aos::Fetcher<message_bridge::Timestamp> pi1_timestamp_on_pi1_fetcher =
1423 pi1_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi1/aos");
1424 aos::Fetcher<message_bridge::Timestamp> pi1_timestamp_on_pi2_fetcher =
1425 pi2_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi1/aos");
1426
1427 aos::Fetcher<examples::Ping> ping_on_pi1_fetcher =
1428 pi1_event_loop->MakeFetcher<examples::Ping>("/test");
1429 aos::Fetcher<examples::Ping> ping_on_pi2_fetcher =
1430 pi2_event_loop->MakeFetcher<examples::Ping>("/test");
1431
1432 aos::Fetcher<message_bridge::Timestamp> pi2_timestamp_on_pi2_fetcher =
1433 pi2_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi2/aos");
1434 aos::Fetcher<message_bridge::Timestamp> pi2_timestamp_on_pi1_fetcher =
1435 pi1_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi2/aos");
1436
1437 aos::Fetcher<examples::Pong> pong_on_pi2_fetcher =
1438 pi2_event_loop->MakeFetcher<examples::Pong>("/test");
1439 aos::Fetcher<examples::Pong> pong_on_pi1_fetcher =
1440 pi1_event_loop->MakeFetcher<examples::Pong>("/test");
1441
1442 const size_t pi1_timestamp_channel = configuration::ChannelIndex(
1443 pi1_event_loop->configuration(), pi1_timestamp_on_pi1_fetcher.channel());
1444 const size_t ping_timestamp_channel = configuration::ChannelIndex(
1445 pi2_event_loop->configuration(), ping_on_pi2_fetcher.channel());
1446
1447 const size_t pi2_timestamp_channel = configuration::ChannelIndex(
1448 pi2_event_loop->configuration(), pi2_timestamp_on_pi2_fetcher.channel());
1449 const size_t pong_timestamp_channel = configuration::ChannelIndex(
1450 pi1_event_loop->configuration(), pong_on_pi1_fetcher.channel());
1451
1452 pi1_event_loop->MakeWatcher(
1453 "/aos/remote_timestamps/pi2",
1454 [&pi1_event_loop, pi1_timestamp_channel, ping_timestamp_channel,
1455 &pi1_timestamp_on_pi1_fetcher, &pi1_timestamp_on_pi2_fetcher,
1456 &ping_on_pi1_fetcher,
1457 &ping_on_pi2_fetcher](const MessageHeader &header) {
1458 const aos::monotonic_clock::time_point header_monotonic_sent_time(
1459 chrono::nanoseconds(header.monotonic_sent_time()));
1460 const aos::realtime_clock::time_point header_realtime_sent_time(
1461 chrono::nanoseconds(header.realtime_sent_time()));
1462 const aos::monotonic_clock::time_point header_monotonic_remote_time(
1463 chrono::nanoseconds(header.monotonic_remote_time()));
1464 const aos::realtime_clock::time_point header_realtime_remote_time(
1465 chrono::nanoseconds(header.realtime_remote_time()));
1466
1467 const Context *pi1_context = nullptr;
1468 const Context *pi2_context = nullptr;
1469
1470 if (header.channel_index() == pi1_timestamp_channel) {
1471 ASSERT_TRUE(pi1_timestamp_on_pi1_fetcher.FetchNext());
1472 ASSERT_TRUE(pi1_timestamp_on_pi2_fetcher.FetchNext());
1473 pi1_context = &pi1_timestamp_on_pi1_fetcher.context();
1474 pi2_context = &pi1_timestamp_on_pi2_fetcher.context();
1475 } else if (header.channel_index() == ping_timestamp_channel) {
1476 ASSERT_TRUE(ping_on_pi1_fetcher.FetchNext());
1477 ASSERT_TRUE(ping_on_pi2_fetcher.FetchNext());
1478 pi1_context = &ping_on_pi1_fetcher.context();
1479 pi2_context = &ping_on_pi2_fetcher.context();
1480 } else {
1481 LOG(FATAL) << "Unknown channel " << FlatbufferToJson(&header) << " "
1482 << configuration::CleanedChannelToString(
1483 pi1_event_loop->configuration()->channels()->Get(
1484 header.channel_index()));
1485 }
1486
1487 EXPECT_EQ(pi1_context->queue_index, header.remote_queue_index());
1488 EXPECT_EQ(pi2_context->remote_queue_index, header.remote_queue_index());
1489 EXPECT_EQ(pi2_context->queue_index, header.queue_index());
1490
1491 EXPECT_EQ(pi2_context->monotonic_event_time,
1492 header_monotonic_sent_time);
1493 EXPECT_EQ(pi2_context->realtime_event_time, header_realtime_sent_time);
1494 EXPECT_EQ(pi2_context->realtime_remote_time,
1495 header_realtime_remote_time);
1496 EXPECT_EQ(pi2_context->monotonic_remote_time,
1497 header_monotonic_remote_time);
1498
1499 EXPECT_EQ(pi1_context->realtime_event_time,
1500 header_realtime_remote_time);
1501 EXPECT_EQ(pi1_context->monotonic_event_time,
1502 header_monotonic_remote_time);
1503 });
1504 pi2_event_loop->MakeWatcher(
1505 "/aos/remote_timestamps/pi1",
1506 [&pi2_event_loop, pi2_timestamp_channel, pong_timestamp_channel,
1507 &pi2_timestamp_on_pi2_fetcher, &pi2_timestamp_on_pi1_fetcher,
1508 &pong_on_pi2_fetcher,
1509 &pong_on_pi1_fetcher](const MessageHeader &header) {
1510 const aos::monotonic_clock::time_point header_monotonic_sent_time(
1511 chrono::nanoseconds(header.monotonic_sent_time()));
1512 const aos::realtime_clock::time_point header_realtime_sent_time(
1513 chrono::nanoseconds(header.realtime_sent_time()));
1514 const aos::monotonic_clock::time_point header_monotonic_remote_time(
1515 chrono::nanoseconds(header.monotonic_remote_time()));
1516 const aos::realtime_clock::time_point header_realtime_remote_time(
1517 chrono::nanoseconds(header.realtime_remote_time()));
1518
1519 const Context *pi2_context = nullptr;
1520 const Context *pi1_context = nullptr;
1521
1522 if (header.channel_index() == pi2_timestamp_channel) {
1523 ASSERT_TRUE(pi2_timestamp_on_pi2_fetcher.FetchNext());
1524 ASSERT_TRUE(pi2_timestamp_on_pi1_fetcher.FetchNext());
1525 pi2_context = &pi2_timestamp_on_pi2_fetcher.context();
1526 pi1_context = &pi2_timestamp_on_pi1_fetcher.context();
1527 } else if (header.channel_index() == pong_timestamp_channel) {
1528 ASSERT_TRUE(pong_on_pi2_fetcher.FetchNext());
1529 ASSERT_TRUE(pong_on_pi1_fetcher.FetchNext());
1530 pi2_context = &pong_on_pi2_fetcher.context();
1531 pi1_context = &pong_on_pi1_fetcher.context();
1532 } else {
1533 LOG(FATAL) << "Unknown channel " << FlatbufferToJson(&header) << " "
1534 << configuration::CleanedChannelToString(
1535 pi2_event_loop->configuration()->channels()->Get(
1536 header.channel_index()));
1537 }
1538
1539 EXPECT_EQ(pi2_context->queue_index, header.remote_queue_index());
1540 EXPECT_EQ(pi1_context->remote_queue_index, header.remote_queue_index());
1541 EXPECT_EQ(pi1_context->queue_index, header.queue_index());
1542
1543 EXPECT_EQ(pi1_context->monotonic_event_time,
1544 header_monotonic_sent_time);
1545 EXPECT_EQ(pi1_context->realtime_event_time, header_realtime_sent_time);
1546 EXPECT_EQ(pi1_context->realtime_remote_time,
1547 header_realtime_remote_time);
1548 EXPECT_EQ(pi1_context->monotonic_remote_time,
1549 header_monotonic_remote_time);
1550
1551 EXPECT_EQ(pi2_context->realtime_event_time,
1552 header_realtime_remote_time);
1553 EXPECT_EQ(pi2_context->monotonic_event_time,
1554 header_monotonic_remote_time);
1555 });
1556
1557 // And confirm we can re-create a log again, while checking the contents.
1558 {
1559 LoggerState pi1_logger = MakeLogger(
1560 configuration::GetNode(log_reader_factory.configuration(), pi1_),
1561 &log_reader_factory);
1562 LoggerState pi2_logger = MakeLogger(
1563 configuration::GetNode(log_reader_factory.configuration(), pi2_),
1564 &log_reader_factory);
1565
1566 StartLogger(&pi1_logger, "relogged");
1567 StartLogger(&pi2_logger, "relogged");
1568
1569 log_reader_factory.Run();
1570 }
1571
1572 EXPECT_EQ(pi2_original_message_header_counter.count(), 0u);
1573 EXPECT_EQ(pi1_original_message_header_counter.count(), 0u);
1574
1575 reader.Deregister();
1576}
1577
Austin Schuh8bd96322020-02-13 21:18:22 -08001578// TODO(austin): We can write a test which recreates a logfile and confirms that
1579// we get it back. That is the ultimate test.
1580
Austin Schuhe309d2a2019-11-29 13:25:21 -08001581} // namespace testing
1582} // namespace logger
1583} // namespace aos