blob: a6385d3efb95467ac15b8e0355936453fa7092a7 [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) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800115 const ::std::string tmpdir = aos::testing::TestTmpDir();
Brian Silverman1f345222020-09-24 21:14:48 -0700116 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) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800147 const ::std::string tmpdir = aos::testing::TestTmpDir();
Brian Silverman1f345222020-09-24 21:14:48 -0700148 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) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800176 const ::std::string tmpdir = aos::testing::TestTmpDir();
Brian Silverman1f345222020-09-24 21:14:48 -0700177 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) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800239 const ::std::string tmpdir = aos::testing::TestTmpDir();
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.
Austin Schuh287d43d2020-12-04 20:19:33 -0800282 LogReader reader(SortParts({logfile0, logfile1}), &config_.message());
Austin Schuhfa895892020-01-07 20:07:41 -0800283
284 // Confirm that we can remap logged channels to point to new buses.
285 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
286
287 // This sends out the fetched messages and advances time to the start of the
288 // log file.
289 reader.Register();
290
Austin Schuh6f3babe2020-01-26 20:34:50 -0800291 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
Austin Schuhfa895892020-01-07 20:07:41 -0800292
293 std::unique_ptr<EventLoop> test_event_loop =
294 reader.event_loop_factory()->MakeEventLoop("log_reader");
295
296 int ping_count = 10;
297 int pong_count = 10;
298
299 // Confirm that the ping value matches in the remapped channel location.
300 test_event_loop->MakeWatcher("/original/test",
301 [&ping_count](const examples::Ping &ping) {
302 EXPECT_EQ(ping.value(), ping_count + 1);
303 ++ping_count;
304 });
305 // Confirm that the ping and pong counts both match, and the value also
306 // matches.
307 test_event_loop->MakeWatcher(
308 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
309 EXPECT_EQ(pong.value(), pong_count + 1);
310 ++pong_count;
311 EXPECT_EQ(ping_count, pong_count);
312 });
313
314 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
315 EXPECT_EQ(ping_count, 2010);
316}
317
Austin Schuh4c4e0092019-12-22 16:18:03 -0800318// Tests that a large number of messages per second doesn't overwhelm writev.
319TEST_F(LoggerTest, ManyMessages) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800320 const ::std::string tmpdir = aos::testing::TestTmpDir();
Austin Schuh2f8fd752020-09-01 22:38:28 -0700321 const ::std::string base_name = tmpdir + "/logfile";
322 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuh4c4e0092019-12-22 16:18:03 -0800323 // Remove the log file.
324 unlink(logfile.c_str());
325
326 LOG(INFO) << "Logging data to " << logfile;
Austin Schuh4c3b9702020-08-30 11:34:55 -0700327 ping_.set_quiet(true);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800328
329 {
Austin Schuh4c4e0092019-12-22 16:18:03 -0800330 std::unique_ptr<EventLoop> logger_event_loop =
331 event_loop_factory_.MakeEventLoop("logger");
332
333 std::unique_ptr<EventLoop> ping_spammer_event_loop =
334 event_loop_factory_.MakeEventLoop("ping_spammer");
335 aos::Sender<examples::Ping> ping_sender =
336 ping_spammer_event_loop->MakeSender<examples::Ping>("/test");
337
338 aos::TimerHandler *timer_handler =
339 ping_spammer_event_loop->AddTimer([&ping_sender]() {
340 aos::Sender<examples::Ping>::Builder builder =
341 ping_sender.MakeBuilder();
342 examples::Ping::Builder ping_builder =
343 builder.MakeBuilder<examples::Ping>();
344 CHECK(builder.Send(ping_builder.Finish()));
345 });
346
347 // 100 ms / 0.05 ms -> 2000 messages. Should be enough to crash it.
348 ping_spammer_event_loop->OnRun([&ping_spammer_event_loop, timer_handler]() {
349 timer_handler->Setup(ping_spammer_event_loop->monotonic_now(),
350 chrono::microseconds(50));
351 });
352
Brian Silverman1f345222020-09-24 21:14:48 -0700353 Logger logger(logger_event_loop.get());
354 logger.set_polling_period(std::chrono::milliseconds(100));
355 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800356
357 event_loop_factory_.RunFor(chrono::milliseconds(1000));
358 }
359}
360
Austin Schuh15649d62019-12-28 16:36:38 -0800361class MultinodeLoggerTest : public ::testing::Test {
362 public:
363 MultinodeLoggerTest()
364 : config_(aos::configuration::ReadConfig(
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800365 "aos/events/logging/multinode_pingpong_config.json")),
Austin Schuhac0771c2020-01-07 18:36:30 -0800366 event_loop_factory_(&config_.message()),
Austin Schuhcde938c2020-02-02 17:30:07 -0800367 pi1_(
368 configuration::GetNode(event_loop_factory_.configuration(), "pi1")),
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700369 pi2_(
370 configuration::GetNode(event_loop_factory_.configuration(), "pi2")),
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800371 tmp_dir_(aos::testing::TestTmpDir()),
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700372 logfile_base_(tmp_dir_ + "/multi_logfile"),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700373 logfiles_(
374 {logfile_base_ + "_pi1_data.part0.bfbs",
375 logfile_base_ + "_pi2_data/test/aos.examples.Pong.part0.bfbs",
376 logfile_base_ + "_pi2_data/test/aos.examples.Pong.part1.bfbs",
377 logfile_base_ + "_pi2_data.part0.bfbs",
378 logfile_base_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
379 "aos.logger.MessageHeader.part0.bfbs",
380 logfile_base_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
381 "aos.logger.MessageHeader.part1.bfbs",
382 logfile_base_ + "_timestamps/pi2/aos/remote_timestamps/pi1/"
383 "aos.logger.MessageHeader.part0.bfbs",
384 logfile_base_ + "_timestamps/pi2/aos/remote_timestamps/pi1/"
385 "aos.logger.MessageHeader.part1.bfbs",
386 logfile_base_ +
387 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part0.bfbs",
388 logfile_base_ +
389 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part1.bfbs",
390 logfile_base_ +
391 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part0.bfbs",
392 logfile_base_ +
393 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part1.bfbs"}),
394 structured_logfiles_{
395 std::vector<std::string>{logfiles_[0]},
396 std::vector<std::string>{logfiles_[1], logfiles_[2]},
397 std::vector<std::string>{logfiles_[3]},
398 std::vector<std::string>{logfiles_[4], logfiles_[5]},
399 std::vector<std::string>{logfiles_[6], logfiles_[7]},
400 std::vector<std::string>{logfiles_[8], logfiles_[9]},
401 std::vector<std::string>{logfiles_[10], logfiles_[11]}},
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700402 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping", pi1_)),
403 ping_(ping_event_loop_.get()),
404 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong", pi2_)),
405 pong_(pong_event_loop_.get()) {
406 // Go through and remove the logfiles if they already exist.
407 for (const auto file : logfiles_) {
408 unlink(file.c_str());
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800409 unlink((file + ".xz").c_str());
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700410 }
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 Schuh287d43d2020-12-04 20:19:33 -0800765 LogReader reader(SortParts(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 Schuh287d43d2020-12-04 20:19:33 -0800941 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
942 EXPECT_DEATH(LogReader(sorted_parts, &extra_nodes_config.message()),
James Kuszmaul46d82582020-05-09 19:50:09 -0700943 "Log file and replay config need to have matching nodes lists.");
James Kuszmaul46d82582020-05-09 19:50:09 -0700944}
945
Austin Schuhcde938c2020-02-02 17:30:07 -0800946// Tests that we can read log files where they don't start at the same monotonic
947// time.
948TEST_F(MultinodeLoggerTest, StaggeredStart) {
Austin Schuhcde938c2020-02-02 17:30:07 -0800949 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700950 LoggerState pi1_logger = MakeLogger(pi1_);
951 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuhcde938c2020-02-02 17:30:07 -0800952
953 event_loop_factory_.RunFor(chrono::milliseconds(95));
954
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700955 StartLogger(&pi1_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800956
957 event_loop_factory_.RunFor(chrono::milliseconds(200));
958
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700959 StartLogger(&pi2_logger);
960
Austin Schuhcde938c2020-02-02 17:30:07 -0800961 event_loop_factory_.RunFor(chrono::milliseconds(20000));
962 }
963
Austin Schuh287d43d2020-12-04 20:19:33 -0800964 LogReader reader(SortParts(logfiles_));
Austin Schuhcde938c2020-02-02 17:30:07 -0800965
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700966 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuhcde938c2020-02-02 17:30:07 -0800967 log_reader_factory.set_send_delay(chrono::microseconds(0));
968
969 // This sends out the fetched messages and advances time to the start of the
970 // log file.
971 reader.Register(&log_reader_factory);
972
973 const Node *pi1 =
974 configuration::GetNode(log_reader_factory.configuration(), "pi1");
975 const Node *pi2 =
976 configuration::GetNode(log_reader_factory.configuration(), "pi2");
977
978 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
979
980 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
981
982 std::unique_ptr<EventLoop> pi1_event_loop =
983 log_reader_factory.MakeEventLoop("test", pi1);
984 std::unique_ptr<EventLoop> pi2_event_loop =
985 log_reader_factory.MakeEventLoop("test", pi2);
986
987 int pi1_ping_count = 30;
988 int pi2_ping_count = 30;
989 int pi1_pong_count = 30;
990 int pi2_pong_count = 30;
991
992 // Confirm that the ping value matches.
993 pi1_event_loop->MakeWatcher(
994 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
995 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
996 << pi1_event_loop->context().monotonic_remote_time << " -> "
997 << pi1_event_loop->context().monotonic_event_time;
998 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
999
1000 ++pi1_ping_count;
1001 });
1002 pi2_event_loop->MakeWatcher(
1003 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
1004 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
1005 << pi2_event_loop->context().monotonic_remote_time << " -> "
1006 << pi2_event_loop->context().monotonic_event_time;
1007 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
1008
1009 ++pi2_ping_count;
1010 });
1011
1012 // Confirm that the ping and pong counts both match, and the value also
1013 // matches.
1014 pi1_event_loop->MakeWatcher(
1015 "/test", [&pi1_event_loop, &pi1_ping_count,
1016 &pi1_pong_count](const examples::Pong &pong) {
1017 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
1018 << pi1_event_loop->context().monotonic_remote_time << " -> "
1019 << pi1_event_loop->context().monotonic_event_time;
1020
1021 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
1022 ++pi1_pong_count;
1023 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
1024 });
1025 pi2_event_loop->MakeWatcher(
1026 "/test", [&pi2_event_loop, &pi2_ping_count,
1027 &pi2_pong_count](const examples::Pong &pong) {
1028 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
1029 << pi2_event_loop->context().monotonic_remote_time << " -> "
1030 << pi2_event_loop->context().monotonic_event_time;
1031
1032 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1033 ++pi2_pong_count;
1034 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1035 });
1036
1037 log_reader_factory.Run();
1038 EXPECT_EQ(pi1_ping_count, 2030);
1039 EXPECT_EQ(pi2_ping_count, 2030);
1040 EXPECT_EQ(pi1_pong_count, 2030);
1041 EXPECT_EQ(pi2_pong_count, 2030);
1042
1043 reader.Deregister();
1044}
Austin Schuh6f3babe2020-01-26 20:34:50 -08001045
Austin Schuh8bd96322020-02-13 21:18:22 -08001046// Tests that we can read log files where the monotonic clocks drift and don't
1047// match correctly. While we are here, also test that different ending times
1048// also is readable.
1049TEST_F(MultinodeLoggerTest, MismatchedClocks) {
Austin Schuhcde938c2020-02-02 17:30:07 -08001050 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001051 LoggerState pi2_logger = MakeLogger(pi2_);
1052
Austin Schuh8bd96322020-02-13 21:18:22 -08001053 NodeEventLoopFactory *pi2 =
1054 event_loop_factory_.GetNodeEventLoopFactory(pi2_);
1055 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
1056 << pi2->realtime_now() << " distributed "
1057 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -08001058
Austin Schuh8bd96322020-02-13 21:18:22 -08001059 const chrono::nanoseconds initial_pi2_offset = -chrono::seconds(1000);
1060 chrono::nanoseconds pi2_offset = initial_pi2_offset;
Austin Schuhcde938c2020-02-02 17:30:07 -08001061
Austin Schuhbe69cf32020-08-27 11:38:33 -07001062 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -08001063 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
1064 << pi2->realtime_now() << " distributed "
1065 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -08001066
Austin Schuh8bd96322020-02-13 21:18:22 -08001067 for (int i = 0; i < 95; ++i) {
1068 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -07001069 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -08001070 event_loop_factory_.RunFor(chrono::milliseconds(1));
1071 }
Austin Schuhcde938c2020-02-02 17:30:07 -08001072
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001073 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -08001074
Austin Schuh8bd96322020-02-13 21:18:22 -08001075 event_loop_factory_.RunFor(chrono::milliseconds(200));
Austin Schuhcde938c2020-02-02 17:30:07 -08001076
Austin Schuh8bd96322020-02-13 21:18:22 -08001077 {
1078 // Run pi1's logger for only part of the time.
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001079 LoggerState pi1_logger = MakeLogger(pi1_);
Austin Schuh8bd96322020-02-13 21:18:22 -08001080
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001081 StartLogger(&pi1_logger);
Austin Schuh8bd96322020-02-13 21:18:22 -08001082
1083 for (int i = 0; i < 20000; ++i) {
1084 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -07001085 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -08001086 event_loop_factory_.RunFor(chrono::milliseconds(1));
1087 }
1088
1089 EXPECT_GT(pi2_offset - initial_pi2_offset,
1090 event_loop_factory_.send_delay() +
1091 event_loop_factory_.network_delay());
1092
1093 for (int i = 0; i < 40000; ++i) {
1094 pi2_offset -= chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -07001095 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -08001096 event_loop_factory_.RunFor(chrono::milliseconds(1));
1097 }
1098 }
1099
1100 // And log a bit more on pi2.
1101 event_loop_factory_.RunFor(chrono::milliseconds(400));
Austin Schuhcde938c2020-02-02 17:30:07 -08001102 }
1103
Austin Schuh287d43d2020-12-04 20:19:33 -08001104 LogReader reader(SortParts(logfiles_));
Austin Schuhcde938c2020-02-02 17:30:07 -08001105
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001106 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuhcde938c2020-02-02 17:30:07 -08001107 log_reader_factory.set_send_delay(chrono::microseconds(0));
1108
Austin Schuhcde938c2020-02-02 17:30:07 -08001109 const Node *pi1 =
1110 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1111 const Node *pi2 =
1112 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1113
Austin Schuh2f8fd752020-09-01 22:38:28 -07001114 // This sends out the fetched messages and advances time to the start of the
1115 // log file.
1116 reader.Register(&log_reader_factory);
1117
1118 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
1119 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
1120 LOG(INFO) << "now pi1 "
1121 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
1122 LOG(INFO) << "now pi2 "
1123 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
1124
Austin Schuhcde938c2020-02-02 17:30:07 -08001125 LOG(INFO) << "Done registering (pi1) "
Austin Schuh391e3172020-09-01 22:48:18 -07001126 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now()
1127 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -08001128 << log_reader_factory.GetNodeEventLoopFactory(pi1)->realtime_now();
1129 LOG(INFO) << "Done registering (pi2) "
Austin Schuh391e3172020-09-01 22:48:18 -07001130 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now()
1131 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -08001132 << log_reader_factory.GetNodeEventLoopFactory(pi2)->realtime_now();
1133
1134 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1135
1136 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1137
1138 std::unique_ptr<EventLoop> pi1_event_loop =
1139 log_reader_factory.MakeEventLoop("test", pi1);
1140 std::unique_ptr<EventLoop> pi2_event_loop =
1141 log_reader_factory.MakeEventLoop("test", pi2);
1142
1143 int pi1_ping_count = 30;
1144 int pi2_ping_count = 30;
1145 int pi1_pong_count = 30;
1146 int pi2_pong_count = 30;
1147
1148 // Confirm that the ping value matches.
1149 pi1_event_loop->MakeWatcher(
1150 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
1151 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
1152 << pi1_event_loop->context().monotonic_remote_time << " -> "
1153 << pi1_event_loop->context().monotonic_event_time;
1154 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
1155
1156 ++pi1_ping_count;
1157 });
1158 pi2_event_loop->MakeWatcher(
1159 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
1160 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
1161 << pi2_event_loop->context().monotonic_remote_time << " -> "
1162 << pi2_event_loop->context().monotonic_event_time;
1163 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
1164
1165 ++pi2_ping_count;
1166 });
1167
1168 // Confirm that the ping and pong counts both match, and the value also
1169 // matches.
1170 pi1_event_loop->MakeWatcher(
1171 "/test", [&pi1_event_loop, &pi1_ping_count,
1172 &pi1_pong_count](const examples::Pong &pong) {
1173 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
1174 << pi1_event_loop->context().monotonic_remote_time << " -> "
1175 << pi1_event_loop->context().monotonic_event_time;
1176
1177 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
1178 ++pi1_pong_count;
1179 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
1180 });
1181 pi2_event_loop->MakeWatcher(
1182 "/test", [&pi2_event_loop, &pi2_ping_count,
1183 &pi2_pong_count](const examples::Pong &pong) {
1184 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
1185 << pi2_event_loop->context().monotonic_remote_time << " -> "
1186 << pi2_event_loop->context().monotonic_event_time;
1187
1188 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1189 ++pi2_pong_count;
1190 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1191 });
1192
1193 log_reader_factory.Run();
Austin Schuh8bd96322020-02-13 21:18:22 -08001194 EXPECT_EQ(pi1_ping_count, 6030);
1195 EXPECT_EQ(pi2_ping_count, 6030);
1196 EXPECT_EQ(pi1_pong_count, 6030);
1197 EXPECT_EQ(pi2_pong_count, 6030);
Austin Schuhcde938c2020-02-02 17:30:07 -08001198
1199 reader.Deregister();
1200}
1201
Austin Schuh5212cad2020-09-09 23:12:09 -07001202// Tests that we can sort a bunch of parts into the pre-determined sorted parts.
1203TEST_F(MultinodeLoggerTest, SortParts) {
1204 // Make a bunch of parts.
1205 {
1206 LoggerState pi1_logger = MakeLogger(pi1_);
1207 LoggerState pi2_logger = MakeLogger(pi2_);
1208
1209 event_loop_factory_.RunFor(chrono::milliseconds(95));
1210
1211 StartLogger(&pi1_logger);
1212 StartLogger(&pi2_logger);
1213
1214 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1215 }
1216
Austin Schuh11d43732020-09-21 17:28:30 -07001217 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
Austin Schuh3bd4c402020-11-06 18:19:06 -08001218 VerifyParts(sorted_parts);
1219}
Austin Schuh11d43732020-09-21 17:28:30 -07001220
Austin Schuh3bd4c402020-11-06 18:19:06 -08001221// Tests that we can sort a bunch of parts with an empty part. We should ignore
1222// it and remove it from the sorted list.
1223TEST_F(MultinodeLoggerTest, SortEmptyParts) {
1224 // Make a bunch of parts.
1225 {
1226 LoggerState pi1_logger = MakeLogger(pi1_);
1227 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuh11d43732020-09-21 17:28:30 -07001228
Austin Schuh3bd4c402020-11-06 18:19:06 -08001229 event_loop_factory_.RunFor(chrono::milliseconds(95));
Austin Schuh11d43732020-09-21 17:28:30 -07001230
Austin Schuh3bd4c402020-11-06 18:19:06 -08001231 StartLogger(&pi1_logger);
1232 StartLogger(&pi2_logger);
Austin Schuh11d43732020-09-21 17:28:30 -07001233
Austin Schuh3bd4c402020-11-06 18:19:06 -08001234 event_loop_factory_.RunFor(chrono::milliseconds(2000));
Austin Schuh11d43732020-09-21 17:28:30 -07001235 }
1236
Austin Schuh3bd4c402020-11-06 18:19:06 -08001237 // TODO(austin): Should we flip out if the file can't open?
1238 const std::string kEmptyFile("foobarinvalidfiledoesnotexist.bfbs");
Austin Schuh11d43732020-09-21 17:28:30 -07001239
Austin Schuh3bd4c402020-11-06 18:19:06 -08001240 aos::util::WriteStringToFileOrDie(kEmptyFile, "");
1241 logfiles_.emplace_back(kEmptyFile);
Austin Schuh5212cad2020-09-09 23:12:09 -07001242
Austin Schuh3bd4c402020-11-06 18:19:06 -08001243 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1244 VerifyParts(sorted_parts, {kEmptyFile});
Austin Schuh5212cad2020-09-09 23:12:09 -07001245}
1246
Austin Schuh3bd4c402020-11-06 18:19:06 -08001247#ifdef LZMA
1248// Tests that we can sort a bunch of parts with an empty .xz file in there. The
1249// empty file should be ignored.
1250TEST_F(MultinodeLoggerTest, SortEmptyCompressedParts) {
1251 // Make a bunch of parts.
1252 {
1253 LoggerState pi1_logger = MakeLogger(pi1_);
1254 LoggerState pi2_logger = MakeLogger(pi2_);
1255
1256 event_loop_factory_.RunFor(chrono::milliseconds(95));
1257
1258 StartLogger(&pi1_logger, "", true);
1259 StartLogger(&pi2_logger, "", true);
1260
1261 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1262 }
1263
1264 // TODO(austin): Should we flip out if the file can't open?
1265 const std::string kEmptyFile("foobarinvalidfiledoesnotexist.bfbs.xz");
1266
1267 AddExtension(".xz");
1268
1269 aos::util::WriteStringToFileOrDie(kEmptyFile, "");
1270 logfiles_.emplace_back(kEmptyFile);
1271
1272 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1273 VerifyParts(sorted_parts, {kEmptyFile});
1274}
1275
1276// Tests that we can sort a bunch of parts with the end missing off a compressed
1277// file. We should use the part we can read.
1278TEST_F(MultinodeLoggerTest, SortTruncatedCompressedParts) {
1279 // Make a bunch of parts.
1280 {
1281 LoggerState pi1_logger = MakeLogger(pi1_);
1282 LoggerState pi2_logger = MakeLogger(pi2_);
1283
1284 event_loop_factory_.RunFor(chrono::milliseconds(95));
1285
1286 StartLogger(&pi1_logger, "", true);
1287 StartLogger(&pi2_logger, "", true);
1288
1289 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1290 }
1291
1292 // Append everything with .xz.
1293 AddExtension(".xz");
1294
1295 // Strip off the end of one of the files. Pick one with a lot of data.
1296 ::std::string compressed_contents =
1297 aos::util::ReadFileToStringOrDie(logfiles_[0]);
1298
1299 aos::util::WriteStringToFileOrDie(
1300 logfiles_[0],
1301 compressed_contents.substr(0, compressed_contents.size() - 100));
1302
1303 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1304 VerifyParts(sorted_parts);
1305}
1306#endif
1307
Austin Schuh01b4c352020-09-21 23:09:39 -07001308// Tests that if we remap a remapped channel, it shows up correctly.
1309TEST_F(MultinodeLoggerTest, RemapLoggedChannel) {
1310 {
1311 LoggerState pi1_logger = MakeLogger(pi1_);
1312 LoggerState pi2_logger = MakeLogger(pi2_);
1313
1314 event_loop_factory_.RunFor(chrono::milliseconds(95));
1315
1316 StartLogger(&pi1_logger);
1317 StartLogger(&pi2_logger);
1318
1319 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1320 }
1321
Austin Schuh287d43d2020-12-04 20:19:33 -08001322 LogReader reader(SortParts(logfiles_));
Austin Schuh01b4c352020-09-21 23:09:39 -07001323
1324 // Remap just on pi1.
1325 reader.RemapLoggedChannel<aos::timing::Report>(
1326 "/aos", configuration::GetNode(reader.configuration(), "pi1"));
1327
1328 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1329 log_reader_factory.set_send_delay(chrono::microseconds(0));
1330
1331 reader.Register(&log_reader_factory);
1332
1333 const Node *pi1 =
1334 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1335 const Node *pi2 =
1336 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1337
1338 // Confirm we can read the data on the remapped channel, just for pi1. Nothing
1339 // else should have moved.
1340 std::unique_ptr<EventLoop> pi1_event_loop =
1341 log_reader_factory.MakeEventLoop("test", pi1);
1342 pi1_event_loop->SkipTimingReport();
1343 std::unique_ptr<EventLoop> full_pi1_event_loop =
1344 log_reader_factory.MakeEventLoop("test", pi1);
1345 full_pi1_event_loop->SkipTimingReport();
1346 std::unique_ptr<EventLoop> pi2_event_loop =
1347 log_reader_factory.MakeEventLoop("test", pi2);
1348 pi2_event_loop->SkipTimingReport();
1349
1350 MessageCounter<aos::timing::Report> pi1_timing_report(pi1_event_loop.get(),
1351 "/aos");
1352 MessageCounter<aos::timing::Report> full_pi1_timing_report(
1353 full_pi1_event_loop.get(), "/pi1/aos");
1354 MessageCounter<aos::timing::Report> pi1_original_timing_report(
1355 pi1_event_loop.get(), "/original/aos");
1356 MessageCounter<aos::timing::Report> full_pi1_original_timing_report(
1357 full_pi1_event_loop.get(), "/original/pi1/aos");
1358 MessageCounter<aos::timing::Report> pi2_timing_report(pi2_event_loop.get(),
1359 "/aos");
1360
1361 log_reader_factory.Run();
1362
1363 EXPECT_EQ(pi1_timing_report.count(), 0u);
1364 EXPECT_EQ(full_pi1_timing_report.count(), 0u);
1365 EXPECT_NE(pi1_original_timing_report.count(), 0u);
1366 EXPECT_NE(full_pi1_original_timing_report.count(), 0u);
1367 EXPECT_NE(pi2_timing_report.count(), 0u);
1368
1369 reader.Deregister();
1370}
1371
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001372// Tests that we properly recreate forwarded timestamps when replaying a log.
1373// This should be enough that we can then re-run the logger and get a valid log
1374// back.
1375TEST_F(MultinodeLoggerTest, MessageHeader) {
1376 {
1377 LoggerState pi1_logger = MakeLogger(pi1_);
1378 LoggerState pi2_logger = MakeLogger(pi2_);
1379
1380 event_loop_factory_.RunFor(chrono::milliseconds(95));
1381
1382 StartLogger(&pi1_logger);
1383 StartLogger(&pi2_logger);
1384
1385 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1386 }
1387
Austin Schuh287d43d2020-12-04 20:19:33 -08001388 LogReader reader(SortParts(logfiles_));
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001389
1390 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1391 log_reader_factory.set_send_delay(chrono::microseconds(0));
1392
1393 // This sends out the fetched messages and advances time to the start of the
1394 // log file.
1395 reader.Register(&log_reader_factory);
1396
1397 const Node *pi1 =
1398 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1399 const Node *pi2 =
1400 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1401
1402 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
1403 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
1404 LOG(INFO) << "now pi1 "
1405 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
1406 LOG(INFO) << "now pi2 "
1407 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
1408
1409 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1410
1411 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1412
1413 std::unique_ptr<EventLoop> pi1_event_loop =
1414 log_reader_factory.MakeEventLoop("test", pi1);
1415 std::unique_ptr<EventLoop> pi2_event_loop =
1416 log_reader_factory.MakeEventLoop("test", pi2);
1417
1418 MessageCounter<MessageHeader> pi1_original_message_header_counter(
1419 pi1_event_loop.get(), "/original/aos/remote_timestamps/pi2");
1420 MessageCounter<MessageHeader> pi2_original_message_header_counter(
1421 pi2_event_loop.get(), "/original/aos/remote_timestamps/pi1");
1422
1423 aos::Fetcher<message_bridge::Timestamp> pi1_timestamp_on_pi1_fetcher =
1424 pi1_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi1/aos");
1425 aos::Fetcher<message_bridge::Timestamp> pi1_timestamp_on_pi2_fetcher =
1426 pi2_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi1/aos");
1427
1428 aos::Fetcher<examples::Ping> ping_on_pi1_fetcher =
1429 pi1_event_loop->MakeFetcher<examples::Ping>("/test");
1430 aos::Fetcher<examples::Ping> ping_on_pi2_fetcher =
1431 pi2_event_loop->MakeFetcher<examples::Ping>("/test");
1432
1433 aos::Fetcher<message_bridge::Timestamp> pi2_timestamp_on_pi2_fetcher =
1434 pi2_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi2/aos");
1435 aos::Fetcher<message_bridge::Timestamp> pi2_timestamp_on_pi1_fetcher =
1436 pi1_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi2/aos");
1437
1438 aos::Fetcher<examples::Pong> pong_on_pi2_fetcher =
1439 pi2_event_loop->MakeFetcher<examples::Pong>("/test");
1440 aos::Fetcher<examples::Pong> pong_on_pi1_fetcher =
1441 pi1_event_loop->MakeFetcher<examples::Pong>("/test");
1442
1443 const size_t pi1_timestamp_channel = configuration::ChannelIndex(
1444 pi1_event_loop->configuration(), pi1_timestamp_on_pi1_fetcher.channel());
1445 const size_t ping_timestamp_channel = configuration::ChannelIndex(
1446 pi2_event_loop->configuration(), ping_on_pi2_fetcher.channel());
1447
1448 const size_t pi2_timestamp_channel = configuration::ChannelIndex(
1449 pi2_event_loop->configuration(), pi2_timestamp_on_pi2_fetcher.channel());
1450 const size_t pong_timestamp_channel = configuration::ChannelIndex(
1451 pi1_event_loop->configuration(), pong_on_pi1_fetcher.channel());
1452
1453 pi1_event_loop->MakeWatcher(
1454 "/aos/remote_timestamps/pi2",
1455 [&pi1_event_loop, pi1_timestamp_channel, ping_timestamp_channel,
1456 &pi1_timestamp_on_pi1_fetcher, &pi1_timestamp_on_pi2_fetcher,
1457 &ping_on_pi1_fetcher,
1458 &ping_on_pi2_fetcher](const MessageHeader &header) {
1459 const aos::monotonic_clock::time_point header_monotonic_sent_time(
1460 chrono::nanoseconds(header.monotonic_sent_time()));
1461 const aos::realtime_clock::time_point header_realtime_sent_time(
1462 chrono::nanoseconds(header.realtime_sent_time()));
1463 const aos::monotonic_clock::time_point header_monotonic_remote_time(
1464 chrono::nanoseconds(header.monotonic_remote_time()));
1465 const aos::realtime_clock::time_point header_realtime_remote_time(
1466 chrono::nanoseconds(header.realtime_remote_time()));
1467
1468 const Context *pi1_context = nullptr;
1469 const Context *pi2_context = nullptr;
1470
1471 if (header.channel_index() == pi1_timestamp_channel) {
1472 ASSERT_TRUE(pi1_timestamp_on_pi1_fetcher.FetchNext());
1473 ASSERT_TRUE(pi1_timestamp_on_pi2_fetcher.FetchNext());
1474 pi1_context = &pi1_timestamp_on_pi1_fetcher.context();
1475 pi2_context = &pi1_timestamp_on_pi2_fetcher.context();
1476 } else if (header.channel_index() == ping_timestamp_channel) {
1477 ASSERT_TRUE(ping_on_pi1_fetcher.FetchNext());
1478 ASSERT_TRUE(ping_on_pi2_fetcher.FetchNext());
1479 pi1_context = &ping_on_pi1_fetcher.context();
1480 pi2_context = &ping_on_pi2_fetcher.context();
1481 } else {
1482 LOG(FATAL) << "Unknown channel " << FlatbufferToJson(&header) << " "
1483 << configuration::CleanedChannelToString(
1484 pi1_event_loop->configuration()->channels()->Get(
1485 header.channel_index()));
1486 }
1487
1488 EXPECT_EQ(pi1_context->queue_index, header.remote_queue_index());
1489 EXPECT_EQ(pi2_context->remote_queue_index, header.remote_queue_index());
1490 EXPECT_EQ(pi2_context->queue_index, header.queue_index());
1491
1492 EXPECT_EQ(pi2_context->monotonic_event_time,
1493 header_monotonic_sent_time);
1494 EXPECT_EQ(pi2_context->realtime_event_time, header_realtime_sent_time);
1495 EXPECT_EQ(pi2_context->realtime_remote_time,
1496 header_realtime_remote_time);
1497 EXPECT_EQ(pi2_context->monotonic_remote_time,
1498 header_monotonic_remote_time);
1499
1500 EXPECT_EQ(pi1_context->realtime_event_time,
1501 header_realtime_remote_time);
1502 EXPECT_EQ(pi1_context->monotonic_event_time,
1503 header_monotonic_remote_time);
1504 });
1505 pi2_event_loop->MakeWatcher(
1506 "/aos/remote_timestamps/pi1",
1507 [&pi2_event_loop, pi2_timestamp_channel, pong_timestamp_channel,
1508 &pi2_timestamp_on_pi2_fetcher, &pi2_timestamp_on_pi1_fetcher,
1509 &pong_on_pi2_fetcher,
1510 &pong_on_pi1_fetcher](const MessageHeader &header) {
1511 const aos::monotonic_clock::time_point header_monotonic_sent_time(
1512 chrono::nanoseconds(header.monotonic_sent_time()));
1513 const aos::realtime_clock::time_point header_realtime_sent_time(
1514 chrono::nanoseconds(header.realtime_sent_time()));
1515 const aos::monotonic_clock::time_point header_monotonic_remote_time(
1516 chrono::nanoseconds(header.monotonic_remote_time()));
1517 const aos::realtime_clock::time_point header_realtime_remote_time(
1518 chrono::nanoseconds(header.realtime_remote_time()));
1519
1520 const Context *pi2_context = nullptr;
1521 const Context *pi1_context = nullptr;
1522
1523 if (header.channel_index() == pi2_timestamp_channel) {
1524 ASSERT_TRUE(pi2_timestamp_on_pi2_fetcher.FetchNext());
1525 ASSERT_TRUE(pi2_timestamp_on_pi1_fetcher.FetchNext());
1526 pi2_context = &pi2_timestamp_on_pi2_fetcher.context();
1527 pi1_context = &pi2_timestamp_on_pi1_fetcher.context();
1528 } else if (header.channel_index() == pong_timestamp_channel) {
1529 ASSERT_TRUE(pong_on_pi2_fetcher.FetchNext());
1530 ASSERT_TRUE(pong_on_pi1_fetcher.FetchNext());
1531 pi2_context = &pong_on_pi2_fetcher.context();
1532 pi1_context = &pong_on_pi1_fetcher.context();
1533 } else {
1534 LOG(FATAL) << "Unknown channel " << FlatbufferToJson(&header) << " "
1535 << configuration::CleanedChannelToString(
1536 pi2_event_loop->configuration()->channels()->Get(
1537 header.channel_index()));
1538 }
1539
1540 EXPECT_EQ(pi2_context->queue_index, header.remote_queue_index());
1541 EXPECT_EQ(pi1_context->remote_queue_index, header.remote_queue_index());
1542 EXPECT_EQ(pi1_context->queue_index, header.queue_index());
1543
1544 EXPECT_EQ(pi1_context->monotonic_event_time,
1545 header_monotonic_sent_time);
1546 EXPECT_EQ(pi1_context->realtime_event_time, header_realtime_sent_time);
1547 EXPECT_EQ(pi1_context->realtime_remote_time,
1548 header_realtime_remote_time);
1549 EXPECT_EQ(pi1_context->monotonic_remote_time,
1550 header_monotonic_remote_time);
1551
1552 EXPECT_EQ(pi2_context->realtime_event_time,
1553 header_realtime_remote_time);
1554 EXPECT_EQ(pi2_context->monotonic_event_time,
1555 header_monotonic_remote_time);
1556 });
1557
1558 // And confirm we can re-create a log again, while checking the contents.
1559 {
1560 LoggerState pi1_logger = MakeLogger(
1561 configuration::GetNode(log_reader_factory.configuration(), pi1_),
1562 &log_reader_factory);
1563 LoggerState pi2_logger = MakeLogger(
1564 configuration::GetNode(log_reader_factory.configuration(), pi2_),
1565 &log_reader_factory);
1566
1567 StartLogger(&pi1_logger, "relogged");
1568 StartLogger(&pi2_logger, "relogged");
1569
1570 log_reader_factory.Run();
1571 }
1572
1573 EXPECT_EQ(pi2_original_message_header_counter.count(), 0u);
1574 EXPECT_EQ(pi1_original_message_header_counter.count(), 0u);
1575
1576 reader.Deregister();
1577}
1578
Austin Schuh8bd96322020-02-13 21:18:22 -08001579// TODO(austin): We can write a test which recreates a logfile and confirms that
1580// we get it back. That is the ultimate test.
1581
Austin Schuhe309d2a2019-11-29 13:25:21 -08001582} // namespace testing
1583} // namespace logger
1584} // namespace aos