blob: 57d274b7188a2293dd317ece71e08feb923f8eb8 [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
15namespace aos {
16namespace logger {
17namespace testing {
18
19namespace chrono = std::chrono;
Austin Schuh01b4c352020-09-21 23:09:39 -070020using aos::testing::MessageCounter;
Austin Schuhe309d2a2019-11-29 13:25:21 -080021
22class LoggerTest : public ::testing::Test {
23 public:
24 LoggerTest()
25 : config_(
26 aos::configuration::ReadConfig("aos/events/pingpong_config.json")),
27 event_loop_factory_(&config_.message()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080028 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080029 ping_(ping_event_loop_.get()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080030 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080031 pong_(pong_event_loop_.get()) {}
32
33 // Config and factory.
34 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
35 SimulatedEventLoopFactory event_loop_factory_;
36
37 // Event loop and app for Ping
38 std::unique_ptr<EventLoop> ping_event_loop_;
39 Ping ping_;
40
41 // Event loop and app for Pong
42 std::unique_ptr<EventLoop> pong_event_loop_;
43 Pong pong_;
44};
45
Brian Silverman1f345222020-09-24 21:14:48 -070046using LoggerDeathTest = LoggerTest;
47
Austin Schuhe309d2a2019-11-29 13:25:21 -080048// Tests that we can startup at all. This confirms that the channels are all in
49// the config.
50TEST_F(LoggerTest, Starts) {
Austin Schuhc243b422020-10-11 15:35:08 -070051 const ::std::string tmpdir = aos::testing::TestTmpDir();
Austin Schuh2f8fd752020-09-01 22:38:28 -070052 const ::std::string base_name = tmpdir + "/logfile";
53 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuhe309d2a2019-11-29 13:25:21 -080054 // Remove it.
55 unlink(logfile.c_str());
56
57 LOG(INFO) << "Logging data to " << logfile;
58
59 {
Austin Schuhe309d2a2019-11-29 13:25:21 -080060 std::unique_ptr<EventLoop> logger_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080061 event_loop_factory_.MakeEventLoop("logger");
Austin Schuhe309d2a2019-11-29 13:25:21 -080062
63 event_loop_factory_.RunFor(chrono::milliseconds(95));
64
Brian Silverman1f345222020-09-24 21:14:48 -070065 Logger logger(logger_event_loop.get());
66 logger.set_polling_period(std::chrono::milliseconds(100));
67 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuhe309d2a2019-11-29 13:25:21 -080068 event_loop_factory_.RunFor(chrono::milliseconds(20000));
69 }
70
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080071 // Even though it doesn't make any difference here, exercise the logic for
72 // passing in a separate config.
73 LogReader reader(logfile, &config_.message());
Austin Schuhe309d2a2019-11-29 13:25:21 -080074
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080075 // Confirm that we can remap logged channels to point to new buses.
76 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
Austin Schuhe309d2a2019-11-29 13:25:21 -080077
Austin Schuh15649d62019-12-28 16:36:38 -080078 // This sends out the fetched messages and advances time to the start of the
79 // log file.
James Kuszmaul84ff3e52020-01-03 19:48:53 -080080 reader.Register();
Austin Schuhe309d2a2019-11-29 13:25:21 -080081
Austin Schuh6f3babe2020-01-26 20:34:50 -080082 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
James Kuszmaul84ff3e52020-01-03 19:48:53 -080083
Austin Schuhe309d2a2019-11-29 13:25:21 -080084 std::unique_ptr<EventLoop> test_event_loop =
James Kuszmaul84ff3e52020-01-03 19:48:53 -080085 reader.event_loop_factory()->MakeEventLoop("log_reader");
Austin Schuhe309d2a2019-11-29 13:25:21 -080086
87 int ping_count = 10;
88 int pong_count = 10;
89
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080090 // Confirm that the ping value matches in the remapped channel location.
91 test_event_loop->MakeWatcher("/original/test",
Austin Schuhe309d2a2019-11-29 13:25:21 -080092 [&ping_count](const examples::Ping &ping) {
93 EXPECT_EQ(ping.value(), ping_count + 1);
94 ++ping_count;
95 });
96 // Confirm that the ping and pong counts both match, and the value also
97 // matches.
98 test_event_loop->MakeWatcher(
99 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
100 EXPECT_EQ(pong.value(), pong_count + 1);
101 ++pong_count;
102 EXPECT_EQ(ping_count, pong_count);
103 });
104
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800105 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
Austin Schuhe309d2a2019-11-29 13:25:21 -0800106 EXPECT_EQ(ping_count, 2010);
Austin Schuhe309d2a2019-11-29 13:25:21 -0800107}
108
Brian Silverman1f345222020-09-24 21:14:48 -0700109// Tests calling StartLogging twice.
110TEST_F(LoggerDeathTest, ExtraStart) {
111 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
112 const ::std::string base_name1 = tmpdir + "/logfile1";
113 const ::std::string logfile1 = base_name1 + ".part0.bfbs";
114 const ::std::string base_name2 = tmpdir + "/logfile2";
115 const ::std::string logfile2 = base_name2 + ".part0.bfbs";
116 unlink(logfile1.c_str());
117 unlink(logfile2.c_str());
118
119 LOG(INFO) << "Logging data to " << logfile1 << " then " << logfile2;
120
121 {
122 std::unique_ptr<EventLoop> logger_event_loop =
123 event_loop_factory_.MakeEventLoop("logger");
124
125 event_loop_factory_.RunFor(chrono::milliseconds(95));
126
127 Logger logger(logger_event_loop.get());
128 logger.set_polling_period(std::chrono::milliseconds(100));
129 logger_event_loop->OnRun(
130 [base_name1, base_name2, &logger_event_loop, &logger]() {
131 logger.StartLogging(std::make_unique<LocalLogNamer>(
132 base_name1, logger_event_loop->node()));
133 EXPECT_DEATH(logger.StartLogging(std::make_unique<LocalLogNamer>(
134 base_name2, logger_event_loop->node())),
135 "Already logging");
136 });
137 event_loop_factory_.RunFor(chrono::milliseconds(20000));
138 }
139}
140
141// Tests calling StopLogging twice.
142TEST_F(LoggerDeathTest, ExtraStop) {
143 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
144 const ::std::string base_name = tmpdir + "/logfile";
145 const ::std::string logfile = base_name + ".part0.bfbs";
146 // Remove it.
147 unlink(logfile.c_str());
148
149 LOG(INFO) << "Logging data to " << logfile;
150
151 {
152 std::unique_ptr<EventLoop> logger_event_loop =
153 event_loop_factory_.MakeEventLoop("logger");
154
155 event_loop_factory_.RunFor(chrono::milliseconds(95));
156
157 Logger logger(logger_event_loop.get());
158 logger.set_polling_period(std::chrono::milliseconds(100));
159 logger_event_loop->OnRun([base_name, &logger_event_loop, &logger]() {
160 logger.StartLogging(std::make_unique<LocalLogNamer>(
161 base_name, logger_event_loop->node()));
162 logger.StopLogging(aos::monotonic_clock::min_time);
163 EXPECT_DEATH(logger.StopLogging(aos::monotonic_clock::min_time),
164 "Not logging right now");
165 });
166 event_loop_factory_.RunFor(chrono::milliseconds(20000));
167 }
168}
169
170// Tests that we can startup twice.
171TEST_F(LoggerTest, StartsTwice) {
172 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
173 const ::std::string base_name1 = tmpdir + "/logfile1";
174 const ::std::string logfile1 = base_name1 + ".part0.bfbs";
175 const ::std::string base_name2 = tmpdir + "/logfile2";
176 const ::std::string logfile2 = base_name2 + ".part0.bfbs";
177 unlink(logfile1.c_str());
178 unlink(logfile2.c_str());
179
180 LOG(INFO) << "Logging data to " << logfile1 << " then " << logfile2;
181
182 {
183 std::unique_ptr<EventLoop> logger_event_loop =
184 event_loop_factory_.MakeEventLoop("logger");
185
186 event_loop_factory_.RunFor(chrono::milliseconds(95));
187
188 Logger logger(logger_event_loop.get());
189 logger.set_polling_period(std::chrono::milliseconds(100));
190 logger.StartLogging(
191 std::make_unique<LocalLogNamer>(base_name1, logger_event_loop->node()));
192 event_loop_factory_.RunFor(chrono::milliseconds(10000));
193 logger.StopLogging(logger_event_loop->monotonic_now());
194 event_loop_factory_.RunFor(chrono::milliseconds(10000));
195 logger.StartLogging(
196 std::make_unique<LocalLogNamer>(base_name2, logger_event_loop->node()));
197 event_loop_factory_.RunFor(chrono::milliseconds(10000));
198 }
199
200 for (const auto &logfile :
201 {std::make_tuple(logfile1, 10), std::make_tuple(logfile2, 2010)}) {
202 SCOPED_TRACE(std::get<0>(logfile));
203 LogReader reader(std::get<0>(logfile));
204 reader.Register();
205
206 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
207
208 std::unique_ptr<EventLoop> test_event_loop =
209 reader.event_loop_factory()->MakeEventLoop("log_reader");
210
211 int ping_count = std::get<1>(logfile);
212 int pong_count = std::get<1>(logfile);
213
214 // Confirm that the ping and pong counts both match, and the value also
215 // matches.
216 test_event_loop->MakeWatcher("/test",
217 [&ping_count](const examples::Ping &ping) {
218 EXPECT_EQ(ping.value(), ping_count + 1);
219 ++ping_count;
220 });
221 test_event_loop->MakeWatcher(
222 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
223 EXPECT_EQ(pong.value(), pong_count + 1);
224 ++pong_count;
225 EXPECT_EQ(ping_count, pong_count);
226 });
227
228 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
229 EXPECT_EQ(ping_count, std::get<1>(logfile) + 1000);
230 }
231}
232
Austin Schuhfa895892020-01-07 20:07:41 -0800233// Tests that we can read and write rotated log files.
234TEST_F(LoggerTest, RotatedLogFile) {
235 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
Austin Schuh2f8fd752020-09-01 22:38:28 -0700236 const ::std::string base_name = tmpdir + "/logfile";
237 const ::std::string logfile0 = base_name + ".part0.bfbs";
238 const ::std::string logfile1 = base_name + ".part1.bfbs";
Austin Schuhfa895892020-01-07 20:07:41 -0800239 // Remove it.
240 unlink(logfile0.c_str());
241 unlink(logfile1.c_str());
242
243 LOG(INFO) << "Logging data to " << logfile0 << " and " << logfile1;
244
245 {
Austin Schuhfa895892020-01-07 20:07:41 -0800246 std::unique_ptr<EventLoop> logger_event_loop =
247 event_loop_factory_.MakeEventLoop("logger");
248
249 event_loop_factory_.RunFor(chrono::milliseconds(95));
250
Brian Silverman1f345222020-09-24 21:14:48 -0700251 Logger logger(logger_event_loop.get());
252 logger.set_polling_period(std::chrono::milliseconds(100));
253 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuhfa895892020-01-07 20:07:41 -0800254 event_loop_factory_.RunFor(chrono::milliseconds(10000));
Austin Schuh2f8fd752020-09-01 22:38:28 -0700255 logger.Rotate();
Austin Schuhfa895892020-01-07 20:07:41 -0800256 event_loop_factory_.RunFor(chrono::milliseconds(10000));
257 }
258
Austin Schuh64fab802020-09-09 22:47:47 -0700259 {
260 // Confirm that the UUIDs match for both the parts and the logger, and the
261 // parts_index increments.
262 std::vector<FlatbufferVector<LogFileHeader>> log_header;
263 for (std::string_view f : {logfile0, logfile1}) {
264 log_header.emplace_back(ReadHeader(f));
265 }
266
Brian Silvermanae7c0332020-09-30 16:58:23 -0700267 EXPECT_EQ(log_header[0].message().log_event_uuid()->string_view(),
268 log_header[1].message().log_event_uuid()->string_view());
Austin Schuh64fab802020-09-09 22:47:47 -0700269 EXPECT_EQ(log_header[0].message().parts_uuid()->string_view(),
270 log_header[1].message().parts_uuid()->string_view());
271
272 EXPECT_EQ(log_header[0].message().parts_index(), 0);
273 EXPECT_EQ(log_header[1].message().parts_index(), 1);
274 }
275
Austin Schuhfa895892020-01-07 20:07:41 -0800276 // Even though it doesn't make any difference here, exercise the logic for
277 // passing in a separate config.
278 LogReader reader(std::vector<std::string>{logfile0, logfile1},
279 &config_.message());
280
281 // Confirm that we can remap logged channels to point to new buses.
282 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
283
284 // This sends out the fetched messages and advances time to the start of the
285 // log file.
286 reader.Register();
287
Austin Schuh6f3babe2020-01-26 20:34:50 -0800288 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
Austin Schuhfa895892020-01-07 20:07:41 -0800289
290 std::unique_ptr<EventLoop> test_event_loop =
291 reader.event_loop_factory()->MakeEventLoop("log_reader");
292
293 int ping_count = 10;
294 int pong_count = 10;
295
296 // Confirm that the ping value matches in the remapped channel location.
297 test_event_loop->MakeWatcher("/original/test",
298 [&ping_count](const examples::Ping &ping) {
299 EXPECT_EQ(ping.value(), ping_count + 1);
300 ++ping_count;
301 });
302 // Confirm that the ping and pong counts both match, and the value also
303 // matches.
304 test_event_loop->MakeWatcher(
305 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
306 EXPECT_EQ(pong.value(), pong_count + 1);
307 ++pong_count;
308 EXPECT_EQ(ping_count, pong_count);
309 });
310
311 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
312 EXPECT_EQ(ping_count, 2010);
313}
314
Austin Schuh4c4e0092019-12-22 16:18:03 -0800315// Tests that a large number of messages per second doesn't overwhelm writev.
316TEST_F(LoggerTest, ManyMessages) {
317 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
Austin Schuh2f8fd752020-09-01 22:38:28 -0700318 const ::std::string base_name = tmpdir + "/logfile";
319 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuh4c4e0092019-12-22 16:18:03 -0800320 // Remove the log file.
321 unlink(logfile.c_str());
322
323 LOG(INFO) << "Logging data to " << logfile;
Austin Schuh4c3b9702020-08-30 11:34:55 -0700324 ping_.set_quiet(true);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800325
326 {
Austin Schuh4c4e0092019-12-22 16:18:03 -0800327 std::unique_ptr<EventLoop> logger_event_loop =
328 event_loop_factory_.MakeEventLoop("logger");
329
330 std::unique_ptr<EventLoop> ping_spammer_event_loop =
331 event_loop_factory_.MakeEventLoop("ping_spammer");
332 aos::Sender<examples::Ping> ping_sender =
333 ping_spammer_event_loop->MakeSender<examples::Ping>("/test");
334
335 aos::TimerHandler *timer_handler =
336 ping_spammer_event_loop->AddTimer([&ping_sender]() {
337 aos::Sender<examples::Ping>::Builder builder =
338 ping_sender.MakeBuilder();
339 examples::Ping::Builder ping_builder =
340 builder.MakeBuilder<examples::Ping>();
341 CHECK(builder.Send(ping_builder.Finish()));
342 });
343
344 // 100 ms / 0.05 ms -> 2000 messages. Should be enough to crash it.
345 ping_spammer_event_loop->OnRun([&ping_spammer_event_loop, timer_handler]() {
346 timer_handler->Setup(ping_spammer_event_loop->monotonic_now(),
347 chrono::microseconds(50));
348 });
349
Brian Silverman1f345222020-09-24 21:14:48 -0700350 Logger logger(logger_event_loop.get());
351 logger.set_polling_period(std::chrono::milliseconds(100));
352 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800353
354 event_loop_factory_.RunFor(chrono::milliseconds(1000));
355 }
356}
357
Austin Schuh15649d62019-12-28 16:36:38 -0800358class MultinodeLoggerTest : public ::testing::Test {
359 public:
360 MultinodeLoggerTest()
361 : config_(aos::configuration::ReadConfig(
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800362 "aos/events/logging/multinode_pingpong_config.json")),
Austin Schuhac0771c2020-01-07 18:36:30 -0800363 event_loop_factory_(&config_.message()),
Austin Schuhcde938c2020-02-02 17:30:07 -0800364 pi1_(
365 configuration::GetNode(event_loop_factory_.configuration(), "pi1")),
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700366 pi2_(
367 configuration::GetNode(event_loop_factory_.configuration(), "pi2")),
368 tmp_dir_(getenv("TEST_TMPDIR")),
369 logfile_base_(tmp_dir_ + "/multi_logfile"),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700370 logfiles_(
371 {logfile_base_ + "_pi1_data.part0.bfbs",
372 logfile_base_ + "_pi2_data/test/aos.examples.Pong.part0.bfbs",
373 logfile_base_ + "_pi2_data/test/aos.examples.Pong.part1.bfbs",
374 logfile_base_ + "_pi2_data.part0.bfbs",
375 logfile_base_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
376 "aos.logger.MessageHeader.part0.bfbs",
377 logfile_base_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
378 "aos.logger.MessageHeader.part1.bfbs",
379 logfile_base_ + "_timestamps/pi2/aos/remote_timestamps/pi1/"
380 "aos.logger.MessageHeader.part0.bfbs",
381 logfile_base_ + "_timestamps/pi2/aos/remote_timestamps/pi1/"
382 "aos.logger.MessageHeader.part1.bfbs",
383 logfile_base_ +
384 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part0.bfbs",
385 logfile_base_ +
386 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part1.bfbs",
387 logfile_base_ +
388 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part0.bfbs",
389 logfile_base_ +
390 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part1.bfbs"}),
391 structured_logfiles_{
392 std::vector<std::string>{logfiles_[0]},
393 std::vector<std::string>{logfiles_[1], logfiles_[2]},
394 std::vector<std::string>{logfiles_[3]},
395 std::vector<std::string>{logfiles_[4], logfiles_[5]},
396 std::vector<std::string>{logfiles_[6], logfiles_[7]},
397 std::vector<std::string>{logfiles_[8], logfiles_[9]},
398 std::vector<std::string>{logfiles_[10], logfiles_[11]}},
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700399 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping", pi1_)),
400 ping_(ping_event_loop_.get()),
401 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong", pi2_)),
402 pong_(pong_event_loop_.get()) {
403 // Go through and remove the logfiles if they already exist.
404 for (const auto file : logfiles_) {
405 unlink(file.c_str());
406 }
407
408 LOG(INFO) << "Logging data to " << logfiles_[0] << ", " << logfiles_[1]
409 << " and " << logfiles_[2];
410 }
411
412 struct LoggerState {
413 std::unique_ptr<EventLoop> event_loop;
414 std::unique_ptr<Logger> logger;
415 };
416
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700417 LoggerState MakeLogger(const Node *node,
418 SimulatedEventLoopFactory *factory = nullptr) {
419 if (factory == nullptr) {
420 factory = &event_loop_factory_;
421 }
422 return {factory->MakeEventLoop("logger", node), {}};
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700423 }
424
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700425 void StartLogger(LoggerState *logger, std::string logfile_base = "") {
426 if (logfile_base.empty()) {
427 logfile_base = logfile_base_;
428 }
429
Brian Silverman1f345222020-09-24 21:14:48 -0700430 logger->logger = std::make_unique<Logger>(logger->event_loop.get());
431 logger->logger->set_polling_period(std::chrono::milliseconds(100));
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700432 logger->event_loop->OnRun([logger, logfile_base]() {
Brian Silverman1f345222020-09-24 21:14:48 -0700433 logger->logger->StartLogging(std::make_unique<MultiNodeLogNamer>(
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700434 logfile_base, logger->event_loop->configuration(),
Brian Silverman1f345222020-09-24 21:14:48 -0700435 logger->event_loop->node()));
436 });
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700437 }
Austin Schuh15649d62019-12-28 16:36:38 -0800438
439 // Config and factory.
440 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
441 SimulatedEventLoopFactory event_loop_factory_;
442
Austin Schuhcde938c2020-02-02 17:30:07 -0800443 const Node *pi1_;
444 const Node *pi2_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700445
446 std::string tmp_dir_;
447 std::string logfile_base_;
Austin Schuh2f8fd752020-09-01 22:38:28 -0700448 std::vector<std::string> logfiles_;
449
450 std::vector<std::vector<std::string>> structured_logfiles_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700451
452 std::unique_ptr<EventLoop> ping_event_loop_;
453 Ping ping_;
454 std::unique_ptr<EventLoop> pong_event_loop_;
455 Pong pong_;
Austin Schuh15649d62019-12-28 16:36:38 -0800456};
457
Austin Schuh391e3172020-09-01 22:48:18 -0700458// Counts the number of messages on a channel. Returns (channel name, channel
459// type, count) for every message matching matcher()
460std::vector<std::tuple<std::string, std::string, int>> CountChannelsMatching(
Austin Schuh6f3babe2020-01-26 20:34:50 -0800461 std::string_view filename,
462 std::function<bool(const MessageHeader *)> matcher) {
463 MessageReader message_reader(filename);
464 std::vector<int> counts(
465 message_reader.log_file_header()->configuration()->channels()->size(), 0);
Austin Schuh15649d62019-12-28 16:36:38 -0800466
Austin Schuh6f3babe2020-01-26 20:34:50 -0800467 while (true) {
468 std::optional<FlatbufferVector<MessageHeader>> msg =
469 message_reader.ReadMessage();
470 if (!msg) {
471 break;
472 }
473
474 if (matcher(&msg.value().message())) {
475 counts[msg.value().message().channel_index()]++;
476 }
477 }
478
Austin Schuh391e3172020-09-01 22:48:18 -0700479 std::vector<std::tuple<std::string, std::string, int>> result;
Austin Schuh6f3babe2020-01-26 20:34:50 -0800480 int channel = 0;
481 for (size_t i = 0; i < counts.size(); ++i) {
482 if (counts[i] != 0) {
Austin Schuh391e3172020-09-01 22:48:18 -0700483 const Channel *channel =
484 message_reader.log_file_header()->configuration()->channels()->Get(i);
485 result.push_back(std::make_tuple(channel->name()->str(),
486 channel->type()->str(), counts[i]));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800487 }
488 ++channel;
489 }
490
491 return result;
492}
493
494// Counts the number of messages (channel, count) for all data messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700495std::vector<std::tuple<std::string, std::string, int>> CountChannelsData(
496 std::string_view filename) {
Austin Schuh6f3babe2020-01-26 20:34:50 -0800497 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
498 if (msg->has_data()) {
499 CHECK(!msg->has_monotonic_remote_time());
500 CHECK(!msg->has_realtime_remote_time());
501 CHECK(!msg->has_remote_queue_index());
502 return true;
503 }
504 return false;
505 });
506}
507
508// Counts the number of messages (channel, count) for all timestamp messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700509std::vector<std::tuple<std::string, std::string, int>> CountChannelsTimestamp(
Austin Schuh6f3babe2020-01-26 20:34:50 -0800510 std::string_view filename) {
511 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
512 if (!msg->has_data()) {
513 CHECK(msg->has_monotonic_remote_time());
514 CHECK(msg->has_realtime_remote_time());
515 CHECK(msg->has_remote_queue_index());
516 return true;
517 }
518 return false;
519 });
520}
521
Austin Schuhcde938c2020-02-02 17:30:07 -0800522// Tests that we can write and read simple multi-node log files.
523TEST_F(MultinodeLoggerTest, SimpleMultiNode) {
Austin Schuh15649d62019-12-28 16:36:38 -0800524 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700525 LoggerState pi1_logger = MakeLogger(pi1_);
526 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuh15649d62019-12-28 16:36:38 -0800527
528 event_loop_factory_.RunFor(chrono::milliseconds(95));
529
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700530 StartLogger(&pi1_logger);
531 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800532
Austin Schuh15649d62019-12-28 16:36:38 -0800533 event_loop_factory_.RunFor(chrono::milliseconds(20000));
534 }
535
Austin Schuh6f3babe2020-01-26 20:34:50 -0800536 {
Austin Schuh64fab802020-09-09 22:47:47 -0700537 std::set<std::string> logfile_uuids;
538 std::set<std::string> parts_uuids;
539 // Confirm that we have the expected number of UUIDs for both the logfile
540 // UUIDs and parts UUIDs.
541 std::vector<FlatbufferVector<LogFileHeader>> log_header;
542 for (std::string_view f : logfiles_) {
543 log_header.emplace_back(ReadHeader(f));
Brian Silvermanae7c0332020-09-30 16:58:23 -0700544 logfile_uuids.insert(log_header.back().message().log_event_uuid()->str());
Austin Schuh64fab802020-09-09 22:47:47 -0700545 parts_uuids.insert(log_header.back().message().parts_uuid()->str());
546 }
Austin Schuh15649d62019-12-28 16:36:38 -0800547
Austin Schuh64fab802020-09-09 22:47:47 -0700548 EXPECT_EQ(logfile_uuids.size(), 2u);
549 EXPECT_EQ(parts_uuids.size(), 7u);
550
551 // And confirm everything is on the correct node.
552 EXPECT_EQ(log_header[0].message().node()->name()->string_view(), "pi1");
553 EXPECT_EQ(log_header[1].message().node()->name()->string_view(), "pi2");
554 EXPECT_EQ(log_header[2].message().node()->name()->string_view(), "pi2");
555 EXPECT_EQ(log_header[3].message().node()->name()->string_view(), "pi2");
556 EXPECT_EQ(log_header[4].message().node()->name()->string_view(), "pi2");
557 EXPECT_EQ(log_header[5].message().node()->name()->string_view(), "pi2");
558 EXPECT_EQ(log_header[6].message().node()->name()->string_view(), "pi1");
559 EXPECT_EQ(log_header[7].message().node()->name()->string_view(), "pi1");
560 EXPECT_EQ(log_header[8].message().node()->name()->string_view(), "pi1");
561 EXPECT_EQ(log_header[9].message().node()->name()->string_view(), "pi1");
562 EXPECT_EQ(log_header[10].message().node()->name()->string_view(), "pi2");
563 EXPECT_EQ(log_header[11].message().node()->name()->string_view(), "pi2");
564
565 // And the parts index matches.
566 EXPECT_EQ(log_header[0].message().parts_index(), 0);
567 EXPECT_EQ(log_header[1].message().parts_index(), 0);
568 EXPECT_EQ(log_header[2].message().parts_index(), 1);
569 EXPECT_EQ(log_header[3].message().parts_index(), 0);
570 EXPECT_EQ(log_header[4].message().parts_index(), 0);
571 EXPECT_EQ(log_header[5].message().parts_index(), 1);
572 EXPECT_EQ(log_header[6].message().parts_index(), 0);
573 EXPECT_EQ(log_header[7].message().parts_index(), 1);
574 EXPECT_EQ(log_header[8].message().parts_index(), 0);
575 EXPECT_EQ(log_header[9].message().parts_index(), 1);
576 EXPECT_EQ(log_header[10].message().parts_index(), 0);
577 EXPECT_EQ(log_header[11].message().parts_index(), 1);
578 }
579
580 {
Austin Schuh391e3172020-09-01 22:48:18 -0700581 using ::testing::UnorderedElementsAre;
582
Austin Schuh6f3babe2020-01-26 20:34:50 -0800583 // Timing reports, pings
Austin Schuh2f8fd752020-09-01 22:38:28 -0700584 EXPECT_THAT(
585 CountChannelsData(logfiles_[0]),
586 UnorderedElementsAre(
587 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200),
588 std::make_tuple("/pi1/aos", "aos.timing.Report", 40),
589 std::make_tuple("/test", "aos.examples.Ping", 2001)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800590 // Timestamps for pong
Austin Schuh2f8fd752020-09-01 22:38:28 -0700591 EXPECT_THAT(
592 CountChannelsTimestamp(logfiles_[0]),
593 UnorderedElementsAre(
594 std::make_tuple("/test", "aos.examples.Pong", 2001),
595 std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800596
597 // Pong data.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700598 EXPECT_THAT(CountChannelsData(logfiles_[1]),
Austin Schuh391e3172020-09-01 22:48:18 -0700599 UnorderedElementsAre(
Austin Schuh2f8fd752020-09-01 22:38:28 -0700600 std::make_tuple("/test", "aos.examples.Pong", 101)));
601 EXPECT_THAT(CountChannelsData(logfiles_[2]),
602 UnorderedElementsAre(
603 std::make_tuple("/test", "aos.examples.Pong", 1900)));
Austin Schuh391e3172020-09-01 22:48:18 -0700604
Austin Schuh6f3babe2020-01-26 20:34:50 -0800605 // No timestamps
Austin Schuh391e3172020-09-01 22:48:18 -0700606 EXPECT_THAT(CountChannelsTimestamp(logfiles_[1]), UnorderedElementsAre());
Austin Schuh2f8fd752020-09-01 22:38:28 -0700607 EXPECT_THAT(CountChannelsTimestamp(logfiles_[2]), UnorderedElementsAre());
Austin Schuh6f3babe2020-01-26 20:34:50 -0800608
609 // Timing reports and pongs.
Austin Schuh2f8fd752020-09-01 22:38:28 -0700610 EXPECT_THAT(
611 CountChannelsData(logfiles_[3]),
612 UnorderedElementsAre(
613 std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200),
614 std::make_tuple("/pi2/aos", "aos.timing.Report", 40),
615 std::make_tuple("/test", "aos.examples.Pong", 2001)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800616 // And ping timestamps.
Austin Schuh2f8fd752020-09-01 22:38:28 -0700617 EXPECT_THAT(
618 CountChannelsTimestamp(logfiles_[3]),
619 UnorderedElementsAre(
620 std::make_tuple("/test", "aos.examples.Ping", 2001),
621 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200)));
622
623 // Timestamps from pi2 on pi1, and the other way.
624 EXPECT_THAT(CountChannelsData(logfiles_[4]), UnorderedElementsAre());
625 EXPECT_THAT(CountChannelsData(logfiles_[5]), UnorderedElementsAre());
626 EXPECT_THAT(CountChannelsData(logfiles_[6]), UnorderedElementsAre());
627 EXPECT_THAT(CountChannelsData(logfiles_[7]), UnorderedElementsAre());
628 EXPECT_THAT(
629 CountChannelsTimestamp(logfiles_[4]),
630 UnorderedElementsAre(
631 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 10),
632 std::make_tuple("/test", "aos.examples.Ping", 101)));
633 EXPECT_THAT(
634 CountChannelsTimestamp(logfiles_[5]),
635 UnorderedElementsAre(
636 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 190),
637 std::make_tuple("/test", "aos.examples.Ping", 1900)));
638 EXPECT_THAT(CountChannelsTimestamp(logfiles_[6]),
639 UnorderedElementsAre(std::make_tuple(
640 "/pi2/aos", "aos.message_bridge.Timestamp", 10)));
641 EXPECT_THAT(CountChannelsTimestamp(logfiles_[7]),
642 UnorderedElementsAre(std::make_tuple(
643 "/pi2/aos", "aos.message_bridge.Timestamp", 190)));
644
645 // And then test that the remotely logged timestamp data files only have
646 // timestamps in them.
647 EXPECT_THAT(CountChannelsTimestamp(logfiles_[8]), UnorderedElementsAre());
648 EXPECT_THAT(CountChannelsTimestamp(logfiles_[9]), UnorderedElementsAre());
649 EXPECT_THAT(CountChannelsTimestamp(logfiles_[10]), UnorderedElementsAre());
650 EXPECT_THAT(CountChannelsTimestamp(logfiles_[11]), UnorderedElementsAre());
651
652 EXPECT_THAT(CountChannelsData(logfiles_[8]),
653 UnorderedElementsAre(std::make_tuple(
654 "/pi1/aos", "aos.message_bridge.Timestamp", 10)));
655 EXPECT_THAT(CountChannelsData(logfiles_[9]),
656 UnorderedElementsAre(std::make_tuple(
657 "/pi1/aos", "aos.message_bridge.Timestamp", 190)));
658
659 EXPECT_THAT(CountChannelsData(logfiles_[10]),
660 UnorderedElementsAre(std::make_tuple(
661 "/pi2/aos", "aos.message_bridge.Timestamp", 10)));
662 EXPECT_THAT(CountChannelsData(logfiles_[11]),
663 UnorderedElementsAre(std::make_tuple(
664 "/pi2/aos", "aos.message_bridge.Timestamp", 190)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800665 }
666
Austin Schuh2f8fd752020-09-01 22:38:28 -0700667 LogReader reader(structured_logfiles_);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800668
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700669 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuh6331ef92020-01-07 18:28:09 -0800670 log_reader_factory.set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800671
672 // This sends out the fetched messages and advances time to the start of the
673 // log file.
Austin Schuh6331ef92020-01-07 18:28:09 -0800674 reader.Register(&log_reader_factory);
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800675
Austin Schuhac0771c2020-01-07 18:36:30 -0800676 const Node *pi1 =
677 configuration::GetNode(log_reader_factory.configuration(), "pi1");
Austin Schuh6f3babe2020-01-26 20:34:50 -0800678 const Node *pi2 =
679 configuration::GetNode(log_reader_factory.configuration(), "pi2");
Austin Schuhac0771c2020-01-07 18:36:30 -0800680
Austin Schuh2f8fd752020-09-01 22:38:28 -0700681 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
682 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
683 LOG(INFO) << "now pi1 "
684 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
685 LOG(INFO) << "now pi2 "
686 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
687
Austin Schuh6f3babe2020-01-26 20:34:50 -0800688 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800689
690 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800691
Austin Schuh6f3babe2020-01-26 20:34:50 -0800692 std::unique_ptr<EventLoop> pi1_event_loop =
Austin Schuhac0771c2020-01-07 18:36:30 -0800693 log_reader_factory.MakeEventLoop("test", pi1);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800694 std::unique_ptr<EventLoop> pi2_event_loop =
695 log_reader_factory.MakeEventLoop("test", pi2);
Austin Schuh15649d62019-12-28 16:36:38 -0800696
Austin Schuh6f3babe2020-01-26 20:34:50 -0800697 int pi1_ping_count = 10;
698 int pi2_ping_count = 10;
699 int pi1_pong_count = 10;
700 int pi2_pong_count = 10;
Austin Schuh15649d62019-12-28 16:36:38 -0800701
702 // Confirm that the ping value matches.
Austin Schuh6f3babe2020-01-26 20:34:50 -0800703 pi1_event_loop->MakeWatcher(
704 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
Austin Schuh2f8fd752020-09-01 22:38:28 -0700705 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping) << " at "
Austin Schuh6f3babe2020-01-26 20:34:50 -0800706 << pi1_event_loop->context().monotonic_remote_time << " -> "
707 << pi1_event_loop->context().monotonic_event_time;
708 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
709 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
710 pi1_ping_count * chrono::milliseconds(10) +
711 monotonic_clock::epoch());
712 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
713 pi1_ping_count * chrono::milliseconds(10) +
714 realtime_clock::epoch());
715 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
716 pi1_event_loop->context().monotonic_event_time);
717 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
718 pi1_event_loop->context().realtime_event_time);
Austin Schuh15649d62019-12-28 16:36:38 -0800719
Austin Schuh6f3babe2020-01-26 20:34:50 -0800720 ++pi1_ping_count;
721 });
722 pi2_event_loop->MakeWatcher(
723 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
Austin Schuh2f8fd752020-09-01 22:38:28 -0700724 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping) << " at "
Austin Schuh6f3babe2020-01-26 20:34:50 -0800725 << pi2_event_loop->context().monotonic_remote_time << " -> "
726 << pi2_event_loop->context().monotonic_event_time;
727 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
728
729 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
730 pi2_ping_count * chrono::milliseconds(10) +
731 monotonic_clock::epoch());
732 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
733 pi2_ping_count * chrono::milliseconds(10) +
734 realtime_clock::epoch());
735 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time +
736 chrono::microseconds(150),
737 pi2_event_loop->context().monotonic_event_time);
738 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time +
739 chrono::microseconds(150),
740 pi2_event_loop->context().realtime_event_time);
741 ++pi2_ping_count;
Austin Schuh15649d62019-12-28 16:36:38 -0800742 });
743
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700744 constexpr ssize_t kQueueIndexOffset = -9;
Austin Schuh6f3babe2020-01-26 20:34:50 -0800745 // Confirm that the ping and pong counts both match, and the value also
746 // matches.
747 pi1_event_loop->MakeWatcher(
748 "/test", [&pi1_event_loop, &pi1_ping_count,
749 &pi1_pong_count](const examples::Pong &pong) {
750 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
751 << pi1_event_loop->context().monotonic_remote_time << " -> "
752 << pi1_event_loop->context().monotonic_event_time;
753
754 EXPECT_EQ(pi1_event_loop->context().remote_queue_index,
755 pi1_pong_count + kQueueIndexOffset);
756 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
757 chrono::microseconds(200) +
758 pi1_pong_count * chrono::milliseconds(10) +
759 monotonic_clock::epoch());
760 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
761 chrono::microseconds(200) +
762 pi1_pong_count * chrono::milliseconds(10) +
763 realtime_clock::epoch());
764
765 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time +
766 chrono::microseconds(150),
767 pi1_event_loop->context().monotonic_event_time);
768 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time +
769 chrono::microseconds(150),
770 pi1_event_loop->context().realtime_event_time);
771
772 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
773 ++pi1_pong_count;
774 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
775 });
776 pi2_event_loop->MakeWatcher(
777 "/test", [&pi2_event_loop, &pi2_ping_count,
778 &pi2_pong_count](const examples::Pong &pong) {
779 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
780 << pi2_event_loop->context().monotonic_remote_time << " -> "
781 << pi2_event_loop->context().monotonic_event_time;
782
783 EXPECT_EQ(pi2_event_loop->context().remote_queue_index,
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700784 pi2_pong_count + kQueueIndexOffset);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800785
786 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
787 chrono::microseconds(200) +
788 pi2_pong_count * chrono::milliseconds(10) +
789 monotonic_clock::epoch());
790 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
791 chrono::microseconds(200) +
792 pi2_pong_count * chrono::milliseconds(10) +
793 realtime_clock::epoch());
794
795 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
796 pi2_event_loop->context().monotonic_event_time);
797 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
798 pi2_event_loop->context().realtime_event_time);
799
800 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
801 ++pi2_pong_count;
802 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
803 });
804
805 log_reader_factory.Run();
806 EXPECT_EQ(pi1_ping_count, 2010);
807 EXPECT_EQ(pi2_ping_count, 2010);
808 EXPECT_EQ(pi1_pong_count, 2010);
809 EXPECT_EQ(pi2_pong_count, 2010);
Austin Schuh6331ef92020-01-07 18:28:09 -0800810
811 reader.Deregister();
Austin Schuh15649d62019-12-28 16:36:38 -0800812}
813
James Kuszmaul46d82582020-05-09 19:50:09 -0700814typedef MultinodeLoggerTest MultinodeLoggerDeathTest;
815
816// Test that if we feed the replay with a mismatched node list that we die on
817// the LogReader constructor.
818TEST_F(MultinodeLoggerDeathTest, MultiNodeBadReplayConfig) {
James Kuszmaul46d82582020-05-09 19:50:09 -0700819 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700820 LoggerState pi1_logger = MakeLogger(pi1_);
821 LoggerState pi2_logger = MakeLogger(pi2_);
James Kuszmaul46d82582020-05-09 19:50:09 -0700822
823 event_loop_factory_.RunFor(chrono::milliseconds(95));
824
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700825 StartLogger(&pi1_logger);
826 StartLogger(&pi2_logger);
James Kuszmaul46d82582020-05-09 19:50:09 -0700827
James Kuszmaul46d82582020-05-09 19:50:09 -0700828 event_loop_factory_.RunFor(chrono::milliseconds(20000));
829 }
830
831 // Test that, if we add an additional node to the replay config that the
832 // logger complains about the mismatch in number of nodes.
833 FlatbufferDetachedBuffer<Configuration> extra_nodes_config =
834 configuration::MergeWithConfig(&config_.message(), R"({
835 "nodes": [
836 {
837 "name": "extra-node"
838 }
839 ]
840 }
841 )");
842
Austin Schuh2f8fd752020-09-01 22:38:28 -0700843 EXPECT_DEATH(LogReader(structured_logfiles_, &extra_nodes_config.message()),
James Kuszmaul46d82582020-05-09 19:50:09 -0700844 "Log file and replay config need to have matching nodes lists.");
James Kuszmaul46d82582020-05-09 19:50:09 -0700845}
846
Austin Schuhcde938c2020-02-02 17:30:07 -0800847// Tests that we can read log files where they don't start at the same monotonic
848// time.
849TEST_F(MultinodeLoggerTest, StaggeredStart) {
Austin Schuhcde938c2020-02-02 17:30:07 -0800850 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700851 LoggerState pi1_logger = MakeLogger(pi1_);
852 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuhcde938c2020-02-02 17:30:07 -0800853
854 event_loop_factory_.RunFor(chrono::milliseconds(95));
855
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700856 StartLogger(&pi1_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800857
858 event_loop_factory_.RunFor(chrono::milliseconds(200));
859
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700860 StartLogger(&pi2_logger);
861
Austin Schuhcde938c2020-02-02 17:30:07 -0800862 event_loop_factory_.RunFor(chrono::milliseconds(20000));
863 }
864
Austin Schuh2f8fd752020-09-01 22:38:28 -0700865 LogReader reader(structured_logfiles_);
Austin Schuhcde938c2020-02-02 17:30:07 -0800866
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700867 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuhcde938c2020-02-02 17:30:07 -0800868 log_reader_factory.set_send_delay(chrono::microseconds(0));
869
870 // This sends out the fetched messages and advances time to the start of the
871 // log file.
872 reader.Register(&log_reader_factory);
873
874 const Node *pi1 =
875 configuration::GetNode(log_reader_factory.configuration(), "pi1");
876 const Node *pi2 =
877 configuration::GetNode(log_reader_factory.configuration(), "pi2");
878
879 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
880
881 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
882
883 std::unique_ptr<EventLoop> pi1_event_loop =
884 log_reader_factory.MakeEventLoop("test", pi1);
885 std::unique_ptr<EventLoop> pi2_event_loop =
886 log_reader_factory.MakeEventLoop("test", pi2);
887
888 int pi1_ping_count = 30;
889 int pi2_ping_count = 30;
890 int pi1_pong_count = 30;
891 int pi2_pong_count = 30;
892
893 // Confirm that the ping value matches.
894 pi1_event_loop->MakeWatcher(
895 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
896 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
897 << pi1_event_loop->context().monotonic_remote_time << " -> "
898 << pi1_event_loop->context().monotonic_event_time;
899 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
900
901 ++pi1_ping_count;
902 });
903 pi2_event_loop->MakeWatcher(
904 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
905 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
906 << pi2_event_loop->context().monotonic_remote_time << " -> "
907 << pi2_event_loop->context().monotonic_event_time;
908 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
909
910 ++pi2_ping_count;
911 });
912
913 // Confirm that the ping and pong counts both match, and the value also
914 // matches.
915 pi1_event_loop->MakeWatcher(
916 "/test", [&pi1_event_loop, &pi1_ping_count,
917 &pi1_pong_count](const examples::Pong &pong) {
918 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
919 << pi1_event_loop->context().monotonic_remote_time << " -> "
920 << pi1_event_loop->context().monotonic_event_time;
921
922 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
923 ++pi1_pong_count;
924 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
925 });
926 pi2_event_loop->MakeWatcher(
927 "/test", [&pi2_event_loop, &pi2_ping_count,
928 &pi2_pong_count](const examples::Pong &pong) {
929 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
930 << pi2_event_loop->context().monotonic_remote_time << " -> "
931 << pi2_event_loop->context().monotonic_event_time;
932
933 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
934 ++pi2_pong_count;
935 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
936 });
937
938 log_reader_factory.Run();
939 EXPECT_EQ(pi1_ping_count, 2030);
940 EXPECT_EQ(pi2_ping_count, 2030);
941 EXPECT_EQ(pi1_pong_count, 2030);
942 EXPECT_EQ(pi2_pong_count, 2030);
943
944 reader.Deregister();
945}
Austin Schuh6f3babe2020-01-26 20:34:50 -0800946
Austin Schuh8bd96322020-02-13 21:18:22 -0800947// Tests that we can read log files where the monotonic clocks drift and don't
948// match correctly. While we are here, also test that different ending times
949// also is readable.
950TEST_F(MultinodeLoggerTest, MismatchedClocks) {
Austin Schuhcde938c2020-02-02 17:30:07 -0800951 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700952 LoggerState pi2_logger = MakeLogger(pi2_);
953
Austin Schuh8bd96322020-02-13 21:18:22 -0800954 NodeEventLoopFactory *pi2 =
955 event_loop_factory_.GetNodeEventLoopFactory(pi2_);
956 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
957 << pi2->realtime_now() << " distributed "
958 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -0800959
Austin Schuh8bd96322020-02-13 21:18:22 -0800960 const chrono::nanoseconds initial_pi2_offset = -chrono::seconds(1000);
961 chrono::nanoseconds pi2_offset = initial_pi2_offset;
Austin Schuhcde938c2020-02-02 17:30:07 -0800962
Austin Schuhbe69cf32020-08-27 11:38:33 -0700963 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800964 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
965 << pi2->realtime_now() << " distributed "
966 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -0800967
Austin Schuh8bd96322020-02-13 21:18:22 -0800968 for (int i = 0; i < 95; ++i) {
969 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -0700970 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800971 event_loop_factory_.RunFor(chrono::milliseconds(1));
972 }
Austin Schuhcde938c2020-02-02 17:30:07 -0800973
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700974 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800975
Austin Schuh8bd96322020-02-13 21:18:22 -0800976 event_loop_factory_.RunFor(chrono::milliseconds(200));
Austin Schuhcde938c2020-02-02 17:30:07 -0800977
Austin Schuh8bd96322020-02-13 21:18:22 -0800978 {
979 // Run pi1's logger for only part of the time.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700980 LoggerState pi1_logger = MakeLogger(pi1_);
Austin Schuh8bd96322020-02-13 21:18:22 -0800981
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700982 StartLogger(&pi1_logger);
Austin Schuh8bd96322020-02-13 21:18:22 -0800983
984 for (int i = 0; i < 20000; ++i) {
985 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -0700986 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800987 event_loop_factory_.RunFor(chrono::milliseconds(1));
988 }
989
990 EXPECT_GT(pi2_offset - initial_pi2_offset,
991 event_loop_factory_.send_delay() +
992 event_loop_factory_.network_delay());
993
994 for (int i = 0; i < 40000; ++i) {
995 pi2_offset -= chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -0700996 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800997 event_loop_factory_.RunFor(chrono::milliseconds(1));
998 }
999 }
1000
1001 // And log a bit more on pi2.
1002 event_loop_factory_.RunFor(chrono::milliseconds(400));
Austin Schuhcde938c2020-02-02 17:30:07 -08001003 }
1004
Austin Schuh2f8fd752020-09-01 22:38:28 -07001005 LogReader reader(structured_logfiles_);
Austin Schuhcde938c2020-02-02 17:30:07 -08001006
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001007 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuhcde938c2020-02-02 17:30:07 -08001008 log_reader_factory.set_send_delay(chrono::microseconds(0));
1009
Austin Schuhcde938c2020-02-02 17:30:07 -08001010 const Node *pi1 =
1011 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1012 const Node *pi2 =
1013 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1014
Austin Schuh2f8fd752020-09-01 22:38:28 -07001015 // This sends out the fetched messages and advances time to the start of the
1016 // log file.
1017 reader.Register(&log_reader_factory);
1018
1019 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
1020 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
1021 LOG(INFO) << "now pi1 "
1022 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
1023 LOG(INFO) << "now pi2 "
1024 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
1025
Austin Schuhcde938c2020-02-02 17:30:07 -08001026 LOG(INFO) << "Done registering (pi1) "
Austin Schuh391e3172020-09-01 22:48:18 -07001027 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now()
1028 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -08001029 << log_reader_factory.GetNodeEventLoopFactory(pi1)->realtime_now();
1030 LOG(INFO) << "Done registering (pi2) "
Austin Schuh391e3172020-09-01 22:48:18 -07001031 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now()
1032 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -08001033 << log_reader_factory.GetNodeEventLoopFactory(pi2)->realtime_now();
1034
1035 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1036
1037 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1038
1039 std::unique_ptr<EventLoop> pi1_event_loop =
1040 log_reader_factory.MakeEventLoop("test", pi1);
1041 std::unique_ptr<EventLoop> pi2_event_loop =
1042 log_reader_factory.MakeEventLoop("test", pi2);
1043
1044 int pi1_ping_count = 30;
1045 int pi2_ping_count = 30;
1046 int pi1_pong_count = 30;
1047 int pi2_pong_count = 30;
1048
1049 // Confirm that the ping value matches.
1050 pi1_event_loop->MakeWatcher(
1051 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
1052 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
1053 << pi1_event_loop->context().monotonic_remote_time << " -> "
1054 << pi1_event_loop->context().monotonic_event_time;
1055 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
1056
1057 ++pi1_ping_count;
1058 });
1059 pi2_event_loop->MakeWatcher(
1060 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
1061 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
1062 << pi2_event_loop->context().monotonic_remote_time << " -> "
1063 << pi2_event_loop->context().monotonic_event_time;
1064 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
1065
1066 ++pi2_ping_count;
1067 });
1068
1069 // Confirm that the ping and pong counts both match, and the value also
1070 // matches.
1071 pi1_event_loop->MakeWatcher(
1072 "/test", [&pi1_event_loop, &pi1_ping_count,
1073 &pi1_pong_count](const examples::Pong &pong) {
1074 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
1075 << pi1_event_loop->context().monotonic_remote_time << " -> "
1076 << pi1_event_loop->context().monotonic_event_time;
1077
1078 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
1079 ++pi1_pong_count;
1080 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
1081 });
1082 pi2_event_loop->MakeWatcher(
1083 "/test", [&pi2_event_loop, &pi2_ping_count,
1084 &pi2_pong_count](const examples::Pong &pong) {
1085 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
1086 << pi2_event_loop->context().monotonic_remote_time << " -> "
1087 << pi2_event_loop->context().monotonic_event_time;
1088
1089 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1090 ++pi2_pong_count;
1091 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1092 });
1093
1094 log_reader_factory.Run();
Austin Schuh8bd96322020-02-13 21:18:22 -08001095 EXPECT_EQ(pi1_ping_count, 6030);
1096 EXPECT_EQ(pi2_ping_count, 6030);
1097 EXPECT_EQ(pi1_pong_count, 6030);
1098 EXPECT_EQ(pi2_pong_count, 6030);
Austin Schuhcde938c2020-02-02 17:30:07 -08001099
1100 reader.Deregister();
1101}
1102
Austin Schuh5212cad2020-09-09 23:12:09 -07001103// Tests that we can sort a bunch of parts into the pre-determined sorted parts.
1104TEST_F(MultinodeLoggerTest, SortParts) {
1105 // Make a bunch of parts.
1106 {
1107 LoggerState pi1_logger = MakeLogger(pi1_);
1108 LoggerState pi2_logger = MakeLogger(pi2_);
1109
1110 event_loop_factory_.RunFor(chrono::milliseconds(95));
1111
1112 StartLogger(&pi1_logger);
1113 StartLogger(&pi2_logger);
1114
1115 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1116 }
1117
Austin Schuh11d43732020-09-21 17:28:30 -07001118 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1119
1120 EXPECT_EQ(sorted_parts.size(), 2u);
1121
1122 // Count up the number of UUIDs and make sure they are what we expect as a
1123 // sanity check.
Brian Silvermanae7c0332020-09-30 16:58:23 -07001124 std::set<std::string> log_event_uuids;
Austin Schuh11d43732020-09-21 17:28:30 -07001125 std::set<std::string> parts_uuids;
1126 std::set<std::string> both_uuids;
1127
1128 size_t missing_rt_count = 0;
1129
Austin Schuhb3352212020-10-19 09:57:06 -07001130 std::vector<std::string> logger_nodes;
Austin Schuh11d43732020-09-21 17:28:30 -07001131 for (const LogFile &log_file : sorted_parts) {
Brian Silvermanae7c0332020-09-30 16:58:23 -07001132 EXPECT_FALSE(log_file.log_event_uuid.empty());
1133 log_event_uuids.insert(log_file.log_event_uuid);
Austin Schuhb3352212020-10-19 09:57:06 -07001134 logger_nodes.emplace_back(log_file.logger_node);
Brian Silvermanae7c0332020-09-30 16:58:23 -07001135 both_uuids.insert(log_file.log_event_uuid);
Austin Schuh11d43732020-09-21 17:28:30 -07001136
1137 for (const LogParts &part : log_file.parts) {
1138 EXPECT_NE(part.monotonic_start_time, aos::monotonic_clock::min_time)
1139 << ": " << part;
Brian Silvermand90905f2020-09-23 14:42:56 -07001140 missing_rt_count +=
1141 part.realtime_start_time == aos::realtime_clock::min_time;
Austin Schuh11d43732020-09-21 17:28:30 -07001142
Brian Silvermanae7c0332020-09-30 16:58:23 -07001143 EXPECT_TRUE(log_event_uuids.find(part.log_event_uuid) !=
1144 log_event_uuids.end());
Austin Schuh11d43732020-09-21 17:28:30 -07001145 EXPECT_NE(part.node, "");
1146 parts_uuids.insert(part.parts_uuid);
1147 both_uuids.insert(part.parts_uuid);
1148 }
1149 }
1150
1151 // We won't have RT timestamps for 5 log files. We don't log the RT start
1152 // time on remote nodes because we don't know it and would be guessing. And
1153 // the log reader can actually do a better job.
1154 EXPECT_EQ(missing_rt_count, 5u);
1155
Brian Silvermanae7c0332020-09-30 16:58:23 -07001156 EXPECT_EQ(log_event_uuids.size(), 2u);
Austin Schuh11d43732020-09-21 17:28:30 -07001157 EXPECT_EQ(parts_uuids.size(), ToLogReaderVector(sorted_parts).size());
Brian Silvermanae7c0332020-09-30 16:58:23 -07001158 EXPECT_EQ(log_event_uuids.size() + parts_uuids.size(), both_uuids.size());
Austin Schuh5212cad2020-09-09 23:12:09 -07001159
1160 // Test that each list of parts is in order. Don't worry about the ordering
1161 // between part file lists though.
1162 // (inner vectors all need to be in order, but outer one doesn't matter).
Austin Schuh11d43732020-09-21 17:28:30 -07001163 EXPECT_THAT(ToLogReaderVector(sorted_parts),
Austin Schuh5212cad2020-09-09 23:12:09 -07001164 ::testing::UnorderedElementsAreArray(structured_logfiles_));
Austin Schuhb3352212020-10-19 09:57:06 -07001165
1166 EXPECT_THAT(logger_nodes, ::testing::UnorderedElementsAre("pi1", "pi2"));
1167
1168 EXPECT_NE(sorted_parts[0].realtime_start_time, aos::realtime_clock::min_time);
1169 EXPECT_NE(sorted_parts[1].realtime_start_time, aos::realtime_clock::min_time);
1170
1171 EXPECT_NE(sorted_parts[0].monotonic_start_time,
1172 aos::monotonic_clock::min_time);
1173 EXPECT_NE(sorted_parts[1].monotonic_start_time,
1174 aos::monotonic_clock::min_time);
Austin Schuh5212cad2020-09-09 23:12:09 -07001175}
1176
Austin Schuh01b4c352020-09-21 23:09:39 -07001177// Tests that if we remap a remapped channel, it shows up correctly.
1178TEST_F(MultinodeLoggerTest, RemapLoggedChannel) {
1179 {
1180 LoggerState pi1_logger = MakeLogger(pi1_);
1181 LoggerState pi2_logger = MakeLogger(pi2_);
1182
1183 event_loop_factory_.RunFor(chrono::milliseconds(95));
1184
1185 StartLogger(&pi1_logger);
1186 StartLogger(&pi2_logger);
1187
1188 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1189 }
1190
1191 LogReader reader(structured_logfiles_);
1192
1193 // Remap just on pi1.
1194 reader.RemapLoggedChannel<aos::timing::Report>(
1195 "/aos", configuration::GetNode(reader.configuration(), "pi1"));
1196
1197 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1198 log_reader_factory.set_send_delay(chrono::microseconds(0));
1199
1200 reader.Register(&log_reader_factory);
1201
1202 const Node *pi1 =
1203 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1204 const Node *pi2 =
1205 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1206
1207 // Confirm we can read the data on the remapped channel, just for pi1. Nothing
1208 // else should have moved.
1209 std::unique_ptr<EventLoop> pi1_event_loop =
1210 log_reader_factory.MakeEventLoop("test", pi1);
1211 pi1_event_loop->SkipTimingReport();
1212 std::unique_ptr<EventLoop> full_pi1_event_loop =
1213 log_reader_factory.MakeEventLoop("test", pi1);
1214 full_pi1_event_loop->SkipTimingReport();
1215 std::unique_ptr<EventLoop> pi2_event_loop =
1216 log_reader_factory.MakeEventLoop("test", pi2);
1217 pi2_event_loop->SkipTimingReport();
1218
1219 MessageCounter<aos::timing::Report> pi1_timing_report(pi1_event_loop.get(),
1220 "/aos");
1221 MessageCounter<aos::timing::Report> full_pi1_timing_report(
1222 full_pi1_event_loop.get(), "/pi1/aos");
1223 MessageCounter<aos::timing::Report> pi1_original_timing_report(
1224 pi1_event_loop.get(), "/original/aos");
1225 MessageCounter<aos::timing::Report> full_pi1_original_timing_report(
1226 full_pi1_event_loop.get(), "/original/pi1/aos");
1227 MessageCounter<aos::timing::Report> pi2_timing_report(pi2_event_loop.get(),
1228 "/aos");
1229
1230 log_reader_factory.Run();
1231
1232 EXPECT_EQ(pi1_timing_report.count(), 0u);
1233 EXPECT_EQ(full_pi1_timing_report.count(), 0u);
1234 EXPECT_NE(pi1_original_timing_report.count(), 0u);
1235 EXPECT_NE(full_pi1_original_timing_report.count(), 0u);
1236 EXPECT_NE(pi2_timing_report.count(), 0u);
1237
1238 reader.Deregister();
1239}
1240
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001241// Tests that we properly recreate forwarded timestamps when replaying a log.
1242// This should be enough that we can then re-run the logger and get a valid log
1243// back.
1244TEST_F(MultinodeLoggerTest, MessageHeader) {
1245 {
1246 LoggerState pi1_logger = MakeLogger(pi1_);
1247 LoggerState pi2_logger = MakeLogger(pi2_);
1248
1249 event_loop_factory_.RunFor(chrono::milliseconds(95));
1250
1251 StartLogger(&pi1_logger);
1252 StartLogger(&pi2_logger);
1253
1254 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1255 }
1256
1257 LogReader reader(structured_logfiles_);
1258
1259 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1260 log_reader_factory.set_send_delay(chrono::microseconds(0));
1261
1262 // This sends out the fetched messages and advances time to the start of the
1263 // log file.
1264 reader.Register(&log_reader_factory);
1265
1266 const Node *pi1 =
1267 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1268 const Node *pi2 =
1269 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1270
1271 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
1272 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
1273 LOG(INFO) << "now pi1 "
1274 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
1275 LOG(INFO) << "now pi2 "
1276 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
1277
1278 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1279
1280 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1281
1282 std::unique_ptr<EventLoop> pi1_event_loop =
1283 log_reader_factory.MakeEventLoop("test", pi1);
1284 std::unique_ptr<EventLoop> pi2_event_loop =
1285 log_reader_factory.MakeEventLoop("test", pi2);
1286
1287 MessageCounter<MessageHeader> pi1_original_message_header_counter(
1288 pi1_event_loop.get(), "/original/aos/remote_timestamps/pi2");
1289 MessageCounter<MessageHeader> pi2_original_message_header_counter(
1290 pi2_event_loop.get(), "/original/aos/remote_timestamps/pi1");
1291
1292 aos::Fetcher<message_bridge::Timestamp> pi1_timestamp_on_pi1_fetcher =
1293 pi1_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi1/aos");
1294 aos::Fetcher<message_bridge::Timestamp> pi1_timestamp_on_pi2_fetcher =
1295 pi2_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi1/aos");
1296
1297 aos::Fetcher<examples::Ping> ping_on_pi1_fetcher =
1298 pi1_event_loop->MakeFetcher<examples::Ping>("/test");
1299 aos::Fetcher<examples::Ping> ping_on_pi2_fetcher =
1300 pi2_event_loop->MakeFetcher<examples::Ping>("/test");
1301
1302 aos::Fetcher<message_bridge::Timestamp> pi2_timestamp_on_pi2_fetcher =
1303 pi2_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi2/aos");
1304 aos::Fetcher<message_bridge::Timestamp> pi2_timestamp_on_pi1_fetcher =
1305 pi1_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi2/aos");
1306
1307 aos::Fetcher<examples::Pong> pong_on_pi2_fetcher =
1308 pi2_event_loop->MakeFetcher<examples::Pong>("/test");
1309 aos::Fetcher<examples::Pong> pong_on_pi1_fetcher =
1310 pi1_event_loop->MakeFetcher<examples::Pong>("/test");
1311
1312 const size_t pi1_timestamp_channel = configuration::ChannelIndex(
1313 pi1_event_loop->configuration(), pi1_timestamp_on_pi1_fetcher.channel());
1314 const size_t ping_timestamp_channel = configuration::ChannelIndex(
1315 pi2_event_loop->configuration(), ping_on_pi2_fetcher.channel());
1316
1317 const size_t pi2_timestamp_channel = configuration::ChannelIndex(
1318 pi2_event_loop->configuration(), pi2_timestamp_on_pi2_fetcher.channel());
1319 const size_t pong_timestamp_channel = configuration::ChannelIndex(
1320 pi1_event_loop->configuration(), pong_on_pi1_fetcher.channel());
1321
1322 pi1_event_loop->MakeWatcher(
1323 "/aos/remote_timestamps/pi2",
1324 [&pi1_event_loop, pi1_timestamp_channel, ping_timestamp_channel,
1325 &pi1_timestamp_on_pi1_fetcher, &pi1_timestamp_on_pi2_fetcher,
1326 &ping_on_pi1_fetcher,
1327 &ping_on_pi2_fetcher](const MessageHeader &header) {
1328 const aos::monotonic_clock::time_point header_monotonic_sent_time(
1329 chrono::nanoseconds(header.monotonic_sent_time()));
1330 const aos::realtime_clock::time_point header_realtime_sent_time(
1331 chrono::nanoseconds(header.realtime_sent_time()));
1332 const aos::monotonic_clock::time_point header_monotonic_remote_time(
1333 chrono::nanoseconds(header.monotonic_remote_time()));
1334 const aos::realtime_clock::time_point header_realtime_remote_time(
1335 chrono::nanoseconds(header.realtime_remote_time()));
1336
1337 const Context *pi1_context = nullptr;
1338 const Context *pi2_context = nullptr;
1339
1340 if (header.channel_index() == pi1_timestamp_channel) {
1341 ASSERT_TRUE(pi1_timestamp_on_pi1_fetcher.FetchNext());
1342 ASSERT_TRUE(pi1_timestamp_on_pi2_fetcher.FetchNext());
1343 pi1_context = &pi1_timestamp_on_pi1_fetcher.context();
1344 pi2_context = &pi1_timestamp_on_pi2_fetcher.context();
1345 } else if (header.channel_index() == ping_timestamp_channel) {
1346 ASSERT_TRUE(ping_on_pi1_fetcher.FetchNext());
1347 ASSERT_TRUE(ping_on_pi2_fetcher.FetchNext());
1348 pi1_context = &ping_on_pi1_fetcher.context();
1349 pi2_context = &ping_on_pi2_fetcher.context();
1350 } else {
1351 LOG(FATAL) << "Unknown channel " << FlatbufferToJson(&header) << " "
1352 << configuration::CleanedChannelToString(
1353 pi1_event_loop->configuration()->channels()->Get(
1354 header.channel_index()));
1355 }
1356
1357 EXPECT_EQ(pi1_context->queue_index, header.remote_queue_index());
1358 EXPECT_EQ(pi2_context->remote_queue_index, header.remote_queue_index());
1359 EXPECT_EQ(pi2_context->queue_index, header.queue_index());
1360
1361 EXPECT_EQ(pi2_context->monotonic_event_time,
1362 header_monotonic_sent_time);
1363 EXPECT_EQ(pi2_context->realtime_event_time, header_realtime_sent_time);
1364 EXPECT_EQ(pi2_context->realtime_remote_time,
1365 header_realtime_remote_time);
1366 EXPECT_EQ(pi2_context->monotonic_remote_time,
1367 header_monotonic_remote_time);
1368
1369 EXPECT_EQ(pi1_context->realtime_event_time,
1370 header_realtime_remote_time);
1371 EXPECT_EQ(pi1_context->monotonic_event_time,
1372 header_monotonic_remote_time);
1373 });
1374 pi2_event_loop->MakeWatcher(
1375 "/aos/remote_timestamps/pi1",
1376 [&pi2_event_loop, pi2_timestamp_channel, pong_timestamp_channel,
1377 &pi2_timestamp_on_pi2_fetcher, &pi2_timestamp_on_pi1_fetcher,
1378 &pong_on_pi2_fetcher,
1379 &pong_on_pi1_fetcher](const MessageHeader &header) {
1380 const aos::monotonic_clock::time_point header_monotonic_sent_time(
1381 chrono::nanoseconds(header.monotonic_sent_time()));
1382 const aos::realtime_clock::time_point header_realtime_sent_time(
1383 chrono::nanoseconds(header.realtime_sent_time()));
1384 const aos::monotonic_clock::time_point header_monotonic_remote_time(
1385 chrono::nanoseconds(header.monotonic_remote_time()));
1386 const aos::realtime_clock::time_point header_realtime_remote_time(
1387 chrono::nanoseconds(header.realtime_remote_time()));
1388
1389 const Context *pi2_context = nullptr;
1390 const Context *pi1_context = nullptr;
1391
1392 if (header.channel_index() == pi2_timestamp_channel) {
1393 ASSERT_TRUE(pi2_timestamp_on_pi2_fetcher.FetchNext());
1394 ASSERT_TRUE(pi2_timestamp_on_pi1_fetcher.FetchNext());
1395 pi2_context = &pi2_timestamp_on_pi2_fetcher.context();
1396 pi1_context = &pi2_timestamp_on_pi1_fetcher.context();
1397 } else if (header.channel_index() == pong_timestamp_channel) {
1398 ASSERT_TRUE(pong_on_pi2_fetcher.FetchNext());
1399 ASSERT_TRUE(pong_on_pi1_fetcher.FetchNext());
1400 pi2_context = &pong_on_pi2_fetcher.context();
1401 pi1_context = &pong_on_pi1_fetcher.context();
1402 } else {
1403 LOG(FATAL) << "Unknown channel " << FlatbufferToJson(&header) << " "
1404 << configuration::CleanedChannelToString(
1405 pi2_event_loop->configuration()->channels()->Get(
1406 header.channel_index()));
1407 }
1408
1409 EXPECT_EQ(pi2_context->queue_index, header.remote_queue_index());
1410 EXPECT_EQ(pi1_context->remote_queue_index, header.remote_queue_index());
1411 EXPECT_EQ(pi1_context->queue_index, header.queue_index());
1412
1413 EXPECT_EQ(pi1_context->monotonic_event_time,
1414 header_monotonic_sent_time);
1415 EXPECT_EQ(pi1_context->realtime_event_time, header_realtime_sent_time);
1416 EXPECT_EQ(pi1_context->realtime_remote_time,
1417 header_realtime_remote_time);
1418 EXPECT_EQ(pi1_context->monotonic_remote_time,
1419 header_monotonic_remote_time);
1420
1421 EXPECT_EQ(pi2_context->realtime_event_time,
1422 header_realtime_remote_time);
1423 EXPECT_EQ(pi2_context->monotonic_event_time,
1424 header_monotonic_remote_time);
1425 });
1426
1427 // And confirm we can re-create a log again, while checking the contents.
1428 {
1429 LoggerState pi1_logger = MakeLogger(
1430 configuration::GetNode(log_reader_factory.configuration(), pi1_),
1431 &log_reader_factory);
1432 LoggerState pi2_logger = MakeLogger(
1433 configuration::GetNode(log_reader_factory.configuration(), pi2_),
1434 &log_reader_factory);
1435
1436 StartLogger(&pi1_logger, "relogged");
1437 StartLogger(&pi2_logger, "relogged");
1438
1439 log_reader_factory.Run();
1440 }
1441
1442 EXPECT_EQ(pi2_original_message_header_counter.count(), 0u);
1443 EXPECT_EQ(pi1_original_message_header_counter.count(), 0u);
1444
1445 reader.Deregister();
1446}
1447
Austin Schuh8bd96322020-02-13 21:18:22 -08001448// TODO(austin): We can write a test which recreates a logfile and confirms that
1449// we get it back. That is the ultimate test.
1450
Austin Schuhe309d2a2019-11-29 13:25:21 -08001451} // namespace testing
1452} // namespace logger
1453} // namespace aos