blob: 16fb2abfe31d68800feeb412252ac49144c5b8c3 [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 Schuh87dd3832021-01-01 23:07:31 -080010#include "aos/network/testing_time_converter.h"
Austin Schuh8d7e0bb2020-10-02 17:57:00 -070011#include "aos/network/timestamp_generated.h"
Austin Schuhc243b422020-10-11 15:35:08 -070012#include "aos/testing/tmpdir.h"
Austin Schuh2f8fd752020-09-01 22:38:28 -070013#include "aos/util/file.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -080014#include "glog/logging.h"
Austin Schuh6f3babe2020-01-26 20:34:50 -080015#include "gmock/gmock.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -080016#include "gtest/gtest.h"
17
Austin Schuh3bd4c402020-11-06 18:19:06 -080018#ifdef LZMA
19#include "aos/events/logging/lzma_encoder.h"
20#endif
21
Austin Schuhe309d2a2019-11-29 13:25:21 -080022namespace aos {
23namespace logger {
24namespace testing {
25
26namespace chrono = std::chrono;
Austin Schuh0de30f32020-12-06 12:44:28 -080027using aos::message_bridge::RemoteMessage;
Austin Schuh01b4c352020-09-21 23:09:39 -070028using aos::testing::MessageCounter;
Austin Schuhe309d2a2019-11-29 13:25:21 -080029
Austin Schuh25b46712021-01-03 00:04:38 -080030constexpr std::string_view kSingleConfigSha1(
31 "bc8c9c2e31589eae6f0e36d766f6a437643e861d9568b7483106841cf7504dea");
Austin Schuh8c399962020-12-25 21:51:45 -080032constexpr std::string_view kConfigSha1(
33 "0000c81e444ac470b8d29fb864621ae93a0e294a7e90c0dc4840d0f0d40fd72e");
34
Austin Schuhe309d2a2019-11-29 13:25:21 -080035class LoggerTest : public ::testing::Test {
36 public:
37 LoggerTest()
38 : config_(
39 aos::configuration::ReadConfig("aos/events/pingpong_config.json")),
40 event_loop_factory_(&config_.message()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080041 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080042 ping_(ping_event_loop_.get()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080043 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080044 pong_(pong_event_loop_.get()) {}
45
46 // Config and factory.
47 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
48 SimulatedEventLoopFactory event_loop_factory_;
49
50 // Event loop and app for Ping
51 std::unique_ptr<EventLoop> ping_event_loop_;
52 Ping ping_;
53
54 // Event loop and app for Pong
55 std::unique_ptr<EventLoop> pong_event_loop_;
56 Pong pong_;
57};
58
Brian Silverman1f345222020-09-24 21:14:48 -070059using LoggerDeathTest = LoggerTest;
60
Austin Schuhe309d2a2019-11-29 13:25:21 -080061// Tests that we can startup at all. This confirms that the channels are all in
62// the config.
63TEST_F(LoggerTest, Starts) {
Austin Schuhc243b422020-10-11 15:35:08 -070064 const ::std::string tmpdir = aos::testing::TestTmpDir();
Austin Schuh2f8fd752020-09-01 22:38:28 -070065 const ::std::string base_name = tmpdir + "/logfile";
Austin Schuh25b46712021-01-03 00:04:38 -080066 const ::std::string config =
67 absl::StrCat(base_name, kSingleConfigSha1, ".bfbs");
Austin Schuh2f8fd752020-09-01 22:38:28 -070068 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuhe309d2a2019-11-29 13:25:21 -080069 // Remove it.
Austin Schuh25b46712021-01-03 00:04:38 -080070 unlink(config.c_str());
Austin Schuhe309d2a2019-11-29 13:25:21 -080071 unlink(logfile.c_str());
72
73 LOG(INFO) << "Logging data to " << logfile;
74
75 {
Austin Schuhe309d2a2019-11-29 13:25:21 -080076 std::unique_ptr<EventLoop> logger_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080077 event_loop_factory_.MakeEventLoop("logger");
Austin Schuhe309d2a2019-11-29 13:25:21 -080078
79 event_loop_factory_.RunFor(chrono::milliseconds(95));
80
Brian Silverman1f345222020-09-24 21:14:48 -070081 Logger logger(logger_event_loop.get());
Austin Schuh8c399962020-12-25 21:51:45 -080082 logger.set_separate_config(false);
Brian Silverman1f345222020-09-24 21:14:48 -070083 logger.set_polling_period(std::chrono::milliseconds(100));
84 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuhe309d2a2019-11-29 13:25:21 -080085 event_loop_factory_.RunFor(chrono::milliseconds(20000));
86 }
87
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080088 // Even though it doesn't make any difference here, exercise the logic for
89 // passing in a separate config.
90 LogReader reader(logfile, &config_.message());
Austin Schuhe309d2a2019-11-29 13:25:21 -080091
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080092 // Confirm that we can remap logged channels to point to new buses.
93 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
Austin Schuhe309d2a2019-11-29 13:25:21 -080094
Austin Schuh15649d62019-12-28 16:36:38 -080095 // This sends out the fetched messages and advances time to the start of the
96 // log file.
James Kuszmaul84ff3e52020-01-03 19:48:53 -080097 reader.Register();
Austin Schuhe309d2a2019-11-29 13:25:21 -080098
Austin Schuh6f3babe2020-01-26 20:34:50 -080099 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800100
Austin Schuhe309d2a2019-11-29 13:25:21 -0800101 std::unique_ptr<EventLoop> test_event_loop =
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800102 reader.event_loop_factory()->MakeEventLoop("log_reader");
Austin Schuhe309d2a2019-11-29 13:25:21 -0800103
104 int ping_count = 10;
105 int pong_count = 10;
106
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -0800107 // Confirm that the ping value matches in the remapped channel location.
108 test_event_loop->MakeWatcher("/original/test",
Austin Schuhe309d2a2019-11-29 13:25:21 -0800109 [&ping_count](const examples::Ping &ping) {
110 EXPECT_EQ(ping.value(), ping_count + 1);
111 ++ping_count;
112 });
113 // Confirm that the ping and pong counts both match, and the value also
114 // matches.
115 test_event_loop->MakeWatcher(
116 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
117 EXPECT_EQ(pong.value(), pong_count + 1);
118 ++pong_count;
119 EXPECT_EQ(ping_count, pong_count);
120 });
121
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800122 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
Austin Schuhe309d2a2019-11-29 13:25:21 -0800123 EXPECT_EQ(ping_count, 2010);
Austin Schuhe309d2a2019-11-29 13:25:21 -0800124}
125
Brian Silverman1f345222020-09-24 21:14:48 -0700126// Tests calling StartLogging twice.
127TEST_F(LoggerDeathTest, ExtraStart) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800128 const ::std::string tmpdir = aos::testing::TestTmpDir();
Brian Silverman1f345222020-09-24 21:14:48 -0700129 const ::std::string base_name1 = tmpdir + "/logfile1";
Austin Schuh25b46712021-01-03 00:04:38 -0800130 const ::std::string config1 =
131 absl::StrCat(base_name1, kSingleConfigSha1, ".bfbs");
Brian Silverman1f345222020-09-24 21:14:48 -0700132 const ::std::string logfile1 = base_name1 + ".part0.bfbs";
133 const ::std::string base_name2 = tmpdir + "/logfile2";
Austin Schuh25b46712021-01-03 00:04:38 -0800134 const ::std::string config2 =
135 absl::StrCat(base_name2, kSingleConfigSha1, ".bfbs");
Brian Silverman1f345222020-09-24 21:14:48 -0700136 const ::std::string logfile2 = base_name2 + ".part0.bfbs";
137 unlink(logfile1.c_str());
Austin Schuh25b46712021-01-03 00:04:38 -0800138 unlink(config1.c_str());
Brian Silverman1f345222020-09-24 21:14:48 -0700139 unlink(logfile2.c_str());
Austin Schuh25b46712021-01-03 00:04:38 -0800140 unlink(config2.c_str());
Brian Silverman1f345222020-09-24 21:14:48 -0700141
142 LOG(INFO) << "Logging data to " << logfile1 << " then " << logfile2;
143
144 {
145 std::unique_ptr<EventLoop> logger_event_loop =
146 event_loop_factory_.MakeEventLoop("logger");
147
148 event_loop_factory_.RunFor(chrono::milliseconds(95));
149
150 Logger logger(logger_event_loop.get());
151 logger.set_polling_period(std::chrono::milliseconds(100));
152 logger_event_loop->OnRun(
153 [base_name1, base_name2, &logger_event_loop, &logger]() {
154 logger.StartLogging(std::make_unique<LocalLogNamer>(
155 base_name1, logger_event_loop->node()));
156 EXPECT_DEATH(logger.StartLogging(std::make_unique<LocalLogNamer>(
157 base_name2, logger_event_loop->node())),
158 "Already logging");
159 });
160 event_loop_factory_.RunFor(chrono::milliseconds(20000));
161 }
162}
163
164// Tests calling StopLogging twice.
165TEST_F(LoggerDeathTest, ExtraStop) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800166 const ::std::string tmpdir = aos::testing::TestTmpDir();
Brian Silverman1f345222020-09-24 21:14:48 -0700167 const ::std::string base_name = tmpdir + "/logfile";
Austin Schuh25b46712021-01-03 00:04:38 -0800168 const ::std::string config =
169 absl::StrCat(base_name, kSingleConfigSha1, ".bfbs");
Brian Silverman1f345222020-09-24 21:14:48 -0700170 const ::std::string logfile = base_name + ".part0.bfbs";
171 // Remove it.
Austin Schuh25b46712021-01-03 00:04:38 -0800172 unlink(config.c_str());
Brian Silverman1f345222020-09-24 21:14:48 -0700173 unlink(logfile.c_str());
174
175 LOG(INFO) << "Logging data to " << logfile;
176
177 {
178 std::unique_ptr<EventLoop> logger_event_loop =
179 event_loop_factory_.MakeEventLoop("logger");
180
181 event_loop_factory_.RunFor(chrono::milliseconds(95));
182
183 Logger logger(logger_event_loop.get());
Austin Schuh8c399962020-12-25 21:51:45 -0800184 logger.set_separate_config(false);
Brian Silverman1f345222020-09-24 21:14:48 -0700185 logger.set_polling_period(std::chrono::milliseconds(100));
186 logger_event_loop->OnRun([base_name, &logger_event_loop, &logger]() {
187 logger.StartLogging(std::make_unique<LocalLogNamer>(
188 base_name, logger_event_loop->node()));
189 logger.StopLogging(aos::monotonic_clock::min_time);
190 EXPECT_DEATH(logger.StopLogging(aos::monotonic_clock::min_time),
191 "Not logging right now");
192 });
193 event_loop_factory_.RunFor(chrono::milliseconds(20000));
194 }
195}
196
197// Tests that we can startup twice.
198TEST_F(LoggerTest, StartsTwice) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800199 const ::std::string tmpdir = aos::testing::TestTmpDir();
Brian Silverman1f345222020-09-24 21:14:48 -0700200 const ::std::string base_name1 = tmpdir + "/logfile1";
Austin Schuh25b46712021-01-03 00:04:38 -0800201 const ::std::string config1 =
202 absl::StrCat(base_name1, kSingleConfigSha1, ".bfbs");
Brian Silverman1f345222020-09-24 21:14:48 -0700203 const ::std::string logfile1 = base_name1 + ".part0.bfbs";
204 const ::std::string base_name2 = tmpdir + "/logfile2";
Austin Schuh25b46712021-01-03 00:04:38 -0800205 const ::std::string config2 =
206 absl::StrCat(base_name2, kSingleConfigSha1, ".bfbs");
Brian Silverman1f345222020-09-24 21:14:48 -0700207 const ::std::string logfile2 = base_name2 + ".part0.bfbs";
208 unlink(logfile1.c_str());
Austin Schuh25b46712021-01-03 00:04:38 -0800209 unlink(config1.c_str());
Brian Silverman1f345222020-09-24 21:14:48 -0700210 unlink(logfile2.c_str());
Austin Schuh25b46712021-01-03 00:04:38 -0800211 unlink(config2.c_str());
Brian Silverman1f345222020-09-24 21:14:48 -0700212
213 LOG(INFO) << "Logging data to " << logfile1 << " then " << logfile2;
214
215 {
216 std::unique_ptr<EventLoop> logger_event_loop =
217 event_loop_factory_.MakeEventLoop("logger");
218
219 event_loop_factory_.RunFor(chrono::milliseconds(95));
220
221 Logger logger(logger_event_loop.get());
Austin Schuh8c399962020-12-25 21:51:45 -0800222 logger.set_separate_config(false);
Brian Silverman1f345222020-09-24 21:14:48 -0700223 logger.set_polling_period(std::chrono::milliseconds(100));
224 logger.StartLogging(
225 std::make_unique<LocalLogNamer>(base_name1, logger_event_loop->node()));
226 event_loop_factory_.RunFor(chrono::milliseconds(10000));
227 logger.StopLogging(logger_event_loop->monotonic_now());
228 event_loop_factory_.RunFor(chrono::milliseconds(10000));
229 logger.StartLogging(
230 std::make_unique<LocalLogNamer>(base_name2, logger_event_loop->node()));
231 event_loop_factory_.RunFor(chrono::milliseconds(10000));
232 }
233
234 for (const auto &logfile :
235 {std::make_tuple(logfile1, 10), std::make_tuple(logfile2, 2010)}) {
236 SCOPED_TRACE(std::get<0>(logfile));
237 LogReader reader(std::get<0>(logfile));
238 reader.Register();
239
240 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
241
242 std::unique_ptr<EventLoop> test_event_loop =
243 reader.event_loop_factory()->MakeEventLoop("log_reader");
244
245 int ping_count = std::get<1>(logfile);
246 int pong_count = std::get<1>(logfile);
247
248 // Confirm that the ping and pong counts both match, and the value also
249 // matches.
250 test_event_loop->MakeWatcher("/test",
251 [&ping_count](const examples::Ping &ping) {
252 EXPECT_EQ(ping.value(), ping_count + 1);
253 ++ping_count;
254 });
255 test_event_loop->MakeWatcher(
256 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
257 EXPECT_EQ(pong.value(), pong_count + 1);
258 ++pong_count;
259 EXPECT_EQ(ping_count, pong_count);
260 });
261
262 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
263 EXPECT_EQ(ping_count, std::get<1>(logfile) + 1000);
264 }
265}
266
Austin Schuhfa895892020-01-07 20:07:41 -0800267// Tests that we can read and write rotated log files.
268TEST_F(LoggerTest, RotatedLogFile) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800269 const ::std::string tmpdir = aos::testing::TestTmpDir();
Austin Schuh2f8fd752020-09-01 22:38:28 -0700270 const ::std::string base_name = tmpdir + "/logfile";
Austin Schuh25b46712021-01-03 00:04:38 -0800271 const ::std::string config =
272 absl::StrCat(base_name, kSingleConfigSha1, ".bfbs");
Austin Schuh2f8fd752020-09-01 22:38:28 -0700273 const ::std::string logfile0 = base_name + ".part0.bfbs";
274 const ::std::string logfile1 = base_name + ".part1.bfbs";
Austin Schuhfa895892020-01-07 20:07:41 -0800275 // Remove it.
Austin Schuh25b46712021-01-03 00:04:38 -0800276 unlink(config.c_str());
Austin Schuhfa895892020-01-07 20:07:41 -0800277 unlink(logfile0.c_str());
278 unlink(logfile1.c_str());
279
280 LOG(INFO) << "Logging data to " << logfile0 << " and " << logfile1;
281
282 {
Austin Schuhfa895892020-01-07 20:07:41 -0800283 std::unique_ptr<EventLoop> logger_event_loop =
284 event_loop_factory_.MakeEventLoop("logger");
285
286 event_loop_factory_.RunFor(chrono::milliseconds(95));
287
Brian Silverman1f345222020-09-24 21:14:48 -0700288 Logger logger(logger_event_loop.get());
Austin Schuh8c399962020-12-25 21:51:45 -0800289 logger.set_separate_config(false);
Brian Silverman1f345222020-09-24 21:14:48 -0700290 logger.set_polling_period(std::chrono::milliseconds(100));
291 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuhfa895892020-01-07 20:07:41 -0800292 event_loop_factory_.RunFor(chrono::milliseconds(10000));
Austin Schuh2f8fd752020-09-01 22:38:28 -0700293 logger.Rotate();
Austin Schuhfa895892020-01-07 20:07:41 -0800294 event_loop_factory_.RunFor(chrono::milliseconds(10000));
295 }
296
Austin Schuh64fab802020-09-09 22:47:47 -0700297 {
298 // Confirm that the UUIDs match for both the parts and the logger, and the
299 // parts_index increments.
Austin Schuhadd6eb32020-11-09 21:24:26 -0800300 std::vector<SizePrefixedFlatbufferVector<LogFileHeader>> log_header;
Austin Schuh64fab802020-09-09 22:47:47 -0700301 for (std::string_view f : {logfile0, logfile1}) {
Austin Schuh3bd4c402020-11-06 18:19:06 -0800302 log_header.emplace_back(ReadHeader(f).value());
Austin Schuh64fab802020-09-09 22:47:47 -0700303 }
304
Brian Silvermanae7c0332020-09-30 16:58:23 -0700305 EXPECT_EQ(log_header[0].message().log_event_uuid()->string_view(),
306 log_header[1].message().log_event_uuid()->string_view());
Austin Schuh64fab802020-09-09 22:47:47 -0700307 EXPECT_EQ(log_header[0].message().parts_uuid()->string_view(),
308 log_header[1].message().parts_uuid()->string_view());
309
310 EXPECT_EQ(log_header[0].message().parts_index(), 0);
311 EXPECT_EQ(log_header[1].message().parts_index(), 1);
312 }
313
Austin Schuhfa895892020-01-07 20:07:41 -0800314 // Even though it doesn't make any difference here, exercise the logic for
315 // passing in a separate config.
Austin Schuh287d43d2020-12-04 20:19:33 -0800316 LogReader reader(SortParts({logfile0, logfile1}), &config_.message());
Austin Schuhfa895892020-01-07 20:07:41 -0800317
318 // Confirm that we can remap logged channels to point to new buses.
319 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
320
321 // This sends out the fetched messages and advances time to the start of the
322 // log file.
323 reader.Register();
324
Austin Schuh6f3babe2020-01-26 20:34:50 -0800325 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
Austin Schuhfa895892020-01-07 20:07:41 -0800326
327 std::unique_ptr<EventLoop> test_event_loop =
328 reader.event_loop_factory()->MakeEventLoop("log_reader");
329
330 int ping_count = 10;
331 int pong_count = 10;
332
333 // Confirm that the ping value matches in the remapped channel location.
334 test_event_loop->MakeWatcher("/original/test",
335 [&ping_count](const examples::Ping &ping) {
336 EXPECT_EQ(ping.value(), ping_count + 1);
337 ++ping_count;
338 });
339 // Confirm that the ping and pong counts both match, and the value also
340 // matches.
341 test_event_loop->MakeWatcher(
342 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
343 EXPECT_EQ(pong.value(), pong_count + 1);
344 ++pong_count;
345 EXPECT_EQ(ping_count, pong_count);
346 });
347
348 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
349 EXPECT_EQ(ping_count, 2010);
350}
351
Austin Schuh4c4e0092019-12-22 16:18:03 -0800352// Tests that a large number of messages per second doesn't overwhelm writev.
353TEST_F(LoggerTest, ManyMessages) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800354 const ::std::string tmpdir = aos::testing::TestTmpDir();
Austin Schuh2f8fd752020-09-01 22:38:28 -0700355 const ::std::string base_name = tmpdir + "/logfile";
Austin Schuh25b46712021-01-03 00:04:38 -0800356 const ::std::string config =
357 absl::StrCat(base_name, kSingleConfigSha1, ".bfbs");
Austin Schuh2f8fd752020-09-01 22:38:28 -0700358 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuh4c4e0092019-12-22 16:18:03 -0800359 // Remove the log file.
Austin Schuh25b46712021-01-03 00:04:38 -0800360 unlink(config.c_str());
Austin Schuh4c4e0092019-12-22 16:18:03 -0800361 unlink(logfile.c_str());
362
363 LOG(INFO) << "Logging data to " << logfile;
Austin Schuh4c3b9702020-08-30 11:34:55 -0700364 ping_.set_quiet(true);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800365
366 {
Austin Schuh4c4e0092019-12-22 16:18:03 -0800367 std::unique_ptr<EventLoop> logger_event_loop =
368 event_loop_factory_.MakeEventLoop("logger");
369
370 std::unique_ptr<EventLoop> ping_spammer_event_loop =
371 event_loop_factory_.MakeEventLoop("ping_spammer");
372 aos::Sender<examples::Ping> ping_sender =
373 ping_spammer_event_loop->MakeSender<examples::Ping>("/test");
374
375 aos::TimerHandler *timer_handler =
376 ping_spammer_event_loop->AddTimer([&ping_sender]() {
377 aos::Sender<examples::Ping>::Builder builder =
378 ping_sender.MakeBuilder();
379 examples::Ping::Builder ping_builder =
380 builder.MakeBuilder<examples::Ping>();
381 CHECK(builder.Send(ping_builder.Finish()));
382 });
383
384 // 100 ms / 0.05 ms -> 2000 messages. Should be enough to crash it.
385 ping_spammer_event_loop->OnRun([&ping_spammer_event_loop, timer_handler]() {
386 timer_handler->Setup(ping_spammer_event_loop->monotonic_now(),
387 chrono::microseconds(50));
388 });
389
Brian Silverman1f345222020-09-24 21:14:48 -0700390 Logger logger(logger_event_loop.get());
Austin Schuh8c399962020-12-25 21:51:45 -0800391 logger.set_separate_config(false);
Brian Silverman1f345222020-09-24 21:14:48 -0700392 logger.set_polling_period(std::chrono::milliseconds(100));
393 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800394
395 event_loop_factory_.RunFor(chrono::milliseconds(1000));
396 }
397}
398
Austin Schuh25b46712021-01-03 00:04:38 -0800399std::vector<std::string> MakeLogFiles(std::string logfile_base1,
400 std::string logfile_base2) {
Austin Schuh315b96b2020-12-11 21:21:12 -0800401 return std::vector<std::string>(
Austin Schuh8c399962020-12-25 21:51:45 -0800402 {logfile_base1 + "_pi1_data.part0.bfbs",
403 logfile_base1 + "_pi2_data/test/aos.examples.Pong.part0.bfbs",
404 logfile_base1 + "_pi2_data/test/aos.examples.Pong.part1.bfbs",
405 logfile_base2 + "_pi2_data.part0.bfbs",
406 logfile_base1 + "_timestamps/pi1/aos/remote_timestamps/pi2/"
407 "aos.message_bridge.RemoteMessage.part0.bfbs",
408 logfile_base1 + "_timestamps/pi1/aos/remote_timestamps/pi2/"
409 "aos.message_bridge.RemoteMessage.part1.bfbs",
410 logfile_base2 + "_timestamps/pi2/aos/remote_timestamps/pi1/"
411 "aos.message_bridge.RemoteMessage.part0.bfbs",
412 logfile_base2 + "_timestamps/pi2/aos/remote_timestamps/pi1/"
413 "aos.message_bridge.RemoteMessage.part1.bfbs",
414 logfile_base2 +
Austin Schuh315b96b2020-12-11 21:21:12 -0800415 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part0.bfbs",
Austin Schuh8c399962020-12-25 21:51:45 -0800416 logfile_base2 +
Austin Schuh315b96b2020-12-11 21:21:12 -0800417 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part1.bfbs",
Austin Schuh8c399962020-12-25 21:51:45 -0800418 logfile_base1 +
Austin Schuh315b96b2020-12-11 21:21:12 -0800419 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part0.bfbs",
Austin Schuh8c399962020-12-25 21:51:45 -0800420 logfile_base1 +
421 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part1.bfbs",
422 absl::StrCat(logfile_base1, "_", kConfigSha1, ".bfbs"),
423 absl::StrCat(logfile_base2, "_", kConfigSha1, ".bfbs")});
Austin Schuh315b96b2020-12-11 21:21:12 -0800424}
425
Austin Schuh15649d62019-12-28 16:36:38 -0800426class MultinodeLoggerTest : public ::testing::Test {
427 public:
428 MultinodeLoggerTest()
429 : config_(aos::configuration::ReadConfig(
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800430 "aos/events/logging/multinode_pingpong_config.json")),
Austin Schuh87dd3832021-01-01 23:07:31 -0800431 time_converter_(configuration::NodesCount(&config_.message())),
Austin Schuhac0771c2020-01-07 18:36:30 -0800432 event_loop_factory_(&config_.message()),
Austin Schuhcde938c2020-02-02 17:30:07 -0800433 pi1_(
434 configuration::GetNode(event_loop_factory_.configuration(), "pi1")),
Austin Schuh87dd3832021-01-01 23:07:31 -0800435 pi1_index_(configuration::GetNodeIndex(
436 event_loop_factory_.configuration(), pi1_)),
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700437 pi2_(
438 configuration::GetNode(event_loop_factory_.configuration(), "pi2")),
Austin Schuh87dd3832021-01-01 23:07:31 -0800439 pi2_index_(configuration::GetNodeIndex(
440 event_loop_factory_.configuration(), pi2_)),
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800441 tmp_dir_(aos::testing::TestTmpDir()),
Austin Schuh8c399962020-12-25 21:51:45 -0800442 logfile_base1_(tmp_dir_ + "/multi_logfile1"),
443 logfile_base2_(tmp_dir_ + "/multi_logfile2"),
Austin Schuh315b96b2020-12-11 21:21:12 -0800444 pi1_reboot_logfiles_(
Austin Schuh8c399962020-12-25 21:51:45 -0800445 {logfile_base1_ + "_pi1_data.part0.bfbs",
446 logfile_base1_ + "_pi2_data/test/aos.examples.Pong.part0.bfbs",
447 logfile_base1_ + "_pi2_data/test/aos.examples.Pong.part1.bfbs",
448 logfile_base1_ + "_pi2_data/test/aos.examples.Pong.part2.bfbs",
449 logfile_base1_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
450 "aos.message_bridge.RemoteMessage.part0.bfbs",
451 logfile_base1_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
452 "aos.message_bridge.RemoteMessage.part1.bfbs",
453 logfile_base1_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
454 "aos.message_bridge.RemoteMessage.part2.bfbs",
455 logfile_base1_ +
Austin Schuh2f8fd752020-09-01 22:38:28 -0700456 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part0.bfbs",
Austin Schuh8c399962020-12-25 21:51:45 -0800457 logfile_base1_ +
Austin Schuh315b96b2020-12-11 21:21:12 -0800458 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part1.bfbs",
Austin Schuh8c399962020-12-25 21:51:45 -0800459 logfile_base1_ +
460 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part2.bfbs",
461 absl::StrCat(logfile_base1_, "_", kConfigSha1, ".bfbs")}),
462 logfiles_(MakeLogFiles(logfile_base1_, logfile_base2_)),
Austin Schuhc9049732020-12-21 22:27:15 -0800463 pi1_single_direction_logfiles_(
Austin Schuh8c399962020-12-25 21:51:45 -0800464 {logfile_base1_ + "_pi1_data.part0.bfbs",
465 logfile_base1_ + "_pi2_data/test/aos.examples.Pong.part0.bfbs",
466 logfile_base1_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
467 "aos.message_bridge.RemoteMessage.part0.bfbs",
468 logfile_base1_ +
469 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part0.bfbs",
470 absl::StrCat(logfile_base1_, "_", kConfigSha1, ".bfbs")}),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700471 structured_logfiles_{
472 std::vector<std::string>{logfiles_[0]},
473 std::vector<std::string>{logfiles_[1], logfiles_[2]},
474 std::vector<std::string>{logfiles_[3]},
475 std::vector<std::string>{logfiles_[4], logfiles_[5]},
476 std::vector<std::string>{logfiles_[6], logfiles_[7]},
477 std::vector<std::string>{logfiles_[8], logfiles_[9]},
478 std::vector<std::string>{logfiles_[10], logfiles_[11]}},
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700479 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping", pi1_)),
480 ping_(ping_event_loop_.get()),
481 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong", pi2_)),
482 pong_(pong_event_loop_.get()) {
Austin Schuh87dd3832021-01-01 23:07:31 -0800483 event_loop_factory_.SetTimeConverter(&time_converter_);
484
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700485 // Go through and remove the logfiles if they already exist.
486 for (const auto file : logfiles_) {
487 unlink(file.c_str());
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800488 unlink((file + ".xz").c_str());
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700489 }
490
Austin Schuh25b46712021-01-03 00:04:38 -0800491 for (const auto file :
492 MakeLogFiles(tmp_dir_ + "/relogged1", tmp_dir_ + "/relogged2")) {
Austin Schuh315b96b2020-12-11 21:21:12 -0800493 unlink(file.c_str());
494 }
495
496 for (const auto file : pi1_reboot_logfiles_) {
497 unlink(file.c_str());
498 }
499
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700500 LOG(INFO) << "Logging data to " << logfiles_[0] << ", " << logfiles_[1]
501 << " and " << logfiles_[2];
502 }
503
504 struct LoggerState {
505 std::unique_ptr<EventLoop> event_loop;
506 std::unique_ptr<Logger> logger;
507 };
508
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700509 LoggerState MakeLogger(const Node *node,
510 SimulatedEventLoopFactory *factory = nullptr) {
511 if (factory == nullptr) {
512 factory = &event_loop_factory_;
513 }
514 return {factory->MakeEventLoop("logger", node), {}};
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700515 }
516
Austin Schuh3bd4c402020-11-06 18:19:06 -0800517 void StartLogger(LoggerState *logger, std::string logfile_base = "",
518 bool compress = false) {
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700519 if (logfile_base.empty()) {
Austin Schuh8c399962020-12-25 21:51:45 -0800520 if (logger->event_loop->node()->name()->string_view() == "pi1") {
521 logfile_base = logfile_base1_;
522 } else {
523 logfile_base = logfile_base2_;
524 }
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700525 }
526
Brian Silverman1f345222020-09-24 21:14:48 -0700527 logger->logger = std::make_unique<Logger>(logger->event_loop.get());
528 logger->logger->set_polling_period(std::chrono::milliseconds(100));
Austin Schuh0ca51f32020-12-25 21:51:45 -0800529 logger->logger->set_name(absl::StrCat(
530 "name_prefix_", logger->event_loop->node()->name()->str()));
Austin Schuh3bd4c402020-11-06 18:19:06 -0800531 logger->event_loop->OnRun([logger, logfile_base, compress]() {
532 std::unique_ptr<MultiNodeLogNamer> namer =
533 std::make_unique<MultiNodeLogNamer>(
534 logfile_base, logger->event_loop->configuration(),
535 logger->event_loop->node());
536 if (compress) {
537#ifdef LZMA
538 namer->set_extension(".xz");
539 namer->set_encoder_factory(
540 []() { return std::make_unique<aos::logger::LzmaEncoder>(3); });
541#else
542 LOG(FATAL) << "Compression unsupported";
543#endif
544 }
545
546 logger->logger->StartLogging(std::move(namer));
Brian Silverman1f345222020-09-24 21:14:48 -0700547 });
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700548 }
Austin Schuh15649d62019-12-28 16:36:38 -0800549
Austin Schuh3bd4c402020-11-06 18:19:06 -0800550 void VerifyParts(const std::vector<LogFile> &sorted_parts,
551 const std::vector<std::string> &corrupted_parts = {}) {
552 EXPECT_EQ(sorted_parts.size(), 2u);
553
554 // Count up the number of UUIDs and make sure they are what we expect as a
555 // sanity check.
556 std::set<std::string> log_event_uuids;
557 std::set<std::string> parts_uuids;
558 std::set<std::string> both_uuids;
559
560 size_t missing_rt_count = 0;
561
562 std::vector<std::string> logger_nodes;
563 for (const LogFile &log_file : sorted_parts) {
564 EXPECT_FALSE(log_file.log_event_uuid.empty());
565 log_event_uuids.insert(log_file.log_event_uuid);
566 logger_nodes.emplace_back(log_file.logger_node);
567 both_uuids.insert(log_file.log_event_uuid);
Austin Schuh0ca51f32020-12-25 21:51:45 -0800568 EXPECT_TRUE(log_file.config);
569 EXPECT_EQ(log_file.name,
570 absl::StrCat("name_prefix_", log_file.logger_node));
Austin Schuh3bd4c402020-11-06 18:19:06 -0800571
572 for (const LogParts &part : log_file.parts) {
573 EXPECT_NE(part.monotonic_start_time, aos::monotonic_clock::min_time)
574 << ": " << part;
575 missing_rt_count +=
576 part.realtime_start_time == aos::realtime_clock::min_time;
577
578 EXPECT_TRUE(log_event_uuids.find(part.log_event_uuid) !=
579 log_event_uuids.end());
580 EXPECT_NE(part.node, "");
Austin Schuh0ca51f32020-12-25 21:51:45 -0800581 EXPECT_TRUE(log_file.config);
Austin Schuh3bd4c402020-11-06 18:19:06 -0800582 parts_uuids.insert(part.parts_uuid);
583 both_uuids.insert(part.parts_uuid);
584 }
585 }
586
587 // We won't have RT timestamps for 5 log files. We don't log the RT start
588 // time on remote nodes because we don't know it and would be guessing. And
589 // the log reader can actually do a better job.
590 EXPECT_EQ(missing_rt_count, 5u);
591
592 EXPECT_EQ(log_event_uuids.size(), 2u);
593 EXPECT_EQ(parts_uuids.size(), ToLogReaderVector(sorted_parts).size());
594 EXPECT_EQ(log_event_uuids.size() + parts_uuids.size(), both_uuids.size());
595
596 // Test that each list of parts is in order. Don't worry about the ordering
597 // between part file lists though.
598 // (inner vectors all need to be in order, but outer one doesn't matter).
599 EXPECT_THAT(ToLogReaderVector(sorted_parts),
600 ::testing::UnorderedElementsAreArray(structured_logfiles_));
601
602 EXPECT_THAT(logger_nodes, ::testing::UnorderedElementsAre("pi1", "pi2"));
603
604 EXPECT_NE(sorted_parts[0].realtime_start_time,
605 aos::realtime_clock::min_time);
606 EXPECT_NE(sorted_parts[1].realtime_start_time,
607 aos::realtime_clock::min_time);
608
609 EXPECT_NE(sorted_parts[0].monotonic_start_time,
610 aos::monotonic_clock::min_time);
611 EXPECT_NE(sorted_parts[1].monotonic_start_time,
612 aos::monotonic_clock::min_time);
613
614 EXPECT_THAT(sorted_parts[0].corrupted, ::testing::Eq(corrupted_parts));
615 EXPECT_THAT(sorted_parts[1].corrupted, ::testing::Eq(corrupted_parts));
616 }
617
Austin Schuhc9049732020-12-21 22:27:15 -0800618 void ConfirmReadable(const std::vector<std::string> &files) {
619 LogReader reader(SortParts(files));
620
621 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
622 reader.Register(&log_reader_factory);
623
624 log_reader_factory.Run();
625
626 reader.Deregister();
627 }
628
Austin Schuh3bd4c402020-11-06 18:19:06 -0800629 void AddExtension(std::string_view extension) {
630 std::transform(logfiles_.begin(), logfiles_.end(), logfiles_.begin(),
631 [extension](const std::string &in) {
632 return absl::StrCat(in, extension);
633 });
634
635 std::transform(structured_logfiles_.begin(), structured_logfiles_.end(),
636 structured_logfiles_.begin(),
637 [extension](std::vector<std::string> in) {
638 std::transform(in.begin(), in.end(), in.begin(),
639 [extension](const std::string &in_str) {
640 return absl::StrCat(in_str, extension);
641 });
642 return in;
643 });
644 }
645
Austin Schuh15649d62019-12-28 16:36:38 -0800646 // Config and factory.
647 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
Austin Schuh87dd3832021-01-01 23:07:31 -0800648 message_bridge::TestingTimeConverter time_converter_;
Austin Schuh15649d62019-12-28 16:36:38 -0800649 SimulatedEventLoopFactory event_loop_factory_;
650
Austin Schuh87dd3832021-01-01 23:07:31 -0800651 const Node *const pi1_;
652 const size_t pi1_index_;
653 const Node *const pi2_;
654 const size_t pi2_index_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700655
656 std::string tmp_dir_;
Austin Schuh8c399962020-12-25 21:51:45 -0800657 std::string logfile_base1_;
658 std::string logfile_base2_;
Austin Schuh315b96b2020-12-11 21:21:12 -0800659 std::vector<std::string> pi1_reboot_logfiles_;
Austin Schuh2f8fd752020-09-01 22:38:28 -0700660 std::vector<std::string> logfiles_;
Austin Schuhc9049732020-12-21 22:27:15 -0800661 std::vector<std::string> pi1_single_direction_logfiles_;
Austin Schuh2f8fd752020-09-01 22:38:28 -0700662
663 std::vector<std::vector<std::string>> structured_logfiles_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700664
665 std::unique_ptr<EventLoop> ping_event_loop_;
666 Ping ping_;
667 std::unique_ptr<EventLoop> pong_event_loop_;
668 Pong pong_;
Austin Schuh15649d62019-12-28 16:36:38 -0800669};
670
Austin Schuh391e3172020-09-01 22:48:18 -0700671// Counts the number of messages on a channel. Returns (channel name, channel
672// type, count) for every message matching matcher()
673std::vector<std::tuple<std::string, std::string, int>> CountChannelsMatching(
Austin Schuh25b46712021-01-03 00:04:38 -0800674 std::shared_ptr<const aos::Configuration> config, std::string_view filename,
Austin Schuh6f3babe2020-01-26 20:34:50 -0800675 std::function<bool(const MessageHeader *)> matcher) {
676 MessageReader message_reader(filename);
Austin Schuh8c399962020-12-25 21:51:45 -0800677 std::vector<int> counts(config->channels()->size(), 0);
Austin Schuh15649d62019-12-28 16:36:38 -0800678
Austin Schuh6f3babe2020-01-26 20:34:50 -0800679 while (true) {
Austin Schuhadd6eb32020-11-09 21:24:26 -0800680 std::optional<SizePrefixedFlatbufferVector<MessageHeader>> msg =
Austin Schuh6f3babe2020-01-26 20:34:50 -0800681 message_reader.ReadMessage();
682 if (!msg) {
683 break;
684 }
685
686 if (matcher(&msg.value().message())) {
687 counts[msg.value().message().channel_index()]++;
688 }
689 }
690
Austin Schuh391e3172020-09-01 22:48:18 -0700691 std::vector<std::tuple<std::string, std::string, int>> result;
Austin Schuh6f3babe2020-01-26 20:34:50 -0800692 int channel = 0;
693 for (size_t i = 0; i < counts.size(); ++i) {
694 if (counts[i] != 0) {
Austin Schuh8c399962020-12-25 21:51:45 -0800695 const Channel *channel = config->channels()->Get(i);
Austin Schuh391e3172020-09-01 22:48:18 -0700696 result.push_back(std::make_tuple(channel->name()->str(),
697 channel->type()->str(), counts[i]));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800698 }
699 ++channel;
700 }
701
702 return result;
703}
704
705// Counts the number of messages (channel, count) for all data messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700706std::vector<std::tuple<std::string, std::string, int>> CountChannelsData(
Austin Schuh8c399962020-12-25 21:51:45 -0800707 std::shared_ptr<const aos::Configuration> config,
Austin Schuh391e3172020-09-01 22:48:18 -0700708 std::string_view filename) {
Austin Schuh8c399962020-12-25 21:51:45 -0800709 return CountChannelsMatching(config, filename, [](const MessageHeader *msg) {
Austin Schuh6f3babe2020-01-26 20:34:50 -0800710 if (msg->has_data()) {
711 CHECK(!msg->has_monotonic_remote_time());
712 CHECK(!msg->has_realtime_remote_time());
713 CHECK(!msg->has_remote_queue_index());
714 return true;
715 }
716 return false;
717 });
718}
719
720// Counts the number of messages (channel, count) for all timestamp messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700721std::vector<std::tuple<std::string, std::string, int>> CountChannelsTimestamp(
Austin Schuh8c399962020-12-25 21:51:45 -0800722 std::shared_ptr<const aos::Configuration> config,
Austin Schuh6f3babe2020-01-26 20:34:50 -0800723 std::string_view filename) {
Austin Schuh8c399962020-12-25 21:51:45 -0800724 return CountChannelsMatching(config, filename, [](const MessageHeader *msg) {
Austin Schuh6f3babe2020-01-26 20:34:50 -0800725 if (!msg->has_data()) {
726 CHECK(msg->has_monotonic_remote_time());
727 CHECK(msg->has_realtime_remote_time());
728 CHECK(msg->has_remote_queue_index());
729 return true;
730 }
731 return false;
732 });
733}
734
Austin Schuhcde938c2020-02-02 17:30:07 -0800735// Tests that we can write and read simple multi-node log files.
736TEST_F(MultinodeLoggerTest, SimpleMultiNode) {
Austin Schuh87dd3832021-01-01 23:07:31 -0800737 time_converter_.StartEqual();
Austin Schuh15649d62019-12-28 16:36:38 -0800738 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700739 LoggerState pi1_logger = MakeLogger(pi1_);
740 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuh15649d62019-12-28 16:36:38 -0800741
742 event_loop_factory_.RunFor(chrono::milliseconds(95));
743
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700744 StartLogger(&pi1_logger);
745 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800746
Austin Schuh15649d62019-12-28 16:36:38 -0800747 event_loop_factory_.RunFor(chrono::milliseconds(20000));
748 }
749
Austin Schuh6f3babe2020-01-26 20:34:50 -0800750 {
Austin Schuh64fab802020-09-09 22:47:47 -0700751 std::set<std::string> logfile_uuids;
752 std::set<std::string> parts_uuids;
753 // Confirm that we have the expected number of UUIDs for both the logfile
754 // UUIDs and parts UUIDs.
Austin Schuhadd6eb32020-11-09 21:24:26 -0800755 std::vector<SizePrefixedFlatbufferVector<LogFileHeader>> log_header;
Austin Schuh64fab802020-09-09 22:47:47 -0700756 for (std::string_view f : logfiles_) {
Austin Schuh3bd4c402020-11-06 18:19:06 -0800757 log_header.emplace_back(ReadHeader(f).value());
Austin Schuh8c399962020-12-25 21:51:45 -0800758 if (!log_header.back().message().has_configuration()) {
759 logfile_uuids.insert(
760 log_header.back().message().log_event_uuid()->str());
761 parts_uuids.insert(log_header.back().message().parts_uuid()->str());
762 }
Austin Schuh64fab802020-09-09 22:47:47 -0700763 }
Austin Schuh15649d62019-12-28 16:36:38 -0800764
Austin Schuh64fab802020-09-09 22:47:47 -0700765 EXPECT_EQ(logfile_uuids.size(), 2u);
766 EXPECT_EQ(parts_uuids.size(), 7u);
767
768 // And confirm everything is on the correct node.
769 EXPECT_EQ(log_header[0].message().node()->name()->string_view(), "pi1");
770 EXPECT_EQ(log_header[1].message().node()->name()->string_view(), "pi2");
771 EXPECT_EQ(log_header[2].message().node()->name()->string_view(), "pi2");
772 EXPECT_EQ(log_header[3].message().node()->name()->string_view(), "pi2");
773 EXPECT_EQ(log_header[4].message().node()->name()->string_view(), "pi2");
774 EXPECT_EQ(log_header[5].message().node()->name()->string_view(), "pi2");
775 EXPECT_EQ(log_header[6].message().node()->name()->string_view(), "pi1");
776 EXPECT_EQ(log_header[7].message().node()->name()->string_view(), "pi1");
777 EXPECT_EQ(log_header[8].message().node()->name()->string_view(), "pi1");
778 EXPECT_EQ(log_header[9].message().node()->name()->string_view(), "pi1");
779 EXPECT_EQ(log_header[10].message().node()->name()->string_view(), "pi2");
780 EXPECT_EQ(log_header[11].message().node()->name()->string_view(), "pi2");
781
782 // And the parts index matches.
783 EXPECT_EQ(log_header[0].message().parts_index(), 0);
784 EXPECT_EQ(log_header[1].message().parts_index(), 0);
785 EXPECT_EQ(log_header[2].message().parts_index(), 1);
786 EXPECT_EQ(log_header[3].message().parts_index(), 0);
787 EXPECT_EQ(log_header[4].message().parts_index(), 0);
788 EXPECT_EQ(log_header[5].message().parts_index(), 1);
789 EXPECT_EQ(log_header[6].message().parts_index(), 0);
790 EXPECT_EQ(log_header[7].message().parts_index(), 1);
791 EXPECT_EQ(log_header[8].message().parts_index(), 0);
792 EXPECT_EQ(log_header[9].message().parts_index(), 1);
793 EXPECT_EQ(log_header[10].message().parts_index(), 0);
794 EXPECT_EQ(log_header[11].message().parts_index(), 1);
795 }
796
Austin Schuh8c399962020-12-25 21:51:45 -0800797 const std::vector<LogFile> sorted_log_files = SortParts(logfiles_);
Austin Schuh64fab802020-09-09 22:47:47 -0700798 {
Austin Schuh391e3172020-09-01 22:48:18 -0700799 using ::testing::UnorderedElementsAre;
Austin Schuh8c399962020-12-25 21:51:45 -0800800 std::shared_ptr<const aos::Configuration> config =
801 sorted_log_files[0].config;
Austin Schuh391e3172020-09-01 22:48:18 -0700802
Austin Schuh6f3babe2020-01-26 20:34:50 -0800803 // Timing reports, pings
Austin Schuh2f8fd752020-09-01 22:38:28 -0700804 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800805 CountChannelsData(config, logfiles_[0]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700806 UnorderedElementsAre(
807 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200),
808 std::make_tuple("/pi1/aos", "aos.timing.Report", 40),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800809 std::make_tuple("/test", "aos.examples.Ping", 2001)))
810 << " : " << logfiles_[0];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800811 // Timestamps for pong
Austin Schuh2f8fd752020-09-01 22:38:28 -0700812 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800813 CountChannelsTimestamp(config, logfiles_[0]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700814 UnorderedElementsAre(
815 std::make_tuple("/test", "aos.examples.Pong", 2001),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800816 std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200)))
817 << " : " << logfiles_[0];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800818
819 // Pong data.
Austin Schuh20ac95d2020-12-05 17:24:19 -0800820 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800821 CountChannelsData(config, logfiles_[1]),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800822 UnorderedElementsAre(std::make_tuple("/test", "aos.examples.Pong", 91)))
823 << " : " << logfiles_[1];
Austin Schuh8c399962020-12-25 21:51:45 -0800824 EXPECT_THAT(CountChannelsData(config, logfiles_[2]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700825 UnorderedElementsAre(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800826 std::make_tuple("/test", "aos.examples.Pong", 1910)))
827 << " : " << logfiles_[1];
Austin Schuh391e3172020-09-01 22:48:18 -0700828
Austin Schuh6f3babe2020-01-26 20:34:50 -0800829 // No timestamps
Austin Schuh25b46712021-01-03 00:04:38 -0800830 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[1]),
831 UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800832 << " : " << logfiles_[1];
Austin Schuh25b46712021-01-03 00:04:38 -0800833 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[2]),
834 UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800835 << " : " << logfiles_[2];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800836
837 // Timing reports and pongs.
Austin Schuh2f8fd752020-09-01 22:38:28 -0700838 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800839 CountChannelsData(config, logfiles_[3]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700840 UnorderedElementsAre(
841 std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200),
842 std::make_tuple("/pi2/aos", "aos.timing.Report", 40),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800843 std::make_tuple("/test", "aos.examples.Pong", 2001)))
844 << " : " << logfiles_[3];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800845 // And ping timestamps.
Austin Schuh2f8fd752020-09-01 22:38:28 -0700846 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800847 CountChannelsTimestamp(config, logfiles_[3]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700848 UnorderedElementsAre(
849 std::make_tuple("/test", "aos.examples.Ping", 2001),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800850 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200)))
851 << " : " << logfiles_[3];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700852
853 // Timestamps from pi2 on pi1, and the other way.
Austin Schuh8c399962020-12-25 21:51:45 -0800854 EXPECT_THAT(CountChannelsData(config, logfiles_[4]), UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800855 << " : " << logfiles_[4];
Austin Schuh8c399962020-12-25 21:51:45 -0800856 EXPECT_THAT(CountChannelsData(config, logfiles_[5]), UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800857 << " : " << logfiles_[5];
Austin Schuh8c399962020-12-25 21:51:45 -0800858 EXPECT_THAT(CountChannelsData(config, logfiles_[6]), UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800859 << " : " << logfiles_[6];
Austin Schuh8c399962020-12-25 21:51:45 -0800860 EXPECT_THAT(CountChannelsData(config, logfiles_[7]), UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800861 << " : " << logfiles_[7];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700862 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800863 CountChannelsTimestamp(config, logfiles_[4]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700864 UnorderedElementsAre(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800865 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 9),
866 std::make_tuple("/test", "aos.examples.Ping", 91)))
867 << " : " << logfiles_[4];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700868 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -0800869 CountChannelsTimestamp(config, logfiles_[5]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700870 UnorderedElementsAre(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800871 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 191),
872 std::make_tuple("/test", "aos.examples.Ping", 1910)))
873 << " : " << logfiles_[5];
Austin Schuh8c399962020-12-25 21:51:45 -0800874 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[6]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700875 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800876 "/pi2/aos", "aos.message_bridge.Timestamp", 9)))
877 << " : " << logfiles_[6];
Austin Schuh8c399962020-12-25 21:51:45 -0800878 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[7]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700879 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800880 "/pi2/aos", "aos.message_bridge.Timestamp", 191)))
881 << " : " << logfiles_[7];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700882
883 // And then test that the remotely logged timestamp data files only have
884 // timestamps in them.
Austin Schuh25b46712021-01-03 00:04:38 -0800885 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[8]),
886 UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800887 << " : " << logfiles_[8];
Austin Schuh25b46712021-01-03 00:04:38 -0800888 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[9]),
889 UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800890 << " : " << logfiles_[9];
Austin Schuh25b46712021-01-03 00:04:38 -0800891 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[10]),
892 UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800893 << " : " << logfiles_[10];
Austin Schuh25b46712021-01-03 00:04:38 -0800894 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[11]),
895 UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -0800896 << " : " << logfiles_[11];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700897
Austin Schuh8c399962020-12-25 21:51:45 -0800898 EXPECT_THAT(CountChannelsData(config, logfiles_[8]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700899 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800900 "/pi1/aos", "aos.message_bridge.Timestamp", 9)))
901 << " : " << logfiles_[8];
Austin Schuh8c399962020-12-25 21:51:45 -0800902 EXPECT_THAT(CountChannelsData(config, logfiles_[9]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700903 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800904 "/pi1/aos", "aos.message_bridge.Timestamp", 191)))
905 << " : " << logfiles_[9];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700906
Austin Schuh8c399962020-12-25 21:51:45 -0800907 EXPECT_THAT(CountChannelsData(config, logfiles_[10]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700908 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800909 "/pi2/aos", "aos.message_bridge.Timestamp", 9)))
910 << " : " << logfiles_[10];
Austin Schuh8c399962020-12-25 21:51:45 -0800911 EXPECT_THAT(CountChannelsData(config, logfiles_[11]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700912 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800913 "/pi2/aos", "aos.message_bridge.Timestamp", 191)))
914 << " : " << logfiles_[11];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800915 }
916
Austin Schuh8c399962020-12-25 21:51:45 -0800917 LogReader reader(sorted_log_files);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800918
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700919 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuh6331ef92020-01-07 18:28:09 -0800920 log_reader_factory.set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800921
922 // This sends out the fetched messages and advances time to the start of the
923 // log file.
Austin Schuh6331ef92020-01-07 18:28:09 -0800924 reader.Register(&log_reader_factory);
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800925
Austin Schuhac0771c2020-01-07 18:36:30 -0800926 const Node *pi1 =
927 configuration::GetNode(log_reader_factory.configuration(), "pi1");
Austin Schuh6f3babe2020-01-26 20:34:50 -0800928 const Node *pi2 =
929 configuration::GetNode(log_reader_factory.configuration(), "pi2");
Austin Schuhac0771c2020-01-07 18:36:30 -0800930
Austin Schuh2f8fd752020-09-01 22:38:28 -0700931 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
932 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
933 LOG(INFO) << "now pi1 "
934 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
935 LOG(INFO) << "now pi2 "
936 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
937
Austin Schuh6f3babe2020-01-26 20:34:50 -0800938 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800939
940 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800941
Austin Schuh6f3babe2020-01-26 20:34:50 -0800942 std::unique_ptr<EventLoop> pi1_event_loop =
Austin Schuhac0771c2020-01-07 18:36:30 -0800943 log_reader_factory.MakeEventLoop("test", pi1);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800944 std::unique_ptr<EventLoop> pi2_event_loop =
945 log_reader_factory.MakeEventLoop("test", pi2);
Austin Schuh15649d62019-12-28 16:36:38 -0800946
Austin Schuh6f3babe2020-01-26 20:34:50 -0800947 int pi1_ping_count = 10;
948 int pi2_ping_count = 10;
949 int pi1_pong_count = 10;
950 int pi2_pong_count = 10;
Austin Schuh15649d62019-12-28 16:36:38 -0800951
952 // Confirm that the ping value matches.
Austin Schuh6f3babe2020-01-26 20:34:50 -0800953 pi1_event_loop->MakeWatcher(
954 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
Austin Schuh2f8fd752020-09-01 22:38:28 -0700955 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping) << " at "
Austin Schuh6f3babe2020-01-26 20:34:50 -0800956 << pi1_event_loop->context().monotonic_remote_time << " -> "
957 << pi1_event_loop->context().monotonic_event_time;
958 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
959 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
960 pi1_ping_count * chrono::milliseconds(10) +
961 monotonic_clock::epoch());
962 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
963 pi1_ping_count * chrono::milliseconds(10) +
964 realtime_clock::epoch());
965 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
966 pi1_event_loop->context().monotonic_event_time);
967 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
968 pi1_event_loop->context().realtime_event_time);
Austin Schuh15649d62019-12-28 16:36:38 -0800969
Austin Schuh6f3babe2020-01-26 20:34:50 -0800970 ++pi1_ping_count;
971 });
972 pi2_event_loop->MakeWatcher(
973 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
Austin Schuh2f8fd752020-09-01 22:38:28 -0700974 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping) << " at "
Austin Schuh6f3babe2020-01-26 20:34:50 -0800975 << pi2_event_loop->context().monotonic_remote_time << " -> "
976 << pi2_event_loop->context().monotonic_event_time;
977 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
978
979 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
980 pi2_ping_count * chrono::milliseconds(10) +
981 monotonic_clock::epoch());
982 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
983 pi2_ping_count * chrono::milliseconds(10) +
984 realtime_clock::epoch());
985 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time +
986 chrono::microseconds(150),
987 pi2_event_loop->context().monotonic_event_time);
988 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time +
989 chrono::microseconds(150),
990 pi2_event_loop->context().realtime_event_time);
991 ++pi2_ping_count;
Austin Schuh15649d62019-12-28 16:36:38 -0800992 });
993
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700994 constexpr ssize_t kQueueIndexOffset = -9;
Austin Schuh6f3babe2020-01-26 20:34:50 -0800995 // Confirm that the ping and pong counts both match, and the value also
996 // matches.
997 pi1_event_loop->MakeWatcher(
998 "/test", [&pi1_event_loop, &pi1_ping_count,
999 &pi1_pong_count](const examples::Pong &pong) {
1000 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
1001 << pi1_event_loop->context().monotonic_remote_time << " -> "
1002 << pi1_event_loop->context().monotonic_event_time;
1003
1004 EXPECT_EQ(pi1_event_loop->context().remote_queue_index,
1005 pi1_pong_count + kQueueIndexOffset);
1006 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
1007 chrono::microseconds(200) +
1008 pi1_pong_count * chrono::milliseconds(10) +
1009 monotonic_clock::epoch());
1010 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
1011 chrono::microseconds(200) +
1012 pi1_pong_count * chrono::milliseconds(10) +
1013 realtime_clock::epoch());
1014
1015 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time +
1016 chrono::microseconds(150),
1017 pi1_event_loop->context().monotonic_event_time);
1018 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time +
1019 chrono::microseconds(150),
1020 pi1_event_loop->context().realtime_event_time);
1021
1022 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
1023 ++pi1_pong_count;
1024 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
1025 });
1026 pi2_event_loop->MakeWatcher(
1027 "/test", [&pi2_event_loop, &pi2_ping_count,
1028 &pi2_pong_count](const examples::Pong &pong) {
1029 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
1030 << pi2_event_loop->context().monotonic_remote_time << " -> "
1031 << pi2_event_loop->context().monotonic_event_time;
1032
1033 EXPECT_EQ(pi2_event_loop->context().remote_queue_index,
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001034 pi2_pong_count + kQueueIndexOffset);
Austin Schuh6f3babe2020-01-26 20:34:50 -08001035
1036 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
1037 chrono::microseconds(200) +
1038 pi2_pong_count * chrono::milliseconds(10) +
1039 monotonic_clock::epoch());
1040 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
1041 chrono::microseconds(200) +
1042 pi2_pong_count * chrono::milliseconds(10) +
1043 realtime_clock::epoch());
1044
1045 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
1046 pi2_event_loop->context().monotonic_event_time);
1047 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
1048 pi2_event_loop->context().realtime_event_time);
1049
1050 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1051 ++pi2_pong_count;
1052 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1053 });
1054
1055 log_reader_factory.Run();
1056 EXPECT_EQ(pi1_ping_count, 2010);
1057 EXPECT_EQ(pi2_ping_count, 2010);
1058 EXPECT_EQ(pi1_pong_count, 2010);
1059 EXPECT_EQ(pi2_pong_count, 2010);
Austin Schuh6331ef92020-01-07 18:28:09 -08001060
1061 reader.Deregister();
Austin Schuh15649d62019-12-28 16:36:38 -08001062}
1063
James Kuszmaul46d82582020-05-09 19:50:09 -07001064typedef MultinodeLoggerTest MultinodeLoggerDeathTest;
1065
1066// Test that if we feed the replay with a mismatched node list that we die on
1067// the LogReader constructor.
1068TEST_F(MultinodeLoggerDeathTest, MultiNodeBadReplayConfig) {
Austin Schuh87dd3832021-01-01 23:07:31 -08001069 time_converter_.StartEqual();
James Kuszmaul46d82582020-05-09 19:50:09 -07001070 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001071 LoggerState pi1_logger = MakeLogger(pi1_);
1072 LoggerState pi2_logger = MakeLogger(pi2_);
James Kuszmaul46d82582020-05-09 19:50:09 -07001073
1074 event_loop_factory_.RunFor(chrono::milliseconds(95));
1075
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001076 StartLogger(&pi1_logger);
1077 StartLogger(&pi2_logger);
James Kuszmaul46d82582020-05-09 19:50:09 -07001078
James Kuszmaul46d82582020-05-09 19:50:09 -07001079 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1080 }
1081
1082 // Test that, if we add an additional node to the replay config that the
1083 // logger complains about the mismatch in number of nodes.
1084 FlatbufferDetachedBuffer<Configuration> extra_nodes_config =
1085 configuration::MergeWithConfig(&config_.message(), R"({
1086 "nodes": [
1087 {
1088 "name": "extra-node"
1089 }
1090 ]
1091 }
1092 )");
1093
Austin Schuh287d43d2020-12-04 20:19:33 -08001094 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1095 EXPECT_DEATH(LogReader(sorted_parts, &extra_nodes_config.message()),
James Kuszmaul46d82582020-05-09 19:50:09 -07001096 "Log file and replay config need to have matching nodes lists.");
James Kuszmaul46d82582020-05-09 19:50:09 -07001097}
1098
Austin Schuhcde938c2020-02-02 17:30:07 -08001099// Tests that we can read log files where they don't start at the same monotonic
1100// time.
1101TEST_F(MultinodeLoggerTest, StaggeredStart) {
Austin Schuh87dd3832021-01-01 23:07:31 -08001102 time_converter_.StartEqual();
Austin Schuhcde938c2020-02-02 17:30:07 -08001103 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001104 LoggerState pi1_logger = MakeLogger(pi1_);
1105 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuhcde938c2020-02-02 17:30:07 -08001106
1107 event_loop_factory_.RunFor(chrono::milliseconds(95));
1108
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001109 StartLogger(&pi1_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -08001110
1111 event_loop_factory_.RunFor(chrono::milliseconds(200));
1112
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001113 StartLogger(&pi2_logger);
1114
Austin Schuhcde938c2020-02-02 17:30:07 -08001115 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1116 }
1117
Austin Schuh287d43d2020-12-04 20:19:33 -08001118 LogReader reader(SortParts(logfiles_));
Austin Schuhcde938c2020-02-02 17:30:07 -08001119
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001120 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuhcde938c2020-02-02 17:30:07 -08001121 log_reader_factory.set_send_delay(chrono::microseconds(0));
1122
1123 // This sends out the fetched messages and advances time to the start of the
1124 // log file.
1125 reader.Register(&log_reader_factory);
1126
1127 const Node *pi1 =
1128 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1129 const Node *pi2 =
1130 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1131
1132 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1133
1134 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1135
1136 std::unique_ptr<EventLoop> pi1_event_loop =
1137 log_reader_factory.MakeEventLoop("test", pi1);
1138 std::unique_ptr<EventLoop> pi2_event_loop =
1139 log_reader_factory.MakeEventLoop("test", pi2);
1140
1141 int pi1_ping_count = 30;
1142 int pi2_ping_count = 30;
1143 int pi1_pong_count = 30;
1144 int pi2_pong_count = 30;
1145
1146 // Confirm that the ping value matches.
1147 pi1_event_loop->MakeWatcher(
1148 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
1149 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
1150 << pi1_event_loop->context().monotonic_remote_time << " -> "
1151 << pi1_event_loop->context().monotonic_event_time;
1152 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
1153
1154 ++pi1_ping_count;
1155 });
1156 pi2_event_loop->MakeWatcher(
1157 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
1158 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
1159 << pi2_event_loop->context().monotonic_remote_time << " -> "
1160 << pi2_event_loop->context().monotonic_event_time;
1161 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
1162
1163 ++pi2_ping_count;
1164 });
1165
1166 // Confirm that the ping and pong counts both match, and the value also
1167 // matches.
1168 pi1_event_loop->MakeWatcher(
1169 "/test", [&pi1_event_loop, &pi1_ping_count,
1170 &pi1_pong_count](const examples::Pong &pong) {
1171 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
1172 << pi1_event_loop->context().monotonic_remote_time << " -> "
1173 << pi1_event_loop->context().monotonic_event_time;
1174
1175 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
1176 ++pi1_pong_count;
1177 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
1178 });
1179 pi2_event_loop->MakeWatcher(
1180 "/test", [&pi2_event_loop, &pi2_ping_count,
1181 &pi2_pong_count](const examples::Pong &pong) {
1182 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
1183 << pi2_event_loop->context().monotonic_remote_time << " -> "
1184 << pi2_event_loop->context().monotonic_event_time;
1185
1186 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1187 ++pi2_pong_count;
1188 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1189 });
1190
1191 log_reader_factory.Run();
1192 EXPECT_EQ(pi1_ping_count, 2030);
1193 EXPECT_EQ(pi2_ping_count, 2030);
1194 EXPECT_EQ(pi1_pong_count, 2030);
1195 EXPECT_EQ(pi2_pong_count, 2030);
1196
1197 reader.Deregister();
1198}
Austin Schuh6f3babe2020-01-26 20:34:50 -08001199
Austin Schuh8bd96322020-02-13 21:18:22 -08001200// Tests that we can read log files where the monotonic clocks drift and don't
1201// match correctly. While we are here, also test that different ending times
1202// also is readable.
1203TEST_F(MultinodeLoggerTest, MismatchedClocks) {
Austin Schuh87dd3832021-01-01 23:07:31 -08001204 // TODO(austin): Negate...
1205 const chrono::nanoseconds initial_pi2_offset = chrono::seconds(1000);
1206
1207 time_converter_.AddMonotonic({monotonic_clock::epoch(),
1208 monotonic_clock::epoch() + initial_pi2_offset});
1209 // Wait for 95 ms, (~0.1 seconds - 1/2 of the ping/pong period), and set the
1210 // skew to be 200 uS/s
1211 const chrono::nanoseconds startup_sleep1 = time_converter_.AddMonotonic(
1212 {chrono::milliseconds(95),
1213 chrono::milliseconds(95) - chrono::nanoseconds(200) * 95});
1214 // Run another 200 ms to have one logger start first.
1215 const chrono::nanoseconds startup_sleep2 = time_converter_.AddMonotonic(
1216 {chrono::milliseconds(200), chrono::milliseconds(200)});
1217 // Slew one way then the other at the same 200 uS/S slew rate. Make sure we
1218 // go far enough to cause problems if this isn't accounted for.
1219 const chrono::nanoseconds logger_run1 = time_converter_.AddMonotonic(
1220 {chrono::milliseconds(20000),
1221 chrono::milliseconds(20000) - chrono::nanoseconds(200) * 20000});
1222 const chrono::nanoseconds logger_run2 = time_converter_.AddMonotonic(
1223 {chrono::milliseconds(40000),
1224 chrono::milliseconds(40000) + chrono::nanoseconds(200) * 40000});
1225 const chrono::nanoseconds logger_run3 = time_converter_.AddMonotonic(
1226 {chrono::milliseconds(400), chrono::milliseconds(400)});
1227
Austin Schuhcde938c2020-02-02 17:30:07 -08001228 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001229 LoggerState pi2_logger = MakeLogger(pi2_);
1230
Austin Schuh87dd3832021-01-01 23:07:31 -08001231 NodeEventLoopFactory *pi1 =
1232 event_loop_factory_.GetNodeEventLoopFactory(pi1_);
Austin Schuh8bd96322020-02-13 21:18:22 -08001233 NodeEventLoopFactory *pi2 =
1234 event_loop_factory_.GetNodeEventLoopFactory(pi2_);
1235 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
1236 << pi2->realtime_now() << " distributed "
1237 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -08001238
Austin Schuh8bd96322020-02-13 21:18:22 -08001239 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
1240 << pi2->realtime_now() << " distributed "
1241 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -08001242
Austin Schuh87dd3832021-01-01 23:07:31 -08001243 event_loop_factory_.RunFor(startup_sleep1);
Austin Schuhcde938c2020-02-02 17:30:07 -08001244
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001245 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -08001246
Austin Schuh87dd3832021-01-01 23:07:31 -08001247 event_loop_factory_.RunFor(startup_sleep2);
Austin Schuhcde938c2020-02-02 17:30:07 -08001248
Austin Schuh8bd96322020-02-13 21:18:22 -08001249 {
1250 // Run pi1's logger for only part of the time.
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001251 LoggerState pi1_logger = MakeLogger(pi1_);
Austin Schuh8bd96322020-02-13 21:18:22 -08001252
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001253 StartLogger(&pi1_logger);
Austin Schuh87dd3832021-01-01 23:07:31 -08001254 event_loop_factory_.RunFor(logger_run1);
Austin Schuh8bd96322020-02-13 21:18:22 -08001255
Austin Schuh87dd3832021-01-01 23:07:31 -08001256 // Make sure we slewed time far enough so that the difference is greater
1257 // than the network delay. This confirms that if we sort incorrectly, it
1258 // would show in the results.
1259 EXPECT_LT(
1260 (pi2->monotonic_now() - pi1->monotonic_now()) - initial_pi2_offset,
1261 -event_loop_factory_.send_delay() -
1262 event_loop_factory_.network_delay());
Austin Schuh8bd96322020-02-13 21:18:22 -08001263
Austin Schuh87dd3832021-01-01 23:07:31 -08001264 event_loop_factory_.RunFor(logger_run2);
Austin Schuh8bd96322020-02-13 21:18:22 -08001265
Austin Schuh87dd3832021-01-01 23:07:31 -08001266 // And now check that we went far enough the other way to make sure we
1267 // cover both problems.
1268 EXPECT_GT(
1269 (pi2->monotonic_now() - pi1->monotonic_now()) - initial_pi2_offset,
1270 event_loop_factory_.send_delay() +
1271 event_loop_factory_.network_delay());
Austin Schuh8bd96322020-02-13 21:18:22 -08001272 }
1273
1274 // And log a bit more on pi2.
Austin Schuh87dd3832021-01-01 23:07:31 -08001275 event_loop_factory_.RunFor(logger_run3);
Austin Schuhcde938c2020-02-02 17:30:07 -08001276 }
1277
Austin Schuh287d43d2020-12-04 20:19:33 -08001278 LogReader reader(SortParts(logfiles_));
Austin Schuhcde938c2020-02-02 17:30:07 -08001279
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001280 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuhcde938c2020-02-02 17:30:07 -08001281 log_reader_factory.set_send_delay(chrono::microseconds(0));
1282
Austin Schuhcde938c2020-02-02 17:30:07 -08001283 const Node *pi1 =
1284 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1285 const Node *pi2 =
1286 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1287
Austin Schuh2f8fd752020-09-01 22:38:28 -07001288 // This sends out the fetched messages and advances time to the start of the
1289 // log file.
1290 reader.Register(&log_reader_factory);
1291
1292 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
1293 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
1294 LOG(INFO) << "now pi1 "
1295 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
1296 LOG(INFO) << "now pi2 "
1297 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
1298
Austin Schuhcde938c2020-02-02 17:30:07 -08001299 LOG(INFO) << "Done registering (pi1) "
Austin Schuh391e3172020-09-01 22:48:18 -07001300 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now()
1301 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -08001302 << log_reader_factory.GetNodeEventLoopFactory(pi1)->realtime_now();
1303 LOG(INFO) << "Done registering (pi2) "
Austin Schuh391e3172020-09-01 22:48:18 -07001304 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now()
1305 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -08001306 << log_reader_factory.GetNodeEventLoopFactory(pi2)->realtime_now();
1307
1308 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1309
1310 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1311
1312 std::unique_ptr<EventLoop> pi1_event_loop =
1313 log_reader_factory.MakeEventLoop("test", pi1);
1314 std::unique_ptr<EventLoop> pi2_event_loop =
1315 log_reader_factory.MakeEventLoop("test", pi2);
1316
1317 int pi1_ping_count = 30;
1318 int pi2_ping_count = 30;
1319 int pi1_pong_count = 30;
1320 int pi2_pong_count = 30;
1321
1322 // Confirm that the ping value matches.
1323 pi1_event_loop->MakeWatcher(
1324 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
1325 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
1326 << pi1_event_loop->context().monotonic_remote_time << " -> "
1327 << pi1_event_loop->context().monotonic_event_time;
1328 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
1329
1330 ++pi1_ping_count;
1331 });
1332 pi2_event_loop->MakeWatcher(
1333 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
1334 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
1335 << pi2_event_loop->context().monotonic_remote_time << " -> "
1336 << pi2_event_loop->context().monotonic_event_time;
1337 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
1338
1339 ++pi2_ping_count;
1340 });
1341
1342 // Confirm that the ping and pong counts both match, and the value also
1343 // matches.
1344 pi1_event_loop->MakeWatcher(
1345 "/test", [&pi1_event_loop, &pi1_ping_count,
1346 &pi1_pong_count](const examples::Pong &pong) {
1347 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
1348 << pi1_event_loop->context().monotonic_remote_time << " -> "
1349 << pi1_event_loop->context().monotonic_event_time;
1350
1351 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
1352 ++pi1_pong_count;
1353 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
1354 });
1355 pi2_event_loop->MakeWatcher(
1356 "/test", [&pi2_event_loop, &pi2_ping_count,
1357 &pi2_pong_count](const examples::Pong &pong) {
1358 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
1359 << pi2_event_loop->context().monotonic_remote_time << " -> "
1360 << pi2_event_loop->context().monotonic_event_time;
1361
1362 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1363 ++pi2_pong_count;
1364 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1365 });
1366
1367 log_reader_factory.Run();
Austin Schuh8bd96322020-02-13 21:18:22 -08001368 EXPECT_EQ(pi1_ping_count, 6030);
1369 EXPECT_EQ(pi2_ping_count, 6030);
1370 EXPECT_EQ(pi1_pong_count, 6030);
1371 EXPECT_EQ(pi2_pong_count, 6030);
Austin Schuhcde938c2020-02-02 17:30:07 -08001372
1373 reader.Deregister();
1374}
1375
Austin Schuh5212cad2020-09-09 23:12:09 -07001376// Tests that we can sort a bunch of parts into the pre-determined sorted parts.
1377TEST_F(MultinodeLoggerTest, SortParts) {
Austin Schuh87dd3832021-01-01 23:07:31 -08001378 time_converter_.StartEqual();
Austin Schuh5212cad2020-09-09 23:12:09 -07001379 // Make a bunch of parts.
1380 {
1381 LoggerState pi1_logger = MakeLogger(pi1_);
1382 LoggerState pi2_logger = MakeLogger(pi2_);
1383
1384 event_loop_factory_.RunFor(chrono::milliseconds(95));
1385
1386 StartLogger(&pi1_logger);
1387 StartLogger(&pi2_logger);
1388
1389 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1390 }
1391
Austin Schuh11d43732020-09-21 17:28:30 -07001392 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
Austin Schuh3bd4c402020-11-06 18:19:06 -08001393 VerifyParts(sorted_parts);
1394}
Austin Schuh11d43732020-09-21 17:28:30 -07001395
Austin Schuh3bd4c402020-11-06 18:19:06 -08001396// Tests that we can sort a bunch of parts with an empty part. We should ignore
1397// it and remove it from the sorted list.
1398TEST_F(MultinodeLoggerTest, SortEmptyParts) {
Austin Schuh87dd3832021-01-01 23:07:31 -08001399 time_converter_.StartEqual();
Austin Schuh3bd4c402020-11-06 18:19:06 -08001400 // Make a bunch of parts.
1401 {
1402 LoggerState pi1_logger = MakeLogger(pi1_);
1403 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuh11d43732020-09-21 17:28:30 -07001404
Austin Schuh3bd4c402020-11-06 18:19:06 -08001405 event_loop_factory_.RunFor(chrono::milliseconds(95));
Austin Schuh11d43732020-09-21 17:28:30 -07001406
Austin Schuh3bd4c402020-11-06 18:19:06 -08001407 StartLogger(&pi1_logger);
1408 StartLogger(&pi2_logger);
Austin Schuh11d43732020-09-21 17:28:30 -07001409
Austin Schuh3bd4c402020-11-06 18:19:06 -08001410 event_loop_factory_.RunFor(chrono::milliseconds(2000));
Austin Schuh11d43732020-09-21 17:28:30 -07001411 }
1412
Austin Schuh3bd4c402020-11-06 18:19:06 -08001413 // TODO(austin): Should we flip out if the file can't open?
1414 const std::string kEmptyFile("foobarinvalidfiledoesnotexist.bfbs");
Austin Schuh11d43732020-09-21 17:28:30 -07001415
Austin Schuh3bd4c402020-11-06 18:19:06 -08001416 aos::util::WriteStringToFileOrDie(kEmptyFile, "");
1417 logfiles_.emplace_back(kEmptyFile);
Austin Schuh5212cad2020-09-09 23:12:09 -07001418
Austin Schuh3bd4c402020-11-06 18:19:06 -08001419 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1420 VerifyParts(sorted_parts, {kEmptyFile});
Austin Schuh5212cad2020-09-09 23:12:09 -07001421}
1422
Austin Schuh3bd4c402020-11-06 18:19:06 -08001423#ifdef LZMA
1424// Tests that we can sort a bunch of parts with an empty .xz file in there. The
1425// empty file should be ignored.
1426TEST_F(MultinodeLoggerTest, SortEmptyCompressedParts) {
Austin Schuh87dd3832021-01-01 23:07:31 -08001427 time_converter_.StartEqual();
Austin Schuh3bd4c402020-11-06 18:19:06 -08001428 // Make a bunch of parts.
1429 {
1430 LoggerState pi1_logger = MakeLogger(pi1_);
1431 LoggerState pi2_logger = MakeLogger(pi2_);
1432
1433 event_loop_factory_.RunFor(chrono::milliseconds(95));
1434
1435 StartLogger(&pi1_logger, "", true);
1436 StartLogger(&pi2_logger, "", true);
1437
1438 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1439 }
1440
1441 // TODO(austin): Should we flip out if the file can't open?
1442 const std::string kEmptyFile("foobarinvalidfiledoesnotexist.bfbs.xz");
1443
1444 AddExtension(".xz");
1445
1446 aos::util::WriteStringToFileOrDie(kEmptyFile, "");
1447 logfiles_.emplace_back(kEmptyFile);
1448
1449 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1450 VerifyParts(sorted_parts, {kEmptyFile});
1451}
1452
1453// Tests that we can sort a bunch of parts with the end missing off a compressed
1454// file. We should use the part we can read.
1455TEST_F(MultinodeLoggerTest, SortTruncatedCompressedParts) {
Austin Schuh87dd3832021-01-01 23:07:31 -08001456 time_converter_.StartEqual();
Austin Schuh3bd4c402020-11-06 18:19:06 -08001457 // Make a bunch of parts.
1458 {
1459 LoggerState pi1_logger = MakeLogger(pi1_);
1460 LoggerState pi2_logger = MakeLogger(pi2_);
1461
1462 event_loop_factory_.RunFor(chrono::milliseconds(95));
1463
1464 StartLogger(&pi1_logger, "", true);
1465 StartLogger(&pi2_logger, "", true);
1466
1467 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1468 }
1469
1470 // Append everything with .xz.
1471 AddExtension(".xz");
1472
1473 // Strip off the end of one of the files. Pick one with a lot of data.
1474 ::std::string compressed_contents =
1475 aos::util::ReadFileToStringOrDie(logfiles_[0]);
1476
1477 aos::util::WriteStringToFileOrDie(
1478 logfiles_[0],
1479 compressed_contents.substr(0, compressed_contents.size() - 100));
1480
1481 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1482 VerifyParts(sorted_parts);
1483}
1484#endif
1485
Austin Schuh01b4c352020-09-21 23:09:39 -07001486// Tests that if we remap a remapped channel, it shows up correctly.
1487TEST_F(MultinodeLoggerTest, RemapLoggedChannel) {
Austin Schuh87dd3832021-01-01 23:07:31 -08001488 time_converter_.StartEqual();
Austin Schuh01b4c352020-09-21 23:09:39 -07001489 {
1490 LoggerState pi1_logger = MakeLogger(pi1_);
1491 LoggerState pi2_logger = MakeLogger(pi2_);
1492
1493 event_loop_factory_.RunFor(chrono::milliseconds(95));
1494
1495 StartLogger(&pi1_logger);
1496 StartLogger(&pi2_logger);
1497
1498 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1499 }
1500
Austin Schuh287d43d2020-12-04 20:19:33 -08001501 LogReader reader(SortParts(logfiles_));
Austin Schuh01b4c352020-09-21 23:09:39 -07001502
1503 // Remap just on pi1.
1504 reader.RemapLoggedChannel<aos::timing::Report>(
1505 "/aos", configuration::GetNode(reader.configuration(), "pi1"));
1506
1507 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1508 log_reader_factory.set_send_delay(chrono::microseconds(0));
1509
1510 reader.Register(&log_reader_factory);
1511
1512 const Node *pi1 =
1513 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1514 const Node *pi2 =
1515 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1516
1517 // Confirm we can read the data on the remapped channel, just for pi1. Nothing
1518 // else should have moved.
1519 std::unique_ptr<EventLoop> pi1_event_loop =
1520 log_reader_factory.MakeEventLoop("test", pi1);
1521 pi1_event_loop->SkipTimingReport();
1522 std::unique_ptr<EventLoop> full_pi1_event_loop =
1523 log_reader_factory.MakeEventLoop("test", pi1);
1524 full_pi1_event_loop->SkipTimingReport();
1525 std::unique_ptr<EventLoop> pi2_event_loop =
1526 log_reader_factory.MakeEventLoop("test", pi2);
1527 pi2_event_loop->SkipTimingReport();
1528
1529 MessageCounter<aos::timing::Report> pi1_timing_report(pi1_event_loop.get(),
1530 "/aos");
1531 MessageCounter<aos::timing::Report> full_pi1_timing_report(
1532 full_pi1_event_loop.get(), "/pi1/aos");
1533 MessageCounter<aos::timing::Report> pi1_original_timing_report(
1534 pi1_event_loop.get(), "/original/aos");
1535 MessageCounter<aos::timing::Report> full_pi1_original_timing_report(
1536 full_pi1_event_loop.get(), "/original/pi1/aos");
1537 MessageCounter<aos::timing::Report> pi2_timing_report(pi2_event_loop.get(),
1538 "/aos");
1539
1540 log_reader_factory.Run();
1541
1542 EXPECT_EQ(pi1_timing_report.count(), 0u);
1543 EXPECT_EQ(full_pi1_timing_report.count(), 0u);
1544 EXPECT_NE(pi1_original_timing_report.count(), 0u);
1545 EXPECT_NE(full_pi1_original_timing_report.count(), 0u);
1546 EXPECT_NE(pi2_timing_report.count(), 0u);
1547
1548 reader.Deregister();
1549}
1550
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001551// Tests that we properly recreate forwarded timestamps when replaying a log.
1552// This should be enough that we can then re-run the logger and get a valid log
1553// back.
1554TEST_F(MultinodeLoggerTest, MessageHeader) {
Austin Schuh87dd3832021-01-01 23:07:31 -08001555 time_converter_.StartEqual();
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001556 {
1557 LoggerState pi1_logger = MakeLogger(pi1_);
1558 LoggerState pi2_logger = MakeLogger(pi2_);
1559
1560 event_loop_factory_.RunFor(chrono::milliseconds(95));
1561
1562 StartLogger(&pi1_logger);
1563 StartLogger(&pi2_logger);
1564
1565 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1566 }
1567
Austin Schuh287d43d2020-12-04 20:19:33 -08001568 LogReader reader(SortParts(logfiles_));
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001569
1570 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1571 log_reader_factory.set_send_delay(chrono::microseconds(0));
1572
1573 // This sends out the fetched messages and advances time to the start of the
1574 // log file.
1575 reader.Register(&log_reader_factory);
1576
1577 const Node *pi1 =
1578 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1579 const Node *pi2 =
1580 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1581
1582 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
1583 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
1584 LOG(INFO) << "now pi1 "
1585 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
1586 LOG(INFO) << "now pi2 "
1587 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
1588
1589 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1590
1591 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1592
1593 std::unique_ptr<EventLoop> pi1_event_loop =
1594 log_reader_factory.MakeEventLoop("test", pi1);
1595 std::unique_ptr<EventLoop> pi2_event_loop =
1596 log_reader_factory.MakeEventLoop("test", pi2);
1597
Austin Schuh0de30f32020-12-06 12:44:28 -08001598 MessageCounter<RemoteMessage> pi1_original_message_header_counter(
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001599 pi1_event_loop.get(), "/original/aos/remote_timestamps/pi2");
Austin Schuh0de30f32020-12-06 12:44:28 -08001600 MessageCounter<RemoteMessage> pi2_original_message_header_counter(
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001601 pi2_event_loop.get(), "/original/aos/remote_timestamps/pi1");
1602
1603 aos::Fetcher<message_bridge::Timestamp> pi1_timestamp_on_pi1_fetcher =
1604 pi1_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi1/aos");
1605 aos::Fetcher<message_bridge::Timestamp> pi1_timestamp_on_pi2_fetcher =
1606 pi2_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi1/aos");
1607
1608 aos::Fetcher<examples::Ping> ping_on_pi1_fetcher =
1609 pi1_event_loop->MakeFetcher<examples::Ping>("/test");
1610 aos::Fetcher<examples::Ping> ping_on_pi2_fetcher =
1611 pi2_event_loop->MakeFetcher<examples::Ping>("/test");
1612
1613 aos::Fetcher<message_bridge::Timestamp> pi2_timestamp_on_pi2_fetcher =
1614 pi2_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi2/aos");
1615 aos::Fetcher<message_bridge::Timestamp> pi2_timestamp_on_pi1_fetcher =
1616 pi1_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi2/aos");
1617
1618 aos::Fetcher<examples::Pong> pong_on_pi2_fetcher =
1619 pi2_event_loop->MakeFetcher<examples::Pong>("/test");
1620 aos::Fetcher<examples::Pong> pong_on_pi1_fetcher =
1621 pi1_event_loop->MakeFetcher<examples::Pong>("/test");
1622
1623 const size_t pi1_timestamp_channel = configuration::ChannelIndex(
1624 pi1_event_loop->configuration(), pi1_timestamp_on_pi1_fetcher.channel());
1625 const size_t ping_timestamp_channel = configuration::ChannelIndex(
1626 pi2_event_loop->configuration(), ping_on_pi2_fetcher.channel());
1627
1628 const size_t pi2_timestamp_channel = configuration::ChannelIndex(
1629 pi2_event_loop->configuration(), pi2_timestamp_on_pi2_fetcher.channel());
1630 const size_t pong_timestamp_channel = configuration::ChannelIndex(
1631 pi1_event_loop->configuration(), pong_on_pi1_fetcher.channel());
1632
Austin Schuh969cd602021-01-03 00:09:45 -08001633 const chrono::nanoseconds network_delay = event_loop_factory_.network_delay();
1634
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001635 pi1_event_loop->MakeWatcher(
1636 "/aos/remote_timestamps/pi2",
Austin Schuh315b96b2020-12-11 21:21:12 -08001637 [&pi1_event_loop, &pi2_event_loop, pi1_timestamp_channel,
1638 ping_timestamp_channel, &pi1_timestamp_on_pi1_fetcher,
1639 &pi1_timestamp_on_pi2_fetcher, &ping_on_pi1_fetcher,
Austin Schuh969cd602021-01-03 00:09:45 -08001640 &ping_on_pi2_fetcher, network_delay](const RemoteMessage &header) {
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001641 const aos::monotonic_clock::time_point header_monotonic_sent_time(
1642 chrono::nanoseconds(header.monotonic_sent_time()));
1643 const aos::realtime_clock::time_point header_realtime_sent_time(
1644 chrono::nanoseconds(header.realtime_sent_time()));
1645 const aos::monotonic_clock::time_point header_monotonic_remote_time(
1646 chrono::nanoseconds(header.monotonic_remote_time()));
1647 const aos::realtime_clock::time_point header_realtime_remote_time(
1648 chrono::nanoseconds(header.realtime_remote_time()));
1649
1650 const Context *pi1_context = nullptr;
1651 const Context *pi2_context = nullptr;
1652
1653 if (header.channel_index() == pi1_timestamp_channel) {
1654 ASSERT_TRUE(pi1_timestamp_on_pi1_fetcher.FetchNext());
1655 ASSERT_TRUE(pi1_timestamp_on_pi2_fetcher.FetchNext());
1656 pi1_context = &pi1_timestamp_on_pi1_fetcher.context();
1657 pi2_context = &pi1_timestamp_on_pi2_fetcher.context();
1658 } else if (header.channel_index() == ping_timestamp_channel) {
1659 ASSERT_TRUE(ping_on_pi1_fetcher.FetchNext());
1660 ASSERT_TRUE(ping_on_pi2_fetcher.FetchNext());
1661 pi1_context = &ping_on_pi1_fetcher.context();
1662 pi2_context = &ping_on_pi2_fetcher.context();
1663 } else {
1664 LOG(FATAL) << "Unknown channel " << FlatbufferToJson(&header) << " "
1665 << configuration::CleanedChannelToString(
1666 pi1_event_loop->configuration()->channels()->Get(
1667 header.channel_index()));
1668 }
1669
Austin Schuh315b96b2020-12-11 21:21:12 -08001670 ASSERT_TRUE(header.has_boot_uuid());
1671 EXPECT_EQ(header.boot_uuid()->string_view(),
1672 pi2_event_loop->boot_uuid().string_view());
1673
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001674 EXPECT_EQ(pi1_context->queue_index, header.remote_queue_index());
1675 EXPECT_EQ(pi2_context->remote_queue_index, header.remote_queue_index());
1676 EXPECT_EQ(pi2_context->queue_index, header.queue_index());
1677
1678 EXPECT_EQ(pi2_context->monotonic_event_time,
1679 header_monotonic_sent_time);
1680 EXPECT_EQ(pi2_context->realtime_event_time, header_realtime_sent_time);
1681 EXPECT_EQ(pi2_context->realtime_remote_time,
1682 header_realtime_remote_time);
1683 EXPECT_EQ(pi2_context->monotonic_remote_time,
1684 header_monotonic_remote_time);
1685
1686 EXPECT_EQ(pi1_context->realtime_event_time,
1687 header_realtime_remote_time);
1688 EXPECT_EQ(pi1_context->monotonic_event_time,
1689 header_monotonic_remote_time);
Austin Schuh969cd602021-01-03 00:09:45 -08001690
1691 EXPECT_EQ(pi1_event_loop->context().monotonic_event_time,
1692 pi2_context->monotonic_event_time +
1693 (pi1_event_loop->monotonic_now() -
1694 pi2_event_loop->monotonic_now()) +
1695 network_delay);
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001696 });
1697 pi2_event_loop->MakeWatcher(
1698 "/aos/remote_timestamps/pi1",
Austin Schuh315b96b2020-12-11 21:21:12 -08001699 [&pi2_event_loop, &pi1_event_loop, pi2_timestamp_channel,
1700 pong_timestamp_channel, &pi2_timestamp_on_pi2_fetcher,
1701 &pi2_timestamp_on_pi1_fetcher, &pong_on_pi2_fetcher,
Austin Schuh969cd602021-01-03 00:09:45 -08001702 &pong_on_pi1_fetcher, network_delay](const RemoteMessage &header) {
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001703 const aos::monotonic_clock::time_point header_monotonic_sent_time(
1704 chrono::nanoseconds(header.monotonic_sent_time()));
1705 const aos::realtime_clock::time_point header_realtime_sent_time(
1706 chrono::nanoseconds(header.realtime_sent_time()));
1707 const aos::monotonic_clock::time_point header_monotonic_remote_time(
1708 chrono::nanoseconds(header.monotonic_remote_time()));
1709 const aos::realtime_clock::time_point header_realtime_remote_time(
1710 chrono::nanoseconds(header.realtime_remote_time()));
1711
1712 const Context *pi2_context = nullptr;
1713 const Context *pi1_context = nullptr;
1714
1715 if (header.channel_index() == pi2_timestamp_channel) {
1716 ASSERT_TRUE(pi2_timestamp_on_pi2_fetcher.FetchNext());
1717 ASSERT_TRUE(pi2_timestamp_on_pi1_fetcher.FetchNext());
1718 pi2_context = &pi2_timestamp_on_pi2_fetcher.context();
1719 pi1_context = &pi2_timestamp_on_pi1_fetcher.context();
1720 } else if (header.channel_index() == pong_timestamp_channel) {
1721 ASSERT_TRUE(pong_on_pi2_fetcher.FetchNext());
1722 ASSERT_TRUE(pong_on_pi1_fetcher.FetchNext());
1723 pi2_context = &pong_on_pi2_fetcher.context();
1724 pi1_context = &pong_on_pi1_fetcher.context();
1725 } else {
1726 LOG(FATAL) << "Unknown channel " << FlatbufferToJson(&header) << " "
1727 << configuration::CleanedChannelToString(
1728 pi2_event_loop->configuration()->channels()->Get(
1729 header.channel_index()));
1730 }
1731
Austin Schuh315b96b2020-12-11 21:21:12 -08001732 ASSERT_TRUE(header.has_boot_uuid());
1733 EXPECT_EQ(header.boot_uuid()->string_view(),
1734 pi1_event_loop->boot_uuid().string_view());
1735
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001736 EXPECT_EQ(pi2_context->queue_index, header.remote_queue_index());
1737 EXPECT_EQ(pi1_context->remote_queue_index, header.remote_queue_index());
1738 EXPECT_EQ(pi1_context->queue_index, header.queue_index());
1739
1740 EXPECT_EQ(pi1_context->monotonic_event_time,
1741 header_monotonic_sent_time);
1742 EXPECT_EQ(pi1_context->realtime_event_time, header_realtime_sent_time);
1743 EXPECT_EQ(pi1_context->realtime_remote_time,
1744 header_realtime_remote_time);
1745 EXPECT_EQ(pi1_context->monotonic_remote_time,
1746 header_monotonic_remote_time);
1747
1748 EXPECT_EQ(pi2_context->realtime_event_time,
1749 header_realtime_remote_time);
1750 EXPECT_EQ(pi2_context->monotonic_event_time,
1751 header_monotonic_remote_time);
Austin Schuh969cd602021-01-03 00:09:45 -08001752
1753 EXPECT_EQ(pi2_event_loop->context().monotonic_event_time,
1754 pi1_context->monotonic_event_time +
1755 (pi2_event_loop->monotonic_now() -
1756 pi1_event_loop->monotonic_now()) +
1757 network_delay);
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001758 });
1759
1760 // And confirm we can re-create a log again, while checking the contents.
1761 {
1762 LoggerState pi1_logger = MakeLogger(
1763 configuration::GetNode(log_reader_factory.configuration(), pi1_),
1764 &log_reader_factory);
1765 LoggerState pi2_logger = MakeLogger(
1766 configuration::GetNode(log_reader_factory.configuration(), pi2_),
1767 &log_reader_factory);
1768
Austin Schuh25b46712021-01-03 00:04:38 -08001769 StartLogger(&pi1_logger, tmp_dir_ + "/relogged1");
1770 StartLogger(&pi2_logger, tmp_dir_ + "/relogged2");
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001771
1772 log_reader_factory.Run();
1773 }
1774
1775 EXPECT_EQ(pi2_original_message_header_counter.count(), 0u);
1776 EXPECT_EQ(pi1_original_message_header_counter.count(), 0u);
1777
1778 reader.Deregister();
1779}
1780
Austin Schuh315b96b2020-12-11 21:21:12 -08001781// Tests that we properly populate and extract the logger_start time by setting
1782// up a clock difference between 2 nodes and looking at the resulting parts.
1783TEST_F(MultinodeLoggerTest, LoggerStartTime) {
Austin Schuh87dd3832021-01-01 23:07:31 -08001784 time_converter_.AddMonotonic(
1785 {monotonic_clock::epoch(),
1786 monotonic_clock::epoch() + chrono::seconds(1000)});
Austin Schuh315b96b2020-12-11 21:21:12 -08001787 {
1788 LoggerState pi1_logger = MakeLogger(pi1_);
1789 LoggerState pi2_logger = MakeLogger(pi2_);
1790
Austin Schuh315b96b2020-12-11 21:21:12 -08001791 StartLogger(&pi1_logger);
1792 StartLogger(&pi2_logger);
1793
1794 event_loop_factory_.RunFor(chrono::milliseconds(10000));
1795 }
1796
1797 for (const LogFile &log_file : SortParts(logfiles_)) {
1798 for (const LogParts &log_part : log_file.parts) {
1799 if (log_part.node == log_file.logger_node) {
1800 EXPECT_EQ(log_part.logger_monotonic_start_time,
1801 aos::monotonic_clock::min_time);
1802 EXPECT_EQ(log_part.logger_realtime_start_time,
1803 aos::realtime_clock::min_time);
1804 } else {
1805 const chrono::seconds offset = log_file.logger_node == "pi1"
1806 ? -chrono::seconds(1000)
1807 : chrono::seconds(1000);
1808 EXPECT_EQ(log_part.logger_monotonic_start_time,
1809 log_part.monotonic_start_time + offset);
1810 EXPECT_EQ(log_part.logger_realtime_start_time,
1811 log_file.realtime_start_time +
1812 (log_part.logger_monotonic_start_time -
1813 log_file.monotonic_start_time));
1814 }
1815 }
1816 }
1817}
1818
Austin Schuh8bd96322020-02-13 21:18:22 -08001819// TODO(austin): We can write a test which recreates a logfile and confirms that
1820// we get it back. That is the ultimate test.
1821
Austin Schuh315b96b2020-12-11 21:21:12 -08001822// Tests that we properly recreate forwarded timestamps when replaying a log.
1823// This should be enough that we can then re-run the logger and get a valid log
1824// back.
1825TEST_F(MultinodeLoggerDeathTest, RemoteReboot) {
Austin Schuh87dd3832021-01-01 23:07:31 -08001826 time_converter_.StartEqual();
Austin Schuh315b96b2020-12-11 21:21:12 -08001827 std::string pi2_boot1;
1828 std::string pi2_boot2;
1829 {
1830 pi2_boot1 = event_loop_factory_.GetNodeEventLoopFactory(pi2_)
1831 ->boot_uuid()
1832 .string_view();
1833 LoggerState pi1_logger = MakeLogger(pi1_);
1834
1835 event_loop_factory_.RunFor(chrono::milliseconds(95));
1836
1837 StartLogger(&pi1_logger);
1838
1839 event_loop_factory_.RunFor(chrono::milliseconds(10000));
1840
1841 event_loop_factory_.GetNodeEventLoopFactory(pi2_)->Reboot();
1842
1843 pi2_boot2 = event_loop_factory_.GetNodeEventLoopFactory(pi2_)
1844 ->boot_uuid()
1845 .string_view();
1846
1847 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1848 }
1849
1850 // Confirm that we refuse to replay logs with missing boot uuids.
1851 EXPECT_DEATH(
1852 {
1853 LogReader reader(SortParts(pi1_reboot_logfiles_));
1854
1855 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1856 log_reader_factory.set_send_delay(chrono::microseconds(0));
1857
1858 // This sends out the fetched messages and advances time to the start of
1859 // the log file.
1860 reader.Register(&log_reader_factory);
1861 },
1862 absl::StrFormat("(%s|%s).*(%s|%s).*Found parts from different boots",
1863 pi2_boot1, pi2_boot2, pi2_boot2, pi2_boot1));
1864}
1865
Austin Schuhc9049732020-12-21 22:27:15 -08001866// Tests that we properly handle one direction of message_bridge being
1867// unavailable.
1868TEST_F(MultinodeLoggerTest, OneDirectionWithNegativeSlope) {
1869 event_loop_factory_.GetNodeEventLoopFactory(pi1_)->Disconnect(pi2_);
Austin Schuh87dd3832021-01-01 23:07:31 -08001870 time_converter_.AddMonotonic(
1871 {monotonic_clock::epoch(),
1872 monotonic_clock::epoch() + chrono::seconds(1000)});
1873
1874 time_converter_.AddMonotonic(
1875 {chrono::milliseconds(10000),
1876 chrono::milliseconds(10000) - chrono::milliseconds(1)});
Austin Schuhc9049732020-12-21 22:27:15 -08001877 {
1878 LoggerState pi1_logger = MakeLogger(pi1_);
1879
1880 event_loop_factory_.RunFor(chrono::milliseconds(95));
1881
1882 StartLogger(&pi1_logger);
1883
1884 event_loop_factory_.RunFor(chrono::milliseconds(10000));
1885 }
1886
1887 // Confirm that we can parse the result. LogReader has enough internal CHECKs
1888 // to confirm the right thing happened.
1889 ConfirmReadable(pi1_single_direction_logfiles_);
1890}
1891
1892// Tests that we properly handle one direction of message_bridge being
1893// unavailable.
1894TEST_F(MultinodeLoggerTest, OneDirectionWithPositiveSlope) {
1895 event_loop_factory_.GetNodeEventLoopFactory(pi1_)->Disconnect(pi2_);
Austin Schuh87dd3832021-01-01 23:07:31 -08001896 time_converter_.AddMonotonic(
1897 {monotonic_clock::epoch(),
1898 monotonic_clock::epoch() + chrono::seconds(500)});
1899
1900 time_converter_.AddMonotonic(
1901 {chrono::milliseconds(10000),
1902 chrono::milliseconds(10000) + chrono::milliseconds(1)});
1903 {
1904 LoggerState pi1_logger = MakeLogger(pi1_);
1905
1906 event_loop_factory_.RunFor(chrono::milliseconds(95));
1907
1908 StartLogger(&pi1_logger);
1909
1910 event_loop_factory_.RunFor(chrono::milliseconds(10000));
1911 }
1912
1913 // Confirm that we can parse the result. LogReader has enough internal CHECKs
1914 // to confirm the right thing happened.
1915 ConfirmReadable(pi1_single_direction_logfiles_);
1916}
1917
1918// Tests that we properly handle a dead node. Do this by just disconnecting it
1919// and only using one nodes of logs.
1920TEST_F(MultinodeLoggerTest, DeadNode) {
1921 event_loop_factory_.GetNodeEventLoopFactory(pi1_)->Disconnect(pi2_);
1922 event_loop_factory_.GetNodeEventLoopFactory(pi2_)->Disconnect(pi1_);
1923 time_converter_.AddMonotonic(
1924 {monotonic_clock::epoch(),
1925 monotonic_clock::epoch() + chrono::seconds(1000)});
Austin Schuhc9049732020-12-21 22:27:15 -08001926 {
1927 LoggerState pi1_logger = MakeLogger(pi1_);
1928
1929 event_loop_factory_.RunFor(chrono::milliseconds(95));
1930
1931 StartLogger(&pi1_logger);
1932
1933 event_loop_factory_.RunFor(chrono::milliseconds(10000));
1934 }
1935
1936 // Confirm that we can parse the result. LogReader has enough internal CHECKs
1937 // to confirm the right thing happened.
1938 ConfirmReadable(pi1_single_direction_logfiles_);
1939}
1940
Austin Schuhe309d2a2019-11-29 13:25:21 -08001941} // namespace testing
1942} // namespace logger
1943} // namespace aos