blob: 05bafe48d2276465e580ff4d427cb9a0e6c0c638 [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 Schuh25b46712021-01-03 00:04:38 -080029constexpr std::string_view kSingleConfigSha1(
30 "bc8c9c2e31589eae6f0e36d766f6a437643e861d9568b7483106841cf7504dea");
Austin Schuh8c399962020-12-25 21:51:45 -080031constexpr std::string_view kConfigSha1(
32 "0000c81e444ac470b8d29fb864621ae93a0e294a7e90c0dc4840d0f0d40fd72e");
33
Austin Schuhe309d2a2019-11-29 13:25:21 -080034class LoggerTest : public ::testing::Test {
35 public:
36 LoggerTest()
37 : config_(
38 aos::configuration::ReadConfig("aos/events/pingpong_config.json")),
39 event_loop_factory_(&config_.message()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080040 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080041 ping_(ping_event_loop_.get()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080042 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080043 pong_(pong_event_loop_.get()) {}
44
45 // Config and factory.
46 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
47 SimulatedEventLoopFactory event_loop_factory_;
48
49 // Event loop and app for Ping
50 std::unique_ptr<EventLoop> ping_event_loop_;
51 Ping ping_;
52
53 // Event loop and app for Pong
54 std::unique_ptr<EventLoop> pong_event_loop_;
55 Pong pong_;
56};
57
Brian Silverman1f345222020-09-24 21:14:48 -070058using LoggerDeathTest = LoggerTest;
59
Austin Schuhe309d2a2019-11-29 13:25:21 -080060// Tests that we can startup at all. This confirms that the channels are all in
61// the config.
62TEST_F(LoggerTest, Starts) {
Austin Schuhc243b422020-10-11 15:35:08 -070063 const ::std::string tmpdir = aos::testing::TestTmpDir();
Austin Schuh2f8fd752020-09-01 22:38:28 -070064 const ::std::string base_name = tmpdir + "/logfile";
Austin Schuh25b46712021-01-03 00:04:38 -080065 const ::std::string config =
66 absl::StrCat(base_name, kSingleConfigSha1, ".bfbs");
Austin Schuh2f8fd752020-09-01 22:38:28 -070067 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuhe309d2a2019-11-29 13:25:21 -080068 // Remove it.
Austin Schuh25b46712021-01-03 00:04:38 -080069 unlink(config.c_str());
Austin Schuhe309d2a2019-11-29 13:25:21 -080070 unlink(logfile.c_str());
71
72 LOG(INFO) << "Logging data to " << logfile;
73
74 {
Austin Schuhe309d2a2019-11-29 13:25:21 -080075 std::unique_ptr<EventLoop> logger_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080076 event_loop_factory_.MakeEventLoop("logger");
Austin Schuhe309d2a2019-11-29 13:25:21 -080077
78 event_loop_factory_.RunFor(chrono::milliseconds(95));
79
Brian Silverman1f345222020-09-24 21:14:48 -070080 Logger logger(logger_event_loop.get());
Austin Schuh8c399962020-12-25 21:51:45 -080081 logger.set_separate_config(false);
Brian Silverman1f345222020-09-24 21:14:48 -070082 logger.set_polling_period(std::chrono::milliseconds(100));
83 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuhe309d2a2019-11-29 13:25:21 -080084 event_loop_factory_.RunFor(chrono::milliseconds(20000));
85 }
86
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080087 // Even though it doesn't make any difference here, exercise the logic for
88 // passing in a separate config.
89 LogReader reader(logfile, &config_.message());
Austin Schuhe309d2a2019-11-29 13:25:21 -080090
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080091 // Confirm that we can remap logged channels to point to new buses.
92 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
Austin Schuhe309d2a2019-11-29 13:25:21 -080093
Austin Schuh15649d62019-12-28 16:36:38 -080094 // This sends out the fetched messages and advances time to the start of the
95 // log file.
James Kuszmaul84ff3e52020-01-03 19:48:53 -080096 reader.Register();
Austin Schuhe309d2a2019-11-29 13:25:21 -080097
Austin Schuh6f3babe2020-01-26 20:34:50 -080098 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
James Kuszmaul84ff3e52020-01-03 19:48:53 -080099
Austin Schuhe309d2a2019-11-29 13:25:21 -0800100 std::unique_ptr<EventLoop> test_event_loop =
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800101 reader.event_loop_factory()->MakeEventLoop("log_reader");
Austin Schuhe309d2a2019-11-29 13:25:21 -0800102
103 int ping_count = 10;
104 int pong_count = 10;
105
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -0800106 // Confirm that the ping value matches in the remapped channel location.
107 test_event_loop->MakeWatcher("/original/test",
Austin Schuhe309d2a2019-11-29 13:25:21 -0800108 [&ping_count](const examples::Ping &ping) {
109 EXPECT_EQ(ping.value(), ping_count + 1);
110 ++ping_count;
111 });
112 // Confirm that the ping and pong counts both match, and the value also
113 // matches.
114 test_event_loop->MakeWatcher(
115 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
116 EXPECT_EQ(pong.value(), pong_count + 1);
117 ++pong_count;
118 EXPECT_EQ(ping_count, pong_count);
119 });
120
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800121 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
Austin Schuhe309d2a2019-11-29 13:25:21 -0800122 EXPECT_EQ(ping_count, 2010);
Austin Schuhe309d2a2019-11-29 13:25:21 -0800123}
124
Brian Silverman1f345222020-09-24 21:14:48 -0700125// Tests calling StartLogging twice.
126TEST_F(LoggerDeathTest, ExtraStart) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800127 const ::std::string tmpdir = aos::testing::TestTmpDir();
Brian Silverman1f345222020-09-24 21:14:48 -0700128 const ::std::string base_name1 = tmpdir + "/logfile1";
Austin Schuh25b46712021-01-03 00:04:38 -0800129 const ::std::string config1 =
130 absl::StrCat(base_name1, kSingleConfigSha1, ".bfbs");
Brian Silverman1f345222020-09-24 21:14:48 -0700131 const ::std::string logfile1 = base_name1 + ".part0.bfbs";
132 const ::std::string base_name2 = tmpdir + "/logfile2";
Austin Schuh25b46712021-01-03 00:04:38 -0800133 const ::std::string config2 =
134 absl::StrCat(base_name2, kSingleConfigSha1, ".bfbs");
Brian Silverman1f345222020-09-24 21:14:48 -0700135 const ::std::string logfile2 = base_name2 + ".part0.bfbs";
136 unlink(logfile1.c_str());
Austin Schuh25b46712021-01-03 00:04:38 -0800137 unlink(config1.c_str());
Brian Silverman1f345222020-09-24 21:14:48 -0700138 unlink(logfile2.c_str());
Austin Schuh25b46712021-01-03 00:04:38 -0800139 unlink(config2.c_str());
Brian Silverman1f345222020-09-24 21:14:48 -0700140
141 LOG(INFO) << "Logging data to " << logfile1 << " then " << logfile2;
142
143 {
144 std::unique_ptr<EventLoop> logger_event_loop =
145 event_loop_factory_.MakeEventLoop("logger");
146
147 event_loop_factory_.RunFor(chrono::milliseconds(95));
148
149 Logger logger(logger_event_loop.get());
150 logger.set_polling_period(std::chrono::milliseconds(100));
151 logger_event_loop->OnRun(
152 [base_name1, base_name2, &logger_event_loop, &logger]() {
153 logger.StartLogging(std::make_unique<LocalLogNamer>(
154 base_name1, logger_event_loop->node()));
155 EXPECT_DEATH(logger.StartLogging(std::make_unique<LocalLogNamer>(
156 base_name2, logger_event_loop->node())),
157 "Already logging");
158 });
159 event_loop_factory_.RunFor(chrono::milliseconds(20000));
160 }
161}
162
163// Tests calling StopLogging twice.
164TEST_F(LoggerDeathTest, ExtraStop) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800165 const ::std::string tmpdir = aos::testing::TestTmpDir();
Brian Silverman1f345222020-09-24 21:14:48 -0700166 const ::std::string base_name = tmpdir + "/logfile";
Austin Schuh25b46712021-01-03 00:04:38 -0800167 const ::std::string config =
168 absl::StrCat(base_name, kSingleConfigSha1, ".bfbs");
Brian Silverman1f345222020-09-24 21:14:48 -0700169 const ::std::string logfile = base_name + ".part0.bfbs";
170 // Remove it.
Austin Schuh25b46712021-01-03 00:04:38 -0800171 unlink(config.c_str());
Brian Silverman1f345222020-09-24 21:14:48 -0700172 unlink(logfile.c_str());
173
174 LOG(INFO) << "Logging data to " << logfile;
175
176 {
177 std::unique_ptr<EventLoop> logger_event_loop =
178 event_loop_factory_.MakeEventLoop("logger");
179
180 event_loop_factory_.RunFor(chrono::milliseconds(95));
181
182 Logger logger(logger_event_loop.get());
Austin Schuh8c399962020-12-25 21:51:45 -0800183 logger.set_separate_config(false);
Brian Silverman1f345222020-09-24 21:14:48 -0700184 logger.set_polling_period(std::chrono::milliseconds(100));
185 logger_event_loop->OnRun([base_name, &logger_event_loop, &logger]() {
186 logger.StartLogging(std::make_unique<LocalLogNamer>(
187 base_name, logger_event_loop->node()));
188 logger.StopLogging(aos::monotonic_clock::min_time);
189 EXPECT_DEATH(logger.StopLogging(aos::monotonic_clock::min_time),
190 "Not logging right now");
191 });
192 event_loop_factory_.RunFor(chrono::milliseconds(20000));
193 }
194}
195
196// Tests that we can startup twice.
197TEST_F(LoggerTest, StartsTwice) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800198 const ::std::string tmpdir = aos::testing::TestTmpDir();
Brian Silverman1f345222020-09-24 21:14:48 -0700199 const ::std::string base_name1 = tmpdir + "/logfile1";
Austin Schuh25b46712021-01-03 00:04:38 -0800200 const ::std::string config1 =
201 absl::StrCat(base_name1, kSingleConfigSha1, ".bfbs");
Brian Silverman1f345222020-09-24 21:14:48 -0700202 const ::std::string logfile1 = base_name1 + ".part0.bfbs";
203 const ::std::string base_name2 = tmpdir + "/logfile2";
Austin Schuh25b46712021-01-03 00:04:38 -0800204 const ::std::string config2 =
205 absl::StrCat(base_name2, kSingleConfigSha1, ".bfbs");
Brian Silverman1f345222020-09-24 21:14:48 -0700206 const ::std::string logfile2 = base_name2 + ".part0.bfbs";
207 unlink(logfile1.c_str());
Austin Schuh25b46712021-01-03 00:04:38 -0800208 unlink(config1.c_str());
Brian Silverman1f345222020-09-24 21:14:48 -0700209 unlink(logfile2.c_str());
Austin Schuh25b46712021-01-03 00:04:38 -0800210 unlink(config2.c_str());
Brian Silverman1f345222020-09-24 21:14:48 -0700211
212 LOG(INFO) << "Logging data to " << logfile1 << " then " << logfile2;
213
214 {
215 std::unique_ptr<EventLoop> logger_event_loop =
216 event_loop_factory_.MakeEventLoop("logger");
217
218 event_loop_factory_.RunFor(chrono::milliseconds(95));
219
220 Logger logger(logger_event_loop.get());
Austin Schuh8c399962020-12-25 21:51:45 -0800221 logger.set_separate_config(false);
Brian Silverman1f345222020-09-24 21:14:48 -0700222 logger.set_polling_period(std::chrono::milliseconds(100));
223 logger.StartLogging(
224 std::make_unique<LocalLogNamer>(base_name1, logger_event_loop->node()));
225 event_loop_factory_.RunFor(chrono::milliseconds(10000));
226 logger.StopLogging(logger_event_loop->monotonic_now());
227 event_loop_factory_.RunFor(chrono::milliseconds(10000));
228 logger.StartLogging(
229 std::make_unique<LocalLogNamer>(base_name2, logger_event_loop->node()));
230 event_loop_factory_.RunFor(chrono::milliseconds(10000));
231 }
232
233 for (const auto &logfile :
234 {std::make_tuple(logfile1, 10), std::make_tuple(logfile2, 2010)}) {
235 SCOPED_TRACE(std::get<0>(logfile));
236 LogReader reader(std::get<0>(logfile));
237 reader.Register();
238
239 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
240
241 std::unique_ptr<EventLoop> test_event_loop =
242 reader.event_loop_factory()->MakeEventLoop("log_reader");
243
244 int ping_count = std::get<1>(logfile);
245 int pong_count = std::get<1>(logfile);
246
247 // Confirm that the ping and pong counts both match, and the value also
248 // matches.
249 test_event_loop->MakeWatcher("/test",
250 [&ping_count](const examples::Ping &ping) {
251 EXPECT_EQ(ping.value(), ping_count + 1);
252 ++ping_count;
253 });
254 test_event_loop->MakeWatcher(
255 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
256 EXPECT_EQ(pong.value(), pong_count + 1);
257 ++pong_count;
258 EXPECT_EQ(ping_count, pong_count);
259 });
260
261 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
262 EXPECT_EQ(ping_count, std::get<1>(logfile) + 1000);
263 }
264}
265
Austin Schuhfa895892020-01-07 20:07:41 -0800266// Tests that we can read and write rotated log files.
267TEST_F(LoggerTest, RotatedLogFile) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800268 const ::std::string tmpdir = aos::testing::TestTmpDir();
Austin Schuh2f8fd752020-09-01 22:38:28 -0700269 const ::std::string base_name = tmpdir + "/logfile";
Austin Schuh25b46712021-01-03 00:04:38 -0800270 const ::std::string config =
271 absl::StrCat(base_name, kSingleConfigSha1, ".bfbs");
Austin Schuh2f8fd752020-09-01 22:38:28 -0700272 const ::std::string logfile0 = base_name + ".part0.bfbs";
273 const ::std::string logfile1 = base_name + ".part1.bfbs";
Austin Schuhfa895892020-01-07 20:07:41 -0800274 // Remove it.
Austin Schuh25b46712021-01-03 00:04:38 -0800275 unlink(config.c_str());
Austin Schuhfa895892020-01-07 20:07:41 -0800276 unlink(logfile0.c_str());
277 unlink(logfile1.c_str());
278
279 LOG(INFO) << "Logging data to " << logfile0 << " and " << logfile1;
280
281 {
Austin Schuhfa895892020-01-07 20:07:41 -0800282 std::unique_ptr<EventLoop> logger_event_loop =
283 event_loop_factory_.MakeEventLoop("logger");
284
285 event_loop_factory_.RunFor(chrono::milliseconds(95));
286
Brian Silverman1f345222020-09-24 21:14:48 -0700287 Logger logger(logger_event_loop.get());
Austin Schuh8c399962020-12-25 21:51:45 -0800288 logger.set_separate_config(false);
Brian Silverman1f345222020-09-24 21:14:48 -0700289 logger.set_polling_period(std::chrono::milliseconds(100));
290 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuhfa895892020-01-07 20:07:41 -0800291 event_loop_factory_.RunFor(chrono::milliseconds(10000));
Austin Schuh2f8fd752020-09-01 22:38:28 -0700292 logger.Rotate();
Austin Schuhfa895892020-01-07 20:07:41 -0800293 event_loop_factory_.RunFor(chrono::milliseconds(10000));
294 }
295
Austin Schuh64fab802020-09-09 22:47:47 -0700296 {
297 // Confirm that the UUIDs match for both the parts and the logger, and the
298 // parts_index increments.
Austin Schuhadd6eb32020-11-09 21:24:26 -0800299 std::vector<SizePrefixedFlatbufferVector<LogFileHeader>> log_header;
Austin Schuh64fab802020-09-09 22:47:47 -0700300 for (std::string_view f : {logfile0, logfile1}) {
Austin Schuh3bd4c402020-11-06 18:19:06 -0800301 log_header.emplace_back(ReadHeader(f).value());
Austin Schuh64fab802020-09-09 22:47:47 -0700302 }
303
Brian Silvermanae7c0332020-09-30 16:58:23 -0700304 EXPECT_EQ(log_header[0].message().log_event_uuid()->string_view(),
305 log_header[1].message().log_event_uuid()->string_view());
Austin Schuh64fab802020-09-09 22:47:47 -0700306 EXPECT_EQ(log_header[0].message().parts_uuid()->string_view(),
307 log_header[1].message().parts_uuid()->string_view());
308
309 EXPECT_EQ(log_header[0].message().parts_index(), 0);
310 EXPECT_EQ(log_header[1].message().parts_index(), 1);
311 }
312
Austin Schuhfa895892020-01-07 20:07:41 -0800313 // Even though it doesn't make any difference here, exercise the logic for
314 // passing in a separate config.
Austin Schuh287d43d2020-12-04 20:19:33 -0800315 LogReader reader(SortParts({logfile0, logfile1}), &config_.message());
Austin Schuhfa895892020-01-07 20:07:41 -0800316
317 // Confirm that we can remap logged channels to point to new buses.
318 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
319
320 // This sends out the fetched messages and advances time to the start of the
321 // log file.
322 reader.Register();
323
Austin Schuh6f3babe2020-01-26 20:34:50 -0800324 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
Austin Schuhfa895892020-01-07 20:07:41 -0800325
326 std::unique_ptr<EventLoop> test_event_loop =
327 reader.event_loop_factory()->MakeEventLoop("log_reader");
328
329 int ping_count = 10;
330 int pong_count = 10;
331
332 // Confirm that the ping value matches in the remapped channel location.
333 test_event_loop->MakeWatcher("/original/test",
334 [&ping_count](const examples::Ping &ping) {
335 EXPECT_EQ(ping.value(), ping_count + 1);
336 ++ping_count;
337 });
338 // Confirm that the ping and pong counts both match, and the value also
339 // matches.
340 test_event_loop->MakeWatcher(
341 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
342 EXPECT_EQ(pong.value(), pong_count + 1);
343 ++pong_count;
344 EXPECT_EQ(ping_count, pong_count);
345 });
346
347 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
348 EXPECT_EQ(ping_count, 2010);
349}
350
Austin Schuh4c4e0092019-12-22 16:18:03 -0800351// Tests that a large number of messages per second doesn't overwhelm writev.
352TEST_F(LoggerTest, ManyMessages) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800353 const ::std::string tmpdir = aos::testing::TestTmpDir();
Austin Schuh2f8fd752020-09-01 22:38:28 -0700354 const ::std::string base_name = tmpdir + "/logfile";
Austin Schuh25b46712021-01-03 00:04:38 -0800355 const ::std::string config =
356 absl::StrCat(base_name, kSingleConfigSha1, ".bfbs");
Austin Schuh2f8fd752020-09-01 22:38:28 -0700357 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuh4c4e0092019-12-22 16:18:03 -0800358 // Remove the log file.
Austin Schuh25b46712021-01-03 00:04:38 -0800359 unlink(config.c_str());
Austin Schuh4c4e0092019-12-22 16:18:03 -0800360 unlink(logfile.c_str());
361
362 LOG(INFO) << "Logging data to " << logfile;
Austin Schuh4c3b9702020-08-30 11:34:55 -0700363 ping_.set_quiet(true);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800364
365 {
Austin Schuh4c4e0092019-12-22 16:18:03 -0800366 std::unique_ptr<EventLoop> logger_event_loop =
367 event_loop_factory_.MakeEventLoop("logger");
368
369 std::unique_ptr<EventLoop> ping_spammer_event_loop =
370 event_loop_factory_.MakeEventLoop("ping_spammer");
371 aos::Sender<examples::Ping> ping_sender =
372 ping_spammer_event_loop->MakeSender<examples::Ping>("/test");
373
374 aos::TimerHandler *timer_handler =
375 ping_spammer_event_loop->AddTimer([&ping_sender]() {
376 aos::Sender<examples::Ping>::Builder builder =
377 ping_sender.MakeBuilder();
378 examples::Ping::Builder ping_builder =
379 builder.MakeBuilder<examples::Ping>();
380 CHECK(builder.Send(ping_builder.Finish()));
381 });
382
383 // 100 ms / 0.05 ms -> 2000 messages. Should be enough to crash it.
384 ping_spammer_event_loop->OnRun([&ping_spammer_event_loop, timer_handler]() {
385 timer_handler->Setup(ping_spammer_event_loop->monotonic_now(),
386 chrono::microseconds(50));
387 });
388
Brian Silverman1f345222020-09-24 21:14:48 -0700389 Logger logger(logger_event_loop.get());
Austin Schuh8c399962020-12-25 21:51:45 -0800390 logger.set_separate_config(false);
Brian Silverman1f345222020-09-24 21:14:48 -0700391 logger.set_polling_period(std::chrono::milliseconds(100));
392 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800393
394 event_loop_factory_.RunFor(chrono::milliseconds(1000));
395 }
396}
397
Austin Schuh25b46712021-01-03 00:04:38 -0800398std::vector<std::string> MakeLogFiles(std::string logfile_base1,
399 std::string logfile_base2) {
Austin Schuh315b96b2020-12-11 21:21:12 -0800400 return std::vector<std::string>(
Austin Schuh8c399962020-12-25 21:51:45 -0800401 {logfile_base1 + "_pi1_data.part0.bfbs",
402 logfile_base1 + "_pi2_data/test/aos.examples.Pong.part0.bfbs",
403 logfile_base1 + "_pi2_data/test/aos.examples.Pong.part1.bfbs",
404 logfile_base2 + "_pi2_data.part0.bfbs",
405 logfile_base1 + "_timestamps/pi1/aos/remote_timestamps/pi2/"
406 "aos.message_bridge.RemoteMessage.part0.bfbs",
407 logfile_base1 + "_timestamps/pi1/aos/remote_timestamps/pi2/"
408 "aos.message_bridge.RemoteMessage.part1.bfbs",
409 logfile_base2 + "_timestamps/pi2/aos/remote_timestamps/pi1/"
410 "aos.message_bridge.RemoteMessage.part0.bfbs",
411 logfile_base2 + "_timestamps/pi2/aos/remote_timestamps/pi1/"
412 "aos.message_bridge.RemoteMessage.part1.bfbs",
413 logfile_base2 +
Austin Schuh315b96b2020-12-11 21:21:12 -0800414 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part0.bfbs",
Austin Schuh8c399962020-12-25 21:51:45 -0800415 logfile_base2 +
Austin Schuh315b96b2020-12-11 21:21:12 -0800416 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part1.bfbs",
Austin Schuh8c399962020-12-25 21:51:45 -0800417 logfile_base1 +
Austin Schuh315b96b2020-12-11 21:21:12 -0800418 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part0.bfbs",
Austin Schuh8c399962020-12-25 21:51:45 -0800419 logfile_base1 +
420 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part1.bfbs",
421 absl::StrCat(logfile_base1, "_", kConfigSha1, ".bfbs"),
422 absl::StrCat(logfile_base2, "_", kConfigSha1, ".bfbs")});
Austin Schuh315b96b2020-12-11 21:21:12 -0800423}
424
Austin Schuh15649d62019-12-28 16:36:38 -0800425class MultinodeLoggerTest : public ::testing::Test {
426 public:
427 MultinodeLoggerTest()
428 : config_(aos::configuration::ReadConfig(
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800429 "aos/events/logging/multinode_pingpong_config.json")),
Austin Schuhac0771c2020-01-07 18:36:30 -0800430 event_loop_factory_(&config_.message()),
Austin Schuhcde938c2020-02-02 17:30:07 -0800431 pi1_(
432 configuration::GetNode(event_loop_factory_.configuration(), "pi1")),
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700433 pi2_(
434 configuration::GetNode(event_loop_factory_.configuration(), "pi2")),
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800435 tmp_dir_(aos::testing::TestTmpDir()),
Austin Schuh8c399962020-12-25 21:51:45 -0800436 logfile_base1_(tmp_dir_ + "/multi_logfile1"),
437 logfile_base2_(tmp_dir_ + "/multi_logfile2"),
Austin Schuh315b96b2020-12-11 21:21:12 -0800438 pi1_reboot_logfiles_(
Austin Schuh8c399962020-12-25 21:51:45 -0800439 {logfile_base1_ + "_pi1_data.part0.bfbs",
440 logfile_base1_ + "_pi2_data/test/aos.examples.Pong.part0.bfbs",
441 logfile_base1_ + "_pi2_data/test/aos.examples.Pong.part1.bfbs",
442 logfile_base1_ + "_pi2_data/test/aos.examples.Pong.part2.bfbs",
443 logfile_base1_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
444 "aos.message_bridge.RemoteMessage.part0.bfbs",
445 logfile_base1_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
446 "aos.message_bridge.RemoteMessage.part1.bfbs",
447 logfile_base1_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
448 "aos.message_bridge.RemoteMessage.part2.bfbs",
449 logfile_base1_ +
Austin Schuh2f8fd752020-09-01 22:38:28 -0700450 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part0.bfbs",
Austin Schuh8c399962020-12-25 21:51:45 -0800451 logfile_base1_ +
Austin Schuh315b96b2020-12-11 21:21:12 -0800452 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part1.bfbs",
Austin Schuh8c399962020-12-25 21:51:45 -0800453 logfile_base1_ +
454 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part2.bfbs",
455 absl::StrCat(logfile_base1_, "_", kConfigSha1, ".bfbs")}),
456 logfiles_(MakeLogFiles(logfile_base1_, logfile_base2_)),
Austin Schuhc9049732020-12-21 22:27:15 -0800457 pi1_single_direction_logfiles_(
Austin Schuh8c399962020-12-25 21:51:45 -0800458 {logfile_base1_ + "_pi1_data.part0.bfbs",
459 logfile_base1_ + "_pi2_data/test/aos.examples.Pong.part0.bfbs",
460 logfile_base1_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
461 "aos.message_bridge.RemoteMessage.part0.bfbs",
462 logfile_base1_ +
463 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part0.bfbs",
464 absl::StrCat(logfile_base1_, "_", kConfigSha1, ".bfbs")}),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700465 structured_logfiles_{
466 std::vector<std::string>{logfiles_[0]},
467 std::vector<std::string>{logfiles_[1], logfiles_[2]},
468 std::vector<std::string>{logfiles_[3]},
469 std::vector<std::string>{logfiles_[4], logfiles_[5]},
470 std::vector<std::string>{logfiles_[6], logfiles_[7]},
471 std::vector<std::string>{logfiles_[8], logfiles_[9]},
472 std::vector<std::string>{logfiles_[10], logfiles_[11]}},
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700473 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping", pi1_)),
474 ping_(ping_event_loop_.get()),
475 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong", pi2_)),
476 pong_(pong_event_loop_.get()) {
477 // Go through and remove the logfiles if they already exist.
478 for (const auto file : logfiles_) {
479 unlink(file.c_str());
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800480 unlink((file + ".xz").c_str());
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700481 }
482
Austin Schuh25b46712021-01-03 00:04:38 -0800483 for (const auto file :
484 MakeLogFiles(tmp_dir_ + "/relogged1", tmp_dir_ + "/relogged2")) {
Austin Schuh315b96b2020-12-11 21:21:12 -0800485 unlink(file.c_str());
486 }
487
488 for (const auto file : pi1_reboot_logfiles_) {
489 unlink(file.c_str());
490 }
491
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700492 LOG(INFO) << "Logging data to " << logfiles_[0] << ", " << logfiles_[1]
493 << " and " << logfiles_[2];
494 }
495
496 struct LoggerState {
497 std::unique_ptr<EventLoop> event_loop;
498 std::unique_ptr<Logger> logger;
499 };
500
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700501 LoggerState MakeLogger(const Node *node,
502 SimulatedEventLoopFactory *factory = nullptr) {
503 if (factory == nullptr) {
504 factory = &event_loop_factory_;
505 }
506 return {factory->MakeEventLoop("logger", node), {}};
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700507 }
508
Austin Schuh3bd4c402020-11-06 18:19:06 -0800509 void StartLogger(LoggerState *logger, std::string logfile_base = "",
510 bool compress = false) {
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700511 if (logfile_base.empty()) {
Austin Schuh8c399962020-12-25 21:51:45 -0800512 if (logger->event_loop->node()->name()->string_view() == "pi1") {
513 logfile_base = logfile_base1_;
514 } else {
515 logfile_base = logfile_base2_;
516 }
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700517 }
518
Brian Silverman1f345222020-09-24 21:14:48 -0700519 logger->logger = std::make_unique<Logger>(logger->event_loop.get());
520 logger->logger->set_polling_period(std::chrono::milliseconds(100));
Austin Schuh0ca51f32020-12-25 21:51:45 -0800521 logger->logger->set_name(absl::StrCat(
522 "name_prefix_", logger->event_loop->node()->name()->str()));
Austin Schuh3bd4c402020-11-06 18:19:06 -0800523 logger->event_loop->OnRun([logger, logfile_base, compress]() {
524 std::unique_ptr<MultiNodeLogNamer> namer =
525 std::make_unique<MultiNodeLogNamer>(
526 logfile_base, logger->event_loop->configuration(),
527 logger->event_loop->node());
528 if (compress) {
529#ifdef LZMA
530 namer->set_extension(".xz");
531 namer->set_encoder_factory(
532 []() { return std::make_unique<aos::logger::LzmaEncoder>(3); });
533#else
534 LOG(FATAL) << "Compression unsupported";
535#endif
536 }
537
538 logger->logger->StartLogging(std::move(namer));
Brian Silverman1f345222020-09-24 21:14:48 -0700539 });
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700540 }
Austin Schuh15649d62019-12-28 16:36:38 -0800541
Austin Schuh3bd4c402020-11-06 18:19:06 -0800542 void VerifyParts(const std::vector<LogFile> &sorted_parts,
543 const std::vector<std::string> &corrupted_parts = {}) {
544 EXPECT_EQ(sorted_parts.size(), 2u);
545
546 // Count up the number of UUIDs and make sure they are what we expect as a
547 // sanity check.
548 std::set<std::string> log_event_uuids;
549 std::set<std::string> parts_uuids;
550 std::set<std::string> both_uuids;
551
552 size_t missing_rt_count = 0;
553
554 std::vector<std::string> logger_nodes;
555 for (const LogFile &log_file : sorted_parts) {
556 EXPECT_FALSE(log_file.log_event_uuid.empty());
557 log_event_uuids.insert(log_file.log_event_uuid);
558 logger_nodes.emplace_back(log_file.logger_node);
559 both_uuids.insert(log_file.log_event_uuid);
Austin Schuh0ca51f32020-12-25 21:51:45 -0800560 EXPECT_TRUE(log_file.config);
561 EXPECT_EQ(log_file.name,
562 absl::StrCat("name_prefix_", log_file.logger_node));
Austin Schuh3bd4c402020-11-06 18:19:06 -0800563
564 for (const LogParts &part : log_file.parts) {
565 EXPECT_NE(part.monotonic_start_time, aos::monotonic_clock::min_time)
566 << ": " << part;
567 missing_rt_count +=
568 part.realtime_start_time == aos::realtime_clock::min_time;
569
570 EXPECT_TRUE(log_event_uuids.find(part.log_event_uuid) !=
571 log_event_uuids.end());
572 EXPECT_NE(part.node, "");
Austin Schuh0ca51f32020-12-25 21:51:45 -0800573 EXPECT_TRUE(log_file.config);
Austin Schuh3bd4c402020-11-06 18:19:06 -0800574 parts_uuids.insert(part.parts_uuid);
575 both_uuids.insert(part.parts_uuid);
576 }
577 }
578
579 // We won't have RT timestamps for 5 log files. We don't log the RT start
580 // time on remote nodes because we don't know it and would be guessing. And
581 // the log reader can actually do a better job.
582 EXPECT_EQ(missing_rt_count, 5u);
583
584 EXPECT_EQ(log_event_uuids.size(), 2u);
585 EXPECT_EQ(parts_uuids.size(), ToLogReaderVector(sorted_parts).size());
586 EXPECT_EQ(log_event_uuids.size() + parts_uuids.size(), both_uuids.size());
587
588 // Test that each list of parts is in order. Don't worry about the ordering
589 // between part file lists though.
590 // (inner vectors all need to be in order, but outer one doesn't matter).
591 EXPECT_THAT(ToLogReaderVector(sorted_parts),
592 ::testing::UnorderedElementsAreArray(structured_logfiles_));
593
594 EXPECT_THAT(logger_nodes, ::testing::UnorderedElementsAre("pi1", "pi2"));
595
596 EXPECT_NE(sorted_parts[0].realtime_start_time,
597 aos::realtime_clock::min_time);
598 EXPECT_NE(sorted_parts[1].realtime_start_time,
599 aos::realtime_clock::min_time);
600
601 EXPECT_NE(sorted_parts[0].monotonic_start_time,
602 aos::monotonic_clock::min_time);
603 EXPECT_NE(sorted_parts[1].monotonic_start_time,
604 aos::monotonic_clock::min_time);
605
606 EXPECT_THAT(sorted_parts[0].corrupted, ::testing::Eq(corrupted_parts));
607 EXPECT_THAT(sorted_parts[1].corrupted, ::testing::Eq(corrupted_parts));
608 }
609
Austin Schuhc9049732020-12-21 22:27:15 -0800610 void ConfirmReadable(const std::vector<std::string> &files) {
611 LogReader reader(SortParts(files));
612
613 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
614 reader.Register(&log_reader_factory);
615
616 log_reader_factory.Run();
617
618 reader.Deregister();
619 }
620
Austin Schuh3bd4c402020-11-06 18:19:06 -0800621 void AddExtension(std::string_view extension) {
622 std::transform(logfiles_.begin(), logfiles_.end(), logfiles_.begin(),
623 [extension](const std::string &in) {
624 return absl::StrCat(in, extension);
625 });
626
627 std::transform(structured_logfiles_.begin(), structured_logfiles_.end(),
628 structured_logfiles_.begin(),
629 [extension](std::vector<std::string> in) {
630 std::transform(in.begin(), in.end(), in.begin(),
631 [extension](const std::string &in_str) {
632 return absl::StrCat(in_str, extension);
633 });
634 return in;
635 });
636 }
637
Austin Schuh15649d62019-12-28 16:36:38 -0800638 // Config and factory.
639 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
640 SimulatedEventLoopFactory event_loop_factory_;
641
Austin Schuhcde938c2020-02-02 17:30:07 -0800642 const Node *pi1_;
643 const Node *pi2_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700644
645 std::string tmp_dir_;
Austin Schuh8c399962020-12-25 21:51:45 -0800646 std::string logfile_base1_;
647 std::string logfile_base2_;
Austin Schuh315b96b2020-12-11 21:21:12 -0800648 std::vector<std::string> pi1_reboot_logfiles_;
Austin Schuh2f8fd752020-09-01 22:38:28 -0700649 std::vector<std::string> logfiles_;
Austin Schuhc9049732020-12-21 22:27:15 -0800650 std::vector<std::string> pi1_single_direction_logfiles_;
Austin Schuh2f8fd752020-09-01 22:38:28 -0700651
652 std::vector<std::vector<std::string>> structured_logfiles_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700653
654 std::unique_ptr<EventLoop> ping_event_loop_;
655 Ping ping_;
656 std::unique_ptr<EventLoop> pong_event_loop_;
657 Pong pong_;
Austin Schuh15649d62019-12-28 16:36:38 -0800658};
659
Austin Schuh391e3172020-09-01 22:48:18 -0700660// Counts the number of messages on a channel. Returns (channel name, channel
661// type, count) for every message matching matcher()
662std::vector<std::tuple<std::string, std::string, int>> CountChannelsMatching(
Austin Schuh25b46712021-01-03 00:04:38 -0800663 std::shared_ptr<const aos::Configuration> config, std::string_view filename,
Austin Schuh6f3babe2020-01-26 20:34:50 -0800664 std::function<bool(const MessageHeader *)> matcher) {
665 MessageReader message_reader(filename);
Austin Schuh8c399962020-12-25 21:51:45 -0800666 std::vector<int> counts(config->channels()->size(), 0);
Austin Schuh15649d62019-12-28 16:36:38 -0800667
Austin Schuh6f3babe2020-01-26 20:34:50 -0800668 while (true) {
Austin Schuhadd6eb32020-11-09 21:24:26 -0800669 std::optional<SizePrefixedFlatbufferVector<MessageHeader>> msg =
Austin Schuh6f3babe2020-01-26 20:34:50 -0800670 message_reader.ReadMessage();
671 if (!msg) {
672 break;
673 }
674
675 if (matcher(&msg.value().message())) {
676 counts[msg.value().message().channel_index()]++;
677 }
678 }
679
Austin Schuh391e3172020-09-01 22:48:18 -0700680 std::vector<std::tuple<std::string, std::string, int>> result;
Austin Schuh6f3babe2020-01-26 20:34:50 -0800681 int channel = 0;
682 for (size_t i = 0; i < counts.size(); ++i) {
683 if (counts[i] != 0) {
Austin Schuh8c399962020-12-25 21:51:45 -0800684 const Channel *channel = config->channels()->Get(i);
Austin Schuh391e3172020-09-01 22:48:18 -0700685 result.push_back(std::make_tuple(channel->name()->str(),
686 channel->type()->str(), counts[i]));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800687 }
688 ++channel;
689 }
690
691 return result;
692}
693
694// Counts the number of messages (channel, count) for all data messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700695std::vector<std::tuple<std::string, std::string, int>> CountChannelsData(
Austin Schuh8c399962020-12-25 21:51:45 -0800696 std::shared_ptr<const aos::Configuration> config,
Austin Schuh391e3172020-09-01 22:48:18 -0700697 std::string_view filename) {
Austin Schuh8c399962020-12-25 21:51:45 -0800698 return CountChannelsMatching(config, filename, [](const MessageHeader *msg) {
Austin Schuh6f3babe2020-01-26 20:34:50 -0800699 if (msg->has_data()) {
700 CHECK(!msg->has_monotonic_remote_time());
701 CHECK(!msg->has_realtime_remote_time());
702 CHECK(!msg->has_remote_queue_index());
703 return true;
704 }
705 return false;
706 });
707}
708
709// Counts the number of messages (channel, count) for all timestamp messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700710std::vector<std::tuple<std::string, std::string, int>> CountChannelsTimestamp(
Austin Schuh8c399962020-12-25 21:51:45 -0800711 std::shared_ptr<const aos::Configuration> config,
Austin Schuh6f3babe2020-01-26 20:34:50 -0800712 std::string_view filename) {
Austin Schuh8c399962020-12-25 21:51:45 -0800713 return CountChannelsMatching(config, filename, [](const MessageHeader *msg) {
Austin Schuh6f3babe2020-01-26 20:34:50 -0800714 if (!msg->has_data()) {
715 CHECK(msg->has_monotonic_remote_time());
716 CHECK(msg->has_realtime_remote_time());
717 CHECK(msg->has_remote_queue_index());
718 return true;
719 }
720 return false;
721 });
722}
723
Austin Schuhcde938c2020-02-02 17:30:07 -0800724// Tests that we can write and read simple multi-node log files.
725TEST_F(MultinodeLoggerTest, SimpleMultiNode) {
Austin Schuh15649d62019-12-28 16:36:38 -0800726 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700727 LoggerState pi1_logger = MakeLogger(pi1_);
728 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuh15649d62019-12-28 16:36:38 -0800729
730 event_loop_factory_.RunFor(chrono::milliseconds(95));
731
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700732 StartLogger(&pi1_logger);
733 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800734
Austin Schuh15649d62019-12-28 16:36:38 -0800735 event_loop_factory_.RunFor(chrono::milliseconds(20000));
736 }
737
Austin Schuh6f3babe2020-01-26 20:34:50 -0800738 {
Austin Schuh64fab802020-09-09 22:47:47 -0700739 std::set<std::string> logfile_uuids;
740 std::set<std::string> parts_uuids;
741 // Confirm that we have the expected number of UUIDs for both the logfile
742 // UUIDs and parts UUIDs.
Austin Schuhadd6eb32020-11-09 21:24:26 -0800743 std::vector<SizePrefixedFlatbufferVector<LogFileHeader>> log_header;
Austin Schuh64fab802020-09-09 22:47:47 -0700744 for (std::string_view f : logfiles_) {
Austin Schuh3bd4c402020-11-06 18:19:06 -0800745 log_header.emplace_back(ReadHeader(f).value());
Austin Schuh8c399962020-12-25 21:51:45 -0800746 if (!log_header.back().message().has_configuration()) {
747 logfile_uuids.insert(
748 log_header.back().message().log_event_uuid()->str());
749 parts_uuids.insert(log_header.back().message().parts_uuid()->str());
750 }
Austin Schuh64fab802020-09-09 22:47:47 -0700751 }
Austin Schuh15649d62019-12-28 16:36:38 -0800752
Austin Schuh64fab802020-09-09 22:47:47 -0700753 EXPECT_EQ(logfile_uuids.size(), 2u);
754 EXPECT_EQ(parts_uuids.size(), 7u);
755
756 // And confirm everything is on the correct node.
757 EXPECT_EQ(log_header[0].message().node()->name()->string_view(), "pi1");
758 EXPECT_EQ(log_header[1].message().node()->name()->string_view(), "pi2");
759 EXPECT_EQ(log_header[2].message().node()->name()->string_view(), "pi2");
760 EXPECT_EQ(log_header[3].message().node()->name()->string_view(), "pi2");
761 EXPECT_EQ(log_header[4].message().node()->name()->string_view(), "pi2");
762 EXPECT_EQ(log_header[5].message().node()->name()->string_view(), "pi2");
763 EXPECT_EQ(log_header[6].message().node()->name()->string_view(), "pi1");
764 EXPECT_EQ(log_header[7].message().node()->name()->string_view(), "pi1");
765 EXPECT_EQ(log_header[8].message().node()->name()->string_view(), "pi1");
766 EXPECT_EQ(log_header[9].message().node()->name()->string_view(), "pi1");
767 EXPECT_EQ(log_header[10].message().node()->name()->string_view(), "pi2");
768 EXPECT_EQ(log_header[11].message().node()->name()->string_view(), "pi2");
769
770 // And the parts index matches.
771 EXPECT_EQ(log_header[0].message().parts_index(), 0);
772 EXPECT_EQ(log_header[1].message().parts_index(), 0);
773 EXPECT_EQ(log_header[2].message().parts_index(), 1);
774 EXPECT_EQ(log_header[3].message().parts_index(), 0);
775 EXPECT_EQ(log_header[4].message().parts_index(), 0);
776 EXPECT_EQ(log_header[5].message().parts_index(), 1);
777 EXPECT_EQ(log_header[6].message().parts_index(), 0);
778 EXPECT_EQ(log_header[7].message().parts_index(), 1);
779 EXPECT_EQ(log_header[8].message().parts_index(), 0);
780 EXPECT_EQ(log_header[9].message().parts_index(), 1);
781 EXPECT_EQ(log_header[10].message().parts_index(), 0);
782 EXPECT_EQ(log_header[11].message().parts_index(), 1);
783 }
784
Austin Schuh8c399962020-12-25 21:51:45 -0800785 const std::vector<LogFile> sorted_log_files = SortParts(logfiles_);
Austin Schuh64fab802020-09-09 22:47:47 -0700786 {
Austin Schuh391e3172020-09-01 22:48:18 -0700787 using ::testing::UnorderedElementsAre;
Austin Schuh8c399962020-12-25 21:51:45 -0800788 std::shared_ptr<const aos::Configuration> config =
789 sorted_log_files[0].config;
Austin Schuh391e3172020-09-01 22:48:18 -0700790
Austin Schuh6f3babe2020-01-26 20:34:50 -0800791 // Timing reports, pings
Austin Schuh2f8fd752020-09-01 22:38:28 -0700792 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800793 CountChannelsData(config, logfiles_[0]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700794 UnorderedElementsAre(
795 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200),
796 std::make_tuple("/pi1/aos", "aos.timing.Report", 40),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800797 std::make_tuple("/test", "aos.examples.Ping", 2001)))
798 << " : " << logfiles_[0];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800799 // Timestamps for pong
Austin Schuh2f8fd752020-09-01 22:38:28 -0700800 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800801 CountChannelsTimestamp(config, logfiles_[0]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700802 UnorderedElementsAre(
803 std::make_tuple("/test", "aos.examples.Pong", 2001),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800804 std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200)))
805 << " : " << logfiles_[0];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800806
807 // Pong data.
Austin Schuh20ac95d2020-12-05 17:24:19 -0800808 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800809 CountChannelsData(config, logfiles_[1]),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800810 UnorderedElementsAre(std::make_tuple("/test", "aos.examples.Pong", 91)))
811 << " : " << logfiles_[1];
Austin Schuh8c399962020-12-25 21:51:45 -0800812 EXPECT_THAT(CountChannelsData(config, logfiles_[2]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700813 UnorderedElementsAre(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800814 std::make_tuple("/test", "aos.examples.Pong", 1910)))
815 << " : " << logfiles_[1];
Austin Schuh391e3172020-09-01 22:48:18 -0700816
Austin Schuh6f3babe2020-01-26 20:34:50 -0800817 // No timestamps
Austin Schuh25b46712021-01-03 00:04:38 -0800818 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[1]),
819 UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800820 << " : " << logfiles_[1];
Austin Schuh25b46712021-01-03 00:04:38 -0800821 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[2]),
822 UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800823 << " : " << logfiles_[2];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800824
825 // Timing reports and pongs.
Austin Schuh2f8fd752020-09-01 22:38:28 -0700826 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800827 CountChannelsData(config, logfiles_[3]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700828 UnorderedElementsAre(
829 std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200),
830 std::make_tuple("/pi2/aos", "aos.timing.Report", 40),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800831 std::make_tuple("/test", "aos.examples.Pong", 2001)))
832 << " : " << logfiles_[3];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800833 // And ping timestamps.
Austin Schuh2f8fd752020-09-01 22:38:28 -0700834 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800835 CountChannelsTimestamp(config, logfiles_[3]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700836 UnorderedElementsAre(
837 std::make_tuple("/test", "aos.examples.Ping", 2001),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800838 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200)))
839 << " : " << logfiles_[3];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700840
841 // Timestamps from pi2 on pi1, and the other way.
Austin Schuh8c399962020-12-25 21:51:45 -0800842 EXPECT_THAT(CountChannelsData(config, logfiles_[4]), UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800843 << " : " << logfiles_[4];
Austin Schuh8c399962020-12-25 21:51:45 -0800844 EXPECT_THAT(CountChannelsData(config, logfiles_[5]), UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800845 << " : " << logfiles_[5];
Austin Schuh8c399962020-12-25 21:51:45 -0800846 EXPECT_THAT(CountChannelsData(config, logfiles_[6]), UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800847 << " : " << logfiles_[6];
Austin Schuh8c399962020-12-25 21:51:45 -0800848 EXPECT_THAT(CountChannelsData(config, logfiles_[7]), UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800849 << " : " << logfiles_[7];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700850 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800851 CountChannelsTimestamp(config, logfiles_[4]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700852 UnorderedElementsAre(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800853 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 9),
854 std::make_tuple("/test", "aos.examples.Ping", 91)))
855 << " : " << logfiles_[4];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700856 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800857 CountChannelsTimestamp(config, logfiles_[5]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700858 UnorderedElementsAre(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800859 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 191),
860 std::make_tuple("/test", "aos.examples.Ping", 1910)))
861 << " : " << logfiles_[5];
Austin Schuh8c399962020-12-25 21:51:45 -0800862 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[6]),
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_[6];
Austin Schuh8c399962020-12-25 21:51:45 -0800866 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[7]),
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_[7];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700870
871 // And then test that the remotely logged timestamp data files only have
872 // timestamps in them.
Austin Schuh25b46712021-01-03 00:04:38 -0800873 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[8]),
874 UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800875 << " : " << logfiles_[8];
Austin Schuh25b46712021-01-03 00:04:38 -0800876 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[9]),
877 UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800878 << " : " << logfiles_[9];
Austin Schuh25b46712021-01-03 00:04:38 -0800879 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[10]),
880 UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800881 << " : " << logfiles_[10];
Austin Schuh25b46712021-01-03 00:04:38 -0800882 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[11]),
883 UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800884 << " : " << logfiles_[11];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700885
Austin Schuh8c399962020-12-25 21:51:45 -0800886 EXPECT_THAT(CountChannelsData(config, logfiles_[8]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700887 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800888 "/pi1/aos", "aos.message_bridge.Timestamp", 9)))
889 << " : " << logfiles_[8];
Austin Schuh8c399962020-12-25 21:51:45 -0800890 EXPECT_THAT(CountChannelsData(config, logfiles_[9]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700891 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800892 "/pi1/aos", "aos.message_bridge.Timestamp", 191)))
893 << " : " << logfiles_[9];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700894
Austin Schuh8c399962020-12-25 21:51:45 -0800895 EXPECT_THAT(CountChannelsData(config, logfiles_[10]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700896 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800897 "/pi2/aos", "aos.message_bridge.Timestamp", 9)))
898 << " : " << logfiles_[10];
Austin Schuh8c399962020-12-25 21:51:45 -0800899 EXPECT_THAT(CountChannelsData(config, logfiles_[11]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700900 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800901 "/pi2/aos", "aos.message_bridge.Timestamp", 191)))
902 << " : " << logfiles_[11];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800903 }
904
Austin Schuh8c399962020-12-25 21:51:45 -0800905 LogReader reader(sorted_log_files);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800906
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700907 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuh6331ef92020-01-07 18:28:09 -0800908 log_reader_factory.set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800909
910 // This sends out the fetched messages and advances time to the start of the
911 // log file.
Austin Schuh6331ef92020-01-07 18:28:09 -0800912 reader.Register(&log_reader_factory);
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800913
Austin Schuhac0771c2020-01-07 18:36:30 -0800914 const Node *pi1 =
915 configuration::GetNode(log_reader_factory.configuration(), "pi1");
Austin Schuh6f3babe2020-01-26 20:34:50 -0800916 const Node *pi2 =
917 configuration::GetNode(log_reader_factory.configuration(), "pi2");
Austin Schuhac0771c2020-01-07 18:36:30 -0800918
Austin Schuh2f8fd752020-09-01 22:38:28 -0700919 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
920 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
921 LOG(INFO) << "now pi1 "
922 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
923 LOG(INFO) << "now pi2 "
924 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
925
Austin Schuh6f3babe2020-01-26 20:34:50 -0800926 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800927
928 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800929
Austin Schuh6f3babe2020-01-26 20:34:50 -0800930 std::unique_ptr<EventLoop> pi1_event_loop =
Austin Schuhac0771c2020-01-07 18:36:30 -0800931 log_reader_factory.MakeEventLoop("test", pi1);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800932 std::unique_ptr<EventLoop> pi2_event_loop =
933 log_reader_factory.MakeEventLoop("test", pi2);
Austin Schuh15649d62019-12-28 16:36:38 -0800934
Austin Schuh6f3babe2020-01-26 20:34:50 -0800935 int pi1_ping_count = 10;
936 int pi2_ping_count = 10;
937 int pi1_pong_count = 10;
938 int pi2_pong_count = 10;
Austin Schuh15649d62019-12-28 16:36:38 -0800939
940 // Confirm that the ping value matches.
Austin Schuh6f3babe2020-01-26 20:34:50 -0800941 pi1_event_loop->MakeWatcher(
942 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
Austin Schuh2f8fd752020-09-01 22:38:28 -0700943 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping) << " at "
Austin Schuh6f3babe2020-01-26 20:34:50 -0800944 << pi1_event_loop->context().monotonic_remote_time << " -> "
945 << pi1_event_loop->context().monotonic_event_time;
946 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
947 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
948 pi1_ping_count * chrono::milliseconds(10) +
949 monotonic_clock::epoch());
950 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
951 pi1_ping_count * chrono::milliseconds(10) +
952 realtime_clock::epoch());
953 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
954 pi1_event_loop->context().monotonic_event_time);
955 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
956 pi1_event_loop->context().realtime_event_time);
Austin Schuh15649d62019-12-28 16:36:38 -0800957
Austin Schuh6f3babe2020-01-26 20:34:50 -0800958 ++pi1_ping_count;
959 });
960 pi2_event_loop->MakeWatcher(
961 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
Austin Schuh2f8fd752020-09-01 22:38:28 -0700962 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping) << " at "
Austin Schuh6f3babe2020-01-26 20:34:50 -0800963 << pi2_event_loop->context().monotonic_remote_time << " -> "
964 << pi2_event_loop->context().monotonic_event_time;
965 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
966
967 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
968 pi2_ping_count * chrono::milliseconds(10) +
969 monotonic_clock::epoch());
970 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
971 pi2_ping_count * chrono::milliseconds(10) +
972 realtime_clock::epoch());
973 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time +
974 chrono::microseconds(150),
975 pi2_event_loop->context().monotonic_event_time);
976 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time +
977 chrono::microseconds(150),
978 pi2_event_loop->context().realtime_event_time);
979 ++pi2_ping_count;
Austin Schuh15649d62019-12-28 16:36:38 -0800980 });
981
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700982 constexpr ssize_t kQueueIndexOffset = -9;
Austin Schuh6f3babe2020-01-26 20:34:50 -0800983 // Confirm that the ping and pong counts both match, and the value also
984 // matches.
985 pi1_event_loop->MakeWatcher(
986 "/test", [&pi1_event_loop, &pi1_ping_count,
987 &pi1_pong_count](const examples::Pong &pong) {
988 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
989 << pi1_event_loop->context().monotonic_remote_time << " -> "
990 << pi1_event_loop->context().monotonic_event_time;
991
992 EXPECT_EQ(pi1_event_loop->context().remote_queue_index,
993 pi1_pong_count + kQueueIndexOffset);
994 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
995 chrono::microseconds(200) +
996 pi1_pong_count * chrono::milliseconds(10) +
997 monotonic_clock::epoch());
998 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
999 chrono::microseconds(200) +
1000 pi1_pong_count * chrono::milliseconds(10) +
1001 realtime_clock::epoch());
1002
1003 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time +
1004 chrono::microseconds(150),
1005 pi1_event_loop->context().monotonic_event_time);
1006 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time +
1007 chrono::microseconds(150),
1008 pi1_event_loop->context().realtime_event_time);
1009
1010 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
1011 ++pi1_pong_count;
1012 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
1013 });
1014 pi2_event_loop->MakeWatcher(
1015 "/test", [&pi2_event_loop, &pi2_ping_count,
1016 &pi2_pong_count](const examples::Pong &pong) {
1017 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
1018 << pi2_event_loop->context().monotonic_remote_time << " -> "
1019 << pi2_event_loop->context().monotonic_event_time;
1020
1021 EXPECT_EQ(pi2_event_loop->context().remote_queue_index,
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001022 pi2_pong_count + kQueueIndexOffset);
Austin Schuh6f3babe2020-01-26 20:34:50 -08001023
1024 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
1025 chrono::microseconds(200) +
1026 pi2_pong_count * chrono::milliseconds(10) +
1027 monotonic_clock::epoch());
1028 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
1029 chrono::microseconds(200) +
1030 pi2_pong_count * chrono::milliseconds(10) +
1031 realtime_clock::epoch());
1032
1033 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
1034 pi2_event_loop->context().monotonic_event_time);
1035 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
1036 pi2_event_loop->context().realtime_event_time);
1037
1038 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1039 ++pi2_pong_count;
1040 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1041 });
1042
1043 log_reader_factory.Run();
1044 EXPECT_EQ(pi1_ping_count, 2010);
1045 EXPECT_EQ(pi2_ping_count, 2010);
1046 EXPECT_EQ(pi1_pong_count, 2010);
1047 EXPECT_EQ(pi2_pong_count, 2010);
Austin Schuh6331ef92020-01-07 18:28:09 -08001048
1049 reader.Deregister();
Austin Schuh15649d62019-12-28 16:36:38 -08001050}
1051
James Kuszmaul46d82582020-05-09 19:50:09 -07001052typedef MultinodeLoggerTest MultinodeLoggerDeathTest;
1053
1054// Test that if we feed the replay with a mismatched node list that we die on
1055// the LogReader constructor.
1056TEST_F(MultinodeLoggerDeathTest, MultiNodeBadReplayConfig) {
James Kuszmaul46d82582020-05-09 19:50:09 -07001057 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001058 LoggerState pi1_logger = MakeLogger(pi1_);
1059 LoggerState pi2_logger = MakeLogger(pi2_);
James Kuszmaul46d82582020-05-09 19:50:09 -07001060
1061 event_loop_factory_.RunFor(chrono::milliseconds(95));
1062
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001063 StartLogger(&pi1_logger);
1064 StartLogger(&pi2_logger);
James Kuszmaul46d82582020-05-09 19:50:09 -07001065
James Kuszmaul46d82582020-05-09 19:50:09 -07001066 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1067 }
1068
1069 // Test that, if we add an additional node to the replay config that the
1070 // logger complains about the mismatch in number of nodes.
1071 FlatbufferDetachedBuffer<Configuration> extra_nodes_config =
1072 configuration::MergeWithConfig(&config_.message(), R"({
1073 "nodes": [
1074 {
1075 "name": "extra-node"
1076 }
1077 ]
1078 }
1079 )");
1080
Austin Schuh287d43d2020-12-04 20:19:33 -08001081 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1082 EXPECT_DEATH(LogReader(sorted_parts, &extra_nodes_config.message()),
James Kuszmaul46d82582020-05-09 19:50:09 -07001083 "Log file and replay config need to have matching nodes lists.");
James Kuszmaul46d82582020-05-09 19:50:09 -07001084}
1085
Austin Schuhcde938c2020-02-02 17:30:07 -08001086// Tests that we can read log files where they don't start at the same monotonic
1087// time.
1088TEST_F(MultinodeLoggerTest, StaggeredStart) {
Austin Schuhcde938c2020-02-02 17:30:07 -08001089 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001090 LoggerState pi1_logger = MakeLogger(pi1_);
1091 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuhcde938c2020-02-02 17:30:07 -08001092
1093 event_loop_factory_.RunFor(chrono::milliseconds(95));
1094
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001095 StartLogger(&pi1_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -08001096
1097 event_loop_factory_.RunFor(chrono::milliseconds(200));
1098
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001099 StartLogger(&pi2_logger);
1100
Austin Schuhcde938c2020-02-02 17:30:07 -08001101 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1102 }
1103
Austin Schuh287d43d2020-12-04 20:19:33 -08001104 LogReader reader(SortParts(logfiles_));
Austin Schuhcde938c2020-02-02 17:30:07 -08001105
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001106 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuhcde938c2020-02-02 17:30:07 -08001107 log_reader_factory.set_send_delay(chrono::microseconds(0));
1108
1109 // This sends out the fetched messages and advances time to the start of the
1110 // log file.
1111 reader.Register(&log_reader_factory);
1112
1113 const Node *pi1 =
1114 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1115 const Node *pi2 =
1116 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1117
1118 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1119
1120 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1121
1122 std::unique_ptr<EventLoop> pi1_event_loop =
1123 log_reader_factory.MakeEventLoop("test", pi1);
1124 std::unique_ptr<EventLoop> pi2_event_loop =
1125 log_reader_factory.MakeEventLoop("test", pi2);
1126
1127 int pi1_ping_count = 30;
1128 int pi2_ping_count = 30;
1129 int pi1_pong_count = 30;
1130 int pi2_pong_count = 30;
1131
1132 // Confirm that the ping value matches.
1133 pi1_event_loop->MakeWatcher(
1134 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
1135 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
1136 << pi1_event_loop->context().monotonic_remote_time << " -> "
1137 << pi1_event_loop->context().monotonic_event_time;
1138 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
1139
1140 ++pi1_ping_count;
1141 });
1142 pi2_event_loop->MakeWatcher(
1143 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
1144 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
1145 << pi2_event_loop->context().monotonic_remote_time << " -> "
1146 << pi2_event_loop->context().monotonic_event_time;
1147 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
1148
1149 ++pi2_ping_count;
1150 });
1151
1152 // Confirm that the ping and pong counts both match, and the value also
1153 // matches.
1154 pi1_event_loop->MakeWatcher(
1155 "/test", [&pi1_event_loop, &pi1_ping_count,
1156 &pi1_pong_count](const examples::Pong &pong) {
1157 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
1158 << pi1_event_loop->context().monotonic_remote_time << " -> "
1159 << pi1_event_loop->context().monotonic_event_time;
1160
1161 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
1162 ++pi1_pong_count;
1163 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
1164 });
1165 pi2_event_loop->MakeWatcher(
1166 "/test", [&pi2_event_loop, &pi2_ping_count,
1167 &pi2_pong_count](const examples::Pong &pong) {
1168 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
1169 << pi2_event_loop->context().monotonic_remote_time << " -> "
1170 << pi2_event_loop->context().monotonic_event_time;
1171
1172 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1173 ++pi2_pong_count;
1174 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1175 });
1176
1177 log_reader_factory.Run();
1178 EXPECT_EQ(pi1_ping_count, 2030);
1179 EXPECT_EQ(pi2_ping_count, 2030);
1180 EXPECT_EQ(pi1_pong_count, 2030);
1181 EXPECT_EQ(pi2_pong_count, 2030);
1182
1183 reader.Deregister();
1184}
Austin Schuh6f3babe2020-01-26 20:34:50 -08001185
Austin Schuh8bd96322020-02-13 21:18:22 -08001186// Tests that we can read log files where the monotonic clocks drift and don't
1187// match correctly. While we are here, also test that different ending times
1188// also is readable.
1189TEST_F(MultinodeLoggerTest, MismatchedClocks) {
Austin Schuhcde938c2020-02-02 17:30:07 -08001190 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001191 LoggerState pi2_logger = MakeLogger(pi2_);
1192
Austin Schuh8bd96322020-02-13 21:18:22 -08001193 NodeEventLoopFactory *pi2 =
1194 event_loop_factory_.GetNodeEventLoopFactory(pi2_);
1195 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
1196 << pi2->realtime_now() << " distributed "
1197 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -08001198
Austin Schuh8bd96322020-02-13 21:18:22 -08001199 const chrono::nanoseconds initial_pi2_offset = -chrono::seconds(1000);
1200 chrono::nanoseconds pi2_offset = initial_pi2_offset;
Austin Schuhcde938c2020-02-02 17:30:07 -08001201
Austin Schuhbe69cf32020-08-27 11:38:33 -07001202 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -08001203 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
1204 << pi2->realtime_now() << " distributed "
1205 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -08001206
Austin Schuh8bd96322020-02-13 21:18:22 -08001207 for (int i = 0; i < 95; ++i) {
1208 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -07001209 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -08001210 event_loop_factory_.RunFor(chrono::milliseconds(1));
1211 }
Austin Schuhcde938c2020-02-02 17:30:07 -08001212
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001213 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -08001214
Austin Schuh8bd96322020-02-13 21:18:22 -08001215 event_loop_factory_.RunFor(chrono::milliseconds(200));
Austin Schuhcde938c2020-02-02 17:30:07 -08001216
Austin Schuh8bd96322020-02-13 21:18:22 -08001217 {
1218 // Run pi1's logger for only part of the time.
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001219 LoggerState pi1_logger = MakeLogger(pi1_);
Austin Schuh8bd96322020-02-13 21:18:22 -08001220
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001221 StartLogger(&pi1_logger);
Austin Schuh8bd96322020-02-13 21:18:22 -08001222
1223 for (int i = 0; i < 20000; ++i) {
1224 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -07001225 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -08001226 event_loop_factory_.RunFor(chrono::milliseconds(1));
1227 }
1228
1229 EXPECT_GT(pi2_offset - initial_pi2_offset,
1230 event_loop_factory_.send_delay() +
1231 event_loop_factory_.network_delay());
1232
1233 for (int i = 0; i < 40000; ++i) {
1234 pi2_offset -= chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -07001235 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -08001236 event_loop_factory_.RunFor(chrono::milliseconds(1));
1237 }
1238 }
1239
1240 // And log a bit more on pi2.
1241 event_loop_factory_.RunFor(chrono::milliseconds(400));
Austin Schuhcde938c2020-02-02 17:30:07 -08001242 }
1243
Austin Schuh287d43d2020-12-04 20:19:33 -08001244 LogReader reader(SortParts(logfiles_));
Austin Schuhcde938c2020-02-02 17:30:07 -08001245
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001246 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuhcde938c2020-02-02 17:30:07 -08001247 log_reader_factory.set_send_delay(chrono::microseconds(0));
1248
Austin Schuhcde938c2020-02-02 17:30:07 -08001249 const Node *pi1 =
1250 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1251 const Node *pi2 =
1252 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1253
Austin Schuh2f8fd752020-09-01 22:38:28 -07001254 // This sends out the fetched messages and advances time to the start of the
1255 // log file.
1256 reader.Register(&log_reader_factory);
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
Austin Schuhcde938c2020-02-02 17:30:07 -08001265 LOG(INFO) << "Done registering (pi1) "
Austin Schuh391e3172020-09-01 22:48:18 -07001266 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now()
1267 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -08001268 << log_reader_factory.GetNodeEventLoopFactory(pi1)->realtime_now();
1269 LOG(INFO) << "Done registering (pi2) "
Austin Schuh391e3172020-09-01 22:48:18 -07001270 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now()
1271 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -08001272 << log_reader_factory.GetNodeEventLoopFactory(pi2)->realtime_now();
1273
1274 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1275
1276 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1277
1278 std::unique_ptr<EventLoop> pi1_event_loop =
1279 log_reader_factory.MakeEventLoop("test", pi1);
1280 std::unique_ptr<EventLoop> pi2_event_loop =
1281 log_reader_factory.MakeEventLoop("test", pi2);
1282
1283 int pi1_ping_count = 30;
1284 int pi2_ping_count = 30;
1285 int pi1_pong_count = 30;
1286 int pi2_pong_count = 30;
1287
1288 // Confirm that the ping value matches.
1289 pi1_event_loop->MakeWatcher(
1290 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
1291 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
1292 << pi1_event_loop->context().monotonic_remote_time << " -> "
1293 << pi1_event_loop->context().monotonic_event_time;
1294 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
1295
1296 ++pi1_ping_count;
1297 });
1298 pi2_event_loop->MakeWatcher(
1299 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
1300 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
1301 << pi2_event_loop->context().monotonic_remote_time << " -> "
1302 << pi2_event_loop->context().monotonic_event_time;
1303 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
1304
1305 ++pi2_ping_count;
1306 });
1307
1308 // Confirm that the ping and pong counts both match, and the value also
1309 // matches.
1310 pi1_event_loop->MakeWatcher(
1311 "/test", [&pi1_event_loop, &pi1_ping_count,
1312 &pi1_pong_count](const examples::Pong &pong) {
1313 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
1314 << pi1_event_loop->context().monotonic_remote_time << " -> "
1315 << pi1_event_loop->context().monotonic_event_time;
1316
1317 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
1318 ++pi1_pong_count;
1319 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
1320 });
1321 pi2_event_loop->MakeWatcher(
1322 "/test", [&pi2_event_loop, &pi2_ping_count,
1323 &pi2_pong_count](const examples::Pong &pong) {
1324 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
1325 << pi2_event_loop->context().monotonic_remote_time << " -> "
1326 << pi2_event_loop->context().monotonic_event_time;
1327
1328 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1329 ++pi2_pong_count;
1330 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1331 });
1332
1333 log_reader_factory.Run();
Austin Schuh8bd96322020-02-13 21:18:22 -08001334 EXPECT_EQ(pi1_ping_count, 6030);
1335 EXPECT_EQ(pi2_ping_count, 6030);
1336 EXPECT_EQ(pi1_pong_count, 6030);
1337 EXPECT_EQ(pi2_pong_count, 6030);
Austin Schuhcde938c2020-02-02 17:30:07 -08001338
1339 reader.Deregister();
1340}
1341
Austin Schuh5212cad2020-09-09 23:12:09 -07001342// Tests that we can sort a bunch of parts into the pre-determined sorted parts.
1343TEST_F(MultinodeLoggerTest, SortParts) {
1344 // Make a bunch of parts.
1345 {
1346 LoggerState pi1_logger = MakeLogger(pi1_);
1347 LoggerState pi2_logger = MakeLogger(pi2_);
1348
1349 event_loop_factory_.RunFor(chrono::milliseconds(95));
1350
1351 StartLogger(&pi1_logger);
1352 StartLogger(&pi2_logger);
1353
1354 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1355 }
1356
Austin Schuh11d43732020-09-21 17:28:30 -07001357 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
Austin Schuh3bd4c402020-11-06 18:19:06 -08001358 VerifyParts(sorted_parts);
1359}
Austin Schuh11d43732020-09-21 17:28:30 -07001360
Austin Schuh3bd4c402020-11-06 18:19:06 -08001361// Tests that we can sort a bunch of parts with an empty part. We should ignore
1362// it and remove it from the sorted list.
1363TEST_F(MultinodeLoggerTest, SortEmptyParts) {
1364 // Make a bunch of parts.
1365 {
1366 LoggerState pi1_logger = MakeLogger(pi1_);
1367 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuh11d43732020-09-21 17:28:30 -07001368
Austin Schuh3bd4c402020-11-06 18:19:06 -08001369 event_loop_factory_.RunFor(chrono::milliseconds(95));
Austin Schuh11d43732020-09-21 17:28:30 -07001370
Austin Schuh3bd4c402020-11-06 18:19:06 -08001371 StartLogger(&pi1_logger);
1372 StartLogger(&pi2_logger);
Austin Schuh11d43732020-09-21 17:28:30 -07001373
Austin Schuh3bd4c402020-11-06 18:19:06 -08001374 event_loop_factory_.RunFor(chrono::milliseconds(2000));
Austin Schuh11d43732020-09-21 17:28:30 -07001375 }
1376
Austin Schuh3bd4c402020-11-06 18:19:06 -08001377 // TODO(austin): Should we flip out if the file can't open?
1378 const std::string kEmptyFile("foobarinvalidfiledoesnotexist.bfbs");
Austin Schuh11d43732020-09-21 17:28:30 -07001379
Austin Schuh3bd4c402020-11-06 18:19:06 -08001380 aos::util::WriteStringToFileOrDie(kEmptyFile, "");
1381 logfiles_.emplace_back(kEmptyFile);
Austin Schuh5212cad2020-09-09 23:12:09 -07001382
Austin Schuh3bd4c402020-11-06 18:19:06 -08001383 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1384 VerifyParts(sorted_parts, {kEmptyFile});
Austin Schuh5212cad2020-09-09 23:12:09 -07001385}
1386
Austin Schuh3bd4c402020-11-06 18:19:06 -08001387#ifdef LZMA
1388// Tests that we can sort a bunch of parts with an empty .xz file in there. The
1389// empty file should be ignored.
1390TEST_F(MultinodeLoggerTest, SortEmptyCompressedParts) {
1391 // Make a bunch of parts.
1392 {
1393 LoggerState pi1_logger = MakeLogger(pi1_);
1394 LoggerState pi2_logger = MakeLogger(pi2_);
1395
1396 event_loop_factory_.RunFor(chrono::milliseconds(95));
1397
1398 StartLogger(&pi1_logger, "", true);
1399 StartLogger(&pi2_logger, "", true);
1400
1401 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1402 }
1403
1404 // TODO(austin): Should we flip out if the file can't open?
1405 const std::string kEmptyFile("foobarinvalidfiledoesnotexist.bfbs.xz");
1406
1407 AddExtension(".xz");
1408
1409 aos::util::WriteStringToFileOrDie(kEmptyFile, "");
1410 logfiles_.emplace_back(kEmptyFile);
1411
1412 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1413 VerifyParts(sorted_parts, {kEmptyFile});
1414}
1415
1416// Tests that we can sort a bunch of parts with the end missing off a compressed
1417// file. We should use the part we can read.
1418TEST_F(MultinodeLoggerTest, SortTruncatedCompressedParts) {
1419 // Make a bunch of parts.
1420 {
1421 LoggerState pi1_logger = MakeLogger(pi1_);
1422 LoggerState pi2_logger = MakeLogger(pi2_);
1423
1424 event_loop_factory_.RunFor(chrono::milliseconds(95));
1425
1426 StartLogger(&pi1_logger, "", true);
1427 StartLogger(&pi2_logger, "", true);
1428
1429 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1430 }
1431
1432 // Append everything with .xz.
1433 AddExtension(".xz");
1434
1435 // Strip off the end of one of the files. Pick one with a lot of data.
1436 ::std::string compressed_contents =
1437 aos::util::ReadFileToStringOrDie(logfiles_[0]);
1438
1439 aos::util::WriteStringToFileOrDie(
1440 logfiles_[0],
1441 compressed_contents.substr(0, compressed_contents.size() - 100));
1442
1443 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1444 VerifyParts(sorted_parts);
1445}
1446#endif
1447
Austin Schuh01b4c352020-09-21 23:09:39 -07001448// Tests that if we remap a remapped channel, it shows up correctly.
1449TEST_F(MultinodeLoggerTest, RemapLoggedChannel) {
1450 {
1451 LoggerState pi1_logger = MakeLogger(pi1_);
1452 LoggerState pi2_logger = MakeLogger(pi2_);
1453
1454 event_loop_factory_.RunFor(chrono::milliseconds(95));
1455
1456 StartLogger(&pi1_logger);
1457 StartLogger(&pi2_logger);
1458
1459 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1460 }
1461
Austin Schuh287d43d2020-12-04 20:19:33 -08001462 LogReader reader(SortParts(logfiles_));
Austin Schuh01b4c352020-09-21 23:09:39 -07001463
1464 // Remap just on pi1.
1465 reader.RemapLoggedChannel<aos::timing::Report>(
1466 "/aos", configuration::GetNode(reader.configuration(), "pi1"));
1467
1468 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1469 log_reader_factory.set_send_delay(chrono::microseconds(0));
1470
1471 reader.Register(&log_reader_factory);
1472
1473 const Node *pi1 =
1474 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1475 const Node *pi2 =
1476 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1477
1478 // Confirm we can read the data on the remapped channel, just for pi1. Nothing
1479 // else should have moved.
1480 std::unique_ptr<EventLoop> pi1_event_loop =
1481 log_reader_factory.MakeEventLoop("test", pi1);
1482 pi1_event_loop->SkipTimingReport();
1483 std::unique_ptr<EventLoop> full_pi1_event_loop =
1484 log_reader_factory.MakeEventLoop("test", pi1);
1485 full_pi1_event_loop->SkipTimingReport();
1486 std::unique_ptr<EventLoop> pi2_event_loop =
1487 log_reader_factory.MakeEventLoop("test", pi2);
1488 pi2_event_loop->SkipTimingReport();
1489
1490 MessageCounter<aos::timing::Report> pi1_timing_report(pi1_event_loop.get(),
1491 "/aos");
1492 MessageCounter<aos::timing::Report> full_pi1_timing_report(
1493 full_pi1_event_loop.get(), "/pi1/aos");
1494 MessageCounter<aos::timing::Report> pi1_original_timing_report(
1495 pi1_event_loop.get(), "/original/aos");
1496 MessageCounter<aos::timing::Report> full_pi1_original_timing_report(
1497 full_pi1_event_loop.get(), "/original/pi1/aos");
1498 MessageCounter<aos::timing::Report> pi2_timing_report(pi2_event_loop.get(),
1499 "/aos");
1500
1501 log_reader_factory.Run();
1502
1503 EXPECT_EQ(pi1_timing_report.count(), 0u);
1504 EXPECT_EQ(full_pi1_timing_report.count(), 0u);
1505 EXPECT_NE(pi1_original_timing_report.count(), 0u);
1506 EXPECT_NE(full_pi1_original_timing_report.count(), 0u);
1507 EXPECT_NE(pi2_timing_report.count(), 0u);
1508
1509 reader.Deregister();
1510}
1511
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001512// Tests that we properly recreate forwarded timestamps when replaying a log.
1513// This should be enough that we can then re-run the logger and get a valid log
1514// back.
1515TEST_F(MultinodeLoggerTest, MessageHeader) {
1516 {
1517 LoggerState pi1_logger = MakeLogger(pi1_);
1518 LoggerState pi2_logger = MakeLogger(pi2_);
1519
1520 event_loop_factory_.RunFor(chrono::milliseconds(95));
1521
1522 StartLogger(&pi1_logger);
1523 StartLogger(&pi2_logger);
1524
1525 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1526 }
1527
Austin Schuh287d43d2020-12-04 20:19:33 -08001528 LogReader reader(SortParts(logfiles_));
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001529
1530 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1531 log_reader_factory.set_send_delay(chrono::microseconds(0));
1532
1533 // This sends out the fetched messages and advances time to the start of the
1534 // log file.
1535 reader.Register(&log_reader_factory);
1536
1537 const Node *pi1 =
1538 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1539 const Node *pi2 =
1540 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1541
1542 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
1543 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
1544 LOG(INFO) << "now pi1 "
1545 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
1546 LOG(INFO) << "now pi2 "
1547 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
1548
1549 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1550
1551 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1552
1553 std::unique_ptr<EventLoop> pi1_event_loop =
1554 log_reader_factory.MakeEventLoop("test", pi1);
1555 std::unique_ptr<EventLoop> pi2_event_loop =
1556 log_reader_factory.MakeEventLoop("test", pi2);
1557
Austin Schuh0de30f32020-12-06 12:44:28 -08001558 MessageCounter<RemoteMessage> pi1_original_message_header_counter(
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001559 pi1_event_loop.get(), "/original/aos/remote_timestamps/pi2");
Austin Schuh0de30f32020-12-06 12:44:28 -08001560 MessageCounter<RemoteMessage> pi2_original_message_header_counter(
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001561 pi2_event_loop.get(), "/original/aos/remote_timestamps/pi1");
1562
1563 aos::Fetcher<message_bridge::Timestamp> pi1_timestamp_on_pi1_fetcher =
1564 pi1_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi1/aos");
1565 aos::Fetcher<message_bridge::Timestamp> pi1_timestamp_on_pi2_fetcher =
1566 pi2_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi1/aos");
1567
1568 aos::Fetcher<examples::Ping> ping_on_pi1_fetcher =
1569 pi1_event_loop->MakeFetcher<examples::Ping>("/test");
1570 aos::Fetcher<examples::Ping> ping_on_pi2_fetcher =
1571 pi2_event_loop->MakeFetcher<examples::Ping>("/test");
1572
1573 aos::Fetcher<message_bridge::Timestamp> pi2_timestamp_on_pi2_fetcher =
1574 pi2_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi2/aos");
1575 aos::Fetcher<message_bridge::Timestamp> pi2_timestamp_on_pi1_fetcher =
1576 pi1_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi2/aos");
1577
1578 aos::Fetcher<examples::Pong> pong_on_pi2_fetcher =
1579 pi2_event_loop->MakeFetcher<examples::Pong>("/test");
1580 aos::Fetcher<examples::Pong> pong_on_pi1_fetcher =
1581 pi1_event_loop->MakeFetcher<examples::Pong>("/test");
1582
1583 const size_t pi1_timestamp_channel = configuration::ChannelIndex(
1584 pi1_event_loop->configuration(), pi1_timestamp_on_pi1_fetcher.channel());
1585 const size_t ping_timestamp_channel = configuration::ChannelIndex(
1586 pi2_event_loop->configuration(), ping_on_pi2_fetcher.channel());
1587
1588 const size_t pi2_timestamp_channel = configuration::ChannelIndex(
1589 pi2_event_loop->configuration(), pi2_timestamp_on_pi2_fetcher.channel());
1590 const size_t pong_timestamp_channel = configuration::ChannelIndex(
1591 pi1_event_loop->configuration(), pong_on_pi1_fetcher.channel());
1592
Austin Schuh969cd602021-01-03 00:09:45 -08001593 const chrono::nanoseconds network_delay = event_loop_factory_.network_delay();
1594
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001595 pi1_event_loop->MakeWatcher(
1596 "/aos/remote_timestamps/pi2",
Austin Schuh315b96b2020-12-11 21:21:12 -08001597 [&pi1_event_loop, &pi2_event_loop, pi1_timestamp_channel,
1598 ping_timestamp_channel, &pi1_timestamp_on_pi1_fetcher,
1599 &pi1_timestamp_on_pi2_fetcher, &ping_on_pi1_fetcher,
Austin Schuh969cd602021-01-03 00:09:45 -08001600 &ping_on_pi2_fetcher, network_delay](const RemoteMessage &header) {
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001601 const aos::monotonic_clock::time_point header_monotonic_sent_time(
1602 chrono::nanoseconds(header.monotonic_sent_time()));
1603 const aos::realtime_clock::time_point header_realtime_sent_time(
1604 chrono::nanoseconds(header.realtime_sent_time()));
1605 const aos::monotonic_clock::time_point header_monotonic_remote_time(
1606 chrono::nanoseconds(header.monotonic_remote_time()));
1607 const aos::realtime_clock::time_point header_realtime_remote_time(
1608 chrono::nanoseconds(header.realtime_remote_time()));
1609
1610 const Context *pi1_context = nullptr;
1611 const Context *pi2_context = nullptr;
1612
1613 if (header.channel_index() == pi1_timestamp_channel) {
1614 ASSERT_TRUE(pi1_timestamp_on_pi1_fetcher.FetchNext());
1615 ASSERT_TRUE(pi1_timestamp_on_pi2_fetcher.FetchNext());
1616 pi1_context = &pi1_timestamp_on_pi1_fetcher.context();
1617 pi2_context = &pi1_timestamp_on_pi2_fetcher.context();
1618 } else if (header.channel_index() == ping_timestamp_channel) {
1619 ASSERT_TRUE(ping_on_pi1_fetcher.FetchNext());
1620 ASSERT_TRUE(ping_on_pi2_fetcher.FetchNext());
1621 pi1_context = &ping_on_pi1_fetcher.context();
1622 pi2_context = &ping_on_pi2_fetcher.context();
1623 } else {
1624 LOG(FATAL) << "Unknown channel " << FlatbufferToJson(&header) << " "
1625 << configuration::CleanedChannelToString(
1626 pi1_event_loop->configuration()->channels()->Get(
1627 header.channel_index()));
1628 }
1629
Austin Schuh315b96b2020-12-11 21:21:12 -08001630 ASSERT_TRUE(header.has_boot_uuid());
1631 EXPECT_EQ(header.boot_uuid()->string_view(),
1632 pi2_event_loop->boot_uuid().string_view());
1633
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001634 EXPECT_EQ(pi1_context->queue_index, header.remote_queue_index());
1635 EXPECT_EQ(pi2_context->remote_queue_index, header.remote_queue_index());
1636 EXPECT_EQ(pi2_context->queue_index, header.queue_index());
1637
1638 EXPECT_EQ(pi2_context->monotonic_event_time,
1639 header_monotonic_sent_time);
1640 EXPECT_EQ(pi2_context->realtime_event_time, header_realtime_sent_time);
1641 EXPECT_EQ(pi2_context->realtime_remote_time,
1642 header_realtime_remote_time);
1643 EXPECT_EQ(pi2_context->monotonic_remote_time,
1644 header_monotonic_remote_time);
1645
1646 EXPECT_EQ(pi1_context->realtime_event_time,
1647 header_realtime_remote_time);
1648 EXPECT_EQ(pi1_context->monotonic_event_time,
1649 header_monotonic_remote_time);
Austin Schuh969cd602021-01-03 00:09:45 -08001650
1651 EXPECT_EQ(pi1_event_loop->context().monotonic_event_time,
1652 pi2_context->monotonic_event_time +
1653 (pi1_event_loop->monotonic_now() -
1654 pi2_event_loop->monotonic_now()) +
1655 network_delay);
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001656 });
1657 pi2_event_loop->MakeWatcher(
1658 "/aos/remote_timestamps/pi1",
Austin Schuh315b96b2020-12-11 21:21:12 -08001659 [&pi2_event_loop, &pi1_event_loop, pi2_timestamp_channel,
1660 pong_timestamp_channel, &pi2_timestamp_on_pi2_fetcher,
1661 &pi2_timestamp_on_pi1_fetcher, &pong_on_pi2_fetcher,
Austin Schuh969cd602021-01-03 00:09:45 -08001662 &pong_on_pi1_fetcher, network_delay](const RemoteMessage &header) {
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001663 const aos::monotonic_clock::time_point header_monotonic_sent_time(
1664 chrono::nanoseconds(header.monotonic_sent_time()));
1665 const aos::realtime_clock::time_point header_realtime_sent_time(
1666 chrono::nanoseconds(header.realtime_sent_time()));
1667 const aos::monotonic_clock::time_point header_monotonic_remote_time(
1668 chrono::nanoseconds(header.monotonic_remote_time()));
1669 const aos::realtime_clock::time_point header_realtime_remote_time(
1670 chrono::nanoseconds(header.realtime_remote_time()));
1671
1672 const Context *pi2_context = nullptr;
1673 const Context *pi1_context = nullptr;
1674
1675 if (header.channel_index() == pi2_timestamp_channel) {
1676 ASSERT_TRUE(pi2_timestamp_on_pi2_fetcher.FetchNext());
1677 ASSERT_TRUE(pi2_timestamp_on_pi1_fetcher.FetchNext());
1678 pi2_context = &pi2_timestamp_on_pi2_fetcher.context();
1679 pi1_context = &pi2_timestamp_on_pi1_fetcher.context();
1680 } else if (header.channel_index() == pong_timestamp_channel) {
1681 ASSERT_TRUE(pong_on_pi2_fetcher.FetchNext());
1682 ASSERT_TRUE(pong_on_pi1_fetcher.FetchNext());
1683 pi2_context = &pong_on_pi2_fetcher.context();
1684 pi1_context = &pong_on_pi1_fetcher.context();
1685 } else {
1686 LOG(FATAL) << "Unknown channel " << FlatbufferToJson(&header) << " "
1687 << configuration::CleanedChannelToString(
1688 pi2_event_loop->configuration()->channels()->Get(
1689 header.channel_index()));
1690 }
1691
Austin Schuh315b96b2020-12-11 21:21:12 -08001692 ASSERT_TRUE(header.has_boot_uuid());
1693 EXPECT_EQ(header.boot_uuid()->string_view(),
1694 pi1_event_loop->boot_uuid().string_view());
1695
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001696 EXPECT_EQ(pi2_context->queue_index, header.remote_queue_index());
1697 EXPECT_EQ(pi1_context->remote_queue_index, header.remote_queue_index());
1698 EXPECT_EQ(pi1_context->queue_index, header.queue_index());
1699
1700 EXPECT_EQ(pi1_context->monotonic_event_time,
1701 header_monotonic_sent_time);
1702 EXPECT_EQ(pi1_context->realtime_event_time, header_realtime_sent_time);
1703 EXPECT_EQ(pi1_context->realtime_remote_time,
1704 header_realtime_remote_time);
1705 EXPECT_EQ(pi1_context->monotonic_remote_time,
1706 header_monotonic_remote_time);
1707
1708 EXPECT_EQ(pi2_context->realtime_event_time,
1709 header_realtime_remote_time);
1710 EXPECT_EQ(pi2_context->monotonic_event_time,
1711 header_monotonic_remote_time);
Austin Schuh969cd602021-01-03 00:09:45 -08001712
1713 EXPECT_EQ(pi2_event_loop->context().monotonic_event_time,
1714 pi1_context->monotonic_event_time +
1715 (pi2_event_loop->monotonic_now() -
1716 pi1_event_loop->monotonic_now()) +
1717 network_delay);
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001718 });
1719
1720 // And confirm we can re-create a log again, while checking the contents.
1721 {
1722 LoggerState pi1_logger = MakeLogger(
1723 configuration::GetNode(log_reader_factory.configuration(), pi1_),
1724 &log_reader_factory);
1725 LoggerState pi2_logger = MakeLogger(
1726 configuration::GetNode(log_reader_factory.configuration(), pi2_),
1727 &log_reader_factory);
1728
Austin Schuh25b46712021-01-03 00:04:38 -08001729 StartLogger(&pi1_logger, tmp_dir_ + "/relogged1");
1730 StartLogger(&pi2_logger, tmp_dir_ + "/relogged2");
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001731
1732 log_reader_factory.Run();
1733 }
1734
1735 EXPECT_EQ(pi2_original_message_header_counter.count(), 0u);
1736 EXPECT_EQ(pi1_original_message_header_counter.count(), 0u);
1737
1738 reader.Deregister();
1739}
1740
Austin Schuh315b96b2020-12-11 21:21:12 -08001741// Tests that we properly populate and extract the logger_start time by setting
1742// up a clock difference between 2 nodes and looking at the resulting parts.
1743TEST_F(MultinodeLoggerTest, LoggerStartTime) {
1744 {
1745 LoggerState pi1_logger = MakeLogger(pi1_);
1746 LoggerState pi2_logger = MakeLogger(pi2_);
1747
1748 NodeEventLoopFactory *pi2 =
1749 event_loop_factory_.GetNodeEventLoopFactory(pi2_);
1750
1751 pi2->SetDistributedOffset(chrono::seconds(1000), 1.0);
1752
1753 StartLogger(&pi1_logger);
1754 StartLogger(&pi2_logger);
1755
1756 event_loop_factory_.RunFor(chrono::milliseconds(10000));
1757 }
1758
1759 for (const LogFile &log_file : SortParts(logfiles_)) {
1760 for (const LogParts &log_part : log_file.parts) {
1761 if (log_part.node == log_file.logger_node) {
1762 EXPECT_EQ(log_part.logger_monotonic_start_time,
1763 aos::monotonic_clock::min_time);
1764 EXPECT_EQ(log_part.logger_realtime_start_time,
1765 aos::realtime_clock::min_time);
1766 } else {
1767 const chrono::seconds offset = log_file.logger_node == "pi1"
1768 ? -chrono::seconds(1000)
1769 : chrono::seconds(1000);
1770 EXPECT_EQ(log_part.logger_monotonic_start_time,
1771 log_part.monotonic_start_time + offset);
1772 EXPECT_EQ(log_part.logger_realtime_start_time,
1773 log_file.realtime_start_time +
1774 (log_part.logger_monotonic_start_time -
1775 log_file.monotonic_start_time));
1776 }
1777 }
1778 }
1779}
1780
Austin Schuh8bd96322020-02-13 21:18:22 -08001781// TODO(austin): We can write a test which recreates a logfile and confirms that
1782// we get it back. That is the ultimate test.
1783
Austin Schuh315b96b2020-12-11 21:21:12 -08001784// Tests that we properly recreate forwarded timestamps when replaying a log.
1785// This should be enough that we can then re-run the logger and get a valid log
1786// back.
1787TEST_F(MultinodeLoggerDeathTest, RemoteReboot) {
1788 std::string pi2_boot1;
1789 std::string pi2_boot2;
1790 {
1791 pi2_boot1 = event_loop_factory_.GetNodeEventLoopFactory(pi2_)
1792 ->boot_uuid()
1793 .string_view();
1794 LoggerState pi1_logger = MakeLogger(pi1_);
1795
1796 event_loop_factory_.RunFor(chrono::milliseconds(95));
1797
1798 StartLogger(&pi1_logger);
1799
1800 event_loop_factory_.RunFor(chrono::milliseconds(10000));
1801
1802 event_loop_factory_.GetNodeEventLoopFactory(pi2_)->Reboot();
1803
1804 pi2_boot2 = event_loop_factory_.GetNodeEventLoopFactory(pi2_)
1805 ->boot_uuid()
1806 .string_view();
1807
1808 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1809 }
1810
1811 // Confirm that we refuse to replay logs with missing boot uuids.
1812 EXPECT_DEATH(
1813 {
1814 LogReader reader(SortParts(pi1_reboot_logfiles_));
1815
1816 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1817 log_reader_factory.set_send_delay(chrono::microseconds(0));
1818
1819 // This sends out the fetched messages and advances time to the start of
1820 // the log file.
1821 reader.Register(&log_reader_factory);
1822 },
1823 absl::StrFormat("(%s|%s).*(%s|%s).*Found parts from different boots",
1824 pi2_boot1, pi2_boot2, pi2_boot2, pi2_boot1));
1825}
1826
Austin Schuhc9049732020-12-21 22:27:15 -08001827// Tests that we properly handle one direction of message_bridge being
1828// unavailable.
1829TEST_F(MultinodeLoggerTest, OneDirectionWithNegativeSlope) {
1830 event_loop_factory_.GetNodeEventLoopFactory(pi1_)->Disconnect(pi2_);
1831 event_loop_factory_.GetNodeEventLoopFactory(pi2_)->SetDistributedOffset(
1832 chrono::seconds(1000), 0.99999);
1833 {
1834 LoggerState pi1_logger = MakeLogger(pi1_);
1835
1836 event_loop_factory_.RunFor(chrono::milliseconds(95));
1837
1838 StartLogger(&pi1_logger);
1839
1840 event_loop_factory_.RunFor(chrono::milliseconds(10000));
1841 }
1842
1843 // Confirm that we can parse the result. LogReader has enough internal CHECKs
1844 // to confirm the right thing happened.
1845 ConfirmReadable(pi1_single_direction_logfiles_);
1846}
1847
1848// Tests that we properly handle one direction of message_bridge being
1849// unavailable.
1850TEST_F(MultinodeLoggerTest, OneDirectionWithPositiveSlope) {
1851 event_loop_factory_.GetNodeEventLoopFactory(pi1_)->Disconnect(pi2_);
1852 event_loop_factory_.GetNodeEventLoopFactory(pi2_)->SetDistributedOffset(
1853 chrono::seconds(500), 1.00001);
1854 {
1855 LoggerState pi1_logger = MakeLogger(pi1_);
1856
1857 event_loop_factory_.RunFor(chrono::milliseconds(95));
1858
1859 StartLogger(&pi1_logger);
1860
1861 event_loop_factory_.RunFor(chrono::milliseconds(10000));
1862 }
1863
1864 // Confirm that we can parse the result. LogReader has enough internal CHECKs
1865 // to confirm the right thing happened.
1866 ConfirmReadable(pi1_single_direction_logfiles_);
1867}
1868
Austin Schuhe309d2a2019-11-29 13:25:21 -08001869} // namespace testing
1870} // namespace logger
1871} // namespace aos