blob: 2b5d6ca7f7a8a079e0ac10b8e2470bc9f4d7deeb [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
Austin Schuh315b96b2020-12-11 21:21:12 -08003#include "absl/strings/str_format.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -08004#include "aos/events/event_loop.h"
Austin Schuh01b4c352020-09-21 23:09:39 -07005#include "aos/events/message_counter.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -08006#include "aos/events/ping_lib.h"
7#include "aos/events/pong_lib.h"
8#include "aos/events/simulated_event_loop.h"
Austin Schuh0de30f32020-12-06 12:44:28 -08009#include "aos/network/remote_message_generated.h"
Austin Schuh8d7e0bb2020-10-02 17:57:00 -070010#include "aos/network/timestamp_generated.h"
Austin Schuhc243b422020-10-11 15:35:08 -070011#include "aos/testing/tmpdir.h"
Austin Schuh2f8fd752020-09-01 22:38:28 -070012#include "aos/util/file.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -080013#include "glog/logging.h"
Austin Schuh6f3babe2020-01-26 20:34:50 -080014#include "gmock/gmock.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -080015#include "gtest/gtest.h"
16
Austin Schuh3bd4c402020-11-06 18:19:06 -080017#ifdef LZMA
18#include "aos/events/logging/lzma_encoder.h"
19#endif
20
Austin Schuhe309d2a2019-11-29 13:25:21 -080021namespace aos {
22namespace logger {
23namespace testing {
24
25namespace chrono = std::chrono;
Austin Schuh0de30f32020-12-06 12:44:28 -080026using aos::message_bridge::RemoteMessage;
Austin Schuh01b4c352020-09-21 23:09:39 -070027using aos::testing::MessageCounter;
Austin Schuhe309d2a2019-11-29 13:25:21 -080028
Austin Schuh8c399962020-12-25 21:51:45 -080029constexpr std::string_view kConfigSha1(
30 "0000c81e444ac470b8d29fb864621ae93a0e294a7e90c0dc4840d0f0d40fd72e");
31
Austin Schuhe309d2a2019-11-29 13:25:21 -080032class LoggerTest : public ::testing::Test {
33 public:
34 LoggerTest()
35 : config_(
36 aos::configuration::ReadConfig("aos/events/pingpong_config.json")),
37 event_loop_factory_(&config_.message()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080038 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080039 ping_(ping_event_loop_.get()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080040 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080041 pong_(pong_event_loop_.get()) {}
42
43 // Config and factory.
44 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
45 SimulatedEventLoopFactory event_loop_factory_;
46
47 // Event loop and app for Ping
48 std::unique_ptr<EventLoop> ping_event_loop_;
49 Ping ping_;
50
51 // Event loop and app for Pong
52 std::unique_ptr<EventLoop> pong_event_loop_;
53 Pong pong_;
54};
55
Brian Silverman1f345222020-09-24 21:14:48 -070056using LoggerDeathTest = LoggerTest;
57
Austin Schuhe309d2a2019-11-29 13:25:21 -080058// Tests that we can startup at all. This confirms that the channels are all in
59// the config.
60TEST_F(LoggerTest, Starts) {
Austin Schuhc243b422020-10-11 15:35:08 -070061 const ::std::string tmpdir = aos::testing::TestTmpDir();
Austin Schuh2f8fd752020-09-01 22:38:28 -070062 const ::std::string base_name = tmpdir + "/logfile";
63 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuhe309d2a2019-11-29 13:25:21 -080064 // Remove it.
65 unlink(logfile.c_str());
66
67 LOG(INFO) << "Logging data to " << logfile;
68
69 {
Austin Schuhe309d2a2019-11-29 13:25:21 -080070 std::unique_ptr<EventLoop> logger_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080071 event_loop_factory_.MakeEventLoop("logger");
Austin Schuhe309d2a2019-11-29 13:25:21 -080072
73 event_loop_factory_.RunFor(chrono::milliseconds(95));
74
Brian Silverman1f345222020-09-24 21:14:48 -070075 Logger logger(logger_event_loop.get());
Austin Schuh8c399962020-12-25 21:51:45 -080076 logger.set_separate_config(false);
Brian Silverman1f345222020-09-24 21:14:48 -070077 logger.set_polling_period(std::chrono::milliseconds(100));
78 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuhe309d2a2019-11-29 13:25:21 -080079 event_loop_factory_.RunFor(chrono::milliseconds(20000));
80 }
81
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080082 // Even though it doesn't make any difference here, exercise the logic for
83 // passing in a separate config.
84 LogReader reader(logfile, &config_.message());
Austin Schuhe309d2a2019-11-29 13:25:21 -080085
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080086 // Confirm that we can remap logged channels to point to new buses.
87 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
Austin Schuhe309d2a2019-11-29 13:25:21 -080088
Austin Schuh15649d62019-12-28 16:36:38 -080089 // This sends out the fetched messages and advances time to the start of the
90 // log file.
James Kuszmaul84ff3e52020-01-03 19:48:53 -080091 reader.Register();
Austin Schuhe309d2a2019-11-29 13:25:21 -080092
Austin Schuh6f3babe2020-01-26 20:34:50 -080093 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
James Kuszmaul84ff3e52020-01-03 19:48:53 -080094
Austin Schuhe309d2a2019-11-29 13:25:21 -080095 std::unique_ptr<EventLoop> test_event_loop =
James Kuszmaul84ff3e52020-01-03 19:48:53 -080096 reader.event_loop_factory()->MakeEventLoop("log_reader");
Austin Schuhe309d2a2019-11-29 13:25:21 -080097
98 int ping_count = 10;
99 int pong_count = 10;
100
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -0800101 // Confirm that the ping value matches in the remapped channel location.
102 test_event_loop->MakeWatcher("/original/test",
Austin Schuhe309d2a2019-11-29 13:25:21 -0800103 [&ping_count](const examples::Ping &ping) {
104 EXPECT_EQ(ping.value(), ping_count + 1);
105 ++ping_count;
106 });
107 // Confirm that the ping and pong counts both match, and the value also
108 // matches.
109 test_event_loop->MakeWatcher(
110 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
111 EXPECT_EQ(pong.value(), pong_count + 1);
112 ++pong_count;
113 EXPECT_EQ(ping_count, pong_count);
114 });
115
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800116 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
Austin Schuhe309d2a2019-11-29 13:25:21 -0800117 EXPECT_EQ(ping_count, 2010);
Austin Schuhe309d2a2019-11-29 13:25:21 -0800118}
119
Brian Silverman1f345222020-09-24 21:14:48 -0700120// Tests calling StartLogging twice.
121TEST_F(LoggerDeathTest, ExtraStart) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800122 const ::std::string tmpdir = aos::testing::TestTmpDir();
Brian Silverman1f345222020-09-24 21:14:48 -0700123 const ::std::string base_name1 = tmpdir + "/logfile1";
124 const ::std::string logfile1 = base_name1 + ".part0.bfbs";
125 const ::std::string base_name2 = tmpdir + "/logfile2";
126 const ::std::string logfile2 = base_name2 + ".part0.bfbs";
127 unlink(logfile1.c_str());
128 unlink(logfile2.c_str());
129
130 LOG(INFO) << "Logging data to " << logfile1 << " then " << logfile2;
131
132 {
133 std::unique_ptr<EventLoop> logger_event_loop =
134 event_loop_factory_.MakeEventLoop("logger");
135
136 event_loop_factory_.RunFor(chrono::milliseconds(95));
137
138 Logger logger(logger_event_loop.get());
139 logger.set_polling_period(std::chrono::milliseconds(100));
140 logger_event_loop->OnRun(
141 [base_name1, base_name2, &logger_event_loop, &logger]() {
142 logger.StartLogging(std::make_unique<LocalLogNamer>(
143 base_name1, logger_event_loop->node()));
144 EXPECT_DEATH(logger.StartLogging(std::make_unique<LocalLogNamer>(
145 base_name2, logger_event_loop->node())),
146 "Already logging");
147 });
148 event_loop_factory_.RunFor(chrono::milliseconds(20000));
149 }
150}
151
152// Tests calling StopLogging twice.
153TEST_F(LoggerDeathTest, ExtraStop) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800154 const ::std::string tmpdir = aos::testing::TestTmpDir();
Brian Silverman1f345222020-09-24 21:14:48 -0700155 const ::std::string base_name = tmpdir + "/logfile";
156 const ::std::string logfile = base_name + ".part0.bfbs";
157 // Remove it.
158 unlink(logfile.c_str());
159
160 LOG(INFO) << "Logging data to " << logfile;
161
162 {
163 std::unique_ptr<EventLoop> logger_event_loop =
164 event_loop_factory_.MakeEventLoop("logger");
165
166 event_loop_factory_.RunFor(chrono::milliseconds(95));
167
168 Logger logger(logger_event_loop.get());
Austin Schuh8c399962020-12-25 21:51:45 -0800169 logger.set_separate_config(false);
Brian Silverman1f345222020-09-24 21:14:48 -0700170 logger.set_polling_period(std::chrono::milliseconds(100));
171 logger_event_loop->OnRun([base_name, &logger_event_loop, &logger]() {
172 logger.StartLogging(std::make_unique<LocalLogNamer>(
173 base_name, logger_event_loop->node()));
174 logger.StopLogging(aos::monotonic_clock::min_time);
175 EXPECT_DEATH(logger.StopLogging(aos::monotonic_clock::min_time),
176 "Not logging right now");
177 });
178 event_loop_factory_.RunFor(chrono::milliseconds(20000));
179 }
180}
181
182// Tests that we can startup twice.
183TEST_F(LoggerTest, StartsTwice) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800184 const ::std::string tmpdir = aos::testing::TestTmpDir();
Brian Silverman1f345222020-09-24 21:14:48 -0700185 const ::std::string base_name1 = tmpdir + "/logfile1";
186 const ::std::string logfile1 = base_name1 + ".part0.bfbs";
187 const ::std::string base_name2 = tmpdir + "/logfile2";
188 const ::std::string logfile2 = base_name2 + ".part0.bfbs";
189 unlink(logfile1.c_str());
190 unlink(logfile2.c_str());
191
192 LOG(INFO) << "Logging data to " << logfile1 << " then " << logfile2;
193
194 {
195 std::unique_ptr<EventLoop> logger_event_loop =
196 event_loop_factory_.MakeEventLoop("logger");
197
198 event_loop_factory_.RunFor(chrono::milliseconds(95));
199
200 Logger logger(logger_event_loop.get());
Austin Schuh8c399962020-12-25 21:51:45 -0800201 logger.set_separate_config(false);
Brian Silverman1f345222020-09-24 21:14:48 -0700202 logger.set_polling_period(std::chrono::milliseconds(100));
203 logger.StartLogging(
204 std::make_unique<LocalLogNamer>(base_name1, logger_event_loop->node()));
205 event_loop_factory_.RunFor(chrono::milliseconds(10000));
206 logger.StopLogging(logger_event_loop->monotonic_now());
207 event_loop_factory_.RunFor(chrono::milliseconds(10000));
208 logger.StartLogging(
209 std::make_unique<LocalLogNamer>(base_name2, logger_event_loop->node()));
210 event_loop_factory_.RunFor(chrono::milliseconds(10000));
211 }
212
213 for (const auto &logfile :
214 {std::make_tuple(logfile1, 10), std::make_tuple(logfile2, 2010)}) {
215 SCOPED_TRACE(std::get<0>(logfile));
216 LogReader reader(std::get<0>(logfile));
217 reader.Register();
218
219 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
220
221 std::unique_ptr<EventLoop> test_event_loop =
222 reader.event_loop_factory()->MakeEventLoop("log_reader");
223
224 int ping_count = std::get<1>(logfile);
225 int pong_count = std::get<1>(logfile);
226
227 // Confirm that the ping and pong counts both match, and the value also
228 // matches.
229 test_event_loop->MakeWatcher("/test",
230 [&ping_count](const examples::Ping &ping) {
231 EXPECT_EQ(ping.value(), ping_count + 1);
232 ++ping_count;
233 });
234 test_event_loop->MakeWatcher(
235 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
236 EXPECT_EQ(pong.value(), pong_count + 1);
237 ++pong_count;
238 EXPECT_EQ(ping_count, pong_count);
239 });
240
241 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
242 EXPECT_EQ(ping_count, std::get<1>(logfile) + 1000);
243 }
244}
245
Austin Schuhfa895892020-01-07 20:07:41 -0800246// Tests that we can read and write rotated log files.
247TEST_F(LoggerTest, RotatedLogFile) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800248 const ::std::string tmpdir = aos::testing::TestTmpDir();
Austin Schuh2f8fd752020-09-01 22:38:28 -0700249 const ::std::string base_name = tmpdir + "/logfile";
250 const ::std::string logfile0 = base_name + ".part0.bfbs";
251 const ::std::string logfile1 = base_name + ".part1.bfbs";
Austin Schuhfa895892020-01-07 20:07:41 -0800252 // Remove it.
253 unlink(logfile0.c_str());
254 unlink(logfile1.c_str());
255
256 LOG(INFO) << "Logging data to " << logfile0 << " and " << logfile1;
257
258 {
Austin Schuhfa895892020-01-07 20:07:41 -0800259 std::unique_ptr<EventLoop> logger_event_loop =
260 event_loop_factory_.MakeEventLoop("logger");
261
262 event_loop_factory_.RunFor(chrono::milliseconds(95));
263
Brian Silverman1f345222020-09-24 21:14:48 -0700264 Logger logger(logger_event_loop.get());
Austin Schuh8c399962020-12-25 21:51:45 -0800265 logger.set_separate_config(false);
Brian Silverman1f345222020-09-24 21:14:48 -0700266 logger.set_polling_period(std::chrono::milliseconds(100));
267 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuhfa895892020-01-07 20:07:41 -0800268 event_loop_factory_.RunFor(chrono::milliseconds(10000));
Austin Schuh2f8fd752020-09-01 22:38:28 -0700269 logger.Rotate();
Austin Schuhfa895892020-01-07 20:07:41 -0800270 event_loop_factory_.RunFor(chrono::milliseconds(10000));
271 }
272
Austin Schuh64fab802020-09-09 22:47:47 -0700273 {
274 // Confirm that the UUIDs match for both the parts and the logger, and the
275 // parts_index increments.
Austin Schuhadd6eb32020-11-09 21:24:26 -0800276 std::vector<SizePrefixedFlatbufferVector<LogFileHeader>> log_header;
Austin Schuh64fab802020-09-09 22:47:47 -0700277 for (std::string_view f : {logfile0, logfile1}) {
Austin Schuh3bd4c402020-11-06 18:19:06 -0800278 log_header.emplace_back(ReadHeader(f).value());
Austin Schuh64fab802020-09-09 22:47:47 -0700279 }
280
Brian Silvermanae7c0332020-09-30 16:58:23 -0700281 EXPECT_EQ(log_header[0].message().log_event_uuid()->string_view(),
282 log_header[1].message().log_event_uuid()->string_view());
Austin Schuh64fab802020-09-09 22:47:47 -0700283 EXPECT_EQ(log_header[0].message().parts_uuid()->string_view(),
284 log_header[1].message().parts_uuid()->string_view());
285
286 EXPECT_EQ(log_header[0].message().parts_index(), 0);
287 EXPECT_EQ(log_header[1].message().parts_index(), 1);
288 }
289
Austin Schuhfa895892020-01-07 20:07:41 -0800290 // Even though it doesn't make any difference here, exercise the logic for
291 // passing in a separate config.
Austin Schuh287d43d2020-12-04 20:19:33 -0800292 LogReader reader(SortParts({logfile0, logfile1}), &config_.message());
Austin Schuhfa895892020-01-07 20:07:41 -0800293
294 // Confirm that we can remap logged channels to point to new buses.
295 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
296
297 // This sends out the fetched messages and advances time to the start of the
298 // log file.
299 reader.Register();
300
Austin Schuh6f3babe2020-01-26 20:34:50 -0800301 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
Austin Schuhfa895892020-01-07 20:07:41 -0800302
303 std::unique_ptr<EventLoop> test_event_loop =
304 reader.event_loop_factory()->MakeEventLoop("log_reader");
305
306 int ping_count = 10;
307 int pong_count = 10;
308
309 // Confirm that the ping value matches in the remapped channel location.
310 test_event_loop->MakeWatcher("/original/test",
311 [&ping_count](const examples::Ping &ping) {
312 EXPECT_EQ(ping.value(), ping_count + 1);
313 ++ping_count;
314 });
315 // Confirm that the ping and pong counts both match, and the value also
316 // matches.
317 test_event_loop->MakeWatcher(
318 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
319 EXPECT_EQ(pong.value(), pong_count + 1);
320 ++pong_count;
321 EXPECT_EQ(ping_count, pong_count);
322 });
323
324 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
325 EXPECT_EQ(ping_count, 2010);
326}
327
Austin Schuh4c4e0092019-12-22 16:18:03 -0800328// Tests that a large number of messages per second doesn't overwhelm writev.
329TEST_F(LoggerTest, ManyMessages) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800330 const ::std::string tmpdir = aos::testing::TestTmpDir();
Austin Schuh2f8fd752020-09-01 22:38:28 -0700331 const ::std::string base_name = tmpdir + "/logfile";
332 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuh4c4e0092019-12-22 16:18:03 -0800333 // Remove the log file.
334 unlink(logfile.c_str());
335
336 LOG(INFO) << "Logging data to " << logfile;
Austin Schuh4c3b9702020-08-30 11:34:55 -0700337 ping_.set_quiet(true);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800338
339 {
Austin Schuh4c4e0092019-12-22 16:18:03 -0800340 std::unique_ptr<EventLoop> logger_event_loop =
341 event_loop_factory_.MakeEventLoop("logger");
342
343 std::unique_ptr<EventLoop> ping_spammer_event_loop =
344 event_loop_factory_.MakeEventLoop("ping_spammer");
345 aos::Sender<examples::Ping> ping_sender =
346 ping_spammer_event_loop->MakeSender<examples::Ping>("/test");
347
348 aos::TimerHandler *timer_handler =
349 ping_spammer_event_loop->AddTimer([&ping_sender]() {
350 aos::Sender<examples::Ping>::Builder builder =
351 ping_sender.MakeBuilder();
352 examples::Ping::Builder ping_builder =
353 builder.MakeBuilder<examples::Ping>();
354 CHECK(builder.Send(ping_builder.Finish()));
355 });
356
357 // 100 ms / 0.05 ms -> 2000 messages. Should be enough to crash it.
358 ping_spammer_event_loop->OnRun([&ping_spammer_event_loop, timer_handler]() {
359 timer_handler->Setup(ping_spammer_event_loop->monotonic_now(),
360 chrono::microseconds(50));
361 });
362
Brian Silverman1f345222020-09-24 21:14:48 -0700363 Logger logger(logger_event_loop.get());
Austin Schuh8c399962020-12-25 21:51:45 -0800364 logger.set_separate_config(false);
Brian Silverman1f345222020-09-24 21:14:48 -0700365 logger.set_polling_period(std::chrono::milliseconds(100));
366 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800367
368 event_loop_factory_.RunFor(chrono::milliseconds(1000));
369 }
370}
371
Austin Schuh8c399962020-12-25 21:51:45 -0800372std::vector<std::string> MakeLogFiles(std::string logfile_base1, std::string logfile_base2) {
Austin Schuh315b96b2020-12-11 21:21:12 -0800373 return std::vector<std::string>(
Austin Schuh8c399962020-12-25 21:51:45 -0800374 {logfile_base1 + "_pi1_data.part0.bfbs",
375 logfile_base1 + "_pi2_data/test/aos.examples.Pong.part0.bfbs",
376 logfile_base1 + "_pi2_data/test/aos.examples.Pong.part1.bfbs",
377 logfile_base2 + "_pi2_data.part0.bfbs",
378 logfile_base1 + "_timestamps/pi1/aos/remote_timestamps/pi2/"
379 "aos.message_bridge.RemoteMessage.part0.bfbs",
380 logfile_base1 + "_timestamps/pi1/aos/remote_timestamps/pi2/"
381 "aos.message_bridge.RemoteMessage.part1.bfbs",
382 logfile_base2 + "_timestamps/pi2/aos/remote_timestamps/pi1/"
383 "aos.message_bridge.RemoteMessage.part0.bfbs",
384 logfile_base2 + "_timestamps/pi2/aos/remote_timestamps/pi1/"
385 "aos.message_bridge.RemoteMessage.part1.bfbs",
386 logfile_base2 +
Austin Schuh315b96b2020-12-11 21:21:12 -0800387 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part0.bfbs",
Austin Schuh8c399962020-12-25 21:51:45 -0800388 logfile_base2 +
Austin Schuh315b96b2020-12-11 21:21:12 -0800389 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part1.bfbs",
Austin Schuh8c399962020-12-25 21:51:45 -0800390 logfile_base1 +
Austin Schuh315b96b2020-12-11 21:21:12 -0800391 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part0.bfbs",
Austin Schuh8c399962020-12-25 21:51:45 -0800392 logfile_base1 +
393 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part1.bfbs",
394 absl::StrCat(logfile_base1, "_", kConfigSha1, ".bfbs"),
395 absl::StrCat(logfile_base2, "_", kConfigSha1, ".bfbs")});
Austin Schuh315b96b2020-12-11 21:21:12 -0800396}
397
Austin Schuh15649d62019-12-28 16:36:38 -0800398class MultinodeLoggerTest : public ::testing::Test {
399 public:
400 MultinodeLoggerTest()
401 : config_(aos::configuration::ReadConfig(
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800402 "aos/events/logging/multinode_pingpong_config.json")),
Austin Schuhac0771c2020-01-07 18:36:30 -0800403 event_loop_factory_(&config_.message()),
Austin Schuhcde938c2020-02-02 17:30:07 -0800404 pi1_(
405 configuration::GetNode(event_loop_factory_.configuration(), "pi1")),
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700406 pi2_(
407 configuration::GetNode(event_loop_factory_.configuration(), "pi2")),
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800408 tmp_dir_(aos::testing::TestTmpDir()),
Austin Schuh8c399962020-12-25 21:51:45 -0800409 logfile_base1_(tmp_dir_ + "/multi_logfile1"),
410 logfile_base2_(tmp_dir_ + "/multi_logfile2"),
Austin Schuh315b96b2020-12-11 21:21:12 -0800411 pi1_reboot_logfiles_(
Austin Schuh8c399962020-12-25 21:51:45 -0800412 {logfile_base1_ + "_pi1_data.part0.bfbs",
413 logfile_base1_ + "_pi2_data/test/aos.examples.Pong.part0.bfbs",
414 logfile_base1_ + "_pi2_data/test/aos.examples.Pong.part1.bfbs",
415 logfile_base1_ + "_pi2_data/test/aos.examples.Pong.part2.bfbs",
416 logfile_base1_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
417 "aos.message_bridge.RemoteMessage.part0.bfbs",
418 logfile_base1_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
419 "aos.message_bridge.RemoteMessage.part1.bfbs",
420 logfile_base1_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
421 "aos.message_bridge.RemoteMessage.part2.bfbs",
422 logfile_base1_ +
Austin Schuh2f8fd752020-09-01 22:38:28 -0700423 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part0.bfbs",
Austin Schuh8c399962020-12-25 21:51:45 -0800424 logfile_base1_ +
Austin Schuh315b96b2020-12-11 21:21:12 -0800425 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part1.bfbs",
Austin Schuh8c399962020-12-25 21:51:45 -0800426 logfile_base1_ +
427 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part2.bfbs",
428 absl::StrCat(logfile_base1_, "_", kConfigSha1, ".bfbs")}),
429 logfiles_(MakeLogFiles(logfile_base1_, logfile_base2_)),
Austin Schuhc9049732020-12-21 22:27:15 -0800430 pi1_single_direction_logfiles_(
Austin Schuh8c399962020-12-25 21:51:45 -0800431 {logfile_base1_ + "_pi1_data.part0.bfbs",
432 logfile_base1_ + "_pi2_data/test/aos.examples.Pong.part0.bfbs",
433 logfile_base1_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
434 "aos.message_bridge.RemoteMessage.part0.bfbs",
435 logfile_base1_ +
436 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part0.bfbs",
437 absl::StrCat(logfile_base1_, "_", kConfigSha1, ".bfbs")}),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700438 structured_logfiles_{
439 std::vector<std::string>{logfiles_[0]},
440 std::vector<std::string>{logfiles_[1], logfiles_[2]},
441 std::vector<std::string>{logfiles_[3]},
442 std::vector<std::string>{logfiles_[4], logfiles_[5]},
443 std::vector<std::string>{logfiles_[6], logfiles_[7]},
444 std::vector<std::string>{logfiles_[8], logfiles_[9]},
445 std::vector<std::string>{logfiles_[10], logfiles_[11]}},
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700446 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping", pi1_)),
447 ping_(ping_event_loop_.get()),
448 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong", pi2_)),
449 pong_(pong_event_loop_.get()) {
450 // Go through and remove the logfiles if they already exist.
451 for (const auto file : logfiles_) {
452 unlink(file.c_str());
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800453 unlink((file + ".xz").c_str());
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700454 }
455
Austin Schuh8c399962020-12-25 21:51:45 -0800456 for (const auto file : MakeLogFiles("relogged1", "relogged2")) {
Austin Schuh315b96b2020-12-11 21:21:12 -0800457 unlink(file.c_str());
458 }
459
460 for (const auto file : pi1_reboot_logfiles_) {
461 unlink(file.c_str());
462 }
463
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700464 LOG(INFO) << "Logging data to " << logfiles_[0] << ", " << logfiles_[1]
465 << " and " << logfiles_[2];
466 }
467
468 struct LoggerState {
469 std::unique_ptr<EventLoop> event_loop;
470 std::unique_ptr<Logger> logger;
471 };
472
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700473 LoggerState MakeLogger(const Node *node,
474 SimulatedEventLoopFactory *factory = nullptr) {
475 if (factory == nullptr) {
476 factory = &event_loop_factory_;
477 }
478 return {factory->MakeEventLoop("logger", node), {}};
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700479 }
480
Austin Schuh3bd4c402020-11-06 18:19:06 -0800481 void StartLogger(LoggerState *logger, std::string logfile_base = "",
482 bool compress = false) {
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700483 if (logfile_base.empty()) {
Austin Schuh8c399962020-12-25 21:51:45 -0800484 if (logger->event_loop->node()->name()->string_view() == "pi1") {
485 logfile_base = logfile_base1_;
486 } else {
487 logfile_base = logfile_base2_;
488 }
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700489 }
490
Brian Silverman1f345222020-09-24 21:14:48 -0700491 logger->logger = std::make_unique<Logger>(logger->event_loop.get());
492 logger->logger->set_polling_period(std::chrono::milliseconds(100));
Austin Schuh0ca51f32020-12-25 21:51:45 -0800493 logger->logger->set_name(absl::StrCat(
494 "name_prefix_", logger->event_loop->node()->name()->str()));
Austin Schuh3bd4c402020-11-06 18:19:06 -0800495 logger->event_loop->OnRun([logger, logfile_base, compress]() {
496 std::unique_ptr<MultiNodeLogNamer> namer =
497 std::make_unique<MultiNodeLogNamer>(
498 logfile_base, logger->event_loop->configuration(),
499 logger->event_loop->node());
500 if (compress) {
501#ifdef LZMA
502 namer->set_extension(".xz");
503 namer->set_encoder_factory(
504 []() { return std::make_unique<aos::logger::LzmaEncoder>(3); });
505#else
506 LOG(FATAL) << "Compression unsupported";
507#endif
508 }
509
510 logger->logger->StartLogging(std::move(namer));
Brian Silverman1f345222020-09-24 21:14:48 -0700511 });
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700512 }
Austin Schuh15649d62019-12-28 16:36:38 -0800513
Austin Schuh3bd4c402020-11-06 18:19:06 -0800514 void VerifyParts(const std::vector<LogFile> &sorted_parts,
515 const std::vector<std::string> &corrupted_parts = {}) {
516 EXPECT_EQ(sorted_parts.size(), 2u);
517
518 // Count up the number of UUIDs and make sure they are what we expect as a
519 // sanity check.
520 std::set<std::string> log_event_uuids;
521 std::set<std::string> parts_uuids;
522 std::set<std::string> both_uuids;
523
524 size_t missing_rt_count = 0;
525
526 std::vector<std::string> logger_nodes;
527 for (const LogFile &log_file : sorted_parts) {
528 EXPECT_FALSE(log_file.log_event_uuid.empty());
529 log_event_uuids.insert(log_file.log_event_uuid);
530 logger_nodes.emplace_back(log_file.logger_node);
531 both_uuids.insert(log_file.log_event_uuid);
Austin Schuh0ca51f32020-12-25 21:51:45 -0800532 EXPECT_TRUE(log_file.config);
533 EXPECT_EQ(log_file.name,
534 absl::StrCat("name_prefix_", log_file.logger_node));
Austin Schuh3bd4c402020-11-06 18:19:06 -0800535
536 for (const LogParts &part : log_file.parts) {
537 EXPECT_NE(part.monotonic_start_time, aos::monotonic_clock::min_time)
538 << ": " << part;
539 missing_rt_count +=
540 part.realtime_start_time == aos::realtime_clock::min_time;
541
542 EXPECT_TRUE(log_event_uuids.find(part.log_event_uuid) !=
543 log_event_uuids.end());
544 EXPECT_NE(part.node, "");
Austin Schuh0ca51f32020-12-25 21:51:45 -0800545 EXPECT_TRUE(log_file.config);
Austin Schuh3bd4c402020-11-06 18:19:06 -0800546 parts_uuids.insert(part.parts_uuid);
547 both_uuids.insert(part.parts_uuid);
548 }
549 }
550
551 // We won't have RT timestamps for 5 log files. We don't log the RT start
552 // time on remote nodes because we don't know it and would be guessing. And
553 // the log reader can actually do a better job.
554 EXPECT_EQ(missing_rt_count, 5u);
555
556 EXPECT_EQ(log_event_uuids.size(), 2u);
557 EXPECT_EQ(parts_uuids.size(), ToLogReaderVector(sorted_parts).size());
558 EXPECT_EQ(log_event_uuids.size() + parts_uuids.size(), both_uuids.size());
559
560 // Test that each list of parts is in order. Don't worry about the ordering
561 // between part file lists though.
562 // (inner vectors all need to be in order, but outer one doesn't matter).
563 EXPECT_THAT(ToLogReaderVector(sorted_parts),
564 ::testing::UnorderedElementsAreArray(structured_logfiles_));
565
566 EXPECT_THAT(logger_nodes, ::testing::UnorderedElementsAre("pi1", "pi2"));
567
568 EXPECT_NE(sorted_parts[0].realtime_start_time,
569 aos::realtime_clock::min_time);
570 EXPECT_NE(sorted_parts[1].realtime_start_time,
571 aos::realtime_clock::min_time);
572
573 EXPECT_NE(sorted_parts[0].monotonic_start_time,
574 aos::monotonic_clock::min_time);
575 EXPECT_NE(sorted_parts[1].monotonic_start_time,
576 aos::monotonic_clock::min_time);
577
578 EXPECT_THAT(sorted_parts[0].corrupted, ::testing::Eq(corrupted_parts));
579 EXPECT_THAT(sorted_parts[1].corrupted, ::testing::Eq(corrupted_parts));
580 }
581
Austin Schuhc9049732020-12-21 22:27:15 -0800582 void ConfirmReadable(const std::vector<std::string> &files) {
583 LogReader reader(SortParts(files));
584
585 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
586 reader.Register(&log_reader_factory);
587
588 log_reader_factory.Run();
589
590 reader.Deregister();
591 }
592
Austin Schuh3bd4c402020-11-06 18:19:06 -0800593 void AddExtension(std::string_view extension) {
594 std::transform(logfiles_.begin(), logfiles_.end(), logfiles_.begin(),
595 [extension](const std::string &in) {
596 return absl::StrCat(in, extension);
597 });
598
599 std::transform(structured_logfiles_.begin(), structured_logfiles_.end(),
600 structured_logfiles_.begin(),
601 [extension](std::vector<std::string> in) {
602 std::transform(in.begin(), in.end(), in.begin(),
603 [extension](const std::string &in_str) {
604 return absl::StrCat(in_str, extension);
605 });
606 return in;
607 });
608 }
609
Austin Schuh15649d62019-12-28 16:36:38 -0800610 // Config and factory.
611 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
612 SimulatedEventLoopFactory event_loop_factory_;
613
Austin Schuhcde938c2020-02-02 17:30:07 -0800614 const Node *pi1_;
615 const Node *pi2_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700616
617 std::string tmp_dir_;
Austin Schuh8c399962020-12-25 21:51:45 -0800618 std::string logfile_base1_;
619 std::string logfile_base2_;
Austin Schuh315b96b2020-12-11 21:21:12 -0800620 std::vector<std::string> pi1_reboot_logfiles_;
Austin Schuh2f8fd752020-09-01 22:38:28 -0700621 std::vector<std::string> logfiles_;
Austin Schuhc9049732020-12-21 22:27:15 -0800622 std::vector<std::string> pi1_single_direction_logfiles_;
Austin Schuh2f8fd752020-09-01 22:38:28 -0700623
624 std::vector<std::vector<std::string>> structured_logfiles_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700625
626 std::unique_ptr<EventLoop> ping_event_loop_;
627 Ping ping_;
628 std::unique_ptr<EventLoop> pong_event_loop_;
629 Pong pong_;
Austin Schuh15649d62019-12-28 16:36:38 -0800630};
631
Austin Schuh391e3172020-09-01 22:48:18 -0700632// Counts the number of messages on a channel. Returns (channel name, channel
633// type, count) for every message matching matcher()
634std::vector<std::tuple<std::string, std::string, int>> CountChannelsMatching(
Austin Schuh8c399962020-12-25 21:51:45 -0800635 std::shared_ptr<const aos::Configuration> config,
Austin Schuh6f3babe2020-01-26 20:34:50 -0800636 std::string_view filename,
637 std::function<bool(const MessageHeader *)> matcher) {
638 MessageReader message_reader(filename);
Austin Schuh8c399962020-12-25 21:51:45 -0800639 std::vector<int> counts(config->channels()->size(), 0);
Austin Schuh15649d62019-12-28 16:36:38 -0800640
Austin Schuh6f3babe2020-01-26 20:34:50 -0800641 while (true) {
Austin Schuhadd6eb32020-11-09 21:24:26 -0800642 std::optional<SizePrefixedFlatbufferVector<MessageHeader>> msg =
Austin Schuh6f3babe2020-01-26 20:34:50 -0800643 message_reader.ReadMessage();
644 if (!msg) {
645 break;
646 }
647
648 if (matcher(&msg.value().message())) {
649 counts[msg.value().message().channel_index()]++;
650 }
651 }
652
Austin Schuh391e3172020-09-01 22:48:18 -0700653 std::vector<std::tuple<std::string, std::string, int>> result;
Austin Schuh6f3babe2020-01-26 20:34:50 -0800654 int channel = 0;
655 for (size_t i = 0; i < counts.size(); ++i) {
656 if (counts[i] != 0) {
Austin Schuh8c399962020-12-25 21:51:45 -0800657 const Channel *channel = config->channels()->Get(i);
Austin Schuh391e3172020-09-01 22:48:18 -0700658 result.push_back(std::make_tuple(channel->name()->str(),
659 channel->type()->str(), counts[i]));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800660 }
661 ++channel;
662 }
663
664 return result;
665}
666
667// Counts the number of messages (channel, count) for all data messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700668std::vector<std::tuple<std::string, std::string, int>> CountChannelsData(
Austin Schuh8c399962020-12-25 21:51:45 -0800669 std::shared_ptr<const aos::Configuration> config,
Austin Schuh391e3172020-09-01 22:48:18 -0700670 std::string_view filename) {
Austin Schuh8c399962020-12-25 21:51:45 -0800671 return CountChannelsMatching(config, filename, [](const MessageHeader *msg) {
Austin Schuh6f3babe2020-01-26 20:34:50 -0800672 if (msg->has_data()) {
673 CHECK(!msg->has_monotonic_remote_time());
674 CHECK(!msg->has_realtime_remote_time());
675 CHECK(!msg->has_remote_queue_index());
676 return true;
677 }
678 return false;
679 });
680}
681
682// Counts the number of messages (channel, count) for all timestamp messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700683std::vector<std::tuple<std::string, std::string, int>> CountChannelsTimestamp(
Austin Schuh8c399962020-12-25 21:51:45 -0800684 std::shared_ptr<const aos::Configuration> config,
Austin Schuh6f3babe2020-01-26 20:34:50 -0800685 std::string_view filename) {
Austin Schuh8c399962020-12-25 21:51:45 -0800686 return CountChannelsMatching(config, filename, [](const MessageHeader *msg) {
Austin Schuh6f3babe2020-01-26 20:34:50 -0800687 if (!msg->has_data()) {
688 CHECK(msg->has_monotonic_remote_time());
689 CHECK(msg->has_realtime_remote_time());
690 CHECK(msg->has_remote_queue_index());
691 return true;
692 }
693 return false;
694 });
695}
696
Austin Schuhcde938c2020-02-02 17:30:07 -0800697// Tests that we can write and read simple multi-node log files.
698TEST_F(MultinodeLoggerTest, SimpleMultiNode) {
Austin Schuh15649d62019-12-28 16:36:38 -0800699 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700700 LoggerState pi1_logger = MakeLogger(pi1_);
701 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuh15649d62019-12-28 16:36:38 -0800702
703 event_loop_factory_.RunFor(chrono::milliseconds(95));
704
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700705 StartLogger(&pi1_logger);
706 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800707
Austin Schuh15649d62019-12-28 16:36:38 -0800708 event_loop_factory_.RunFor(chrono::milliseconds(20000));
709 }
710
Austin Schuh6f3babe2020-01-26 20:34:50 -0800711 {
Austin Schuh64fab802020-09-09 22:47:47 -0700712 std::set<std::string> logfile_uuids;
713 std::set<std::string> parts_uuids;
714 // Confirm that we have the expected number of UUIDs for both the logfile
715 // UUIDs and parts UUIDs.
Austin Schuhadd6eb32020-11-09 21:24:26 -0800716 std::vector<SizePrefixedFlatbufferVector<LogFileHeader>> log_header;
Austin Schuh64fab802020-09-09 22:47:47 -0700717 for (std::string_view f : logfiles_) {
Austin Schuh3bd4c402020-11-06 18:19:06 -0800718 log_header.emplace_back(ReadHeader(f).value());
Austin Schuh8c399962020-12-25 21:51:45 -0800719 if (!log_header.back().message().has_configuration()) {
720 logfile_uuids.insert(
721 log_header.back().message().log_event_uuid()->str());
722 parts_uuids.insert(log_header.back().message().parts_uuid()->str());
723 }
Austin Schuh64fab802020-09-09 22:47:47 -0700724 }
Austin Schuh15649d62019-12-28 16:36:38 -0800725
Austin Schuh64fab802020-09-09 22:47:47 -0700726 EXPECT_EQ(logfile_uuids.size(), 2u);
727 EXPECT_EQ(parts_uuids.size(), 7u);
728
729 // And confirm everything is on the correct node.
730 EXPECT_EQ(log_header[0].message().node()->name()->string_view(), "pi1");
731 EXPECT_EQ(log_header[1].message().node()->name()->string_view(), "pi2");
732 EXPECT_EQ(log_header[2].message().node()->name()->string_view(), "pi2");
733 EXPECT_EQ(log_header[3].message().node()->name()->string_view(), "pi2");
734 EXPECT_EQ(log_header[4].message().node()->name()->string_view(), "pi2");
735 EXPECT_EQ(log_header[5].message().node()->name()->string_view(), "pi2");
736 EXPECT_EQ(log_header[6].message().node()->name()->string_view(), "pi1");
737 EXPECT_EQ(log_header[7].message().node()->name()->string_view(), "pi1");
738 EXPECT_EQ(log_header[8].message().node()->name()->string_view(), "pi1");
739 EXPECT_EQ(log_header[9].message().node()->name()->string_view(), "pi1");
740 EXPECT_EQ(log_header[10].message().node()->name()->string_view(), "pi2");
741 EXPECT_EQ(log_header[11].message().node()->name()->string_view(), "pi2");
742
743 // And the parts index matches.
744 EXPECT_EQ(log_header[0].message().parts_index(), 0);
745 EXPECT_EQ(log_header[1].message().parts_index(), 0);
746 EXPECT_EQ(log_header[2].message().parts_index(), 1);
747 EXPECT_EQ(log_header[3].message().parts_index(), 0);
748 EXPECT_EQ(log_header[4].message().parts_index(), 0);
749 EXPECT_EQ(log_header[5].message().parts_index(), 1);
750 EXPECT_EQ(log_header[6].message().parts_index(), 0);
751 EXPECT_EQ(log_header[7].message().parts_index(), 1);
752 EXPECT_EQ(log_header[8].message().parts_index(), 0);
753 EXPECT_EQ(log_header[9].message().parts_index(), 1);
754 EXPECT_EQ(log_header[10].message().parts_index(), 0);
755 EXPECT_EQ(log_header[11].message().parts_index(), 1);
756 }
757
Austin Schuh8c399962020-12-25 21:51:45 -0800758 const std::vector<LogFile> sorted_log_files = SortParts(logfiles_);
Austin Schuh64fab802020-09-09 22:47:47 -0700759 {
Austin Schuh391e3172020-09-01 22:48:18 -0700760 using ::testing::UnorderedElementsAre;
Austin Schuh8c399962020-12-25 21:51:45 -0800761 std::shared_ptr<const aos::Configuration> config =
762 sorted_log_files[0].config;
Austin Schuh391e3172020-09-01 22:48:18 -0700763
Austin Schuh6f3babe2020-01-26 20:34:50 -0800764 // Timing reports, pings
Austin Schuh2f8fd752020-09-01 22:38:28 -0700765 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800766 CountChannelsData(config, logfiles_[0]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700767 UnorderedElementsAre(
768 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200),
769 std::make_tuple("/pi1/aos", "aos.timing.Report", 40),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800770 std::make_tuple("/test", "aos.examples.Ping", 2001)))
771 << " : " << logfiles_[0];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800772 // Timestamps for pong
Austin Schuh2f8fd752020-09-01 22:38:28 -0700773 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800774 CountChannelsTimestamp(config, logfiles_[0]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700775 UnorderedElementsAre(
776 std::make_tuple("/test", "aos.examples.Pong", 2001),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800777 std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200)))
778 << " : " << logfiles_[0];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800779
780 // Pong data.
Austin Schuh20ac95d2020-12-05 17:24:19 -0800781 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800782 CountChannelsData(config, logfiles_[1]),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800783 UnorderedElementsAre(std::make_tuple("/test", "aos.examples.Pong", 91)))
784 << " : " << logfiles_[1];
Austin Schuh8c399962020-12-25 21:51:45 -0800785 EXPECT_THAT(CountChannelsData(config, logfiles_[2]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700786 UnorderedElementsAre(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800787 std::make_tuple("/test", "aos.examples.Pong", 1910)))
788 << " : " << logfiles_[1];
Austin Schuh391e3172020-09-01 22:48:18 -0700789
Austin Schuh6f3babe2020-01-26 20:34:50 -0800790 // No timestamps
Austin Schuh8c399962020-12-25 21:51:45 -0800791 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[1]), UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800792 << " : " << logfiles_[1];
Austin Schuh8c399962020-12-25 21:51:45 -0800793 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[2]), UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800794 << " : " << logfiles_[2];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800795
796 // Timing reports and pongs.
Austin Schuh2f8fd752020-09-01 22:38:28 -0700797 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800798 CountChannelsData(config, logfiles_[3]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700799 UnorderedElementsAre(
800 std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200),
801 std::make_tuple("/pi2/aos", "aos.timing.Report", 40),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800802 std::make_tuple("/test", "aos.examples.Pong", 2001)))
803 << " : " << logfiles_[3];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800804 // And ping timestamps.
Austin Schuh2f8fd752020-09-01 22:38:28 -0700805 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800806 CountChannelsTimestamp(config, logfiles_[3]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700807 UnorderedElementsAre(
808 std::make_tuple("/test", "aos.examples.Ping", 2001),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800809 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200)))
810 << " : " << logfiles_[3];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700811
812 // Timestamps from pi2 on pi1, and the other way.
Austin Schuh8c399962020-12-25 21:51:45 -0800813 EXPECT_THAT(CountChannelsData(config, logfiles_[4]), UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800814 << " : " << logfiles_[4];
Austin Schuh8c399962020-12-25 21:51:45 -0800815 EXPECT_THAT(CountChannelsData(config, logfiles_[5]), UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800816 << " : " << logfiles_[5];
Austin Schuh8c399962020-12-25 21:51:45 -0800817 EXPECT_THAT(CountChannelsData(config, logfiles_[6]), UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800818 << " : " << logfiles_[6];
Austin Schuh8c399962020-12-25 21:51:45 -0800819 EXPECT_THAT(CountChannelsData(config, logfiles_[7]), UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800820 << " : " << logfiles_[7];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700821 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800822 CountChannelsTimestamp(config, logfiles_[4]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700823 UnorderedElementsAre(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800824 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 9),
825 std::make_tuple("/test", "aos.examples.Ping", 91)))
826 << " : " << logfiles_[4];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700827 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800828 CountChannelsTimestamp(config, logfiles_[5]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700829 UnorderedElementsAre(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800830 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 191),
831 std::make_tuple("/test", "aos.examples.Ping", 1910)))
832 << " : " << logfiles_[5];
Austin Schuh8c399962020-12-25 21:51:45 -0800833 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[6]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700834 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800835 "/pi2/aos", "aos.message_bridge.Timestamp", 9)))
836 << " : " << logfiles_[6];
Austin Schuh8c399962020-12-25 21:51:45 -0800837 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[7]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700838 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800839 "/pi2/aos", "aos.message_bridge.Timestamp", 191)))
840 << " : " << logfiles_[7];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700841
842 // And then test that the remotely logged timestamp data files only have
843 // timestamps in them.
Austin Schuh8c399962020-12-25 21:51:45 -0800844 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[8]), UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800845 << " : " << logfiles_[8];
Austin Schuh8c399962020-12-25 21:51:45 -0800846 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[9]), UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800847 << " : " << logfiles_[9];
Austin Schuh8c399962020-12-25 21:51:45 -0800848 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[10]), UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800849 << " : " << logfiles_[10];
Austin Schuh8c399962020-12-25 21:51:45 -0800850 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[11]), UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800851 << " : " << logfiles_[11];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700852
Austin Schuh8c399962020-12-25 21:51:45 -0800853 EXPECT_THAT(CountChannelsData(config, logfiles_[8]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700854 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800855 "/pi1/aos", "aos.message_bridge.Timestamp", 9)))
856 << " : " << logfiles_[8];
Austin Schuh8c399962020-12-25 21:51:45 -0800857 EXPECT_THAT(CountChannelsData(config, logfiles_[9]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700858 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800859 "/pi1/aos", "aos.message_bridge.Timestamp", 191)))
860 << " : " << logfiles_[9];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700861
Austin Schuh8c399962020-12-25 21:51:45 -0800862 EXPECT_THAT(CountChannelsData(config, logfiles_[10]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700863 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800864 "/pi2/aos", "aos.message_bridge.Timestamp", 9)))
865 << " : " << logfiles_[10];
Austin Schuh8c399962020-12-25 21:51:45 -0800866 EXPECT_THAT(CountChannelsData(config, logfiles_[11]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700867 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800868 "/pi2/aos", "aos.message_bridge.Timestamp", 191)))
869 << " : " << logfiles_[11];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800870 }
871
Austin Schuh8c399962020-12-25 21:51:45 -0800872 LogReader reader(sorted_log_files);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800873
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700874 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuh6331ef92020-01-07 18:28:09 -0800875 log_reader_factory.set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800876
877 // This sends out the fetched messages and advances time to the start of the
878 // log file.
Austin Schuh6331ef92020-01-07 18:28:09 -0800879 reader.Register(&log_reader_factory);
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800880
Austin Schuhac0771c2020-01-07 18:36:30 -0800881 const Node *pi1 =
882 configuration::GetNode(log_reader_factory.configuration(), "pi1");
Austin Schuh6f3babe2020-01-26 20:34:50 -0800883 const Node *pi2 =
884 configuration::GetNode(log_reader_factory.configuration(), "pi2");
Austin Schuhac0771c2020-01-07 18:36:30 -0800885
Austin Schuh2f8fd752020-09-01 22:38:28 -0700886 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
887 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
888 LOG(INFO) << "now pi1 "
889 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
890 LOG(INFO) << "now pi2 "
891 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
892
Austin Schuh6f3babe2020-01-26 20:34:50 -0800893 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800894
895 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800896
Austin Schuh6f3babe2020-01-26 20:34:50 -0800897 std::unique_ptr<EventLoop> pi1_event_loop =
Austin Schuhac0771c2020-01-07 18:36:30 -0800898 log_reader_factory.MakeEventLoop("test", pi1);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800899 std::unique_ptr<EventLoop> pi2_event_loop =
900 log_reader_factory.MakeEventLoop("test", pi2);
Austin Schuh15649d62019-12-28 16:36:38 -0800901
Austin Schuh6f3babe2020-01-26 20:34:50 -0800902 int pi1_ping_count = 10;
903 int pi2_ping_count = 10;
904 int pi1_pong_count = 10;
905 int pi2_pong_count = 10;
Austin Schuh15649d62019-12-28 16:36:38 -0800906
907 // Confirm that the ping value matches.
Austin Schuh6f3babe2020-01-26 20:34:50 -0800908 pi1_event_loop->MakeWatcher(
909 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
Austin Schuh2f8fd752020-09-01 22:38:28 -0700910 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping) << " at "
Austin Schuh6f3babe2020-01-26 20:34:50 -0800911 << pi1_event_loop->context().monotonic_remote_time << " -> "
912 << pi1_event_loop->context().monotonic_event_time;
913 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
914 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
915 pi1_ping_count * chrono::milliseconds(10) +
916 monotonic_clock::epoch());
917 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
918 pi1_ping_count * chrono::milliseconds(10) +
919 realtime_clock::epoch());
920 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
921 pi1_event_loop->context().monotonic_event_time);
922 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
923 pi1_event_loop->context().realtime_event_time);
Austin Schuh15649d62019-12-28 16:36:38 -0800924
Austin Schuh6f3babe2020-01-26 20:34:50 -0800925 ++pi1_ping_count;
926 });
927 pi2_event_loop->MakeWatcher(
928 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
Austin Schuh2f8fd752020-09-01 22:38:28 -0700929 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping) << " at "
Austin Schuh6f3babe2020-01-26 20:34:50 -0800930 << pi2_event_loop->context().monotonic_remote_time << " -> "
931 << pi2_event_loop->context().monotonic_event_time;
932 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
933
934 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
935 pi2_ping_count * chrono::milliseconds(10) +
936 monotonic_clock::epoch());
937 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
938 pi2_ping_count * chrono::milliseconds(10) +
939 realtime_clock::epoch());
940 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time +
941 chrono::microseconds(150),
942 pi2_event_loop->context().monotonic_event_time);
943 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time +
944 chrono::microseconds(150),
945 pi2_event_loop->context().realtime_event_time);
946 ++pi2_ping_count;
Austin Schuh15649d62019-12-28 16:36:38 -0800947 });
948
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700949 constexpr ssize_t kQueueIndexOffset = -9;
Austin Schuh6f3babe2020-01-26 20:34:50 -0800950 // Confirm that the ping and pong counts both match, and the value also
951 // matches.
952 pi1_event_loop->MakeWatcher(
953 "/test", [&pi1_event_loop, &pi1_ping_count,
954 &pi1_pong_count](const examples::Pong &pong) {
955 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
956 << pi1_event_loop->context().monotonic_remote_time << " -> "
957 << pi1_event_loop->context().monotonic_event_time;
958
959 EXPECT_EQ(pi1_event_loop->context().remote_queue_index,
960 pi1_pong_count + kQueueIndexOffset);
961 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
962 chrono::microseconds(200) +
963 pi1_pong_count * chrono::milliseconds(10) +
964 monotonic_clock::epoch());
965 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
966 chrono::microseconds(200) +
967 pi1_pong_count * chrono::milliseconds(10) +
968 realtime_clock::epoch());
969
970 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time +
971 chrono::microseconds(150),
972 pi1_event_loop->context().monotonic_event_time);
973 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time +
974 chrono::microseconds(150),
975 pi1_event_loop->context().realtime_event_time);
976
977 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
978 ++pi1_pong_count;
979 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
980 });
981 pi2_event_loop->MakeWatcher(
982 "/test", [&pi2_event_loop, &pi2_ping_count,
983 &pi2_pong_count](const examples::Pong &pong) {
984 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
985 << pi2_event_loop->context().monotonic_remote_time << " -> "
986 << pi2_event_loop->context().monotonic_event_time;
987
988 EXPECT_EQ(pi2_event_loop->context().remote_queue_index,
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700989 pi2_pong_count + kQueueIndexOffset);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800990
991 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
992 chrono::microseconds(200) +
993 pi2_pong_count * chrono::milliseconds(10) +
994 monotonic_clock::epoch());
995 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
996 chrono::microseconds(200) +
997 pi2_pong_count * chrono::milliseconds(10) +
998 realtime_clock::epoch());
999
1000 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
1001 pi2_event_loop->context().monotonic_event_time);
1002 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
1003 pi2_event_loop->context().realtime_event_time);
1004
1005 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1006 ++pi2_pong_count;
1007 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1008 });
1009
1010 log_reader_factory.Run();
1011 EXPECT_EQ(pi1_ping_count, 2010);
1012 EXPECT_EQ(pi2_ping_count, 2010);
1013 EXPECT_EQ(pi1_pong_count, 2010);
1014 EXPECT_EQ(pi2_pong_count, 2010);
Austin Schuh6331ef92020-01-07 18:28:09 -08001015
1016 reader.Deregister();
Austin Schuh15649d62019-12-28 16:36:38 -08001017}
1018
James Kuszmaul46d82582020-05-09 19:50:09 -07001019typedef MultinodeLoggerTest MultinodeLoggerDeathTest;
1020
1021// Test that if we feed the replay with a mismatched node list that we die on
1022// the LogReader constructor.
1023TEST_F(MultinodeLoggerDeathTest, MultiNodeBadReplayConfig) {
James Kuszmaul46d82582020-05-09 19:50:09 -07001024 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001025 LoggerState pi1_logger = MakeLogger(pi1_);
1026 LoggerState pi2_logger = MakeLogger(pi2_);
James Kuszmaul46d82582020-05-09 19:50:09 -07001027
1028 event_loop_factory_.RunFor(chrono::milliseconds(95));
1029
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001030 StartLogger(&pi1_logger);
1031 StartLogger(&pi2_logger);
James Kuszmaul46d82582020-05-09 19:50:09 -07001032
James Kuszmaul46d82582020-05-09 19:50:09 -07001033 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1034 }
1035
1036 // Test that, if we add an additional node to the replay config that the
1037 // logger complains about the mismatch in number of nodes.
1038 FlatbufferDetachedBuffer<Configuration> extra_nodes_config =
1039 configuration::MergeWithConfig(&config_.message(), R"({
1040 "nodes": [
1041 {
1042 "name": "extra-node"
1043 }
1044 ]
1045 }
1046 )");
1047
Austin Schuh287d43d2020-12-04 20:19:33 -08001048 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1049 EXPECT_DEATH(LogReader(sorted_parts, &extra_nodes_config.message()),
James Kuszmaul46d82582020-05-09 19:50:09 -07001050 "Log file and replay config need to have matching nodes lists.");
James Kuszmaul46d82582020-05-09 19:50:09 -07001051}
1052
Austin Schuhcde938c2020-02-02 17:30:07 -08001053// Tests that we can read log files where they don't start at the same monotonic
1054// time.
1055TEST_F(MultinodeLoggerTest, StaggeredStart) {
Austin Schuhcde938c2020-02-02 17:30:07 -08001056 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001057 LoggerState pi1_logger = MakeLogger(pi1_);
1058 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuhcde938c2020-02-02 17:30:07 -08001059
1060 event_loop_factory_.RunFor(chrono::milliseconds(95));
1061
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001062 StartLogger(&pi1_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -08001063
1064 event_loop_factory_.RunFor(chrono::milliseconds(200));
1065
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001066 StartLogger(&pi2_logger);
1067
Austin Schuhcde938c2020-02-02 17:30:07 -08001068 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1069 }
1070
Austin Schuh287d43d2020-12-04 20:19:33 -08001071 LogReader reader(SortParts(logfiles_));
Austin Schuhcde938c2020-02-02 17:30:07 -08001072
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001073 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuhcde938c2020-02-02 17:30:07 -08001074 log_reader_factory.set_send_delay(chrono::microseconds(0));
1075
1076 // This sends out the fetched messages and advances time to the start of the
1077 // log file.
1078 reader.Register(&log_reader_factory);
1079
1080 const Node *pi1 =
1081 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1082 const Node *pi2 =
1083 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1084
1085 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1086
1087 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1088
1089 std::unique_ptr<EventLoop> pi1_event_loop =
1090 log_reader_factory.MakeEventLoop("test", pi1);
1091 std::unique_ptr<EventLoop> pi2_event_loop =
1092 log_reader_factory.MakeEventLoop("test", pi2);
1093
1094 int pi1_ping_count = 30;
1095 int pi2_ping_count = 30;
1096 int pi1_pong_count = 30;
1097 int pi2_pong_count = 30;
1098
1099 // Confirm that the ping value matches.
1100 pi1_event_loop->MakeWatcher(
1101 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
1102 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
1103 << pi1_event_loop->context().monotonic_remote_time << " -> "
1104 << pi1_event_loop->context().monotonic_event_time;
1105 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
1106
1107 ++pi1_ping_count;
1108 });
1109 pi2_event_loop->MakeWatcher(
1110 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
1111 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
1112 << pi2_event_loop->context().monotonic_remote_time << " -> "
1113 << pi2_event_loop->context().monotonic_event_time;
1114 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
1115
1116 ++pi2_ping_count;
1117 });
1118
1119 // Confirm that the ping and pong counts both match, and the value also
1120 // matches.
1121 pi1_event_loop->MakeWatcher(
1122 "/test", [&pi1_event_loop, &pi1_ping_count,
1123 &pi1_pong_count](const examples::Pong &pong) {
1124 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
1125 << pi1_event_loop->context().monotonic_remote_time << " -> "
1126 << pi1_event_loop->context().monotonic_event_time;
1127
1128 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
1129 ++pi1_pong_count;
1130 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
1131 });
1132 pi2_event_loop->MakeWatcher(
1133 "/test", [&pi2_event_loop, &pi2_ping_count,
1134 &pi2_pong_count](const examples::Pong &pong) {
1135 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
1136 << pi2_event_loop->context().monotonic_remote_time << " -> "
1137 << pi2_event_loop->context().monotonic_event_time;
1138
1139 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1140 ++pi2_pong_count;
1141 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1142 });
1143
1144 log_reader_factory.Run();
1145 EXPECT_EQ(pi1_ping_count, 2030);
1146 EXPECT_EQ(pi2_ping_count, 2030);
1147 EXPECT_EQ(pi1_pong_count, 2030);
1148 EXPECT_EQ(pi2_pong_count, 2030);
1149
1150 reader.Deregister();
1151}
Austin Schuh6f3babe2020-01-26 20:34:50 -08001152
Austin Schuh8bd96322020-02-13 21:18:22 -08001153// Tests that we can read log files where the monotonic clocks drift and don't
1154// match correctly. While we are here, also test that different ending times
1155// also is readable.
1156TEST_F(MultinodeLoggerTest, MismatchedClocks) {
Austin Schuhcde938c2020-02-02 17:30:07 -08001157 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001158 LoggerState pi2_logger = MakeLogger(pi2_);
1159
Austin Schuh8bd96322020-02-13 21:18:22 -08001160 NodeEventLoopFactory *pi2 =
1161 event_loop_factory_.GetNodeEventLoopFactory(pi2_);
1162 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
1163 << pi2->realtime_now() << " distributed "
1164 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -08001165
Austin Schuh8bd96322020-02-13 21:18:22 -08001166 const chrono::nanoseconds initial_pi2_offset = -chrono::seconds(1000);
1167 chrono::nanoseconds pi2_offset = initial_pi2_offset;
Austin Schuhcde938c2020-02-02 17:30:07 -08001168
Austin Schuhbe69cf32020-08-27 11:38:33 -07001169 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -08001170 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
1171 << pi2->realtime_now() << " distributed "
1172 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -08001173
Austin Schuh8bd96322020-02-13 21:18:22 -08001174 for (int i = 0; i < 95; ++i) {
1175 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -07001176 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -08001177 event_loop_factory_.RunFor(chrono::milliseconds(1));
1178 }
Austin Schuhcde938c2020-02-02 17:30:07 -08001179
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001180 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -08001181
Austin Schuh8bd96322020-02-13 21:18:22 -08001182 event_loop_factory_.RunFor(chrono::milliseconds(200));
Austin Schuhcde938c2020-02-02 17:30:07 -08001183
Austin Schuh8bd96322020-02-13 21:18:22 -08001184 {
1185 // Run pi1's logger for only part of the time.
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001186 LoggerState pi1_logger = MakeLogger(pi1_);
Austin Schuh8bd96322020-02-13 21:18:22 -08001187
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001188 StartLogger(&pi1_logger);
Austin Schuh8bd96322020-02-13 21:18:22 -08001189
1190 for (int i = 0; i < 20000; ++i) {
1191 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -07001192 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -08001193 event_loop_factory_.RunFor(chrono::milliseconds(1));
1194 }
1195
1196 EXPECT_GT(pi2_offset - initial_pi2_offset,
1197 event_loop_factory_.send_delay() +
1198 event_loop_factory_.network_delay());
1199
1200 for (int i = 0; i < 40000; ++i) {
1201 pi2_offset -= chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -07001202 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -08001203 event_loop_factory_.RunFor(chrono::milliseconds(1));
1204 }
1205 }
1206
1207 // And log a bit more on pi2.
1208 event_loop_factory_.RunFor(chrono::milliseconds(400));
Austin Schuhcde938c2020-02-02 17:30:07 -08001209 }
1210
Austin Schuh287d43d2020-12-04 20:19:33 -08001211 LogReader reader(SortParts(logfiles_));
Austin Schuhcde938c2020-02-02 17:30:07 -08001212
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001213 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuhcde938c2020-02-02 17:30:07 -08001214 log_reader_factory.set_send_delay(chrono::microseconds(0));
1215
Austin Schuhcde938c2020-02-02 17:30:07 -08001216 const Node *pi1 =
1217 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1218 const Node *pi2 =
1219 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1220
Austin Schuh2f8fd752020-09-01 22:38:28 -07001221 // This sends out the fetched messages and advances time to the start of the
1222 // log file.
1223 reader.Register(&log_reader_factory);
1224
1225 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
1226 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
1227 LOG(INFO) << "now pi1 "
1228 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
1229 LOG(INFO) << "now pi2 "
1230 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
1231
Austin Schuhcde938c2020-02-02 17:30:07 -08001232 LOG(INFO) << "Done registering (pi1) "
Austin Schuh391e3172020-09-01 22:48:18 -07001233 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now()
1234 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -08001235 << log_reader_factory.GetNodeEventLoopFactory(pi1)->realtime_now();
1236 LOG(INFO) << "Done registering (pi2) "
Austin Schuh391e3172020-09-01 22:48:18 -07001237 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now()
1238 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -08001239 << log_reader_factory.GetNodeEventLoopFactory(pi2)->realtime_now();
1240
1241 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1242
1243 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1244
1245 std::unique_ptr<EventLoop> pi1_event_loop =
1246 log_reader_factory.MakeEventLoop("test", pi1);
1247 std::unique_ptr<EventLoop> pi2_event_loop =
1248 log_reader_factory.MakeEventLoop("test", pi2);
1249
1250 int pi1_ping_count = 30;
1251 int pi2_ping_count = 30;
1252 int pi1_pong_count = 30;
1253 int pi2_pong_count = 30;
1254
1255 // Confirm that the ping value matches.
1256 pi1_event_loop->MakeWatcher(
1257 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
1258 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
1259 << pi1_event_loop->context().monotonic_remote_time << " -> "
1260 << pi1_event_loop->context().monotonic_event_time;
1261 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
1262
1263 ++pi1_ping_count;
1264 });
1265 pi2_event_loop->MakeWatcher(
1266 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
1267 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
1268 << pi2_event_loop->context().monotonic_remote_time << " -> "
1269 << pi2_event_loop->context().monotonic_event_time;
1270 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
1271
1272 ++pi2_ping_count;
1273 });
1274
1275 // Confirm that the ping and pong counts both match, and the value also
1276 // matches.
1277 pi1_event_loop->MakeWatcher(
1278 "/test", [&pi1_event_loop, &pi1_ping_count,
1279 &pi1_pong_count](const examples::Pong &pong) {
1280 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
1281 << pi1_event_loop->context().monotonic_remote_time << " -> "
1282 << pi1_event_loop->context().monotonic_event_time;
1283
1284 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
1285 ++pi1_pong_count;
1286 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
1287 });
1288 pi2_event_loop->MakeWatcher(
1289 "/test", [&pi2_event_loop, &pi2_ping_count,
1290 &pi2_pong_count](const examples::Pong &pong) {
1291 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
1292 << pi2_event_loop->context().monotonic_remote_time << " -> "
1293 << pi2_event_loop->context().monotonic_event_time;
1294
1295 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1296 ++pi2_pong_count;
1297 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1298 });
1299
1300 log_reader_factory.Run();
Austin Schuh8bd96322020-02-13 21:18:22 -08001301 EXPECT_EQ(pi1_ping_count, 6030);
1302 EXPECT_EQ(pi2_ping_count, 6030);
1303 EXPECT_EQ(pi1_pong_count, 6030);
1304 EXPECT_EQ(pi2_pong_count, 6030);
Austin Schuhcde938c2020-02-02 17:30:07 -08001305
1306 reader.Deregister();
1307}
1308
Austin Schuh5212cad2020-09-09 23:12:09 -07001309// Tests that we can sort a bunch of parts into the pre-determined sorted parts.
1310TEST_F(MultinodeLoggerTest, SortParts) {
1311 // Make a bunch of parts.
1312 {
1313 LoggerState pi1_logger = MakeLogger(pi1_);
1314 LoggerState pi2_logger = MakeLogger(pi2_);
1315
1316 event_loop_factory_.RunFor(chrono::milliseconds(95));
1317
1318 StartLogger(&pi1_logger);
1319 StartLogger(&pi2_logger);
1320
1321 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1322 }
1323
Austin Schuh11d43732020-09-21 17:28:30 -07001324 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
Austin Schuh3bd4c402020-11-06 18:19:06 -08001325 VerifyParts(sorted_parts);
1326}
Austin Schuh11d43732020-09-21 17:28:30 -07001327
Austin Schuh3bd4c402020-11-06 18:19:06 -08001328// Tests that we can sort a bunch of parts with an empty part. We should ignore
1329// it and remove it from the sorted list.
1330TEST_F(MultinodeLoggerTest, SortEmptyParts) {
1331 // Make a bunch of parts.
1332 {
1333 LoggerState pi1_logger = MakeLogger(pi1_);
1334 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuh11d43732020-09-21 17:28:30 -07001335
Austin Schuh3bd4c402020-11-06 18:19:06 -08001336 event_loop_factory_.RunFor(chrono::milliseconds(95));
Austin Schuh11d43732020-09-21 17:28:30 -07001337
Austin Schuh3bd4c402020-11-06 18:19:06 -08001338 StartLogger(&pi1_logger);
1339 StartLogger(&pi2_logger);
Austin Schuh11d43732020-09-21 17:28:30 -07001340
Austin Schuh3bd4c402020-11-06 18:19:06 -08001341 event_loop_factory_.RunFor(chrono::milliseconds(2000));
Austin Schuh11d43732020-09-21 17:28:30 -07001342 }
1343
Austin Schuh3bd4c402020-11-06 18:19:06 -08001344 // TODO(austin): Should we flip out if the file can't open?
1345 const std::string kEmptyFile("foobarinvalidfiledoesnotexist.bfbs");
Austin Schuh11d43732020-09-21 17:28:30 -07001346
Austin Schuh3bd4c402020-11-06 18:19:06 -08001347 aos::util::WriteStringToFileOrDie(kEmptyFile, "");
1348 logfiles_.emplace_back(kEmptyFile);
Austin Schuh5212cad2020-09-09 23:12:09 -07001349
Austin Schuh3bd4c402020-11-06 18:19:06 -08001350 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1351 VerifyParts(sorted_parts, {kEmptyFile});
Austin Schuh5212cad2020-09-09 23:12:09 -07001352}
1353
Austin Schuh3bd4c402020-11-06 18:19:06 -08001354#ifdef LZMA
1355// Tests that we can sort a bunch of parts with an empty .xz file in there. The
1356// empty file should be ignored.
1357TEST_F(MultinodeLoggerTest, SortEmptyCompressedParts) {
1358 // Make a bunch of parts.
1359 {
1360 LoggerState pi1_logger = MakeLogger(pi1_);
1361 LoggerState pi2_logger = MakeLogger(pi2_);
1362
1363 event_loop_factory_.RunFor(chrono::milliseconds(95));
1364
1365 StartLogger(&pi1_logger, "", true);
1366 StartLogger(&pi2_logger, "", true);
1367
1368 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1369 }
1370
1371 // TODO(austin): Should we flip out if the file can't open?
1372 const std::string kEmptyFile("foobarinvalidfiledoesnotexist.bfbs.xz");
1373
1374 AddExtension(".xz");
1375
1376 aos::util::WriteStringToFileOrDie(kEmptyFile, "");
1377 logfiles_.emplace_back(kEmptyFile);
1378
1379 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1380 VerifyParts(sorted_parts, {kEmptyFile});
1381}
1382
1383// Tests that we can sort a bunch of parts with the end missing off a compressed
1384// file. We should use the part we can read.
1385TEST_F(MultinodeLoggerTest, SortTruncatedCompressedParts) {
1386 // Make a bunch of parts.
1387 {
1388 LoggerState pi1_logger = MakeLogger(pi1_);
1389 LoggerState pi2_logger = MakeLogger(pi2_);
1390
1391 event_loop_factory_.RunFor(chrono::milliseconds(95));
1392
1393 StartLogger(&pi1_logger, "", true);
1394 StartLogger(&pi2_logger, "", true);
1395
1396 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1397 }
1398
1399 // Append everything with .xz.
1400 AddExtension(".xz");
1401
1402 // Strip off the end of one of the files. Pick one with a lot of data.
1403 ::std::string compressed_contents =
1404 aos::util::ReadFileToStringOrDie(logfiles_[0]);
1405
1406 aos::util::WriteStringToFileOrDie(
1407 logfiles_[0],
1408 compressed_contents.substr(0, compressed_contents.size() - 100));
1409
1410 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1411 VerifyParts(sorted_parts);
1412}
1413#endif
1414
Austin Schuh01b4c352020-09-21 23:09:39 -07001415// Tests that if we remap a remapped channel, it shows up correctly.
1416TEST_F(MultinodeLoggerTest, RemapLoggedChannel) {
1417 {
1418 LoggerState pi1_logger = MakeLogger(pi1_);
1419 LoggerState pi2_logger = MakeLogger(pi2_);
1420
1421 event_loop_factory_.RunFor(chrono::milliseconds(95));
1422
1423 StartLogger(&pi1_logger);
1424 StartLogger(&pi2_logger);
1425
1426 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1427 }
1428
Austin Schuh287d43d2020-12-04 20:19:33 -08001429 LogReader reader(SortParts(logfiles_));
Austin Schuh01b4c352020-09-21 23:09:39 -07001430
1431 // Remap just on pi1.
1432 reader.RemapLoggedChannel<aos::timing::Report>(
1433 "/aos", configuration::GetNode(reader.configuration(), "pi1"));
1434
1435 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1436 log_reader_factory.set_send_delay(chrono::microseconds(0));
1437
1438 reader.Register(&log_reader_factory);
1439
1440 const Node *pi1 =
1441 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1442 const Node *pi2 =
1443 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1444
1445 // Confirm we can read the data on the remapped channel, just for pi1. Nothing
1446 // else should have moved.
1447 std::unique_ptr<EventLoop> pi1_event_loop =
1448 log_reader_factory.MakeEventLoop("test", pi1);
1449 pi1_event_loop->SkipTimingReport();
1450 std::unique_ptr<EventLoop> full_pi1_event_loop =
1451 log_reader_factory.MakeEventLoop("test", pi1);
1452 full_pi1_event_loop->SkipTimingReport();
1453 std::unique_ptr<EventLoop> pi2_event_loop =
1454 log_reader_factory.MakeEventLoop("test", pi2);
1455 pi2_event_loop->SkipTimingReport();
1456
1457 MessageCounter<aos::timing::Report> pi1_timing_report(pi1_event_loop.get(),
1458 "/aos");
1459 MessageCounter<aos::timing::Report> full_pi1_timing_report(
1460 full_pi1_event_loop.get(), "/pi1/aos");
1461 MessageCounter<aos::timing::Report> pi1_original_timing_report(
1462 pi1_event_loop.get(), "/original/aos");
1463 MessageCounter<aos::timing::Report> full_pi1_original_timing_report(
1464 full_pi1_event_loop.get(), "/original/pi1/aos");
1465 MessageCounter<aos::timing::Report> pi2_timing_report(pi2_event_loop.get(),
1466 "/aos");
1467
1468 log_reader_factory.Run();
1469
1470 EXPECT_EQ(pi1_timing_report.count(), 0u);
1471 EXPECT_EQ(full_pi1_timing_report.count(), 0u);
1472 EXPECT_NE(pi1_original_timing_report.count(), 0u);
1473 EXPECT_NE(full_pi1_original_timing_report.count(), 0u);
1474 EXPECT_NE(pi2_timing_report.count(), 0u);
1475
1476 reader.Deregister();
1477}
1478
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001479// Tests that we properly recreate forwarded timestamps when replaying a log.
1480// This should be enough that we can then re-run the logger and get a valid log
1481// back.
1482TEST_F(MultinodeLoggerTest, MessageHeader) {
1483 {
1484 LoggerState pi1_logger = MakeLogger(pi1_);
1485 LoggerState pi2_logger = MakeLogger(pi2_);
1486
1487 event_loop_factory_.RunFor(chrono::milliseconds(95));
1488
1489 StartLogger(&pi1_logger);
1490 StartLogger(&pi2_logger);
1491
1492 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1493 }
1494
Austin Schuh287d43d2020-12-04 20:19:33 -08001495 LogReader reader(SortParts(logfiles_));
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001496
1497 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1498 log_reader_factory.set_send_delay(chrono::microseconds(0));
1499
1500 // This sends out the fetched messages and advances time to the start of the
1501 // log file.
1502 reader.Register(&log_reader_factory);
1503
1504 const Node *pi1 =
1505 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1506 const Node *pi2 =
1507 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1508
1509 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
1510 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
1511 LOG(INFO) << "now pi1 "
1512 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
1513 LOG(INFO) << "now pi2 "
1514 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
1515
1516 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1517
1518 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1519
1520 std::unique_ptr<EventLoop> pi1_event_loop =
1521 log_reader_factory.MakeEventLoop("test", pi1);
1522 std::unique_ptr<EventLoop> pi2_event_loop =
1523 log_reader_factory.MakeEventLoop("test", pi2);
1524
Austin Schuh0de30f32020-12-06 12:44:28 -08001525 MessageCounter<RemoteMessage> pi1_original_message_header_counter(
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001526 pi1_event_loop.get(), "/original/aos/remote_timestamps/pi2");
Austin Schuh0de30f32020-12-06 12:44:28 -08001527 MessageCounter<RemoteMessage> pi2_original_message_header_counter(
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001528 pi2_event_loop.get(), "/original/aos/remote_timestamps/pi1");
1529
1530 aos::Fetcher<message_bridge::Timestamp> pi1_timestamp_on_pi1_fetcher =
1531 pi1_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi1/aos");
1532 aos::Fetcher<message_bridge::Timestamp> pi1_timestamp_on_pi2_fetcher =
1533 pi2_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi1/aos");
1534
1535 aos::Fetcher<examples::Ping> ping_on_pi1_fetcher =
1536 pi1_event_loop->MakeFetcher<examples::Ping>("/test");
1537 aos::Fetcher<examples::Ping> ping_on_pi2_fetcher =
1538 pi2_event_loop->MakeFetcher<examples::Ping>("/test");
1539
1540 aos::Fetcher<message_bridge::Timestamp> pi2_timestamp_on_pi2_fetcher =
1541 pi2_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi2/aos");
1542 aos::Fetcher<message_bridge::Timestamp> pi2_timestamp_on_pi1_fetcher =
1543 pi1_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi2/aos");
1544
1545 aos::Fetcher<examples::Pong> pong_on_pi2_fetcher =
1546 pi2_event_loop->MakeFetcher<examples::Pong>("/test");
1547 aos::Fetcher<examples::Pong> pong_on_pi1_fetcher =
1548 pi1_event_loop->MakeFetcher<examples::Pong>("/test");
1549
1550 const size_t pi1_timestamp_channel = configuration::ChannelIndex(
1551 pi1_event_loop->configuration(), pi1_timestamp_on_pi1_fetcher.channel());
1552 const size_t ping_timestamp_channel = configuration::ChannelIndex(
1553 pi2_event_loop->configuration(), ping_on_pi2_fetcher.channel());
1554
1555 const size_t pi2_timestamp_channel = configuration::ChannelIndex(
1556 pi2_event_loop->configuration(), pi2_timestamp_on_pi2_fetcher.channel());
1557 const size_t pong_timestamp_channel = configuration::ChannelIndex(
1558 pi1_event_loop->configuration(), pong_on_pi1_fetcher.channel());
1559
1560 pi1_event_loop->MakeWatcher(
1561 "/aos/remote_timestamps/pi2",
Austin Schuh315b96b2020-12-11 21:21:12 -08001562 [&pi1_event_loop, &pi2_event_loop, pi1_timestamp_channel,
1563 ping_timestamp_channel, &pi1_timestamp_on_pi1_fetcher,
1564 &pi1_timestamp_on_pi2_fetcher, &ping_on_pi1_fetcher,
Austin Schuh0de30f32020-12-06 12:44:28 -08001565 &ping_on_pi2_fetcher](const RemoteMessage &header) {
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001566 const aos::monotonic_clock::time_point header_monotonic_sent_time(
1567 chrono::nanoseconds(header.monotonic_sent_time()));
1568 const aos::realtime_clock::time_point header_realtime_sent_time(
1569 chrono::nanoseconds(header.realtime_sent_time()));
1570 const aos::monotonic_clock::time_point header_monotonic_remote_time(
1571 chrono::nanoseconds(header.monotonic_remote_time()));
1572 const aos::realtime_clock::time_point header_realtime_remote_time(
1573 chrono::nanoseconds(header.realtime_remote_time()));
1574
1575 const Context *pi1_context = nullptr;
1576 const Context *pi2_context = nullptr;
1577
1578 if (header.channel_index() == pi1_timestamp_channel) {
1579 ASSERT_TRUE(pi1_timestamp_on_pi1_fetcher.FetchNext());
1580 ASSERT_TRUE(pi1_timestamp_on_pi2_fetcher.FetchNext());
1581 pi1_context = &pi1_timestamp_on_pi1_fetcher.context();
1582 pi2_context = &pi1_timestamp_on_pi2_fetcher.context();
1583 } else if (header.channel_index() == ping_timestamp_channel) {
1584 ASSERT_TRUE(ping_on_pi1_fetcher.FetchNext());
1585 ASSERT_TRUE(ping_on_pi2_fetcher.FetchNext());
1586 pi1_context = &ping_on_pi1_fetcher.context();
1587 pi2_context = &ping_on_pi2_fetcher.context();
1588 } else {
1589 LOG(FATAL) << "Unknown channel " << FlatbufferToJson(&header) << " "
1590 << configuration::CleanedChannelToString(
1591 pi1_event_loop->configuration()->channels()->Get(
1592 header.channel_index()));
1593 }
1594
Austin Schuh315b96b2020-12-11 21:21:12 -08001595 ASSERT_TRUE(header.has_boot_uuid());
1596 EXPECT_EQ(header.boot_uuid()->string_view(),
1597 pi2_event_loop->boot_uuid().string_view());
1598
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001599 EXPECT_EQ(pi1_context->queue_index, header.remote_queue_index());
1600 EXPECT_EQ(pi2_context->remote_queue_index, header.remote_queue_index());
1601 EXPECT_EQ(pi2_context->queue_index, header.queue_index());
1602
1603 EXPECT_EQ(pi2_context->monotonic_event_time,
1604 header_monotonic_sent_time);
1605 EXPECT_EQ(pi2_context->realtime_event_time, header_realtime_sent_time);
1606 EXPECT_EQ(pi2_context->realtime_remote_time,
1607 header_realtime_remote_time);
1608 EXPECT_EQ(pi2_context->monotonic_remote_time,
1609 header_monotonic_remote_time);
1610
1611 EXPECT_EQ(pi1_context->realtime_event_time,
1612 header_realtime_remote_time);
1613 EXPECT_EQ(pi1_context->monotonic_event_time,
1614 header_monotonic_remote_time);
1615 });
1616 pi2_event_loop->MakeWatcher(
1617 "/aos/remote_timestamps/pi1",
Austin Schuh315b96b2020-12-11 21:21:12 -08001618 [&pi2_event_loop, &pi1_event_loop, pi2_timestamp_channel,
1619 pong_timestamp_channel, &pi2_timestamp_on_pi2_fetcher,
1620 &pi2_timestamp_on_pi1_fetcher, &pong_on_pi2_fetcher,
Austin Schuh0de30f32020-12-06 12:44:28 -08001621 &pong_on_pi1_fetcher](const RemoteMessage &header) {
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001622 const aos::monotonic_clock::time_point header_monotonic_sent_time(
1623 chrono::nanoseconds(header.monotonic_sent_time()));
1624 const aos::realtime_clock::time_point header_realtime_sent_time(
1625 chrono::nanoseconds(header.realtime_sent_time()));
1626 const aos::monotonic_clock::time_point header_monotonic_remote_time(
1627 chrono::nanoseconds(header.monotonic_remote_time()));
1628 const aos::realtime_clock::time_point header_realtime_remote_time(
1629 chrono::nanoseconds(header.realtime_remote_time()));
1630
1631 const Context *pi2_context = nullptr;
1632 const Context *pi1_context = nullptr;
1633
1634 if (header.channel_index() == pi2_timestamp_channel) {
1635 ASSERT_TRUE(pi2_timestamp_on_pi2_fetcher.FetchNext());
1636 ASSERT_TRUE(pi2_timestamp_on_pi1_fetcher.FetchNext());
1637 pi2_context = &pi2_timestamp_on_pi2_fetcher.context();
1638 pi1_context = &pi2_timestamp_on_pi1_fetcher.context();
1639 } else if (header.channel_index() == pong_timestamp_channel) {
1640 ASSERT_TRUE(pong_on_pi2_fetcher.FetchNext());
1641 ASSERT_TRUE(pong_on_pi1_fetcher.FetchNext());
1642 pi2_context = &pong_on_pi2_fetcher.context();
1643 pi1_context = &pong_on_pi1_fetcher.context();
1644 } else {
1645 LOG(FATAL) << "Unknown channel " << FlatbufferToJson(&header) << " "
1646 << configuration::CleanedChannelToString(
1647 pi2_event_loop->configuration()->channels()->Get(
1648 header.channel_index()));
1649 }
1650
Austin Schuh315b96b2020-12-11 21:21:12 -08001651 ASSERT_TRUE(header.has_boot_uuid());
1652 EXPECT_EQ(header.boot_uuid()->string_view(),
1653 pi1_event_loop->boot_uuid().string_view());
1654
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001655 EXPECT_EQ(pi2_context->queue_index, header.remote_queue_index());
1656 EXPECT_EQ(pi1_context->remote_queue_index, header.remote_queue_index());
1657 EXPECT_EQ(pi1_context->queue_index, header.queue_index());
1658
1659 EXPECT_EQ(pi1_context->monotonic_event_time,
1660 header_monotonic_sent_time);
1661 EXPECT_EQ(pi1_context->realtime_event_time, header_realtime_sent_time);
1662 EXPECT_EQ(pi1_context->realtime_remote_time,
1663 header_realtime_remote_time);
1664 EXPECT_EQ(pi1_context->monotonic_remote_time,
1665 header_monotonic_remote_time);
1666
1667 EXPECT_EQ(pi2_context->realtime_event_time,
1668 header_realtime_remote_time);
1669 EXPECT_EQ(pi2_context->monotonic_event_time,
1670 header_monotonic_remote_time);
1671 });
1672
1673 // And confirm we can re-create a log again, while checking the contents.
1674 {
1675 LoggerState pi1_logger = MakeLogger(
1676 configuration::GetNode(log_reader_factory.configuration(), pi1_),
1677 &log_reader_factory);
1678 LoggerState pi2_logger = MakeLogger(
1679 configuration::GetNode(log_reader_factory.configuration(), pi2_),
1680 &log_reader_factory);
1681
Austin Schuh8c399962020-12-25 21:51:45 -08001682 StartLogger(&pi1_logger, "relogged1");
1683 StartLogger(&pi2_logger, "relogged2");
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001684
1685 log_reader_factory.Run();
1686 }
1687
1688 EXPECT_EQ(pi2_original_message_header_counter.count(), 0u);
1689 EXPECT_EQ(pi1_original_message_header_counter.count(), 0u);
1690
1691 reader.Deregister();
1692}
1693
Austin Schuh315b96b2020-12-11 21:21:12 -08001694// Tests that we properly populate and extract the logger_start time by setting
1695// up a clock difference between 2 nodes and looking at the resulting parts.
1696TEST_F(MultinodeLoggerTest, LoggerStartTime) {
1697 {
1698 LoggerState pi1_logger = MakeLogger(pi1_);
1699 LoggerState pi2_logger = MakeLogger(pi2_);
1700
1701 NodeEventLoopFactory *pi2 =
1702 event_loop_factory_.GetNodeEventLoopFactory(pi2_);
1703
1704 pi2->SetDistributedOffset(chrono::seconds(1000), 1.0);
1705
1706 StartLogger(&pi1_logger);
1707 StartLogger(&pi2_logger);
1708
1709 event_loop_factory_.RunFor(chrono::milliseconds(10000));
1710 }
1711
1712 for (const LogFile &log_file : SortParts(logfiles_)) {
1713 for (const LogParts &log_part : log_file.parts) {
1714 if (log_part.node == log_file.logger_node) {
1715 EXPECT_EQ(log_part.logger_monotonic_start_time,
1716 aos::monotonic_clock::min_time);
1717 EXPECT_EQ(log_part.logger_realtime_start_time,
1718 aos::realtime_clock::min_time);
1719 } else {
1720 const chrono::seconds offset = log_file.logger_node == "pi1"
1721 ? -chrono::seconds(1000)
1722 : chrono::seconds(1000);
1723 EXPECT_EQ(log_part.logger_monotonic_start_time,
1724 log_part.monotonic_start_time + offset);
1725 EXPECT_EQ(log_part.logger_realtime_start_time,
1726 log_file.realtime_start_time +
1727 (log_part.logger_monotonic_start_time -
1728 log_file.monotonic_start_time));
1729 }
1730 }
1731 }
1732}
1733
Austin Schuh8bd96322020-02-13 21:18:22 -08001734// TODO(austin): We can write a test which recreates a logfile and confirms that
1735// we get it back. That is the ultimate test.
1736
Austin Schuh315b96b2020-12-11 21:21:12 -08001737// Tests that we properly recreate forwarded timestamps when replaying a log.
1738// This should be enough that we can then re-run the logger and get a valid log
1739// back.
1740TEST_F(MultinodeLoggerDeathTest, RemoteReboot) {
1741 std::string pi2_boot1;
1742 std::string pi2_boot2;
1743 {
1744 pi2_boot1 = event_loop_factory_.GetNodeEventLoopFactory(pi2_)
1745 ->boot_uuid()
1746 .string_view();
1747 LoggerState pi1_logger = MakeLogger(pi1_);
1748
1749 event_loop_factory_.RunFor(chrono::milliseconds(95));
1750
1751 StartLogger(&pi1_logger);
1752
1753 event_loop_factory_.RunFor(chrono::milliseconds(10000));
1754
1755 event_loop_factory_.GetNodeEventLoopFactory(pi2_)->Reboot();
1756
1757 pi2_boot2 = event_loop_factory_.GetNodeEventLoopFactory(pi2_)
1758 ->boot_uuid()
1759 .string_view();
1760
1761 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1762 }
1763
1764 // Confirm that we refuse to replay logs with missing boot uuids.
1765 EXPECT_DEATH(
1766 {
1767 LogReader reader(SortParts(pi1_reboot_logfiles_));
1768
1769 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1770 log_reader_factory.set_send_delay(chrono::microseconds(0));
1771
1772 // This sends out the fetched messages and advances time to the start of
1773 // the log file.
1774 reader.Register(&log_reader_factory);
1775 },
1776 absl::StrFormat("(%s|%s).*(%s|%s).*Found parts from different boots",
1777 pi2_boot1, pi2_boot2, pi2_boot2, pi2_boot1));
1778}
1779
Austin Schuhc9049732020-12-21 22:27:15 -08001780// Tests that we properly handle one direction of message_bridge being
1781// unavailable.
1782TEST_F(MultinodeLoggerTest, OneDirectionWithNegativeSlope) {
1783 event_loop_factory_.GetNodeEventLoopFactory(pi1_)->Disconnect(pi2_);
1784 event_loop_factory_.GetNodeEventLoopFactory(pi2_)->SetDistributedOffset(
1785 chrono::seconds(1000), 0.99999);
1786 {
1787 LoggerState pi1_logger = MakeLogger(pi1_);
1788
1789 event_loop_factory_.RunFor(chrono::milliseconds(95));
1790
1791 StartLogger(&pi1_logger);
1792
1793 event_loop_factory_.RunFor(chrono::milliseconds(10000));
1794 }
1795
1796 // Confirm that we can parse the result. LogReader has enough internal CHECKs
1797 // to confirm the right thing happened.
1798 ConfirmReadable(pi1_single_direction_logfiles_);
1799}
1800
1801// Tests that we properly handle one direction of message_bridge being
1802// unavailable.
1803TEST_F(MultinodeLoggerTest, OneDirectionWithPositiveSlope) {
1804 event_loop_factory_.GetNodeEventLoopFactory(pi1_)->Disconnect(pi2_);
1805 event_loop_factory_.GetNodeEventLoopFactory(pi2_)->SetDistributedOffset(
1806 chrono::seconds(500), 1.00001);
1807 {
1808 LoggerState pi1_logger = MakeLogger(pi1_);
1809
1810 event_loop_factory_.RunFor(chrono::milliseconds(95));
1811
1812 StartLogger(&pi1_logger);
1813
1814 event_loop_factory_.RunFor(chrono::milliseconds(10000));
1815 }
1816
1817 // Confirm that we can parse the result. LogReader has enough internal CHECKs
1818 // to confirm the right thing happened.
1819 ConfirmReadable(pi1_single_direction_logfiles_);
1820}
1821
Austin Schuhe309d2a2019-11-29 13:25:21 -08001822} // namespace testing
1823} // namespace logger
1824} // namespace aos