blob: 51994e33bdcef8201eeea8447b0d2f6333c71701 [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 Schuh2f8fd752020-09-01 22:38:28 -07009#include "aos/util/file.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -080010#include "glog/logging.h"
Austin Schuh6f3babe2020-01-26 20:34:50 -080011#include "gmock/gmock.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -080012#include "gtest/gtest.h"
13
14namespace aos {
15namespace logger {
16namespace testing {
17
18namespace chrono = std::chrono;
Austin Schuh01b4c352020-09-21 23:09:39 -070019using aos::testing::MessageCounter;
Austin Schuhe309d2a2019-11-29 13:25:21 -080020
21class LoggerTest : public ::testing::Test {
22 public:
23 LoggerTest()
24 : config_(
25 aos::configuration::ReadConfig("aos/events/pingpong_config.json")),
26 event_loop_factory_(&config_.message()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080027 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080028 ping_(ping_event_loop_.get()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080029 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080030 pong_(pong_event_loop_.get()) {}
31
32 // Config and factory.
33 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
34 SimulatedEventLoopFactory event_loop_factory_;
35
36 // Event loop and app for Ping
37 std::unique_ptr<EventLoop> ping_event_loop_;
38 Ping ping_;
39
40 // Event loop and app for Pong
41 std::unique_ptr<EventLoop> pong_event_loop_;
42 Pong pong_;
43};
44
Brian Silverman1f345222020-09-24 21:14:48 -070045using LoggerDeathTest = LoggerTest;
46
Austin Schuhe309d2a2019-11-29 13:25:21 -080047// Tests that we can startup at all. This confirms that the channels are all in
48// the config.
49TEST_F(LoggerTest, Starts) {
50 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
Austin Schuh2f8fd752020-09-01 22:38:28 -070051 const ::std::string base_name = tmpdir + "/logfile";
52 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuhe309d2a2019-11-29 13:25:21 -080053 // Remove it.
54 unlink(logfile.c_str());
55
56 LOG(INFO) << "Logging data to " << logfile;
57
58 {
Austin Schuhe309d2a2019-11-29 13:25:21 -080059 std::unique_ptr<EventLoop> logger_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080060 event_loop_factory_.MakeEventLoop("logger");
Austin Schuhe309d2a2019-11-29 13:25:21 -080061
62 event_loop_factory_.RunFor(chrono::milliseconds(95));
63
Brian Silverman1f345222020-09-24 21:14:48 -070064 Logger logger(logger_event_loop.get());
65 logger.set_polling_period(std::chrono::milliseconds(100));
66 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuhe309d2a2019-11-29 13:25:21 -080067 event_loop_factory_.RunFor(chrono::milliseconds(20000));
68 }
69
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080070 // Even though it doesn't make any difference here, exercise the logic for
71 // passing in a separate config.
72 LogReader reader(logfile, &config_.message());
Austin Schuhe309d2a2019-11-29 13:25:21 -080073
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080074 // Confirm that we can remap logged channels to point to new buses.
75 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
Austin Schuhe309d2a2019-11-29 13:25:21 -080076
Austin Schuh15649d62019-12-28 16:36:38 -080077 // This sends out the fetched messages and advances time to the start of the
78 // log file.
James Kuszmaul84ff3e52020-01-03 19:48:53 -080079 reader.Register();
Austin Schuhe309d2a2019-11-29 13:25:21 -080080
Austin Schuh6f3babe2020-01-26 20:34:50 -080081 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
James Kuszmaul84ff3e52020-01-03 19:48:53 -080082
Austin Schuhe309d2a2019-11-29 13:25:21 -080083 std::unique_ptr<EventLoop> test_event_loop =
James Kuszmaul84ff3e52020-01-03 19:48:53 -080084 reader.event_loop_factory()->MakeEventLoop("log_reader");
Austin Schuhe309d2a2019-11-29 13:25:21 -080085
86 int ping_count = 10;
87 int pong_count = 10;
88
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080089 // Confirm that the ping value matches in the remapped channel location.
90 test_event_loop->MakeWatcher("/original/test",
Austin Schuhe309d2a2019-11-29 13:25:21 -080091 [&ping_count](const examples::Ping &ping) {
92 EXPECT_EQ(ping.value(), ping_count + 1);
93 ++ping_count;
94 });
95 // Confirm that the ping and pong counts both match, and the value also
96 // matches.
97 test_event_loop->MakeWatcher(
98 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
99 EXPECT_EQ(pong.value(), pong_count + 1);
100 ++pong_count;
101 EXPECT_EQ(ping_count, pong_count);
102 });
103
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800104 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
Austin Schuhe309d2a2019-11-29 13:25:21 -0800105 EXPECT_EQ(ping_count, 2010);
Austin Schuhe309d2a2019-11-29 13:25:21 -0800106}
107
Brian Silverman1f345222020-09-24 21:14:48 -0700108// Tests calling StartLogging twice.
109TEST_F(LoggerDeathTest, ExtraStart) {
110 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
111 const ::std::string base_name1 = tmpdir + "/logfile1";
112 const ::std::string logfile1 = base_name1 + ".part0.bfbs";
113 const ::std::string base_name2 = tmpdir + "/logfile2";
114 const ::std::string logfile2 = base_name2 + ".part0.bfbs";
115 unlink(logfile1.c_str());
116 unlink(logfile2.c_str());
117
118 LOG(INFO) << "Logging data to " << logfile1 << " then " << logfile2;
119
120 {
121 std::unique_ptr<EventLoop> logger_event_loop =
122 event_loop_factory_.MakeEventLoop("logger");
123
124 event_loop_factory_.RunFor(chrono::milliseconds(95));
125
126 Logger logger(logger_event_loop.get());
127 logger.set_polling_period(std::chrono::milliseconds(100));
128 logger_event_loop->OnRun(
129 [base_name1, base_name2, &logger_event_loop, &logger]() {
130 logger.StartLogging(std::make_unique<LocalLogNamer>(
131 base_name1, logger_event_loop->node()));
132 EXPECT_DEATH(logger.StartLogging(std::make_unique<LocalLogNamer>(
133 base_name2, logger_event_loop->node())),
134 "Already logging");
135 });
136 event_loop_factory_.RunFor(chrono::milliseconds(20000));
137 }
138}
139
140// Tests calling StopLogging twice.
141TEST_F(LoggerDeathTest, ExtraStop) {
142 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
143 const ::std::string base_name = tmpdir + "/logfile";
144 const ::std::string logfile = base_name + ".part0.bfbs";
145 // Remove it.
146 unlink(logfile.c_str());
147
148 LOG(INFO) << "Logging data to " << logfile;
149
150 {
151 std::unique_ptr<EventLoop> logger_event_loop =
152 event_loop_factory_.MakeEventLoop("logger");
153
154 event_loop_factory_.RunFor(chrono::milliseconds(95));
155
156 Logger logger(logger_event_loop.get());
157 logger.set_polling_period(std::chrono::milliseconds(100));
158 logger_event_loop->OnRun([base_name, &logger_event_loop, &logger]() {
159 logger.StartLogging(std::make_unique<LocalLogNamer>(
160 base_name, logger_event_loop->node()));
161 logger.StopLogging(aos::monotonic_clock::min_time);
162 EXPECT_DEATH(logger.StopLogging(aos::monotonic_clock::min_time),
163 "Not logging right now");
164 });
165 event_loop_factory_.RunFor(chrono::milliseconds(20000));
166 }
167}
168
169// Tests that we can startup twice.
170TEST_F(LoggerTest, StartsTwice) {
171 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
172 const ::std::string base_name1 = tmpdir + "/logfile1";
173 const ::std::string logfile1 = base_name1 + ".part0.bfbs";
174 const ::std::string base_name2 = tmpdir + "/logfile2";
175 const ::std::string logfile2 = base_name2 + ".part0.bfbs";
176 unlink(logfile1.c_str());
177 unlink(logfile2.c_str());
178
179 LOG(INFO) << "Logging data to " << logfile1 << " then " << logfile2;
180
181 {
182 std::unique_ptr<EventLoop> logger_event_loop =
183 event_loop_factory_.MakeEventLoop("logger");
184
185 event_loop_factory_.RunFor(chrono::milliseconds(95));
186
187 Logger logger(logger_event_loop.get());
188 logger.set_polling_period(std::chrono::milliseconds(100));
189 logger.StartLogging(
190 std::make_unique<LocalLogNamer>(base_name1, logger_event_loop->node()));
191 event_loop_factory_.RunFor(chrono::milliseconds(10000));
192 logger.StopLogging(logger_event_loop->monotonic_now());
193 event_loop_factory_.RunFor(chrono::milliseconds(10000));
194 logger.StartLogging(
195 std::make_unique<LocalLogNamer>(base_name2, logger_event_loop->node()));
196 event_loop_factory_.RunFor(chrono::milliseconds(10000));
197 }
198
199 for (const auto &logfile :
200 {std::make_tuple(logfile1, 10), std::make_tuple(logfile2, 2010)}) {
201 SCOPED_TRACE(std::get<0>(logfile));
202 LogReader reader(std::get<0>(logfile));
203 reader.Register();
204
205 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
206
207 std::unique_ptr<EventLoop> test_event_loop =
208 reader.event_loop_factory()->MakeEventLoop("log_reader");
209
210 int ping_count = std::get<1>(logfile);
211 int pong_count = std::get<1>(logfile);
212
213 // Confirm that the ping and pong counts both match, and the value also
214 // matches.
215 test_event_loop->MakeWatcher("/test",
216 [&ping_count](const examples::Ping &ping) {
217 EXPECT_EQ(ping.value(), ping_count + 1);
218 ++ping_count;
219 });
220 test_event_loop->MakeWatcher(
221 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
222 EXPECT_EQ(pong.value(), pong_count + 1);
223 ++pong_count;
224 EXPECT_EQ(ping_count, pong_count);
225 });
226
227 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
228 EXPECT_EQ(ping_count, std::get<1>(logfile) + 1000);
229 }
230}
231
Austin Schuhfa895892020-01-07 20:07:41 -0800232// Tests that we can read and write rotated log files.
233TEST_F(LoggerTest, RotatedLogFile) {
234 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
Austin Schuh2f8fd752020-09-01 22:38:28 -0700235 const ::std::string base_name = tmpdir + "/logfile";
236 const ::std::string logfile0 = base_name + ".part0.bfbs";
237 const ::std::string logfile1 = base_name + ".part1.bfbs";
Austin Schuhfa895892020-01-07 20:07:41 -0800238 // Remove it.
239 unlink(logfile0.c_str());
240 unlink(logfile1.c_str());
241
242 LOG(INFO) << "Logging data to " << logfile0 << " and " << logfile1;
243
244 {
Austin Schuhfa895892020-01-07 20:07:41 -0800245 std::unique_ptr<EventLoop> logger_event_loop =
246 event_loop_factory_.MakeEventLoop("logger");
247
248 event_loop_factory_.RunFor(chrono::milliseconds(95));
249
Brian Silverman1f345222020-09-24 21:14:48 -0700250 Logger logger(logger_event_loop.get());
251 logger.set_polling_period(std::chrono::milliseconds(100));
252 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuhfa895892020-01-07 20:07:41 -0800253 event_loop_factory_.RunFor(chrono::milliseconds(10000));
Austin Schuh2f8fd752020-09-01 22:38:28 -0700254 logger.Rotate();
Austin Schuhfa895892020-01-07 20:07:41 -0800255 event_loop_factory_.RunFor(chrono::milliseconds(10000));
256 }
257
Austin Schuh64fab802020-09-09 22:47:47 -0700258 {
259 // Confirm that the UUIDs match for both the parts and the logger, and the
260 // parts_index increments.
261 std::vector<FlatbufferVector<LogFileHeader>> log_header;
262 for (std::string_view f : {logfile0, logfile1}) {
263 log_header.emplace_back(ReadHeader(f));
264 }
265
Brian Silvermanae7c0332020-09-30 16:58:23 -0700266 EXPECT_EQ(log_header[0].message().log_event_uuid()->string_view(),
267 log_header[1].message().log_event_uuid()->string_view());
Austin Schuh64fab802020-09-09 22:47:47 -0700268 EXPECT_EQ(log_header[0].message().parts_uuid()->string_view(),
269 log_header[1].message().parts_uuid()->string_view());
270
271 EXPECT_EQ(log_header[0].message().parts_index(), 0);
272 EXPECT_EQ(log_header[1].message().parts_index(), 1);
273 }
274
Austin Schuhfa895892020-01-07 20:07:41 -0800275 // Even though it doesn't make any difference here, exercise the logic for
276 // passing in a separate config.
277 LogReader reader(std::vector<std::string>{logfile0, logfile1},
278 &config_.message());
279
280 // Confirm that we can remap logged channels to point to new buses.
281 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
282
283 // This sends out the fetched messages and advances time to the start of the
284 // log file.
285 reader.Register();
286
Austin Schuh6f3babe2020-01-26 20:34:50 -0800287 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
Austin Schuhfa895892020-01-07 20:07:41 -0800288
289 std::unique_ptr<EventLoop> test_event_loop =
290 reader.event_loop_factory()->MakeEventLoop("log_reader");
291
292 int ping_count = 10;
293 int pong_count = 10;
294
295 // Confirm that the ping value matches in the remapped channel location.
296 test_event_loop->MakeWatcher("/original/test",
297 [&ping_count](const examples::Ping &ping) {
298 EXPECT_EQ(ping.value(), ping_count + 1);
299 ++ping_count;
300 });
301 // Confirm that the ping and pong counts both match, and the value also
302 // matches.
303 test_event_loop->MakeWatcher(
304 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
305 EXPECT_EQ(pong.value(), pong_count + 1);
306 ++pong_count;
307 EXPECT_EQ(ping_count, pong_count);
308 });
309
310 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
311 EXPECT_EQ(ping_count, 2010);
312}
313
Austin Schuh4c4e0092019-12-22 16:18:03 -0800314// Tests that a large number of messages per second doesn't overwhelm writev.
315TEST_F(LoggerTest, ManyMessages) {
316 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
Austin Schuh2f8fd752020-09-01 22:38:28 -0700317 const ::std::string base_name = tmpdir + "/logfile";
318 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuh4c4e0092019-12-22 16:18:03 -0800319 // Remove the log file.
320 unlink(logfile.c_str());
321
322 LOG(INFO) << "Logging data to " << logfile;
Austin Schuh4c3b9702020-08-30 11:34:55 -0700323 ping_.set_quiet(true);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800324
325 {
Austin Schuh4c4e0092019-12-22 16:18:03 -0800326 std::unique_ptr<EventLoop> logger_event_loop =
327 event_loop_factory_.MakeEventLoop("logger");
328
329 std::unique_ptr<EventLoop> ping_spammer_event_loop =
330 event_loop_factory_.MakeEventLoop("ping_spammer");
331 aos::Sender<examples::Ping> ping_sender =
332 ping_spammer_event_loop->MakeSender<examples::Ping>("/test");
333
334 aos::TimerHandler *timer_handler =
335 ping_spammer_event_loop->AddTimer([&ping_sender]() {
336 aos::Sender<examples::Ping>::Builder builder =
337 ping_sender.MakeBuilder();
338 examples::Ping::Builder ping_builder =
339 builder.MakeBuilder<examples::Ping>();
340 CHECK(builder.Send(ping_builder.Finish()));
341 });
342
343 // 100 ms / 0.05 ms -> 2000 messages. Should be enough to crash it.
344 ping_spammer_event_loop->OnRun([&ping_spammer_event_loop, timer_handler]() {
345 timer_handler->Setup(ping_spammer_event_loop->monotonic_now(),
346 chrono::microseconds(50));
347 });
348
Brian Silverman1f345222020-09-24 21:14:48 -0700349 Logger logger(logger_event_loop.get());
350 logger.set_polling_period(std::chrono::milliseconds(100));
351 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800352
353 event_loop_factory_.RunFor(chrono::milliseconds(1000));
354 }
355}
356
Austin Schuh15649d62019-12-28 16:36:38 -0800357class MultinodeLoggerTest : public ::testing::Test {
358 public:
359 MultinodeLoggerTest()
360 : config_(aos::configuration::ReadConfig(
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800361 "aos/events/logging/multinode_pingpong_config.json")),
Austin Schuhac0771c2020-01-07 18:36:30 -0800362 event_loop_factory_(&config_.message()),
Austin Schuhcde938c2020-02-02 17:30:07 -0800363 pi1_(
364 configuration::GetNode(event_loop_factory_.configuration(), "pi1")),
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700365 pi2_(
366 configuration::GetNode(event_loop_factory_.configuration(), "pi2")),
367 tmp_dir_(getenv("TEST_TMPDIR")),
368 logfile_base_(tmp_dir_ + "/multi_logfile"),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700369 logfiles_(
370 {logfile_base_ + "_pi1_data.part0.bfbs",
371 logfile_base_ + "_pi2_data/test/aos.examples.Pong.part0.bfbs",
372 logfile_base_ + "_pi2_data/test/aos.examples.Pong.part1.bfbs",
373 logfile_base_ + "_pi2_data.part0.bfbs",
374 logfile_base_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
375 "aos.logger.MessageHeader.part0.bfbs",
376 logfile_base_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
377 "aos.logger.MessageHeader.part1.bfbs",
378 logfile_base_ + "_timestamps/pi2/aos/remote_timestamps/pi1/"
379 "aos.logger.MessageHeader.part0.bfbs",
380 logfile_base_ + "_timestamps/pi2/aos/remote_timestamps/pi1/"
381 "aos.logger.MessageHeader.part1.bfbs",
382 logfile_base_ +
383 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part0.bfbs",
384 logfile_base_ +
385 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part1.bfbs",
386 logfile_base_ +
387 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part0.bfbs",
388 logfile_base_ +
389 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part1.bfbs"}),
390 structured_logfiles_{
391 std::vector<std::string>{logfiles_[0]},
392 std::vector<std::string>{logfiles_[1], logfiles_[2]},
393 std::vector<std::string>{logfiles_[3]},
394 std::vector<std::string>{logfiles_[4], logfiles_[5]},
395 std::vector<std::string>{logfiles_[6], logfiles_[7]},
396 std::vector<std::string>{logfiles_[8], logfiles_[9]},
397 std::vector<std::string>{logfiles_[10], logfiles_[11]}},
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700398 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping", pi1_)),
399 ping_(ping_event_loop_.get()),
400 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong", pi2_)),
401 pong_(pong_event_loop_.get()) {
402 // Go through and remove the logfiles if they already exist.
403 for (const auto file : logfiles_) {
404 unlink(file.c_str());
405 }
406
407 LOG(INFO) << "Logging data to " << logfiles_[0] << ", " << logfiles_[1]
408 << " and " << logfiles_[2];
409 }
410
411 struct LoggerState {
412 std::unique_ptr<EventLoop> event_loop;
413 std::unique_ptr<Logger> logger;
414 };
415
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700416 LoggerState MakeLogger(const Node *node,
417 SimulatedEventLoopFactory *factory = nullptr) {
418 if (factory == nullptr) {
419 factory = &event_loop_factory_;
420 }
421 return {factory->MakeEventLoop("logger", node), {}};
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700422 }
423
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700424 void StartLogger(LoggerState *logger, std::string logfile_base = "") {
425 if (logfile_base.empty()) {
426 logfile_base = logfile_base_;
427 }
428
Brian Silverman1f345222020-09-24 21:14:48 -0700429 logger->logger = std::make_unique<Logger>(logger->event_loop.get());
430 logger->logger->set_polling_period(std::chrono::milliseconds(100));
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700431 logger->event_loop->OnRun([logger, logfile_base]() {
Brian Silverman1f345222020-09-24 21:14:48 -0700432 logger->logger->StartLogging(std::make_unique<MultiNodeLogNamer>(
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700433 logfile_base, logger->event_loop->configuration(),
Brian Silverman1f345222020-09-24 21:14:48 -0700434 logger->event_loop->node()));
435 });
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700436 }
Austin Schuh15649d62019-12-28 16:36:38 -0800437
438 // Config and factory.
439 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
440 SimulatedEventLoopFactory event_loop_factory_;
441
Austin Schuhcde938c2020-02-02 17:30:07 -0800442 const Node *pi1_;
443 const Node *pi2_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700444
445 std::string tmp_dir_;
446 std::string logfile_base_;
Austin Schuh2f8fd752020-09-01 22:38:28 -0700447 std::vector<std::string> logfiles_;
448
449 std::vector<std::vector<std::string>> structured_logfiles_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700450
451 std::unique_ptr<EventLoop> ping_event_loop_;
452 Ping ping_;
453 std::unique_ptr<EventLoop> pong_event_loop_;
454 Pong pong_;
Austin Schuh15649d62019-12-28 16:36:38 -0800455};
456
Austin Schuh391e3172020-09-01 22:48:18 -0700457// Counts the number of messages on a channel. Returns (channel name, channel
458// type, count) for every message matching matcher()
459std::vector<std::tuple<std::string, std::string, int>> CountChannelsMatching(
Austin Schuh6f3babe2020-01-26 20:34:50 -0800460 std::string_view filename,
461 std::function<bool(const MessageHeader *)> matcher) {
462 MessageReader message_reader(filename);
463 std::vector<int> counts(
464 message_reader.log_file_header()->configuration()->channels()->size(), 0);
Austin Schuh15649d62019-12-28 16:36:38 -0800465
Austin Schuh6f3babe2020-01-26 20:34:50 -0800466 while (true) {
467 std::optional<FlatbufferVector<MessageHeader>> msg =
468 message_reader.ReadMessage();
469 if (!msg) {
470 break;
471 }
472
473 if (matcher(&msg.value().message())) {
474 counts[msg.value().message().channel_index()]++;
475 }
476 }
477
Austin Schuh391e3172020-09-01 22:48:18 -0700478 std::vector<std::tuple<std::string, std::string, int>> result;
Austin Schuh6f3babe2020-01-26 20:34:50 -0800479 int channel = 0;
480 for (size_t i = 0; i < counts.size(); ++i) {
481 if (counts[i] != 0) {
Austin Schuh391e3172020-09-01 22:48:18 -0700482 const Channel *channel =
483 message_reader.log_file_header()->configuration()->channels()->Get(i);
484 result.push_back(std::make_tuple(channel->name()->str(),
485 channel->type()->str(), counts[i]));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800486 }
487 ++channel;
488 }
489
490 return result;
491}
492
493// Counts the number of messages (channel, count) for all data messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700494std::vector<std::tuple<std::string, std::string, int>> CountChannelsData(
495 std::string_view filename) {
Austin Schuh6f3babe2020-01-26 20:34:50 -0800496 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
497 if (msg->has_data()) {
498 CHECK(!msg->has_monotonic_remote_time());
499 CHECK(!msg->has_realtime_remote_time());
500 CHECK(!msg->has_remote_queue_index());
501 return true;
502 }
503 return false;
504 });
505}
506
507// Counts the number of messages (channel, count) for all timestamp messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700508std::vector<std::tuple<std::string, std::string, int>> CountChannelsTimestamp(
Austin Schuh6f3babe2020-01-26 20:34:50 -0800509 std::string_view filename) {
510 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
511 if (!msg->has_data()) {
512 CHECK(msg->has_monotonic_remote_time());
513 CHECK(msg->has_realtime_remote_time());
514 CHECK(msg->has_remote_queue_index());
515 return true;
516 }
517 return false;
518 });
519}
520
Austin Schuhcde938c2020-02-02 17:30:07 -0800521// Tests that we can write and read simple multi-node log files.
522TEST_F(MultinodeLoggerTest, SimpleMultiNode) {
Austin Schuh15649d62019-12-28 16:36:38 -0800523 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700524 LoggerState pi1_logger = MakeLogger(pi1_);
525 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuh15649d62019-12-28 16:36:38 -0800526
527 event_loop_factory_.RunFor(chrono::milliseconds(95));
528
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700529 StartLogger(&pi1_logger);
530 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800531
Austin Schuh15649d62019-12-28 16:36:38 -0800532 event_loop_factory_.RunFor(chrono::milliseconds(20000));
533 }
534
Austin Schuh6f3babe2020-01-26 20:34:50 -0800535 {
Austin Schuh64fab802020-09-09 22:47:47 -0700536 std::set<std::string> logfile_uuids;
537 std::set<std::string> parts_uuids;
538 // Confirm that we have the expected number of UUIDs for both the logfile
539 // UUIDs and parts UUIDs.
540 std::vector<FlatbufferVector<LogFileHeader>> log_header;
541 for (std::string_view f : logfiles_) {
542 log_header.emplace_back(ReadHeader(f));
Brian Silvermanae7c0332020-09-30 16:58:23 -0700543 logfile_uuids.insert(log_header.back().message().log_event_uuid()->str());
Austin Schuh64fab802020-09-09 22:47:47 -0700544 parts_uuids.insert(log_header.back().message().parts_uuid()->str());
545 }
Austin Schuh15649d62019-12-28 16:36:38 -0800546
Austin Schuh64fab802020-09-09 22:47:47 -0700547 EXPECT_EQ(logfile_uuids.size(), 2u);
548 EXPECT_EQ(parts_uuids.size(), 7u);
549
550 // And confirm everything is on the correct node.
551 EXPECT_EQ(log_header[0].message().node()->name()->string_view(), "pi1");
552 EXPECT_EQ(log_header[1].message().node()->name()->string_view(), "pi2");
553 EXPECT_EQ(log_header[2].message().node()->name()->string_view(), "pi2");
554 EXPECT_EQ(log_header[3].message().node()->name()->string_view(), "pi2");
555 EXPECT_EQ(log_header[4].message().node()->name()->string_view(), "pi2");
556 EXPECT_EQ(log_header[5].message().node()->name()->string_view(), "pi2");
557 EXPECT_EQ(log_header[6].message().node()->name()->string_view(), "pi1");
558 EXPECT_EQ(log_header[7].message().node()->name()->string_view(), "pi1");
559 EXPECT_EQ(log_header[8].message().node()->name()->string_view(), "pi1");
560 EXPECT_EQ(log_header[9].message().node()->name()->string_view(), "pi1");
561 EXPECT_EQ(log_header[10].message().node()->name()->string_view(), "pi2");
562 EXPECT_EQ(log_header[11].message().node()->name()->string_view(), "pi2");
563
564 // And the parts index matches.
565 EXPECT_EQ(log_header[0].message().parts_index(), 0);
566 EXPECT_EQ(log_header[1].message().parts_index(), 0);
567 EXPECT_EQ(log_header[2].message().parts_index(), 1);
568 EXPECT_EQ(log_header[3].message().parts_index(), 0);
569 EXPECT_EQ(log_header[4].message().parts_index(), 0);
570 EXPECT_EQ(log_header[5].message().parts_index(), 1);
571 EXPECT_EQ(log_header[6].message().parts_index(), 0);
572 EXPECT_EQ(log_header[7].message().parts_index(), 1);
573 EXPECT_EQ(log_header[8].message().parts_index(), 0);
574 EXPECT_EQ(log_header[9].message().parts_index(), 1);
575 EXPECT_EQ(log_header[10].message().parts_index(), 0);
576 EXPECT_EQ(log_header[11].message().parts_index(), 1);
577 }
578
579 {
Austin Schuh391e3172020-09-01 22:48:18 -0700580 using ::testing::UnorderedElementsAre;
581
Austin Schuh6f3babe2020-01-26 20:34:50 -0800582 // Timing reports, pings
Austin Schuh2f8fd752020-09-01 22:38:28 -0700583 EXPECT_THAT(
584 CountChannelsData(logfiles_[0]),
585 UnorderedElementsAre(
586 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200),
587 std::make_tuple("/pi1/aos", "aos.timing.Report", 40),
588 std::make_tuple("/test", "aos.examples.Ping", 2001)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800589 // Timestamps for pong
Austin Schuh2f8fd752020-09-01 22:38:28 -0700590 EXPECT_THAT(
591 CountChannelsTimestamp(logfiles_[0]),
592 UnorderedElementsAre(
593 std::make_tuple("/test", "aos.examples.Pong", 2001),
594 std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800595
596 // Pong data.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700597 EXPECT_THAT(CountChannelsData(logfiles_[1]),
Austin Schuh391e3172020-09-01 22:48:18 -0700598 UnorderedElementsAre(
Austin Schuh2f8fd752020-09-01 22:38:28 -0700599 std::make_tuple("/test", "aos.examples.Pong", 101)));
600 EXPECT_THAT(CountChannelsData(logfiles_[2]),
601 UnorderedElementsAre(
602 std::make_tuple("/test", "aos.examples.Pong", 1900)));
Austin Schuh391e3172020-09-01 22:48:18 -0700603
Austin Schuh6f3babe2020-01-26 20:34:50 -0800604 // No timestamps
Austin Schuh391e3172020-09-01 22:48:18 -0700605 EXPECT_THAT(CountChannelsTimestamp(logfiles_[1]), UnorderedElementsAre());
Austin Schuh2f8fd752020-09-01 22:38:28 -0700606 EXPECT_THAT(CountChannelsTimestamp(logfiles_[2]), UnorderedElementsAre());
Austin Schuh6f3babe2020-01-26 20:34:50 -0800607
608 // Timing reports and pongs.
Austin Schuh2f8fd752020-09-01 22:38:28 -0700609 EXPECT_THAT(
610 CountChannelsData(logfiles_[3]),
611 UnorderedElementsAre(
612 std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200),
613 std::make_tuple("/pi2/aos", "aos.timing.Report", 40),
614 std::make_tuple("/test", "aos.examples.Pong", 2001)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800615 // And ping timestamps.
Austin Schuh2f8fd752020-09-01 22:38:28 -0700616 EXPECT_THAT(
617 CountChannelsTimestamp(logfiles_[3]),
618 UnorderedElementsAre(
619 std::make_tuple("/test", "aos.examples.Ping", 2001),
620 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200)));
621
622 // Timestamps from pi2 on pi1, and the other way.
623 EXPECT_THAT(CountChannelsData(logfiles_[4]), UnorderedElementsAre());
624 EXPECT_THAT(CountChannelsData(logfiles_[5]), UnorderedElementsAre());
625 EXPECT_THAT(CountChannelsData(logfiles_[6]), UnorderedElementsAre());
626 EXPECT_THAT(CountChannelsData(logfiles_[7]), UnorderedElementsAre());
627 EXPECT_THAT(
628 CountChannelsTimestamp(logfiles_[4]),
629 UnorderedElementsAre(
630 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 10),
631 std::make_tuple("/test", "aos.examples.Ping", 101)));
632 EXPECT_THAT(
633 CountChannelsTimestamp(logfiles_[5]),
634 UnorderedElementsAre(
635 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 190),
636 std::make_tuple("/test", "aos.examples.Ping", 1900)));
637 EXPECT_THAT(CountChannelsTimestamp(logfiles_[6]),
638 UnorderedElementsAre(std::make_tuple(
639 "/pi2/aos", "aos.message_bridge.Timestamp", 10)));
640 EXPECT_THAT(CountChannelsTimestamp(logfiles_[7]),
641 UnorderedElementsAre(std::make_tuple(
642 "/pi2/aos", "aos.message_bridge.Timestamp", 190)));
643
644 // And then test that the remotely logged timestamp data files only have
645 // timestamps in them.
646 EXPECT_THAT(CountChannelsTimestamp(logfiles_[8]), UnorderedElementsAre());
647 EXPECT_THAT(CountChannelsTimestamp(logfiles_[9]), UnorderedElementsAre());
648 EXPECT_THAT(CountChannelsTimestamp(logfiles_[10]), UnorderedElementsAre());
649 EXPECT_THAT(CountChannelsTimestamp(logfiles_[11]), UnorderedElementsAre());
650
651 EXPECT_THAT(CountChannelsData(logfiles_[8]),
652 UnorderedElementsAre(std::make_tuple(
653 "/pi1/aos", "aos.message_bridge.Timestamp", 10)));
654 EXPECT_THAT(CountChannelsData(logfiles_[9]),
655 UnorderedElementsAre(std::make_tuple(
656 "/pi1/aos", "aos.message_bridge.Timestamp", 190)));
657
658 EXPECT_THAT(CountChannelsData(logfiles_[10]),
659 UnorderedElementsAre(std::make_tuple(
660 "/pi2/aos", "aos.message_bridge.Timestamp", 10)));
661 EXPECT_THAT(CountChannelsData(logfiles_[11]),
662 UnorderedElementsAre(std::make_tuple(
663 "/pi2/aos", "aos.message_bridge.Timestamp", 190)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800664 }
665
Austin Schuh2f8fd752020-09-01 22:38:28 -0700666 LogReader reader(structured_logfiles_);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800667
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700668 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuh6331ef92020-01-07 18:28:09 -0800669 log_reader_factory.set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800670
671 // This sends out the fetched messages and advances time to the start of the
672 // log file.
Austin Schuh6331ef92020-01-07 18:28:09 -0800673 reader.Register(&log_reader_factory);
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800674
Austin Schuhac0771c2020-01-07 18:36:30 -0800675 const Node *pi1 =
676 configuration::GetNode(log_reader_factory.configuration(), "pi1");
Austin Schuh6f3babe2020-01-26 20:34:50 -0800677 const Node *pi2 =
678 configuration::GetNode(log_reader_factory.configuration(), "pi2");
Austin Schuhac0771c2020-01-07 18:36:30 -0800679
Austin Schuh2f8fd752020-09-01 22:38:28 -0700680 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
681 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
682 LOG(INFO) << "now pi1 "
683 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
684 LOG(INFO) << "now pi2 "
685 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
686
Austin Schuh6f3babe2020-01-26 20:34:50 -0800687 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800688
689 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800690
Austin Schuh6f3babe2020-01-26 20:34:50 -0800691 std::unique_ptr<EventLoop> pi1_event_loop =
Austin Schuhac0771c2020-01-07 18:36:30 -0800692 log_reader_factory.MakeEventLoop("test", pi1);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800693 std::unique_ptr<EventLoop> pi2_event_loop =
694 log_reader_factory.MakeEventLoop("test", pi2);
Austin Schuh15649d62019-12-28 16:36:38 -0800695
Austin Schuh6f3babe2020-01-26 20:34:50 -0800696 int pi1_ping_count = 10;
697 int pi2_ping_count = 10;
698 int pi1_pong_count = 10;
699 int pi2_pong_count = 10;
Austin Schuh15649d62019-12-28 16:36:38 -0800700
701 // Confirm that the ping value matches.
Austin Schuh6f3babe2020-01-26 20:34:50 -0800702 pi1_event_loop->MakeWatcher(
703 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
Austin Schuh2f8fd752020-09-01 22:38:28 -0700704 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping) << " at "
Austin Schuh6f3babe2020-01-26 20:34:50 -0800705 << pi1_event_loop->context().monotonic_remote_time << " -> "
706 << pi1_event_loop->context().monotonic_event_time;
707 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
708 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
709 pi1_ping_count * chrono::milliseconds(10) +
710 monotonic_clock::epoch());
711 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
712 pi1_ping_count * chrono::milliseconds(10) +
713 realtime_clock::epoch());
714 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
715 pi1_event_loop->context().monotonic_event_time);
716 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
717 pi1_event_loop->context().realtime_event_time);
Austin Schuh15649d62019-12-28 16:36:38 -0800718
Austin Schuh6f3babe2020-01-26 20:34:50 -0800719 ++pi1_ping_count;
720 });
721 pi2_event_loop->MakeWatcher(
722 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
Austin Schuh2f8fd752020-09-01 22:38:28 -0700723 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping) << " at "
Austin Schuh6f3babe2020-01-26 20:34:50 -0800724 << pi2_event_loop->context().monotonic_remote_time << " -> "
725 << pi2_event_loop->context().monotonic_event_time;
726 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
727
728 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
729 pi2_ping_count * chrono::milliseconds(10) +
730 monotonic_clock::epoch());
731 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
732 pi2_ping_count * chrono::milliseconds(10) +
733 realtime_clock::epoch());
734 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time +
735 chrono::microseconds(150),
736 pi2_event_loop->context().monotonic_event_time);
737 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time +
738 chrono::microseconds(150),
739 pi2_event_loop->context().realtime_event_time);
740 ++pi2_ping_count;
Austin Schuh15649d62019-12-28 16:36:38 -0800741 });
742
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700743 constexpr ssize_t kQueueIndexOffset = -9;
Austin Schuh6f3babe2020-01-26 20:34:50 -0800744 // Confirm that the ping and pong counts both match, and the value also
745 // matches.
746 pi1_event_loop->MakeWatcher(
747 "/test", [&pi1_event_loop, &pi1_ping_count,
748 &pi1_pong_count](const examples::Pong &pong) {
749 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
750 << pi1_event_loop->context().monotonic_remote_time << " -> "
751 << pi1_event_loop->context().monotonic_event_time;
752
753 EXPECT_EQ(pi1_event_loop->context().remote_queue_index,
754 pi1_pong_count + kQueueIndexOffset);
755 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
756 chrono::microseconds(200) +
757 pi1_pong_count * chrono::milliseconds(10) +
758 monotonic_clock::epoch());
759 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
760 chrono::microseconds(200) +
761 pi1_pong_count * chrono::milliseconds(10) +
762 realtime_clock::epoch());
763
764 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time +
765 chrono::microseconds(150),
766 pi1_event_loop->context().monotonic_event_time);
767 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time +
768 chrono::microseconds(150),
769 pi1_event_loop->context().realtime_event_time);
770
771 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
772 ++pi1_pong_count;
773 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
774 });
775 pi2_event_loop->MakeWatcher(
776 "/test", [&pi2_event_loop, &pi2_ping_count,
777 &pi2_pong_count](const examples::Pong &pong) {
778 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
779 << pi2_event_loop->context().monotonic_remote_time << " -> "
780 << pi2_event_loop->context().monotonic_event_time;
781
782 EXPECT_EQ(pi2_event_loop->context().remote_queue_index,
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700783 pi2_pong_count + kQueueIndexOffset);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800784
785 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
786 chrono::microseconds(200) +
787 pi2_pong_count * chrono::milliseconds(10) +
788 monotonic_clock::epoch());
789 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
790 chrono::microseconds(200) +
791 pi2_pong_count * chrono::milliseconds(10) +
792 realtime_clock::epoch());
793
794 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
795 pi2_event_loop->context().monotonic_event_time);
796 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
797 pi2_event_loop->context().realtime_event_time);
798
799 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
800 ++pi2_pong_count;
801 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
802 });
803
804 log_reader_factory.Run();
805 EXPECT_EQ(pi1_ping_count, 2010);
806 EXPECT_EQ(pi2_ping_count, 2010);
807 EXPECT_EQ(pi1_pong_count, 2010);
808 EXPECT_EQ(pi2_pong_count, 2010);
Austin Schuh6331ef92020-01-07 18:28:09 -0800809
810 reader.Deregister();
Austin Schuh15649d62019-12-28 16:36:38 -0800811}
812
James Kuszmaul46d82582020-05-09 19:50:09 -0700813typedef MultinodeLoggerTest MultinodeLoggerDeathTest;
814
815// Test that if we feed the replay with a mismatched node list that we die on
816// the LogReader constructor.
817TEST_F(MultinodeLoggerDeathTest, MultiNodeBadReplayConfig) {
James Kuszmaul46d82582020-05-09 19:50:09 -0700818 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700819 LoggerState pi1_logger = MakeLogger(pi1_);
820 LoggerState pi2_logger = MakeLogger(pi2_);
James Kuszmaul46d82582020-05-09 19:50:09 -0700821
822 event_loop_factory_.RunFor(chrono::milliseconds(95));
823
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700824 StartLogger(&pi1_logger);
825 StartLogger(&pi2_logger);
James Kuszmaul46d82582020-05-09 19:50:09 -0700826
James Kuszmaul46d82582020-05-09 19:50:09 -0700827 event_loop_factory_.RunFor(chrono::milliseconds(20000));
828 }
829
830 // Test that, if we add an additional node to the replay config that the
831 // logger complains about the mismatch in number of nodes.
832 FlatbufferDetachedBuffer<Configuration> extra_nodes_config =
833 configuration::MergeWithConfig(&config_.message(), R"({
834 "nodes": [
835 {
836 "name": "extra-node"
837 }
838 ]
839 }
840 )");
841
Austin Schuh2f8fd752020-09-01 22:38:28 -0700842 EXPECT_DEATH(LogReader(structured_logfiles_, &extra_nodes_config.message()),
James Kuszmaul46d82582020-05-09 19:50:09 -0700843 "Log file and replay config need to have matching nodes lists.");
James Kuszmaul46d82582020-05-09 19:50:09 -0700844}
845
Austin Schuhcde938c2020-02-02 17:30:07 -0800846// Tests that we can read log files where they don't start at the same monotonic
847// time.
848TEST_F(MultinodeLoggerTest, StaggeredStart) {
Austin Schuhcde938c2020-02-02 17:30:07 -0800849 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700850 LoggerState pi1_logger = MakeLogger(pi1_);
851 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuhcde938c2020-02-02 17:30:07 -0800852
853 event_loop_factory_.RunFor(chrono::milliseconds(95));
854
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700855 StartLogger(&pi1_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800856
857 event_loop_factory_.RunFor(chrono::milliseconds(200));
858
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700859 StartLogger(&pi2_logger);
860
Austin Schuhcde938c2020-02-02 17:30:07 -0800861 event_loop_factory_.RunFor(chrono::milliseconds(20000));
862 }
863
Austin Schuh2f8fd752020-09-01 22:38:28 -0700864 LogReader reader(structured_logfiles_);
Austin Schuhcde938c2020-02-02 17:30:07 -0800865
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700866 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuhcde938c2020-02-02 17:30:07 -0800867 log_reader_factory.set_send_delay(chrono::microseconds(0));
868
869 // This sends out the fetched messages and advances time to the start of the
870 // log file.
871 reader.Register(&log_reader_factory);
872
873 const Node *pi1 =
874 configuration::GetNode(log_reader_factory.configuration(), "pi1");
875 const Node *pi2 =
876 configuration::GetNode(log_reader_factory.configuration(), "pi2");
877
878 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
879
880 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
881
882 std::unique_ptr<EventLoop> pi1_event_loop =
883 log_reader_factory.MakeEventLoop("test", pi1);
884 std::unique_ptr<EventLoop> pi2_event_loop =
885 log_reader_factory.MakeEventLoop("test", pi2);
886
887 int pi1_ping_count = 30;
888 int pi2_ping_count = 30;
889 int pi1_pong_count = 30;
890 int pi2_pong_count = 30;
891
892 // Confirm that the ping value matches.
893 pi1_event_loop->MakeWatcher(
894 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
895 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
896 << pi1_event_loop->context().monotonic_remote_time << " -> "
897 << pi1_event_loop->context().monotonic_event_time;
898 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
899
900 ++pi1_ping_count;
901 });
902 pi2_event_loop->MakeWatcher(
903 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
904 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
905 << pi2_event_loop->context().monotonic_remote_time << " -> "
906 << pi2_event_loop->context().monotonic_event_time;
907 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
908
909 ++pi2_ping_count;
910 });
911
912 // Confirm that the ping and pong counts both match, and the value also
913 // matches.
914 pi1_event_loop->MakeWatcher(
915 "/test", [&pi1_event_loop, &pi1_ping_count,
916 &pi1_pong_count](const examples::Pong &pong) {
917 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
918 << pi1_event_loop->context().monotonic_remote_time << " -> "
919 << pi1_event_loop->context().monotonic_event_time;
920
921 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
922 ++pi1_pong_count;
923 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
924 });
925 pi2_event_loop->MakeWatcher(
926 "/test", [&pi2_event_loop, &pi2_ping_count,
927 &pi2_pong_count](const examples::Pong &pong) {
928 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
929 << pi2_event_loop->context().monotonic_remote_time << " -> "
930 << pi2_event_loop->context().monotonic_event_time;
931
932 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
933 ++pi2_pong_count;
934 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
935 });
936
937 log_reader_factory.Run();
938 EXPECT_EQ(pi1_ping_count, 2030);
939 EXPECT_EQ(pi2_ping_count, 2030);
940 EXPECT_EQ(pi1_pong_count, 2030);
941 EXPECT_EQ(pi2_pong_count, 2030);
942
943 reader.Deregister();
944}
Austin Schuh6f3babe2020-01-26 20:34:50 -0800945
Austin Schuh8bd96322020-02-13 21:18:22 -0800946// Tests that we can read log files where the monotonic clocks drift and don't
947// match correctly. While we are here, also test that different ending times
948// also is readable.
949TEST_F(MultinodeLoggerTest, MismatchedClocks) {
Austin Schuhcde938c2020-02-02 17:30:07 -0800950 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700951 LoggerState pi2_logger = MakeLogger(pi2_);
952
Austin Schuh8bd96322020-02-13 21:18:22 -0800953 NodeEventLoopFactory *pi2 =
954 event_loop_factory_.GetNodeEventLoopFactory(pi2_);
955 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
956 << pi2->realtime_now() << " distributed "
957 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -0800958
Austin Schuh8bd96322020-02-13 21:18:22 -0800959 const chrono::nanoseconds initial_pi2_offset = -chrono::seconds(1000);
960 chrono::nanoseconds pi2_offset = initial_pi2_offset;
Austin Schuhcde938c2020-02-02 17:30:07 -0800961
Austin Schuhbe69cf32020-08-27 11:38:33 -0700962 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800963 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
964 << pi2->realtime_now() << " distributed "
965 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -0800966
Austin Schuh8bd96322020-02-13 21:18:22 -0800967 for (int i = 0; i < 95; ++i) {
968 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -0700969 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800970 event_loop_factory_.RunFor(chrono::milliseconds(1));
971 }
Austin Schuhcde938c2020-02-02 17:30:07 -0800972
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700973 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800974
Austin Schuh8bd96322020-02-13 21:18:22 -0800975 event_loop_factory_.RunFor(chrono::milliseconds(200));
Austin Schuhcde938c2020-02-02 17:30:07 -0800976
Austin Schuh8bd96322020-02-13 21:18:22 -0800977 {
978 // Run pi1's logger for only part of the time.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700979 LoggerState pi1_logger = MakeLogger(pi1_);
Austin Schuh8bd96322020-02-13 21:18:22 -0800980
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700981 StartLogger(&pi1_logger);
Austin Schuh8bd96322020-02-13 21:18:22 -0800982
983 for (int i = 0; i < 20000; ++i) {
984 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -0700985 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800986 event_loop_factory_.RunFor(chrono::milliseconds(1));
987 }
988
989 EXPECT_GT(pi2_offset - initial_pi2_offset,
990 event_loop_factory_.send_delay() +
991 event_loop_factory_.network_delay());
992
993 for (int i = 0; i < 40000; ++i) {
994 pi2_offset -= chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -0700995 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800996 event_loop_factory_.RunFor(chrono::milliseconds(1));
997 }
998 }
999
1000 // And log a bit more on pi2.
1001 event_loop_factory_.RunFor(chrono::milliseconds(400));
Austin Schuhcde938c2020-02-02 17:30:07 -08001002 }
1003
Austin Schuh2f8fd752020-09-01 22:38:28 -07001004 LogReader reader(structured_logfiles_);
Austin Schuhcde938c2020-02-02 17:30:07 -08001005
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001006 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuhcde938c2020-02-02 17:30:07 -08001007 log_reader_factory.set_send_delay(chrono::microseconds(0));
1008
Austin Schuhcde938c2020-02-02 17:30:07 -08001009 const Node *pi1 =
1010 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1011 const Node *pi2 =
1012 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1013
Austin Schuh2f8fd752020-09-01 22:38:28 -07001014 // This sends out the fetched messages and advances time to the start of the
1015 // log file.
1016 reader.Register(&log_reader_factory);
1017
1018 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
1019 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
1020 LOG(INFO) << "now pi1 "
1021 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
1022 LOG(INFO) << "now pi2 "
1023 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
1024
Austin Schuhcde938c2020-02-02 17:30:07 -08001025 LOG(INFO) << "Done registering (pi1) "
Austin Schuh391e3172020-09-01 22:48:18 -07001026 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now()
1027 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -08001028 << log_reader_factory.GetNodeEventLoopFactory(pi1)->realtime_now();
1029 LOG(INFO) << "Done registering (pi2) "
Austin Schuh391e3172020-09-01 22:48:18 -07001030 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now()
1031 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -08001032 << log_reader_factory.GetNodeEventLoopFactory(pi2)->realtime_now();
1033
1034 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1035
1036 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1037
1038 std::unique_ptr<EventLoop> pi1_event_loop =
1039 log_reader_factory.MakeEventLoop("test", pi1);
1040 std::unique_ptr<EventLoop> pi2_event_loop =
1041 log_reader_factory.MakeEventLoop("test", pi2);
1042
1043 int pi1_ping_count = 30;
1044 int pi2_ping_count = 30;
1045 int pi1_pong_count = 30;
1046 int pi2_pong_count = 30;
1047
1048 // Confirm that the ping value matches.
1049 pi1_event_loop->MakeWatcher(
1050 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
1051 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
1052 << pi1_event_loop->context().monotonic_remote_time << " -> "
1053 << pi1_event_loop->context().monotonic_event_time;
1054 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
1055
1056 ++pi1_ping_count;
1057 });
1058 pi2_event_loop->MakeWatcher(
1059 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
1060 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
1061 << pi2_event_loop->context().monotonic_remote_time << " -> "
1062 << pi2_event_loop->context().monotonic_event_time;
1063 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
1064
1065 ++pi2_ping_count;
1066 });
1067
1068 // Confirm that the ping and pong counts both match, and the value also
1069 // matches.
1070 pi1_event_loop->MakeWatcher(
1071 "/test", [&pi1_event_loop, &pi1_ping_count,
1072 &pi1_pong_count](const examples::Pong &pong) {
1073 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
1074 << pi1_event_loop->context().monotonic_remote_time << " -> "
1075 << pi1_event_loop->context().monotonic_event_time;
1076
1077 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
1078 ++pi1_pong_count;
1079 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
1080 });
1081 pi2_event_loop->MakeWatcher(
1082 "/test", [&pi2_event_loop, &pi2_ping_count,
1083 &pi2_pong_count](const examples::Pong &pong) {
1084 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
1085 << pi2_event_loop->context().monotonic_remote_time << " -> "
1086 << pi2_event_loop->context().monotonic_event_time;
1087
1088 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1089 ++pi2_pong_count;
1090 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1091 });
1092
1093 log_reader_factory.Run();
Austin Schuh8bd96322020-02-13 21:18:22 -08001094 EXPECT_EQ(pi1_ping_count, 6030);
1095 EXPECT_EQ(pi2_ping_count, 6030);
1096 EXPECT_EQ(pi1_pong_count, 6030);
1097 EXPECT_EQ(pi2_pong_count, 6030);
Austin Schuhcde938c2020-02-02 17:30:07 -08001098
1099 reader.Deregister();
1100}
1101
Austin Schuh5212cad2020-09-09 23:12:09 -07001102// Tests that we can sort a bunch of parts into the pre-determined sorted parts.
1103TEST_F(MultinodeLoggerTest, SortParts) {
1104 // Make a bunch of parts.
1105 {
1106 LoggerState pi1_logger = MakeLogger(pi1_);
1107 LoggerState pi2_logger = MakeLogger(pi2_);
1108
1109 event_loop_factory_.RunFor(chrono::milliseconds(95));
1110
1111 StartLogger(&pi1_logger);
1112 StartLogger(&pi2_logger);
1113
1114 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1115 }
1116
Austin Schuh11d43732020-09-21 17:28:30 -07001117 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1118
1119 EXPECT_EQ(sorted_parts.size(), 2u);
1120
1121 // Count up the number of UUIDs and make sure they are what we expect as a
1122 // sanity check.
Brian Silvermanae7c0332020-09-30 16:58:23 -07001123 std::set<std::string> log_event_uuids;
Austin Schuh11d43732020-09-21 17:28:30 -07001124 std::set<std::string> parts_uuids;
1125 std::set<std::string> both_uuids;
1126
1127 size_t missing_rt_count = 0;
1128
1129 for (const LogFile &log_file : sorted_parts) {
Brian Silvermanae7c0332020-09-30 16:58:23 -07001130 EXPECT_FALSE(log_file.log_event_uuid.empty());
1131 log_event_uuids.insert(log_file.log_event_uuid);
1132 both_uuids.insert(log_file.log_event_uuid);
Austin Schuh11d43732020-09-21 17:28:30 -07001133
1134 for (const LogParts &part : log_file.parts) {
1135 EXPECT_NE(part.monotonic_start_time, aos::monotonic_clock::min_time)
1136 << ": " << part;
Brian Silvermand90905f2020-09-23 14:42:56 -07001137 missing_rt_count +=
1138 part.realtime_start_time == aos::realtime_clock::min_time;
Austin Schuh11d43732020-09-21 17:28:30 -07001139
Brian Silvermanae7c0332020-09-30 16:58:23 -07001140 EXPECT_TRUE(log_event_uuids.find(part.log_event_uuid) !=
1141 log_event_uuids.end());
Austin Schuh11d43732020-09-21 17:28:30 -07001142 EXPECT_NE(part.node, "");
1143 parts_uuids.insert(part.parts_uuid);
1144 both_uuids.insert(part.parts_uuid);
1145 }
1146 }
1147
1148 // We won't have RT timestamps for 5 log files. We don't log the RT start
1149 // time on remote nodes because we don't know it and would be guessing. And
1150 // the log reader can actually do a better job.
1151 EXPECT_EQ(missing_rt_count, 5u);
1152
Brian Silvermanae7c0332020-09-30 16:58:23 -07001153 EXPECT_EQ(log_event_uuids.size(), 2u);
Austin Schuh11d43732020-09-21 17:28:30 -07001154 EXPECT_EQ(parts_uuids.size(), ToLogReaderVector(sorted_parts).size());
Brian Silvermanae7c0332020-09-30 16:58:23 -07001155 EXPECT_EQ(log_event_uuids.size() + parts_uuids.size(), both_uuids.size());
Austin Schuh5212cad2020-09-09 23:12:09 -07001156
1157 // Test that each list of parts is in order. Don't worry about the ordering
1158 // between part file lists though.
1159 // (inner vectors all need to be in order, but outer one doesn't matter).
Austin Schuh11d43732020-09-21 17:28:30 -07001160 EXPECT_THAT(ToLogReaderVector(sorted_parts),
Austin Schuh5212cad2020-09-09 23:12:09 -07001161 ::testing::UnorderedElementsAreArray(structured_logfiles_));
1162}
1163
Austin Schuh01b4c352020-09-21 23:09:39 -07001164// Tests that if we remap a remapped channel, it shows up correctly.
1165TEST_F(MultinodeLoggerTest, RemapLoggedChannel) {
1166 {
1167 LoggerState pi1_logger = MakeLogger(pi1_);
1168 LoggerState pi2_logger = MakeLogger(pi2_);
1169
1170 event_loop_factory_.RunFor(chrono::milliseconds(95));
1171
1172 StartLogger(&pi1_logger);
1173 StartLogger(&pi2_logger);
1174
1175 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1176 }
1177
1178 LogReader reader(structured_logfiles_);
1179
1180 // Remap just on pi1.
1181 reader.RemapLoggedChannel<aos::timing::Report>(
1182 "/aos", configuration::GetNode(reader.configuration(), "pi1"));
1183
1184 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1185 log_reader_factory.set_send_delay(chrono::microseconds(0));
1186
1187 reader.Register(&log_reader_factory);
1188
1189 const Node *pi1 =
1190 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1191 const Node *pi2 =
1192 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1193
1194 // Confirm we can read the data on the remapped channel, just for pi1. Nothing
1195 // else should have moved.
1196 std::unique_ptr<EventLoop> pi1_event_loop =
1197 log_reader_factory.MakeEventLoop("test", pi1);
1198 pi1_event_loop->SkipTimingReport();
1199 std::unique_ptr<EventLoop> full_pi1_event_loop =
1200 log_reader_factory.MakeEventLoop("test", pi1);
1201 full_pi1_event_loop->SkipTimingReport();
1202 std::unique_ptr<EventLoop> pi2_event_loop =
1203 log_reader_factory.MakeEventLoop("test", pi2);
1204 pi2_event_loop->SkipTimingReport();
1205
1206 MessageCounter<aos::timing::Report> pi1_timing_report(pi1_event_loop.get(),
1207 "/aos");
1208 MessageCounter<aos::timing::Report> full_pi1_timing_report(
1209 full_pi1_event_loop.get(), "/pi1/aos");
1210 MessageCounter<aos::timing::Report> pi1_original_timing_report(
1211 pi1_event_loop.get(), "/original/aos");
1212 MessageCounter<aos::timing::Report> full_pi1_original_timing_report(
1213 full_pi1_event_loop.get(), "/original/pi1/aos");
1214 MessageCounter<aos::timing::Report> pi2_timing_report(pi2_event_loop.get(),
1215 "/aos");
1216
1217 log_reader_factory.Run();
1218
1219 EXPECT_EQ(pi1_timing_report.count(), 0u);
1220 EXPECT_EQ(full_pi1_timing_report.count(), 0u);
1221 EXPECT_NE(pi1_original_timing_report.count(), 0u);
1222 EXPECT_NE(full_pi1_original_timing_report.count(), 0u);
1223 EXPECT_NE(pi2_timing_report.count(), 0u);
1224
1225 reader.Deregister();
1226}
1227
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001228// Tests that we properly recreate forwarded timestamps when replaying a log.
1229// This should be enough that we can then re-run the logger and get a valid log
1230// back.
1231TEST_F(MultinodeLoggerTest, MessageHeader) {
1232 {
1233 LoggerState pi1_logger = MakeLogger(pi1_);
1234 LoggerState pi2_logger = MakeLogger(pi2_);
1235
1236 event_loop_factory_.RunFor(chrono::milliseconds(95));
1237
1238 StartLogger(&pi1_logger);
1239 StartLogger(&pi2_logger);
1240
1241 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1242 }
1243
1244 LogReader reader(structured_logfiles_);
1245
1246 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1247 log_reader_factory.set_send_delay(chrono::microseconds(0));
1248
1249 // This sends out the fetched messages and advances time to the start of the
1250 // log file.
1251 reader.Register(&log_reader_factory);
1252
1253 const Node *pi1 =
1254 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1255 const Node *pi2 =
1256 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1257
1258 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
1259 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
1260 LOG(INFO) << "now pi1 "
1261 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
1262 LOG(INFO) << "now pi2 "
1263 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
1264
1265 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1266
1267 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1268
1269 std::unique_ptr<EventLoop> pi1_event_loop =
1270 log_reader_factory.MakeEventLoop("test", pi1);
1271 std::unique_ptr<EventLoop> pi2_event_loop =
1272 log_reader_factory.MakeEventLoop("test", pi2);
1273
1274 MessageCounter<MessageHeader> pi1_original_message_header_counter(
1275 pi1_event_loop.get(), "/original/aos/remote_timestamps/pi2");
1276 MessageCounter<MessageHeader> pi2_original_message_header_counter(
1277 pi2_event_loop.get(), "/original/aos/remote_timestamps/pi1");
1278
1279 aos::Fetcher<message_bridge::Timestamp> pi1_timestamp_on_pi1_fetcher =
1280 pi1_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi1/aos");
1281 aos::Fetcher<message_bridge::Timestamp> pi1_timestamp_on_pi2_fetcher =
1282 pi2_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi1/aos");
1283
1284 aos::Fetcher<examples::Ping> ping_on_pi1_fetcher =
1285 pi1_event_loop->MakeFetcher<examples::Ping>("/test");
1286 aos::Fetcher<examples::Ping> ping_on_pi2_fetcher =
1287 pi2_event_loop->MakeFetcher<examples::Ping>("/test");
1288
1289 aos::Fetcher<message_bridge::Timestamp> pi2_timestamp_on_pi2_fetcher =
1290 pi2_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi2/aos");
1291 aos::Fetcher<message_bridge::Timestamp> pi2_timestamp_on_pi1_fetcher =
1292 pi1_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi2/aos");
1293
1294 aos::Fetcher<examples::Pong> pong_on_pi2_fetcher =
1295 pi2_event_loop->MakeFetcher<examples::Pong>("/test");
1296 aos::Fetcher<examples::Pong> pong_on_pi1_fetcher =
1297 pi1_event_loop->MakeFetcher<examples::Pong>("/test");
1298
1299 const size_t pi1_timestamp_channel = configuration::ChannelIndex(
1300 pi1_event_loop->configuration(), pi1_timestamp_on_pi1_fetcher.channel());
1301 const size_t ping_timestamp_channel = configuration::ChannelIndex(
1302 pi2_event_loop->configuration(), ping_on_pi2_fetcher.channel());
1303
1304 const size_t pi2_timestamp_channel = configuration::ChannelIndex(
1305 pi2_event_loop->configuration(), pi2_timestamp_on_pi2_fetcher.channel());
1306 const size_t pong_timestamp_channel = configuration::ChannelIndex(
1307 pi1_event_loop->configuration(), pong_on_pi1_fetcher.channel());
1308
1309 pi1_event_loop->MakeWatcher(
1310 "/aos/remote_timestamps/pi2",
1311 [&pi1_event_loop, pi1_timestamp_channel, ping_timestamp_channel,
1312 &pi1_timestamp_on_pi1_fetcher, &pi1_timestamp_on_pi2_fetcher,
1313 &ping_on_pi1_fetcher,
1314 &ping_on_pi2_fetcher](const MessageHeader &header) {
1315 const aos::monotonic_clock::time_point header_monotonic_sent_time(
1316 chrono::nanoseconds(header.monotonic_sent_time()));
1317 const aos::realtime_clock::time_point header_realtime_sent_time(
1318 chrono::nanoseconds(header.realtime_sent_time()));
1319 const aos::monotonic_clock::time_point header_monotonic_remote_time(
1320 chrono::nanoseconds(header.monotonic_remote_time()));
1321 const aos::realtime_clock::time_point header_realtime_remote_time(
1322 chrono::nanoseconds(header.realtime_remote_time()));
1323
1324 const Context *pi1_context = nullptr;
1325 const Context *pi2_context = nullptr;
1326
1327 if (header.channel_index() == pi1_timestamp_channel) {
1328 ASSERT_TRUE(pi1_timestamp_on_pi1_fetcher.FetchNext());
1329 ASSERT_TRUE(pi1_timestamp_on_pi2_fetcher.FetchNext());
1330 pi1_context = &pi1_timestamp_on_pi1_fetcher.context();
1331 pi2_context = &pi1_timestamp_on_pi2_fetcher.context();
1332 } else if (header.channel_index() == ping_timestamp_channel) {
1333 ASSERT_TRUE(ping_on_pi1_fetcher.FetchNext());
1334 ASSERT_TRUE(ping_on_pi2_fetcher.FetchNext());
1335 pi1_context = &ping_on_pi1_fetcher.context();
1336 pi2_context = &ping_on_pi2_fetcher.context();
1337 } else {
1338 LOG(FATAL) << "Unknown channel " << FlatbufferToJson(&header) << " "
1339 << configuration::CleanedChannelToString(
1340 pi1_event_loop->configuration()->channels()->Get(
1341 header.channel_index()));
1342 }
1343
1344 EXPECT_EQ(pi1_context->queue_index, header.remote_queue_index());
1345 EXPECT_EQ(pi2_context->remote_queue_index, header.remote_queue_index());
1346 EXPECT_EQ(pi2_context->queue_index, header.queue_index());
1347
1348 EXPECT_EQ(pi2_context->monotonic_event_time,
1349 header_monotonic_sent_time);
1350 EXPECT_EQ(pi2_context->realtime_event_time, header_realtime_sent_time);
1351 EXPECT_EQ(pi2_context->realtime_remote_time,
1352 header_realtime_remote_time);
1353 EXPECT_EQ(pi2_context->monotonic_remote_time,
1354 header_monotonic_remote_time);
1355
1356 EXPECT_EQ(pi1_context->realtime_event_time,
1357 header_realtime_remote_time);
1358 EXPECT_EQ(pi1_context->monotonic_event_time,
1359 header_monotonic_remote_time);
1360 });
1361 pi2_event_loop->MakeWatcher(
1362 "/aos/remote_timestamps/pi1",
1363 [&pi2_event_loop, pi2_timestamp_channel, pong_timestamp_channel,
1364 &pi2_timestamp_on_pi2_fetcher, &pi2_timestamp_on_pi1_fetcher,
1365 &pong_on_pi2_fetcher,
1366 &pong_on_pi1_fetcher](const MessageHeader &header) {
1367 const aos::monotonic_clock::time_point header_monotonic_sent_time(
1368 chrono::nanoseconds(header.monotonic_sent_time()));
1369 const aos::realtime_clock::time_point header_realtime_sent_time(
1370 chrono::nanoseconds(header.realtime_sent_time()));
1371 const aos::monotonic_clock::time_point header_monotonic_remote_time(
1372 chrono::nanoseconds(header.monotonic_remote_time()));
1373 const aos::realtime_clock::time_point header_realtime_remote_time(
1374 chrono::nanoseconds(header.realtime_remote_time()));
1375
1376 const Context *pi2_context = nullptr;
1377 const Context *pi1_context = nullptr;
1378
1379 if (header.channel_index() == pi2_timestamp_channel) {
1380 ASSERT_TRUE(pi2_timestamp_on_pi2_fetcher.FetchNext());
1381 ASSERT_TRUE(pi2_timestamp_on_pi1_fetcher.FetchNext());
1382 pi2_context = &pi2_timestamp_on_pi2_fetcher.context();
1383 pi1_context = &pi2_timestamp_on_pi1_fetcher.context();
1384 } else if (header.channel_index() == pong_timestamp_channel) {
1385 ASSERT_TRUE(pong_on_pi2_fetcher.FetchNext());
1386 ASSERT_TRUE(pong_on_pi1_fetcher.FetchNext());
1387 pi2_context = &pong_on_pi2_fetcher.context();
1388 pi1_context = &pong_on_pi1_fetcher.context();
1389 } else {
1390 LOG(FATAL) << "Unknown channel " << FlatbufferToJson(&header) << " "
1391 << configuration::CleanedChannelToString(
1392 pi2_event_loop->configuration()->channels()->Get(
1393 header.channel_index()));
1394 }
1395
1396 EXPECT_EQ(pi2_context->queue_index, header.remote_queue_index());
1397 EXPECT_EQ(pi1_context->remote_queue_index, header.remote_queue_index());
1398 EXPECT_EQ(pi1_context->queue_index, header.queue_index());
1399
1400 EXPECT_EQ(pi1_context->monotonic_event_time,
1401 header_monotonic_sent_time);
1402 EXPECT_EQ(pi1_context->realtime_event_time, header_realtime_sent_time);
1403 EXPECT_EQ(pi1_context->realtime_remote_time,
1404 header_realtime_remote_time);
1405 EXPECT_EQ(pi1_context->monotonic_remote_time,
1406 header_monotonic_remote_time);
1407
1408 EXPECT_EQ(pi2_context->realtime_event_time,
1409 header_realtime_remote_time);
1410 EXPECT_EQ(pi2_context->monotonic_event_time,
1411 header_monotonic_remote_time);
1412 });
1413
1414 // And confirm we can re-create a log again, while checking the contents.
1415 {
1416 LoggerState pi1_logger = MakeLogger(
1417 configuration::GetNode(log_reader_factory.configuration(), pi1_),
1418 &log_reader_factory);
1419 LoggerState pi2_logger = MakeLogger(
1420 configuration::GetNode(log_reader_factory.configuration(), pi2_),
1421 &log_reader_factory);
1422
1423 StartLogger(&pi1_logger, "relogged");
1424 StartLogger(&pi2_logger, "relogged");
1425
1426 log_reader_factory.Run();
1427 }
1428
1429 EXPECT_EQ(pi2_original_message_header_counter.count(), 0u);
1430 EXPECT_EQ(pi1_original_message_header_counter.count(), 0u);
1431
1432 reader.Deregister();
1433}
1434
Austin Schuh8bd96322020-02-13 21:18:22 -08001435// TODO(austin): We can write a test which recreates a logfile and confirms that
1436// we get it back. That is the ultimate test.
1437
Austin Schuhe309d2a2019-11-29 13:25:21 -08001438} // namespace testing
1439} // namespace logger
1440} // namespace aos