blob: f60a62ad6e852556b2b87a46cc9ba1d460224544 [file] [log] [blame]
Austin Schuhb06f03b2021-02-17 22:00:37 -08001#include "aos/events/logging/log_reader.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 Schuhb06f03b2021-02-17 22:00:37 -08005#include "aos/events/logging/log_writer.h"
Austin Schuh01b4c352020-09-21 23:09:39 -07006#include "aos/events/message_counter.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -08007#include "aos/events/ping_lib.h"
8#include "aos/events/pong_lib.h"
9#include "aos/events/simulated_event_loop.h"
Austin Schuh0de30f32020-12-06 12:44:28 -080010#include "aos/network/remote_message_generated.h"
Austin Schuh87dd3832021-01-01 23:07:31 -080011#include "aos/network/testing_time_converter.h"
Austin Schuh8d7e0bb2020-10-02 17:57:00 -070012#include "aos/network/timestamp_generated.h"
Austin Schuhc243b422020-10-11 15:35:08 -070013#include "aos/testing/tmpdir.h"
Austin Schuh2f8fd752020-09-01 22:38:28 -070014#include "aos/util/file.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -080015#include "glog/logging.h"
Austin Schuh6f3babe2020-01-26 20:34:50 -080016#include "gmock/gmock.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -080017#include "gtest/gtest.h"
18
Austin Schuh3bd4c402020-11-06 18:19:06 -080019#ifdef LZMA
20#include "aos/events/logging/lzma_encoder.h"
21#endif
22
Austin Schuhe309d2a2019-11-29 13:25:21 -080023namespace aos {
24namespace logger {
25namespace testing {
26
27namespace chrono = std::chrono;
Austin Schuh0de30f32020-12-06 12:44:28 -080028using aos::message_bridge::RemoteMessage;
Austin Schuh01b4c352020-09-21 23:09:39 -070029using aos::testing::MessageCounter;
Austin Schuhe309d2a2019-11-29 13:25:21 -080030
Austin Schuhee4713b2021-03-21 19:25:17 -070031constexpr std::string_view kSingleConfigSha256(
Austin Schuh25b46712021-01-03 00:04:38 -080032 "bc8c9c2e31589eae6f0e36d766f6a437643e861d9568b7483106841cf7504dea");
Austin Schuh8c399962020-12-25 21:51:45 -080033
Austin Schuhb06f03b2021-02-17 22:00:37 -080034std::vector<std::vector<std::string>> ToLogReaderVector(
35 const std::vector<LogFile> &log_files) {
36 std::vector<std::vector<std::string>> result;
37 for (const LogFile &log_file : log_files) {
38 for (const LogParts &log_parts : log_file.parts) {
39 std::vector<std::string> parts;
40 for (const std::string &part : log_parts.parts) {
41 parts.emplace_back(part);
42 }
43 result.emplace_back(std::move(parts));
44 }
45 }
46 return result;
47}
48
Austin Schuhe309d2a2019-11-29 13:25:21 -080049class LoggerTest : public ::testing::Test {
50 public:
51 LoggerTest()
52 : config_(
53 aos::configuration::ReadConfig("aos/events/pingpong_config.json")),
54 event_loop_factory_(&config_.message()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080055 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080056 ping_(ping_event_loop_.get()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080057 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080058 pong_(pong_event_loop_.get()) {}
59
60 // Config and factory.
61 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
62 SimulatedEventLoopFactory event_loop_factory_;
63
64 // Event loop and app for Ping
65 std::unique_ptr<EventLoop> ping_event_loop_;
66 Ping ping_;
67
68 // Event loop and app for Pong
69 std::unique_ptr<EventLoop> pong_event_loop_;
70 Pong pong_;
71};
72
Brian Silverman1f345222020-09-24 21:14:48 -070073using LoggerDeathTest = LoggerTest;
74
Austin Schuhe309d2a2019-11-29 13:25:21 -080075// Tests that we can startup at all. This confirms that the channels are all in
76// the config.
77TEST_F(LoggerTest, Starts) {
Austin Schuhc243b422020-10-11 15:35:08 -070078 const ::std::string tmpdir = aos::testing::TestTmpDir();
Austin Schuh2f8fd752020-09-01 22:38:28 -070079 const ::std::string base_name = tmpdir + "/logfile";
Austin Schuh25b46712021-01-03 00:04:38 -080080 const ::std::string config =
Austin Schuhee4713b2021-03-21 19:25:17 -070081 absl::StrCat(base_name, kSingleConfigSha256, ".bfbs");
Austin Schuh2f8fd752020-09-01 22:38:28 -070082 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuhe309d2a2019-11-29 13:25:21 -080083 // Remove it.
Austin Schuh25b46712021-01-03 00:04:38 -080084 unlink(config.c_str());
Austin Schuhe309d2a2019-11-29 13:25:21 -080085 unlink(logfile.c_str());
86
87 LOG(INFO) << "Logging data to " << logfile;
88
89 {
Austin Schuhe309d2a2019-11-29 13:25:21 -080090 std::unique_ptr<EventLoop> logger_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080091 event_loop_factory_.MakeEventLoop("logger");
Austin Schuhe309d2a2019-11-29 13:25:21 -080092
93 event_loop_factory_.RunFor(chrono::milliseconds(95));
94
Brian Silverman1f345222020-09-24 21:14:48 -070095 Logger logger(logger_event_loop.get());
Austin Schuh8c399962020-12-25 21:51:45 -080096 logger.set_separate_config(false);
Brian Silverman1f345222020-09-24 21:14:48 -070097 logger.set_polling_period(std::chrono::milliseconds(100));
98 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuhe309d2a2019-11-29 13:25:21 -080099 event_loop_factory_.RunFor(chrono::milliseconds(20000));
100 }
101
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -0800102 // Even though it doesn't make any difference here, exercise the logic for
103 // passing in a separate config.
104 LogReader reader(logfile, &config_.message());
Austin Schuhe309d2a2019-11-29 13:25:21 -0800105
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -0800106 // Confirm that we can remap logged channels to point to new buses.
107 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
Austin Schuhe309d2a2019-11-29 13:25:21 -0800108
Austin Schuh15649d62019-12-28 16:36:38 -0800109 // This sends out the fetched messages and advances time to the start of the
110 // log file.
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800111 reader.Register();
Austin Schuhe309d2a2019-11-29 13:25:21 -0800112
Austin Schuh07676622021-01-21 18:59:17 -0800113 EXPECT_THAT(reader.LoggedNodes(), ::testing::ElementsAre(nullptr));
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800114
Austin Schuhe309d2a2019-11-29 13:25:21 -0800115 std::unique_ptr<EventLoop> test_event_loop =
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800116 reader.event_loop_factory()->MakeEventLoop("log_reader");
Austin Schuhe309d2a2019-11-29 13:25:21 -0800117
118 int ping_count = 10;
119 int pong_count = 10;
120
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -0800121 // Confirm that the ping value matches in the remapped channel location.
122 test_event_loop->MakeWatcher("/original/test",
Austin Schuhe309d2a2019-11-29 13:25:21 -0800123 [&ping_count](const examples::Ping &ping) {
124 EXPECT_EQ(ping.value(), ping_count + 1);
125 ++ping_count;
126 });
127 // Confirm that the ping and pong counts both match, and the value also
128 // matches.
129 test_event_loop->MakeWatcher(
130 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
131 EXPECT_EQ(pong.value(), pong_count + 1);
132 ++pong_count;
133 EXPECT_EQ(ping_count, pong_count);
134 });
135
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800136 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
Austin Schuhe309d2a2019-11-29 13:25:21 -0800137 EXPECT_EQ(ping_count, 2010);
Austin Schuhe309d2a2019-11-29 13:25:21 -0800138}
139
Brian Silverman1f345222020-09-24 21:14:48 -0700140// Tests calling StartLogging twice.
141TEST_F(LoggerDeathTest, ExtraStart) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800142 const ::std::string tmpdir = aos::testing::TestTmpDir();
Brian Silverman1f345222020-09-24 21:14:48 -0700143 const ::std::string base_name1 = tmpdir + "/logfile1";
Austin Schuh25b46712021-01-03 00:04:38 -0800144 const ::std::string config1 =
Austin Schuhee4713b2021-03-21 19:25:17 -0700145 absl::StrCat(base_name1, kSingleConfigSha256, ".bfbs");
Brian Silverman1f345222020-09-24 21:14:48 -0700146 const ::std::string logfile1 = base_name1 + ".part0.bfbs";
147 const ::std::string base_name2 = tmpdir + "/logfile2";
Austin Schuh25b46712021-01-03 00:04:38 -0800148 const ::std::string config2 =
Austin Schuhee4713b2021-03-21 19:25:17 -0700149 absl::StrCat(base_name2, kSingleConfigSha256, ".bfbs");
Brian Silverman1f345222020-09-24 21:14:48 -0700150 const ::std::string logfile2 = base_name2 + ".part0.bfbs";
151 unlink(logfile1.c_str());
Austin Schuh25b46712021-01-03 00:04:38 -0800152 unlink(config1.c_str());
Brian Silverman1f345222020-09-24 21:14:48 -0700153 unlink(logfile2.c_str());
Austin Schuh25b46712021-01-03 00:04:38 -0800154 unlink(config2.c_str());
Brian Silverman1f345222020-09-24 21:14:48 -0700155
156 LOG(INFO) << "Logging data to " << logfile1 << " then " << logfile2;
157
158 {
159 std::unique_ptr<EventLoop> logger_event_loop =
160 event_loop_factory_.MakeEventLoop("logger");
161
162 event_loop_factory_.RunFor(chrono::milliseconds(95));
163
164 Logger logger(logger_event_loop.get());
165 logger.set_polling_period(std::chrono::milliseconds(100));
166 logger_event_loop->OnRun(
167 [base_name1, base_name2, &logger_event_loop, &logger]() {
168 logger.StartLogging(std::make_unique<LocalLogNamer>(
169 base_name1, logger_event_loop->node()));
170 EXPECT_DEATH(logger.StartLogging(std::make_unique<LocalLogNamer>(
171 base_name2, logger_event_loop->node())),
172 "Already logging");
173 });
174 event_loop_factory_.RunFor(chrono::milliseconds(20000));
175 }
176}
177
178// Tests calling StopLogging twice.
179TEST_F(LoggerDeathTest, ExtraStop) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800180 const ::std::string tmpdir = aos::testing::TestTmpDir();
Brian Silverman1f345222020-09-24 21:14:48 -0700181 const ::std::string base_name = tmpdir + "/logfile";
Austin Schuh25b46712021-01-03 00:04:38 -0800182 const ::std::string config =
Austin Schuhee4713b2021-03-21 19:25:17 -0700183 absl::StrCat(base_name, kSingleConfigSha256, ".bfbs");
Brian Silverman1f345222020-09-24 21:14:48 -0700184 const ::std::string logfile = base_name + ".part0.bfbs";
185 // Remove it.
Austin Schuh25b46712021-01-03 00:04:38 -0800186 unlink(config.c_str());
Brian Silverman1f345222020-09-24 21:14:48 -0700187 unlink(logfile.c_str());
188
189 LOG(INFO) << "Logging data to " << logfile;
190
191 {
192 std::unique_ptr<EventLoop> logger_event_loop =
193 event_loop_factory_.MakeEventLoop("logger");
194
195 event_loop_factory_.RunFor(chrono::milliseconds(95));
196
197 Logger logger(logger_event_loop.get());
Austin Schuh8c399962020-12-25 21:51:45 -0800198 logger.set_separate_config(false);
Brian Silverman1f345222020-09-24 21:14:48 -0700199 logger.set_polling_period(std::chrono::milliseconds(100));
200 logger_event_loop->OnRun([base_name, &logger_event_loop, &logger]() {
201 logger.StartLogging(std::make_unique<LocalLogNamer>(
202 base_name, logger_event_loop->node()));
203 logger.StopLogging(aos::monotonic_clock::min_time);
204 EXPECT_DEATH(logger.StopLogging(aos::monotonic_clock::min_time),
205 "Not logging right now");
206 });
207 event_loop_factory_.RunFor(chrono::milliseconds(20000));
208 }
209}
210
211// Tests that we can startup twice.
212TEST_F(LoggerTest, StartsTwice) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800213 const ::std::string tmpdir = aos::testing::TestTmpDir();
Brian Silverman1f345222020-09-24 21:14:48 -0700214 const ::std::string base_name1 = tmpdir + "/logfile1";
Austin Schuh25b46712021-01-03 00:04:38 -0800215 const ::std::string config1 =
Austin Schuhee4713b2021-03-21 19:25:17 -0700216 absl::StrCat(base_name1, kSingleConfigSha256, ".bfbs");
Brian Silverman1f345222020-09-24 21:14:48 -0700217 const ::std::string logfile1 = base_name1 + ".part0.bfbs";
218 const ::std::string base_name2 = tmpdir + "/logfile2";
Austin Schuh25b46712021-01-03 00:04:38 -0800219 const ::std::string config2 =
Austin Schuhee4713b2021-03-21 19:25:17 -0700220 absl::StrCat(base_name2, kSingleConfigSha256, ".bfbs");
Brian Silverman1f345222020-09-24 21:14:48 -0700221 const ::std::string logfile2 = base_name2 + ".part0.bfbs";
222 unlink(logfile1.c_str());
Austin Schuh25b46712021-01-03 00:04:38 -0800223 unlink(config1.c_str());
Brian Silverman1f345222020-09-24 21:14:48 -0700224 unlink(logfile2.c_str());
Austin Schuh25b46712021-01-03 00:04:38 -0800225 unlink(config2.c_str());
Brian Silverman1f345222020-09-24 21:14:48 -0700226
227 LOG(INFO) << "Logging data to " << logfile1 << " then " << logfile2;
228
229 {
230 std::unique_ptr<EventLoop> logger_event_loop =
231 event_loop_factory_.MakeEventLoop("logger");
232
233 event_loop_factory_.RunFor(chrono::milliseconds(95));
234
235 Logger logger(logger_event_loop.get());
Austin Schuh8c399962020-12-25 21:51:45 -0800236 logger.set_separate_config(false);
Brian Silverman1f345222020-09-24 21:14:48 -0700237 logger.set_polling_period(std::chrono::milliseconds(100));
238 logger.StartLogging(
239 std::make_unique<LocalLogNamer>(base_name1, logger_event_loop->node()));
240 event_loop_factory_.RunFor(chrono::milliseconds(10000));
241 logger.StopLogging(logger_event_loop->monotonic_now());
242 event_loop_factory_.RunFor(chrono::milliseconds(10000));
243 logger.StartLogging(
244 std::make_unique<LocalLogNamer>(base_name2, logger_event_loop->node()));
245 event_loop_factory_.RunFor(chrono::milliseconds(10000));
246 }
247
248 for (const auto &logfile :
249 {std::make_tuple(logfile1, 10), std::make_tuple(logfile2, 2010)}) {
250 SCOPED_TRACE(std::get<0>(logfile));
251 LogReader reader(std::get<0>(logfile));
252 reader.Register();
253
Austin Schuh07676622021-01-21 18:59:17 -0800254 EXPECT_THAT(reader.LoggedNodes(), ::testing::ElementsAre(nullptr));
Brian Silverman1f345222020-09-24 21:14:48 -0700255
256 std::unique_ptr<EventLoop> test_event_loop =
257 reader.event_loop_factory()->MakeEventLoop("log_reader");
258
259 int ping_count = std::get<1>(logfile);
260 int pong_count = std::get<1>(logfile);
261
262 // Confirm that the ping and pong counts both match, and the value also
263 // matches.
264 test_event_loop->MakeWatcher("/test",
265 [&ping_count](const examples::Ping &ping) {
266 EXPECT_EQ(ping.value(), ping_count + 1);
267 ++ping_count;
268 });
269 test_event_loop->MakeWatcher(
270 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
271 EXPECT_EQ(pong.value(), pong_count + 1);
272 ++pong_count;
273 EXPECT_EQ(ping_count, pong_count);
274 });
275
276 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
277 EXPECT_EQ(ping_count, std::get<1>(logfile) + 1000);
278 }
279}
280
Austin Schuhfa895892020-01-07 20:07:41 -0800281// Tests that we can read and write rotated log files.
282TEST_F(LoggerTest, RotatedLogFile) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800283 const ::std::string tmpdir = aos::testing::TestTmpDir();
Austin Schuh2f8fd752020-09-01 22:38:28 -0700284 const ::std::string base_name = tmpdir + "/logfile";
Austin Schuh25b46712021-01-03 00:04:38 -0800285 const ::std::string config =
Austin Schuhee4713b2021-03-21 19:25:17 -0700286 absl::StrCat(base_name, kSingleConfigSha256, ".bfbs");
Austin Schuh2f8fd752020-09-01 22:38:28 -0700287 const ::std::string logfile0 = base_name + ".part0.bfbs";
288 const ::std::string logfile1 = base_name + ".part1.bfbs";
Austin Schuhfa895892020-01-07 20:07:41 -0800289 // Remove it.
Austin Schuh25b46712021-01-03 00:04:38 -0800290 unlink(config.c_str());
Austin Schuhfa895892020-01-07 20:07:41 -0800291 unlink(logfile0.c_str());
292 unlink(logfile1.c_str());
293
294 LOG(INFO) << "Logging data to " << logfile0 << " and " << logfile1;
295
296 {
Austin Schuhfa895892020-01-07 20:07:41 -0800297 std::unique_ptr<EventLoop> logger_event_loop =
298 event_loop_factory_.MakeEventLoop("logger");
299
300 event_loop_factory_.RunFor(chrono::milliseconds(95));
301
Brian Silverman1f345222020-09-24 21:14:48 -0700302 Logger logger(logger_event_loop.get());
Austin Schuh8c399962020-12-25 21:51:45 -0800303 logger.set_separate_config(false);
Brian Silverman1f345222020-09-24 21:14:48 -0700304 logger.set_polling_period(std::chrono::milliseconds(100));
305 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuhfa895892020-01-07 20:07:41 -0800306 event_loop_factory_.RunFor(chrono::milliseconds(10000));
Austin Schuh2f8fd752020-09-01 22:38:28 -0700307 logger.Rotate();
Austin Schuhfa895892020-01-07 20:07:41 -0800308 event_loop_factory_.RunFor(chrono::milliseconds(10000));
309 }
310
Austin Schuh64fab802020-09-09 22:47:47 -0700311 {
312 // Confirm that the UUIDs match for both the parts and the logger, and the
313 // parts_index increments.
Austin Schuhadd6eb32020-11-09 21:24:26 -0800314 std::vector<SizePrefixedFlatbufferVector<LogFileHeader>> log_header;
Austin Schuh64fab802020-09-09 22:47:47 -0700315 for (std::string_view f : {logfile0, logfile1}) {
Austin Schuh3bd4c402020-11-06 18:19:06 -0800316 log_header.emplace_back(ReadHeader(f).value());
Austin Schuh64fab802020-09-09 22:47:47 -0700317 }
318
Brian Silvermanae7c0332020-09-30 16:58:23 -0700319 EXPECT_EQ(log_header[0].message().log_event_uuid()->string_view(),
320 log_header[1].message().log_event_uuid()->string_view());
Austin Schuh64fab802020-09-09 22:47:47 -0700321 EXPECT_EQ(log_header[0].message().parts_uuid()->string_view(),
322 log_header[1].message().parts_uuid()->string_view());
323
324 EXPECT_EQ(log_header[0].message().parts_index(), 0);
325 EXPECT_EQ(log_header[1].message().parts_index(), 1);
326 }
327
Austin Schuhfa895892020-01-07 20:07:41 -0800328 // Even though it doesn't make any difference here, exercise the logic for
329 // passing in a separate config.
Austin Schuh287d43d2020-12-04 20:19:33 -0800330 LogReader reader(SortParts({logfile0, logfile1}), &config_.message());
Austin Schuhfa895892020-01-07 20:07:41 -0800331
332 // Confirm that we can remap logged channels to point to new buses.
333 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
334
335 // This sends out the fetched messages and advances time to the start of the
336 // log file.
337 reader.Register();
338
Austin Schuh07676622021-01-21 18:59:17 -0800339 EXPECT_THAT(reader.LoggedNodes(), ::testing::ElementsAre(nullptr));
Austin Schuhfa895892020-01-07 20:07:41 -0800340
341 std::unique_ptr<EventLoop> test_event_loop =
342 reader.event_loop_factory()->MakeEventLoop("log_reader");
343
344 int ping_count = 10;
345 int pong_count = 10;
346
347 // Confirm that the ping value matches in the remapped channel location.
348 test_event_loop->MakeWatcher("/original/test",
349 [&ping_count](const examples::Ping &ping) {
350 EXPECT_EQ(ping.value(), ping_count + 1);
351 ++ping_count;
352 });
353 // Confirm that the ping and pong counts both match, and the value also
354 // matches.
355 test_event_loop->MakeWatcher(
356 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
357 EXPECT_EQ(pong.value(), pong_count + 1);
358 ++pong_count;
359 EXPECT_EQ(ping_count, pong_count);
360 });
361
362 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
363 EXPECT_EQ(ping_count, 2010);
364}
365
Austin Schuh4c4e0092019-12-22 16:18:03 -0800366// Tests that a large number of messages per second doesn't overwhelm writev.
367TEST_F(LoggerTest, ManyMessages) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800368 const ::std::string tmpdir = aos::testing::TestTmpDir();
Austin Schuh2f8fd752020-09-01 22:38:28 -0700369 const ::std::string base_name = tmpdir + "/logfile";
Austin Schuh25b46712021-01-03 00:04:38 -0800370 const ::std::string config =
Austin Schuhee4713b2021-03-21 19:25:17 -0700371 absl::StrCat(base_name, kSingleConfigSha256, ".bfbs");
Austin Schuh2f8fd752020-09-01 22:38:28 -0700372 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuh4c4e0092019-12-22 16:18:03 -0800373 // Remove the log file.
Austin Schuh25b46712021-01-03 00:04:38 -0800374 unlink(config.c_str());
Austin Schuh4c4e0092019-12-22 16:18:03 -0800375 unlink(logfile.c_str());
376
377 LOG(INFO) << "Logging data to " << logfile;
Austin Schuh4c3b9702020-08-30 11:34:55 -0700378 ping_.set_quiet(true);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800379
380 {
Austin Schuh4c4e0092019-12-22 16:18:03 -0800381 std::unique_ptr<EventLoop> logger_event_loop =
382 event_loop_factory_.MakeEventLoop("logger");
383
384 std::unique_ptr<EventLoop> ping_spammer_event_loop =
385 event_loop_factory_.MakeEventLoop("ping_spammer");
386 aos::Sender<examples::Ping> ping_sender =
387 ping_spammer_event_loop->MakeSender<examples::Ping>("/test");
388
389 aos::TimerHandler *timer_handler =
390 ping_spammer_event_loop->AddTimer([&ping_sender]() {
391 aos::Sender<examples::Ping>::Builder builder =
392 ping_sender.MakeBuilder();
393 examples::Ping::Builder ping_builder =
394 builder.MakeBuilder<examples::Ping>();
395 CHECK(builder.Send(ping_builder.Finish()));
396 });
397
398 // 100 ms / 0.05 ms -> 2000 messages. Should be enough to crash it.
399 ping_spammer_event_loop->OnRun([&ping_spammer_event_loop, timer_handler]() {
400 timer_handler->Setup(ping_spammer_event_loop->monotonic_now(),
401 chrono::microseconds(50));
402 });
403
Brian Silverman1f345222020-09-24 21:14:48 -0700404 Logger logger(logger_event_loop.get());
Austin Schuh8c399962020-12-25 21:51:45 -0800405 logger.set_separate_config(false);
Brian Silverman1f345222020-09-24 21:14:48 -0700406 logger.set_polling_period(std::chrono::milliseconds(100));
407 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800408
409 event_loop_factory_.RunFor(chrono::milliseconds(1000));
410 }
411}
412
Austin Schuh61e973f2021-02-21 21:43:56 -0800413// Parameters to run all the tests with.
414struct Param {
415 // The config file to use.
416 std::string config;
417 // If true, the RemoteMessage channel should be shared between all the remote
418 // channels. If false, there will be 1 RemoteMessage channel per remote
419 // channel.
420 bool shared;
421 // sha256 of the config.
Austin Schuhcdd90272021-03-15 12:46:16 -0700422 std::string_view sha256;
Austin Schuh61e973f2021-02-21 21:43:56 -0800423};
Austin Schuh315b96b2020-12-11 21:21:12 -0800424
Austin Schuh61e973f2021-02-21 21:43:56 -0800425class MultinodeLoggerTest : public ::testing::TestWithParam<struct Param> {
Austin Schuh15649d62019-12-28 16:36:38 -0800426 public:
427 MultinodeLoggerTest()
428 : config_(aos::configuration::ReadConfig(
Austin Schuh61e973f2021-02-21 21:43:56 -0800429 absl::StrCat("aos/events/logging/", GetParam().config))),
Austin Schuh87dd3832021-01-01 23:07:31 -0800430 time_converter_(configuration::NodesCount(&config_.message())),
Austin Schuhac0771c2020-01-07 18:36:30 -0800431 event_loop_factory_(&config_.message()),
Austin Schuhcde938c2020-02-02 17:30:07 -0800432 pi1_(
433 configuration::GetNode(event_loop_factory_.configuration(), "pi1")),
Austin Schuh87dd3832021-01-01 23:07:31 -0800434 pi1_index_(configuration::GetNodeIndex(
435 event_loop_factory_.configuration(), pi1_)),
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700436 pi2_(
437 configuration::GetNode(event_loop_factory_.configuration(), "pi2")),
Austin Schuh87dd3832021-01-01 23:07:31 -0800438 pi2_index_(configuration::GetNodeIndex(
439 event_loop_factory_.configuration(), pi2_)),
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800440 tmp_dir_(aos::testing::TestTmpDir()),
Austin Schuh8c399962020-12-25 21:51:45 -0800441 logfile_base1_(tmp_dir_ + "/multi_logfile1"),
442 logfile_base2_(tmp_dir_ + "/multi_logfile2"),
Austin Schuh61e973f2021-02-21 21:43:56 -0800443 pi1_reboot_logfiles_(MakePi1RebootLogfiles()),
Austin Schuh8c399962020-12-25 21:51:45 -0800444 logfiles_(MakeLogFiles(logfile_base1_, logfile_base2_)),
Austin Schuh61e973f2021-02-21 21:43:56 -0800445 pi1_single_direction_logfiles_(MakePi1SingleDirectionLogfiles()),
446 structured_logfiles_(StructureLogFiles()),
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700447 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping", pi1_)),
448 ping_(ping_event_loop_.get()),
449 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong", pi2_)),
450 pong_(pong_event_loop_.get()) {
Austin Schuh61e973f2021-02-21 21:43:56 -0800451 LOG(INFO) << "Config " << GetParam().config;
Austin Schuh87dd3832021-01-01 23:07:31 -0800452 event_loop_factory_.SetTimeConverter(&time_converter_);
453
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700454 // Go through and remove the logfiles if they already exist.
455 for (const auto file : logfiles_) {
456 unlink(file.c_str());
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800457 unlink((file + ".xz").c_str());
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700458 }
459
Austin Schuh25b46712021-01-03 00:04:38 -0800460 for (const auto file :
461 MakeLogFiles(tmp_dir_ + "/relogged1", tmp_dir_ + "/relogged2")) {
Austin Schuh315b96b2020-12-11 21:21:12 -0800462 unlink(file.c_str());
463 }
464
465 for (const auto file : pi1_reboot_logfiles_) {
466 unlink(file.c_str());
467 }
468
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700469 LOG(INFO) << "Logging data to " << logfiles_[0] << ", " << logfiles_[1]
470 << " and " << logfiles_[2];
471 }
472
Austin Schuh61e973f2021-02-21 21:43:56 -0800473 bool shared() const { return GetParam().shared; }
474
475 std::vector<std::string> MakeLogFiles(std::string logfile_base1,
476 std::string logfile_base2) {
477 std::vector<std::string> result;
478 result.emplace_back(
479 absl::StrCat(logfile_base1, "_", GetParam().sha256, ".bfbs"));
480 result.emplace_back(
481 absl::StrCat(logfile_base2, "_", GetParam().sha256, ".bfbs"));
482 result.emplace_back(logfile_base1 + "_pi1_data.part0.bfbs");
483 result.emplace_back(logfile_base1 +
484 "_pi2_data/test/aos.examples.Pong.part0.bfbs");
485 result.emplace_back(logfile_base1 +
486 "_pi2_data/test/aos.examples.Pong.part1.bfbs");
487 result.emplace_back(logfile_base2 + "_pi2_data.part0.bfbs");
488 result.emplace_back(
489 logfile_base2 +
490 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part0.bfbs");
491 result.emplace_back(
492 logfile_base2 +
493 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part1.bfbs");
494 result.emplace_back(
495 logfile_base1 +
496 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part0.bfbs");
497 result.emplace_back(
498 logfile_base1 +
499 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part1.bfbs");
500 if (shared()) {
501 result.emplace_back(logfile_base1 +
502 "_timestamps/pi1/aos/remote_timestamps/pi2/"
503 "aos.message_bridge.RemoteMessage.part0.bfbs");
504 result.emplace_back(logfile_base1 +
505 "_timestamps/pi1/aos/remote_timestamps/pi2/"
506 "aos.message_bridge.RemoteMessage.part1.bfbs");
507 result.emplace_back(logfile_base2 +
508 "_timestamps/pi2/aos/remote_timestamps/pi1/"
509 "aos.message_bridge.RemoteMessage.part0.bfbs");
510 result.emplace_back(logfile_base2 +
511 "_timestamps/pi2/aos/remote_timestamps/pi1/"
512 "aos.message_bridge.RemoteMessage.part1.bfbs");
513 } else {
514 result.emplace_back(logfile_base1 +
515 "_timestamps/pi1/aos/remote_timestamps/pi2/pi1/aos/"
516 "aos-message_bridge-Timestamp/"
517 "aos.message_bridge.RemoteMessage.part0.bfbs");
518 result.emplace_back(logfile_base1 +
519 "_timestamps/pi1/aos/remote_timestamps/pi2/pi1/aos/"
520 "aos-message_bridge-Timestamp/"
521 "aos.message_bridge.RemoteMessage.part1.bfbs");
522 result.emplace_back(logfile_base2 +
523 "_timestamps/pi2/aos/remote_timestamps/pi1/pi2/aos/"
524 "aos-message_bridge-Timestamp/"
525 "aos.message_bridge.RemoteMessage.part0.bfbs");
526 result.emplace_back(logfile_base2 +
527 "_timestamps/pi2/aos/remote_timestamps/pi1/pi2/aos/"
528 "aos-message_bridge-Timestamp/"
529 "aos.message_bridge.RemoteMessage.part1.bfbs");
530 result.emplace_back(logfile_base1 +
531 "_timestamps/pi1/aos/remote_timestamps/pi2/test/"
532 "aos-examples-Ping/"
533 "aos.message_bridge.RemoteMessage.part0.bfbs");
534 result.emplace_back(logfile_base1 +
535 "_timestamps/pi1/aos/remote_timestamps/pi2/test/"
536 "aos-examples-Ping/"
537 "aos.message_bridge.RemoteMessage.part1.bfbs");
538 }
539
540 return result;
541 }
542
543 std::vector<std::string> MakePi1RebootLogfiles() {
544 std::vector<std::string> result;
545 result.emplace_back(logfile_base1_ + "_pi1_data.part0.bfbs");
546 result.emplace_back(logfile_base1_ +
547 "_pi2_data/test/aos.examples.Pong.part0.bfbs");
548 result.emplace_back(logfile_base1_ +
549 "_pi2_data/test/aos.examples.Pong.part1.bfbs");
550 result.emplace_back(logfile_base1_ +
551 "_pi2_data/test/aos.examples.Pong.part2.bfbs");
552 result.emplace_back(
553 logfile_base1_ +
554 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part0.bfbs");
555 result.emplace_back(
556 logfile_base1_ +
557 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part1.bfbs");
558 result.emplace_back(
559 logfile_base1_ +
560 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part2.bfbs");
561 result.emplace_back(
562 absl::StrCat(logfile_base1_, "_", GetParam().sha256, ".bfbs"));
563 if (shared()) {
564 result.emplace_back(logfile_base1_ +
565 "_timestamps/pi1/aos/remote_timestamps/pi2/"
566 "aos.message_bridge.RemoteMessage.part0.bfbs");
567 result.emplace_back(logfile_base1_ +
568 "_timestamps/pi1/aos/remote_timestamps/pi2/"
569 "aos.message_bridge.RemoteMessage.part1.bfbs");
570 result.emplace_back(logfile_base1_ +
571 "_timestamps/pi1/aos/remote_timestamps/pi2/"
572 "aos.message_bridge.RemoteMessage.part2.bfbs");
573 } else {
574 result.emplace_back(logfile_base1_ +
575 "_timestamps/pi1/aos/remote_timestamps/pi2/pi1/aos/"
576 "aos-message_bridge-Timestamp/"
577 "aos.message_bridge.RemoteMessage.part0.bfbs");
578 result.emplace_back(logfile_base1_ +
579 "_timestamps/pi1/aos/remote_timestamps/pi2/pi1/aos/"
580 "aos-message_bridge-Timestamp/"
581 "aos.message_bridge.RemoteMessage.part1.bfbs");
582 result.emplace_back(logfile_base1_ +
583 "_timestamps/pi1/aos/remote_timestamps/pi2/pi1/aos/"
584 "aos-message_bridge-Timestamp/"
585 "aos.message_bridge.RemoteMessage.part2.bfbs");
586
587 result.emplace_back(logfile_base1_ +
588 "_timestamps/pi1/aos/remote_timestamps/pi2/test/"
589 "aos-examples-Ping/"
590 "aos.message_bridge.RemoteMessage.part0.bfbs");
591 result.emplace_back(logfile_base1_ +
592 "_timestamps/pi1/aos/remote_timestamps/pi2/test/"
593 "aos-examples-Ping/"
594 "aos.message_bridge.RemoteMessage.part1.bfbs");
595 result.emplace_back(logfile_base1_ +
596 "_timestamps/pi1/aos/remote_timestamps/pi2/test/"
597 "aos-examples-Ping/"
598 "aos.message_bridge.RemoteMessage.part2.bfbs");
599 }
600 return result;
601 }
602
603 std::vector<std::string> MakePi1SingleDirectionLogfiles() {
604 std::vector<std::string> result;
605 result.emplace_back(logfile_base1_ + "_pi1_data.part0.bfbs");
606 result.emplace_back(logfile_base1_ +
607 "_pi2_data/test/aos.examples.Pong.part0.bfbs");
608 result.emplace_back(
609 logfile_base1_ +
610 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part0.bfbs");
611 result.emplace_back(
612 absl::StrCat(logfile_base1_, "_", GetParam().sha256, ".bfbs"));
613
614 if (shared()) {
615 result.emplace_back(logfile_base1_ +
616 "_timestamps/pi1/aos/remote_timestamps/pi2/"
617 "aos.message_bridge.RemoteMessage.part0.bfbs");
618 } else {
619 result.emplace_back(logfile_base1_ +
620 "_timestamps/pi1/aos/remote_timestamps/pi2/pi1/aos/"
621 "aos-message_bridge-Timestamp/"
622 "aos.message_bridge.RemoteMessage.part0.bfbs");
623 result.emplace_back(logfile_base1_ +
624 "_timestamps/pi1/aos/remote_timestamps/pi2/test/"
625 "aos-examples-Ping/"
626 "aos.message_bridge.RemoteMessage.part0.bfbs");
627 }
628 return result;
629 }
630
631 std::vector<std::vector<std::string>> StructureLogFiles() {
632 std::vector<std::vector<std::string>> result{
633 std::vector<std::string>{logfiles_[2]},
634 std::vector<std::string>{logfiles_[3], logfiles_[4]},
635 std::vector<std::string>{logfiles_[5]},
636 std::vector<std::string>{logfiles_[6], logfiles_[7]},
637 std::vector<std::string>{logfiles_[8], logfiles_[9]},
638 std::vector<std::string>{logfiles_[10], logfiles_[11]},
639 std::vector<std::string>{logfiles_[12], logfiles_[13]}};
640
641 if (!shared()) {
642 result.emplace_back(
643 std::vector<std::string>{logfiles_[14], logfiles_[15]});
644 }
645
646 return result;
647 }
648
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700649 struct LoggerState {
650 std::unique_ptr<EventLoop> event_loop;
651 std::unique_ptr<Logger> logger;
652 };
653
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700654 LoggerState MakeLogger(const Node *node,
655 SimulatedEventLoopFactory *factory = nullptr) {
656 if (factory == nullptr) {
657 factory = &event_loop_factory_;
658 }
659 return {factory->MakeEventLoop("logger", node), {}};
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700660 }
661
Austin Schuh3bd4c402020-11-06 18:19:06 -0800662 void StartLogger(LoggerState *logger, std::string logfile_base = "",
663 bool compress = false) {
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700664 if (logfile_base.empty()) {
Austin Schuh8c399962020-12-25 21:51:45 -0800665 if (logger->event_loop->node()->name()->string_view() == "pi1") {
666 logfile_base = logfile_base1_;
667 } else {
668 logfile_base = logfile_base2_;
669 }
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700670 }
671
Brian Silverman1f345222020-09-24 21:14:48 -0700672 logger->logger = std::make_unique<Logger>(logger->event_loop.get());
673 logger->logger->set_polling_period(std::chrono::milliseconds(100));
Austin Schuh0ca51f32020-12-25 21:51:45 -0800674 logger->logger->set_name(absl::StrCat(
675 "name_prefix_", logger->event_loop->node()->name()->str()));
Austin Schuh3bd4c402020-11-06 18:19:06 -0800676 logger->event_loop->OnRun([logger, logfile_base, compress]() {
677 std::unique_ptr<MultiNodeLogNamer> namer =
678 std::make_unique<MultiNodeLogNamer>(
679 logfile_base, logger->event_loop->configuration(),
680 logger->event_loop->node());
681 if (compress) {
682#ifdef LZMA
683 namer->set_extension(".xz");
684 namer->set_encoder_factory(
685 []() { return std::make_unique<aos::logger::LzmaEncoder>(3); });
686#else
687 LOG(FATAL) << "Compression unsupported";
688#endif
689 }
690
691 logger->logger->StartLogging(std::move(namer));
Brian Silverman1f345222020-09-24 21:14:48 -0700692 });
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700693 }
Austin Schuh15649d62019-12-28 16:36:38 -0800694
Austin Schuh3bd4c402020-11-06 18:19:06 -0800695 void VerifyParts(const std::vector<LogFile> &sorted_parts,
696 const std::vector<std::string> &corrupted_parts = {}) {
697 EXPECT_EQ(sorted_parts.size(), 2u);
698
699 // Count up the number of UUIDs and make sure they are what we expect as a
700 // sanity check.
701 std::set<std::string> log_event_uuids;
702 std::set<std::string> parts_uuids;
703 std::set<std::string> both_uuids;
704
705 size_t missing_rt_count = 0;
706
707 std::vector<std::string> logger_nodes;
708 for (const LogFile &log_file : sorted_parts) {
709 EXPECT_FALSE(log_file.log_event_uuid.empty());
710 log_event_uuids.insert(log_file.log_event_uuid);
711 logger_nodes.emplace_back(log_file.logger_node);
712 both_uuids.insert(log_file.log_event_uuid);
Austin Schuh0ca51f32020-12-25 21:51:45 -0800713 EXPECT_TRUE(log_file.config);
714 EXPECT_EQ(log_file.name,
715 absl::StrCat("name_prefix_", log_file.logger_node));
Austin Schuh3bd4c402020-11-06 18:19:06 -0800716
717 for (const LogParts &part : log_file.parts) {
718 EXPECT_NE(part.monotonic_start_time, aos::monotonic_clock::min_time)
719 << ": " << part;
720 missing_rt_count +=
721 part.realtime_start_time == aos::realtime_clock::min_time;
722
723 EXPECT_TRUE(log_event_uuids.find(part.log_event_uuid) !=
724 log_event_uuids.end());
725 EXPECT_NE(part.node, "");
Austin Schuh0ca51f32020-12-25 21:51:45 -0800726 EXPECT_TRUE(log_file.config);
Austin Schuh3bd4c402020-11-06 18:19:06 -0800727 parts_uuids.insert(part.parts_uuid);
728 both_uuids.insert(part.parts_uuid);
729 }
730 }
731
Austin Schuh61e973f2021-02-21 21:43:56 -0800732 // We won't have RT timestamps for 5 or 6 log files. We don't log the RT
733 // start time on remote nodes because we don't know it and would be
734 // guessing. And the log reader can actually do a better job. The number
735 // depends on if we have the remote timestamps split across 2 files, or just
736 // across 1, depending on if we are using a split or combined timestamp
737 // channel config.
738 EXPECT_EQ(missing_rt_count, shared() ? 5u : 6u);
Austin Schuh3bd4c402020-11-06 18:19:06 -0800739
740 EXPECT_EQ(log_event_uuids.size(), 2u);
741 EXPECT_EQ(parts_uuids.size(), ToLogReaderVector(sorted_parts).size());
742 EXPECT_EQ(log_event_uuids.size() + parts_uuids.size(), both_uuids.size());
743
744 // Test that each list of parts is in order. Don't worry about the ordering
745 // between part file lists though.
746 // (inner vectors all need to be in order, but outer one doesn't matter).
747 EXPECT_THAT(ToLogReaderVector(sorted_parts),
748 ::testing::UnorderedElementsAreArray(structured_logfiles_));
749
750 EXPECT_THAT(logger_nodes, ::testing::UnorderedElementsAre("pi1", "pi2"));
751
752 EXPECT_NE(sorted_parts[0].realtime_start_time,
753 aos::realtime_clock::min_time);
754 EXPECT_NE(sorted_parts[1].realtime_start_time,
755 aos::realtime_clock::min_time);
756
757 EXPECT_NE(sorted_parts[0].monotonic_start_time,
758 aos::monotonic_clock::min_time);
759 EXPECT_NE(sorted_parts[1].monotonic_start_time,
760 aos::monotonic_clock::min_time);
761
762 EXPECT_THAT(sorted_parts[0].corrupted, ::testing::Eq(corrupted_parts));
763 EXPECT_THAT(sorted_parts[1].corrupted, ::testing::Eq(corrupted_parts));
764 }
765
Austin Schuhc9049732020-12-21 22:27:15 -0800766 void ConfirmReadable(const std::vector<std::string> &files) {
767 LogReader reader(SortParts(files));
768
769 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
770 reader.Register(&log_reader_factory);
771
772 log_reader_factory.Run();
773
774 reader.Deregister();
775 }
776
Austin Schuh3bd4c402020-11-06 18:19:06 -0800777 void AddExtension(std::string_view extension) {
778 std::transform(logfiles_.begin(), logfiles_.end(), logfiles_.begin(),
779 [extension](const std::string &in) {
780 return absl::StrCat(in, extension);
781 });
782
783 std::transform(structured_logfiles_.begin(), structured_logfiles_.end(),
784 structured_logfiles_.begin(),
785 [extension](std::vector<std::string> in) {
786 std::transform(in.begin(), in.end(), in.begin(),
787 [extension](const std::string &in_str) {
788 return absl::StrCat(in_str, extension);
789 });
790 return in;
791 });
792 }
793
Austin Schuh15649d62019-12-28 16:36:38 -0800794 // Config and factory.
795 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
Austin Schuh87dd3832021-01-01 23:07:31 -0800796 message_bridge::TestingTimeConverter time_converter_;
Austin Schuh15649d62019-12-28 16:36:38 -0800797 SimulatedEventLoopFactory event_loop_factory_;
798
Austin Schuh87dd3832021-01-01 23:07:31 -0800799 const Node *const pi1_;
800 const size_t pi1_index_;
801 const Node *const pi2_;
802 const size_t pi2_index_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700803
804 std::string tmp_dir_;
Austin Schuh8c399962020-12-25 21:51:45 -0800805 std::string logfile_base1_;
806 std::string logfile_base2_;
Austin Schuh315b96b2020-12-11 21:21:12 -0800807 std::vector<std::string> pi1_reboot_logfiles_;
Austin Schuh2f8fd752020-09-01 22:38:28 -0700808 std::vector<std::string> logfiles_;
Austin Schuhc9049732020-12-21 22:27:15 -0800809 std::vector<std::string> pi1_single_direction_logfiles_;
Austin Schuh2f8fd752020-09-01 22:38:28 -0700810
811 std::vector<std::vector<std::string>> structured_logfiles_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700812
813 std::unique_ptr<EventLoop> ping_event_loop_;
814 Ping ping_;
815 std::unique_ptr<EventLoop> pong_event_loop_;
816 Pong pong_;
Austin Schuh15649d62019-12-28 16:36:38 -0800817};
818
Austin Schuh391e3172020-09-01 22:48:18 -0700819// Counts the number of messages on a channel. Returns (channel name, channel
820// type, count) for every message matching matcher()
821std::vector<std::tuple<std::string, std::string, int>> CountChannelsMatching(
Austin Schuh25b46712021-01-03 00:04:38 -0800822 std::shared_ptr<const aos::Configuration> config, std::string_view filename,
Austin Schuh6f3babe2020-01-26 20:34:50 -0800823 std::function<bool(const MessageHeader *)> matcher) {
824 MessageReader message_reader(filename);
Austin Schuh8c399962020-12-25 21:51:45 -0800825 std::vector<int> counts(config->channels()->size(), 0);
Austin Schuh15649d62019-12-28 16:36:38 -0800826
Austin Schuh6f3babe2020-01-26 20:34:50 -0800827 while (true) {
Austin Schuhadd6eb32020-11-09 21:24:26 -0800828 std::optional<SizePrefixedFlatbufferVector<MessageHeader>> msg =
Austin Schuh6f3babe2020-01-26 20:34:50 -0800829 message_reader.ReadMessage();
830 if (!msg) {
831 break;
832 }
833
834 if (matcher(&msg.value().message())) {
835 counts[msg.value().message().channel_index()]++;
836 }
837 }
838
Austin Schuh391e3172020-09-01 22:48:18 -0700839 std::vector<std::tuple<std::string, std::string, int>> result;
Austin Schuh6f3babe2020-01-26 20:34:50 -0800840 int channel = 0;
841 for (size_t i = 0; i < counts.size(); ++i) {
842 if (counts[i] != 0) {
Austin Schuh8c399962020-12-25 21:51:45 -0800843 const Channel *channel = config->channels()->Get(i);
Austin Schuh391e3172020-09-01 22:48:18 -0700844 result.push_back(std::make_tuple(channel->name()->str(),
845 channel->type()->str(), counts[i]));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800846 }
847 ++channel;
848 }
849
850 return result;
851}
852
853// Counts the number of messages (channel, count) for all data messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700854std::vector<std::tuple<std::string, std::string, int>> CountChannelsData(
Austin Schuh8c399962020-12-25 21:51:45 -0800855 std::shared_ptr<const aos::Configuration> config,
Austin Schuh391e3172020-09-01 22:48:18 -0700856 std::string_view filename) {
Austin Schuh8c399962020-12-25 21:51:45 -0800857 return CountChannelsMatching(config, filename, [](const MessageHeader *msg) {
Austin Schuh6f3babe2020-01-26 20:34:50 -0800858 if (msg->has_data()) {
859 CHECK(!msg->has_monotonic_remote_time());
860 CHECK(!msg->has_realtime_remote_time());
861 CHECK(!msg->has_remote_queue_index());
862 return true;
863 }
864 return false;
865 });
866}
867
868// Counts the number of messages (channel, count) for all timestamp messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700869std::vector<std::tuple<std::string, std::string, int>> CountChannelsTimestamp(
Austin Schuh8c399962020-12-25 21:51:45 -0800870 std::shared_ptr<const aos::Configuration> config,
Austin Schuh6f3babe2020-01-26 20:34:50 -0800871 std::string_view filename) {
Austin Schuh8c399962020-12-25 21:51:45 -0800872 return CountChannelsMatching(config, filename, [](const MessageHeader *msg) {
Austin Schuh6f3babe2020-01-26 20:34:50 -0800873 if (!msg->has_data()) {
874 CHECK(msg->has_monotonic_remote_time());
875 CHECK(msg->has_realtime_remote_time());
876 CHECK(msg->has_remote_queue_index());
877 return true;
878 }
879 return false;
880 });
881}
882
Austin Schuhcde938c2020-02-02 17:30:07 -0800883// Tests that we can write and read simple multi-node log files.
Austin Schuh61e973f2021-02-21 21:43:56 -0800884TEST_P(MultinodeLoggerTest, SimpleMultiNode) {
Austin Schuh87dd3832021-01-01 23:07:31 -0800885 time_converter_.StartEqual();
Austin Schuh15649d62019-12-28 16:36:38 -0800886 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700887 LoggerState pi1_logger = MakeLogger(pi1_);
888 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuh15649d62019-12-28 16:36:38 -0800889
890 event_loop_factory_.RunFor(chrono::milliseconds(95));
891
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700892 StartLogger(&pi1_logger);
893 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800894
Austin Schuh15649d62019-12-28 16:36:38 -0800895 event_loop_factory_.RunFor(chrono::milliseconds(20000));
896 }
897
Austin Schuh6f3babe2020-01-26 20:34:50 -0800898 {
Austin Schuh64fab802020-09-09 22:47:47 -0700899 std::set<std::string> logfile_uuids;
900 std::set<std::string> parts_uuids;
901 // Confirm that we have the expected number of UUIDs for both the logfile
902 // UUIDs and parts UUIDs.
Austin Schuhadd6eb32020-11-09 21:24:26 -0800903 std::vector<SizePrefixedFlatbufferVector<LogFileHeader>> log_header;
Austin Schuh64fab802020-09-09 22:47:47 -0700904 for (std::string_view f : logfiles_) {
Austin Schuh3bd4c402020-11-06 18:19:06 -0800905 log_header.emplace_back(ReadHeader(f).value());
Austin Schuh8c399962020-12-25 21:51:45 -0800906 if (!log_header.back().message().has_configuration()) {
907 logfile_uuids.insert(
908 log_header.back().message().log_event_uuid()->str());
909 parts_uuids.insert(log_header.back().message().parts_uuid()->str());
910 }
Austin Schuh64fab802020-09-09 22:47:47 -0700911 }
Austin Schuh15649d62019-12-28 16:36:38 -0800912
Austin Schuh64fab802020-09-09 22:47:47 -0700913 EXPECT_EQ(logfile_uuids.size(), 2u);
Austin Schuh61e973f2021-02-21 21:43:56 -0800914 if (shared()) {
915 EXPECT_EQ(parts_uuids.size(), 7u);
916 } else {
917 EXPECT_EQ(parts_uuids.size(), 8u);
918 }
Austin Schuh64fab802020-09-09 22:47:47 -0700919
920 // And confirm everything is on the correct node.
Austin Schuh61e973f2021-02-21 21:43:56 -0800921 EXPECT_EQ(log_header[2].message().node()->name()->string_view(), "pi1");
Austin Schuh64fab802020-09-09 22:47:47 -0700922 EXPECT_EQ(log_header[3].message().node()->name()->string_view(), "pi2");
923 EXPECT_EQ(log_header[4].message().node()->name()->string_view(), "pi2");
924 EXPECT_EQ(log_header[5].message().node()->name()->string_view(), "pi2");
925 EXPECT_EQ(log_header[6].message().node()->name()->string_view(), "pi1");
926 EXPECT_EQ(log_header[7].message().node()->name()->string_view(), "pi1");
Austin Schuh61e973f2021-02-21 21:43:56 -0800927 EXPECT_EQ(log_header[8].message().node()->name()->string_view(), "pi2");
928 EXPECT_EQ(log_header[9].message().node()->name()->string_view(), "pi2");
Austin Schuh64fab802020-09-09 22:47:47 -0700929 EXPECT_EQ(log_header[10].message().node()->name()->string_view(), "pi2");
930 EXPECT_EQ(log_header[11].message().node()->name()->string_view(), "pi2");
Austin Schuh61e973f2021-02-21 21:43:56 -0800931 EXPECT_EQ(log_header[12].message().node()->name()->string_view(), "pi1");
932 EXPECT_EQ(log_header[13].message().node()->name()->string_view(), "pi1");
933 if (!shared()) {
934 EXPECT_EQ(log_header[14].message().node()->name()->string_view(), "pi2");
935 EXPECT_EQ(log_header[15].message().node()->name()->string_view(), "pi2");
936 }
Austin Schuh64fab802020-09-09 22:47:47 -0700937
938 // And the parts index matches.
Austin Schuh61e973f2021-02-21 21:43:56 -0800939 EXPECT_EQ(log_header[2].message().parts_index(), 0);
Austin Schuh64fab802020-09-09 22:47:47 -0700940 EXPECT_EQ(log_header[3].message().parts_index(), 0);
Austin Schuh61e973f2021-02-21 21:43:56 -0800941 EXPECT_EQ(log_header[4].message().parts_index(), 1);
942 EXPECT_EQ(log_header[5].message().parts_index(), 0);
Austin Schuh64fab802020-09-09 22:47:47 -0700943 EXPECT_EQ(log_header[6].message().parts_index(), 0);
944 EXPECT_EQ(log_header[7].message().parts_index(), 1);
945 EXPECT_EQ(log_header[8].message().parts_index(), 0);
946 EXPECT_EQ(log_header[9].message().parts_index(), 1);
947 EXPECT_EQ(log_header[10].message().parts_index(), 0);
948 EXPECT_EQ(log_header[11].message().parts_index(), 1);
Austin Schuh61e973f2021-02-21 21:43:56 -0800949 EXPECT_EQ(log_header[12].message().parts_index(), 0);
950 EXPECT_EQ(log_header[13].message().parts_index(), 1);
951 if (!shared()) {
952 EXPECT_EQ(log_header[14].message().parts_index(), 0);
953 EXPECT_EQ(log_header[15].message().parts_index(), 1);
954 }
Austin Schuh64fab802020-09-09 22:47:47 -0700955 }
956
Austin Schuh8c399962020-12-25 21:51:45 -0800957 const std::vector<LogFile> sorted_log_files = SortParts(logfiles_);
Austin Schuh64fab802020-09-09 22:47:47 -0700958 {
Austin Schuh391e3172020-09-01 22:48:18 -0700959 using ::testing::UnorderedElementsAre;
Austin Schuh8c399962020-12-25 21:51:45 -0800960 std::shared_ptr<const aos::Configuration> config =
961 sorted_log_files[0].config;
Austin Schuh391e3172020-09-01 22:48:18 -0700962
Austin Schuh6f3babe2020-01-26 20:34:50 -0800963 // Timing reports, pings
Austin Schuh2f8fd752020-09-01 22:38:28 -0700964 EXPECT_THAT(
Austin Schuh61e973f2021-02-21 21:43:56 -0800965 CountChannelsData(config, logfiles_[2]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700966 UnorderedElementsAre(
967 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200),
James Kuszmaul4f106fb2021-01-05 20:53:02 -0800968 std::make_tuple("/pi1/aos", "aos.message_bridge.ServerStatistics",
969 21),
970 std::make_tuple("/pi1/aos", "aos.message_bridge.ClientStatistics",
971 200),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700972 std::make_tuple("/pi1/aos", "aos.timing.Report", 40),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800973 std::make_tuple("/test", "aos.examples.Ping", 2001)))
Austin Schuh61e973f2021-02-21 21:43:56 -0800974 << " : " << logfiles_[2];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800975 // Timestamps for pong
Austin Schuh2f8fd752020-09-01 22:38:28 -0700976 EXPECT_THAT(
Austin Schuh61e973f2021-02-21 21:43:56 -0800977 CountChannelsTimestamp(config, logfiles_[2]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700978 UnorderedElementsAre(
979 std::make_tuple("/test", "aos.examples.Pong", 2001),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800980 std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200)))
Austin Schuh61e973f2021-02-21 21:43:56 -0800981 << " : " << logfiles_[2];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800982
983 // Pong data.
Austin Schuh20ac95d2020-12-05 17:24:19 -0800984 EXPECT_THAT(
Austin Schuh61e973f2021-02-21 21:43:56 -0800985 CountChannelsData(config, logfiles_[3]),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800986 UnorderedElementsAre(std::make_tuple("/test", "aos.examples.Pong", 91)))
Austin Schuh61e973f2021-02-21 21:43:56 -0800987 << " : " << logfiles_[3];
988 EXPECT_THAT(CountChannelsData(config, logfiles_[4]),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700989 UnorderedElementsAre(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800990 std::make_tuple("/test", "aos.examples.Pong", 1910)))
Austin Schuh61e973f2021-02-21 21:43:56 -0800991 << " : " << logfiles_[3];
Austin Schuh391e3172020-09-01 22:48:18 -0700992
Austin Schuh6f3babe2020-01-26 20:34:50 -0800993 // No timestamps
Austin Schuh61e973f2021-02-21 21:43:56 -0800994 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[3]),
Austin Schuh25b46712021-01-03 00:04:38 -0800995 UnorderedElementsAre())
Austin Schuh61e973f2021-02-21 21:43:56 -0800996 << " : " << logfiles_[3];
997 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[4]),
Austin Schuh25b46712021-01-03 00:04:38 -0800998 UnorderedElementsAre())
Austin Schuh61e973f2021-02-21 21:43:56 -0800999 << " : " << logfiles_[4];
Austin Schuh6f3babe2020-01-26 20:34:50 -08001000
1001 // Timing reports and pongs.
Austin Schuh2f8fd752020-09-01 22:38:28 -07001002 EXPECT_THAT(
Austin Schuh61e973f2021-02-21 21:43:56 -08001003 CountChannelsData(config, logfiles_[5]),
Austin Schuh2f8fd752020-09-01 22:38:28 -07001004 UnorderedElementsAre(
1005 std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200),
James Kuszmaul4f106fb2021-01-05 20:53:02 -08001006 std::make_tuple("/pi2/aos", "aos.message_bridge.ServerStatistics",
1007 21),
1008 std::make_tuple("/pi2/aos", "aos.message_bridge.ClientStatistics",
1009 200),
Austin Schuh2f8fd752020-09-01 22:38:28 -07001010 std::make_tuple("/pi2/aos", "aos.timing.Report", 40),
Austin Schuh20ac95d2020-12-05 17:24:19 -08001011 std::make_tuple("/test", "aos.examples.Pong", 2001)))
Austin Schuh20ac95d2020-12-05 17:24:19 -08001012 << " : " << logfiles_[5];
Austin Schuh61e973f2021-02-21 21:43:56 -08001013 // And ping timestamps.
Austin Schuh2f8fd752020-09-01 22:38:28 -07001014 EXPECT_THAT(
Austin Schuh8c399962020-12-25 21:51:45 -08001015 CountChannelsTimestamp(config, logfiles_[5]),
Austin Schuh2f8fd752020-09-01 22:38:28 -07001016 UnorderedElementsAre(
Austin Schuh61e973f2021-02-21 21:43:56 -08001017 std::make_tuple("/test", "aos.examples.Ping", 2001),
1018 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200)))
Austin Schuh20ac95d2020-12-05 17:24:19 -08001019 << " : " << logfiles_[5];
Austin Schuh2f8fd752020-09-01 22:38:28 -07001020
1021 // And then test that the remotely logged timestamp data files only have
1022 // timestamps in them.
Austin Schuh61e973f2021-02-21 21:43:56 -08001023 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[6]),
1024 UnorderedElementsAre())
1025 << " : " << logfiles_[6];
1026 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[7]),
1027 UnorderedElementsAre())
1028 << " : " << logfiles_[7];
Austin Schuh25b46712021-01-03 00:04:38 -08001029 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[8]),
1030 UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -08001031 << " : " << logfiles_[8];
Austin Schuh25b46712021-01-03 00:04:38 -08001032 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[9]),
1033 UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -08001034 << " : " << logfiles_[9];
Austin Schuh61e973f2021-02-21 21:43:56 -08001035
1036 EXPECT_THAT(CountChannelsData(config, logfiles_[6]),
1037 UnorderedElementsAre(std::make_tuple(
1038 "/pi1/aos", "aos.message_bridge.Timestamp", 9)))
1039 << " : " << logfiles_[6];
1040 EXPECT_THAT(CountChannelsData(config, logfiles_[7]),
1041 UnorderedElementsAre(std::make_tuple(
1042 "/pi1/aos", "aos.message_bridge.Timestamp", 191)))
1043 << " : " << logfiles_[7];
Austin Schuh2f8fd752020-09-01 22:38:28 -07001044
Austin Schuh8c399962020-12-25 21:51:45 -08001045 EXPECT_THAT(CountChannelsData(config, logfiles_[8]),
Austin Schuh2f8fd752020-09-01 22:38:28 -07001046 UnorderedElementsAre(std::make_tuple(
Austin Schuh61e973f2021-02-21 21:43:56 -08001047 "/pi2/aos", "aos.message_bridge.Timestamp", 9)))
Austin Schuh20ac95d2020-12-05 17:24:19 -08001048 << " : " << logfiles_[8];
Austin Schuh8c399962020-12-25 21:51:45 -08001049 EXPECT_THAT(CountChannelsData(config, logfiles_[9]),
Austin Schuh2f8fd752020-09-01 22:38:28 -07001050 UnorderedElementsAre(std::make_tuple(
Austin Schuh61e973f2021-02-21 21:43:56 -08001051 "/pi2/aos", "aos.message_bridge.Timestamp", 191)))
Austin Schuh20ac95d2020-12-05 17:24:19 -08001052 << " : " << logfiles_[9];
Austin Schuh2f8fd752020-09-01 22:38:28 -07001053
Austin Schuh61e973f2021-02-21 21:43:56 -08001054 // Timestamps from pi2 on pi1, and the other way.
Austin Schuh8c399962020-12-25 21:51:45 -08001055 EXPECT_THAT(CountChannelsData(config, logfiles_[10]),
Austin Schuh61e973f2021-02-21 21:43:56 -08001056 UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -08001057 << " : " << logfiles_[10];
Austin Schuh8c399962020-12-25 21:51:45 -08001058 EXPECT_THAT(CountChannelsData(config, logfiles_[11]),
Austin Schuh61e973f2021-02-21 21:43:56 -08001059 UnorderedElementsAre())
Austin Schuh20ac95d2020-12-05 17:24:19 -08001060 << " : " << logfiles_[11];
Austin Schuh61e973f2021-02-21 21:43:56 -08001061 EXPECT_THAT(CountChannelsData(config, logfiles_[12]),
1062 UnorderedElementsAre())
1063 << " : " << logfiles_[12];
1064 EXPECT_THAT(CountChannelsData(config, logfiles_[13]),
1065 UnorderedElementsAre())
1066 << " : " << logfiles_[13];
1067 if (!shared()) {
1068 EXPECT_THAT(CountChannelsData(config, logfiles_[14]),
1069 UnorderedElementsAre())
1070 << " : " << logfiles_[14];
1071 EXPECT_THAT(CountChannelsData(config, logfiles_[15]),
1072 UnorderedElementsAre())
1073 << " : " << logfiles_[15];
1074 }
1075
1076 if (shared()) {
1077 EXPECT_THAT(
1078 CountChannelsTimestamp(config, logfiles_[10]),
1079 UnorderedElementsAre(
1080 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 9),
1081 std::make_tuple("/test", "aos.examples.Ping", 91)))
1082 << " : " << logfiles_[10];
1083 EXPECT_THAT(
1084 CountChannelsTimestamp(config, logfiles_[11]),
1085 UnorderedElementsAre(
1086 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 191),
1087 std::make_tuple("/test", "aos.examples.Ping", 1910)))
1088 << " : " << logfiles_[11];
1089 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[12]),
1090 UnorderedElementsAre(std::make_tuple(
1091 "/pi2/aos", "aos.message_bridge.Timestamp", 9)))
1092 << " : " << logfiles_[12];
1093 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[13]),
1094 UnorderedElementsAre(std::make_tuple(
1095 "/pi2/aos", "aos.message_bridge.Timestamp", 191)))
1096 << " : " << logfiles_[13];
1097 } else {
1098 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[10]),
1099 UnorderedElementsAre(std::make_tuple(
1100 "/pi1/aos", "aos.message_bridge.Timestamp", 9)))
1101 << " : " << logfiles_[10];
1102 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[11]),
1103 UnorderedElementsAre(std::make_tuple(
1104 "/pi1/aos", "aos.message_bridge.Timestamp", 191)))
1105 << " : " << logfiles_[11];
1106 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[12]),
1107 UnorderedElementsAre(std::make_tuple(
1108 "/pi2/aos", "aos.message_bridge.Timestamp", 9)))
1109 << " : " << logfiles_[12];
1110 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[13]),
1111 UnorderedElementsAre(std::make_tuple(
1112 "/pi2/aos", "aos.message_bridge.Timestamp", 191)))
1113 << " : " << logfiles_[13];
1114 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[14]),
1115 UnorderedElementsAre(
1116 std::make_tuple("/test", "aos.examples.Ping", 91)))
1117 << " : " << logfiles_[14];
1118 EXPECT_THAT(CountChannelsTimestamp(config, logfiles_[15]),
1119 UnorderedElementsAre(
1120 std::make_tuple("/test", "aos.examples.Ping", 1910)))
1121 << " : " << logfiles_[15];
1122 }
Austin Schuh6f3babe2020-01-26 20:34:50 -08001123 }
1124
Austin Schuh8c399962020-12-25 21:51:45 -08001125 LogReader reader(sorted_log_files);
Austin Schuh6f3babe2020-01-26 20:34:50 -08001126
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001127 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuh6331ef92020-01-07 18:28:09 -08001128 log_reader_factory.set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -08001129
1130 // This sends out the fetched messages and advances time to the start of the
1131 // log file.
Austin Schuh6331ef92020-01-07 18:28:09 -08001132 reader.Register(&log_reader_factory);
James Kuszmaul84ff3e52020-01-03 19:48:53 -08001133
Austin Schuhac0771c2020-01-07 18:36:30 -08001134 const Node *pi1 =
1135 configuration::GetNode(log_reader_factory.configuration(), "pi1");
Austin Schuh6f3babe2020-01-26 20:34:50 -08001136 const Node *pi2 =
1137 configuration::GetNode(log_reader_factory.configuration(), "pi2");
Austin Schuhac0771c2020-01-07 18:36:30 -08001138
Austin Schuh2f8fd752020-09-01 22:38:28 -07001139 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
1140 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
1141 LOG(INFO) << "now pi1 "
1142 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
1143 LOG(INFO) << "now pi2 "
1144 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
1145
Austin Schuh07676622021-01-21 18:59:17 -08001146 EXPECT_THAT(reader.LoggedNodes(),
1147 ::testing::ElementsAre(
1148 configuration::GetNode(reader.logged_configuration(), pi1),
1149 configuration::GetNode(reader.logged_configuration(), pi2)));
James Kuszmaul84ff3e52020-01-03 19:48:53 -08001150
1151 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -08001152
Austin Schuh6f3babe2020-01-26 20:34:50 -08001153 std::unique_ptr<EventLoop> pi1_event_loop =
Austin Schuhac0771c2020-01-07 18:36:30 -08001154 log_reader_factory.MakeEventLoop("test", pi1);
Austin Schuh6f3babe2020-01-26 20:34:50 -08001155 std::unique_ptr<EventLoop> pi2_event_loop =
1156 log_reader_factory.MakeEventLoop("test", pi2);
Austin Schuh15649d62019-12-28 16:36:38 -08001157
Austin Schuh6f3babe2020-01-26 20:34:50 -08001158 int pi1_ping_count = 10;
1159 int pi2_ping_count = 10;
1160 int pi1_pong_count = 10;
1161 int pi2_pong_count = 10;
Austin Schuh15649d62019-12-28 16:36:38 -08001162
1163 // Confirm that the ping value matches.
Austin Schuh6f3babe2020-01-26 20:34:50 -08001164 pi1_event_loop->MakeWatcher(
1165 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
Austin Schuh2f8fd752020-09-01 22:38:28 -07001166 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping) << " at "
Austin Schuh6f3babe2020-01-26 20:34:50 -08001167 << pi1_event_loop->context().monotonic_remote_time << " -> "
1168 << pi1_event_loop->context().monotonic_event_time;
1169 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
1170 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
1171 pi1_ping_count * chrono::milliseconds(10) +
1172 monotonic_clock::epoch());
1173 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
1174 pi1_ping_count * chrono::milliseconds(10) +
1175 realtime_clock::epoch());
1176 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
1177 pi1_event_loop->context().monotonic_event_time);
1178 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
1179 pi1_event_loop->context().realtime_event_time);
Austin Schuh15649d62019-12-28 16:36:38 -08001180
Austin Schuh6f3babe2020-01-26 20:34:50 -08001181 ++pi1_ping_count;
1182 });
1183 pi2_event_loop->MakeWatcher(
1184 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
Austin Schuh2f8fd752020-09-01 22:38:28 -07001185 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping) << " at "
Austin Schuh6f3babe2020-01-26 20:34:50 -08001186 << pi2_event_loop->context().monotonic_remote_time << " -> "
1187 << pi2_event_loop->context().monotonic_event_time;
1188 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
1189
1190 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
1191 pi2_ping_count * chrono::milliseconds(10) +
1192 monotonic_clock::epoch());
1193 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
1194 pi2_ping_count * chrono::milliseconds(10) +
1195 realtime_clock::epoch());
1196 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time +
1197 chrono::microseconds(150),
1198 pi2_event_loop->context().monotonic_event_time);
1199 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time +
1200 chrono::microseconds(150),
1201 pi2_event_loop->context().realtime_event_time);
1202 ++pi2_ping_count;
Austin Schuh15649d62019-12-28 16:36:38 -08001203 });
1204
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001205 constexpr ssize_t kQueueIndexOffset = -9;
Austin Schuh6f3babe2020-01-26 20:34:50 -08001206 // Confirm that the ping and pong counts both match, and the value also
1207 // matches.
1208 pi1_event_loop->MakeWatcher(
1209 "/test", [&pi1_event_loop, &pi1_ping_count,
1210 &pi1_pong_count](const examples::Pong &pong) {
1211 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
1212 << pi1_event_loop->context().monotonic_remote_time << " -> "
1213 << pi1_event_loop->context().monotonic_event_time;
1214
1215 EXPECT_EQ(pi1_event_loop->context().remote_queue_index,
1216 pi1_pong_count + kQueueIndexOffset);
1217 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
1218 chrono::microseconds(200) +
1219 pi1_pong_count * chrono::milliseconds(10) +
1220 monotonic_clock::epoch());
1221 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
1222 chrono::microseconds(200) +
1223 pi1_pong_count * chrono::milliseconds(10) +
1224 realtime_clock::epoch());
1225
1226 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time +
1227 chrono::microseconds(150),
1228 pi1_event_loop->context().monotonic_event_time);
1229 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time +
1230 chrono::microseconds(150),
1231 pi1_event_loop->context().realtime_event_time);
1232
1233 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
1234 ++pi1_pong_count;
1235 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
1236 });
1237 pi2_event_loop->MakeWatcher(
1238 "/test", [&pi2_event_loop, &pi2_ping_count,
1239 &pi2_pong_count](const examples::Pong &pong) {
1240 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
1241 << pi2_event_loop->context().monotonic_remote_time << " -> "
1242 << pi2_event_loop->context().monotonic_event_time;
1243
1244 EXPECT_EQ(pi2_event_loop->context().remote_queue_index,
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001245 pi2_pong_count + kQueueIndexOffset);
Austin Schuh6f3babe2020-01-26 20:34:50 -08001246
1247 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
1248 chrono::microseconds(200) +
1249 pi2_pong_count * chrono::milliseconds(10) +
1250 monotonic_clock::epoch());
1251 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
1252 chrono::microseconds(200) +
1253 pi2_pong_count * chrono::milliseconds(10) +
1254 realtime_clock::epoch());
1255
1256 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
1257 pi2_event_loop->context().monotonic_event_time);
1258 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
1259 pi2_event_loop->context().realtime_event_time);
1260
1261 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1262 ++pi2_pong_count;
1263 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1264 });
1265
1266 log_reader_factory.Run();
1267 EXPECT_EQ(pi1_ping_count, 2010);
1268 EXPECT_EQ(pi2_ping_count, 2010);
1269 EXPECT_EQ(pi1_pong_count, 2010);
1270 EXPECT_EQ(pi2_pong_count, 2010);
Austin Schuh6331ef92020-01-07 18:28:09 -08001271
1272 reader.Deregister();
Austin Schuh15649d62019-12-28 16:36:38 -08001273}
1274
James Kuszmaul46d82582020-05-09 19:50:09 -07001275typedef MultinodeLoggerTest MultinodeLoggerDeathTest;
1276
1277// Test that if we feed the replay with a mismatched node list that we die on
1278// the LogReader constructor.
Austin Schuh61e973f2021-02-21 21:43:56 -08001279TEST_P(MultinodeLoggerDeathTest, MultiNodeBadReplayConfig) {
Austin Schuh87dd3832021-01-01 23:07:31 -08001280 time_converter_.StartEqual();
James Kuszmaul46d82582020-05-09 19:50:09 -07001281 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001282 LoggerState pi1_logger = MakeLogger(pi1_);
1283 LoggerState pi2_logger = MakeLogger(pi2_);
James Kuszmaul46d82582020-05-09 19:50:09 -07001284
1285 event_loop_factory_.RunFor(chrono::milliseconds(95));
1286
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001287 StartLogger(&pi1_logger);
1288 StartLogger(&pi2_logger);
James Kuszmaul46d82582020-05-09 19:50:09 -07001289
James Kuszmaul46d82582020-05-09 19:50:09 -07001290 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1291 }
1292
1293 // Test that, if we add an additional node to the replay config that the
1294 // logger complains about the mismatch in number of nodes.
1295 FlatbufferDetachedBuffer<Configuration> extra_nodes_config =
1296 configuration::MergeWithConfig(&config_.message(), R"({
1297 "nodes": [
1298 {
1299 "name": "extra-node"
1300 }
1301 ]
1302 }
1303 )");
1304
Austin Schuh287d43d2020-12-04 20:19:33 -08001305 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1306 EXPECT_DEATH(LogReader(sorted_parts, &extra_nodes_config.message()),
James Kuszmaul46d82582020-05-09 19:50:09 -07001307 "Log file and replay config need to have matching nodes lists.");
James Kuszmaul46d82582020-05-09 19:50:09 -07001308}
1309
Austin Schuhcde938c2020-02-02 17:30:07 -08001310// Tests that we can read log files where they don't start at the same monotonic
1311// time.
Austin Schuh61e973f2021-02-21 21:43:56 -08001312TEST_P(MultinodeLoggerTest, StaggeredStart) {
Austin Schuh87dd3832021-01-01 23:07:31 -08001313 time_converter_.StartEqual();
Austin Schuhcde938c2020-02-02 17:30:07 -08001314 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001315 LoggerState pi1_logger = MakeLogger(pi1_);
1316 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuhcde938c2020-02-02 17:30:07 -08001317
1318 event_loop_factory_.RunFor(chrono::milliseconds(95));
1319
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001320 StartLogger(&pi1_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -08001321
1322 event_loop_factory_.RunFor(chrono::milliseconds(200));
1323
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001324 StartLogger(&pi2_logger);
1325
Austin Schuhcde938c2020-02-02 17:30:07 -08001326 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1327 }
1328
Austin Schuh287d43d2020-12-04 20:19:33 -08001329 LogReader reader(SortParts(logfiles_));
Austin Schuhcde938c2020-02-02 17:30:07 -08001330
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001331 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuhcde938c2020-02-02 17:30:07 -08001332 log_reader_factory.set_send_delay(chrono::microseconds(0));
1333
1334 // This sends out the fetched messages and advances time to the start of the
1335 // log file.
1336 reader.Register(&log_reader_factory);
1337
1338 const Node *pi1 =
1339 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1340 const Node *pi2 =
1341 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1342
Austin Schuh07676622021-01-21 18:59:17 -08001343 EXPECT_THAT(reader.LoggedNodes(),
1344 ::testing::ElementsAre(
1345 configuration::GetNode(reader.logged_configuration(), pi1),
1346 configuration::GetNode(reader.logged_configuration(), pi2)));
Austin Schuhcde938c2020-02-02 17:30:07 -08001347
1348 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1349
1350 std::unique_ptr<EventLoop> pi1_event_loop =
1351 log_reader_factory.MakeEventLoop("test", pi1);
1352 std::unique_ptr<EventLoop> pi2_event_loop =
1353 log_reader_factory.MakeEventLoop("test", pi2);
1354
1355 int pi1_ping_count = 30;
1356 int pi2_ping_count = 30;
1357 int pi1_pong_count = 30;
1358 int pi2_pong_count = 30;
1359
1360 // Confirm that the ping value matches.
1361 pi1_event_loop->MakeWatcher(
1362 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
1363 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
1364 << pi1_event_loop->context().monotonic_remote_time << " -> "
1365 << pi1_event_loop->context().monotonic_event_time;
1366 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
1367
1368 ++pi1_ping_count;
1369 });
1370 pi2_event_loop->MakeWatcher(
1371 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
1372 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
1373 << pi2_event_loop->context().monotonic_remote_time << " -> "
1374 << pi2_event_loop->context().monotonic_event_time;
1375 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
1376
1377 ++pi2_ping_count;
1378 });
1379
1380 // Confirm that the ping and pong counts both match, and the value also
1381 // matches.
1382 pi1_event_loop->MakeWatcher(
1383 "/test", [&pi1_event_loop, &pi1_ping_count,
1384 &pi1_pong_count](const examples::Pong &pong) {
1385 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
1386 << pi1_event_loop->context().monotonic_remote_time << " -> "
1387 << pi1_event_loop->context().monotonic_event_time;
1388
1389 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
1390 ++pi1_pong_count;
1391 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
1392 });
1393 pi2_event_loop->MakeWatcher(
1394 "/test", [&pi2_event_loop, &pi2_ping_count,
1395 &pi2_pong_count](const examples::Pong &pong) {
1396 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
1397 << pi2_event_loop->context().monotonic_remote_time << " -> "
1398 << pi2_event_loop->context().monotonic_event_time;
1399
1400 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1401 ++pi2_pong_count;
1402 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1403 });
1404
1405 log_reader_factory.Run();
1406 EXPECT_EQ(pi1_ping_count, 2030);
1407 EXPECT_EQ(pi2_ping_count, 2030);
1408 EXPECT_EQ(pi1_pong_count, 2030);
1409 EXPECT_EQ(pi2_pong_count, 2030);
1410
1411 reader.Deregister();
1412}
Austin Schuh6f3babe2020-01-26 20:34:50 -08001413
Austin Schuh8bd96322020-02-13 21:18:22 -08001414// Tests that we can read log files where the monotonic clocks drift and don't
1415// match correctly. While we are here, also test that different ending times
1416// also is readable.
Austin Schuh61e973f2021-02-21 21:43:56 -08001417TEST_P(MultinodeLoggerTest, MismatchedClocks) {
Austin Schuh87dd3832021-01-01 23:07:31 -08001418 // TODO(austin): Negate...
1419 const chrono::nanoseconds initial_pi2_offset = chrono::seconds(1000);
1420
1421 time_converter_.AddMonotonic({monotonic_clock::epoch(),
1422 monotonic_clock::epoch() + initial_pi2_offset});
1423 // Wait for 95 ms, (~0.1 seconds - 1/2 of the ping/pong period), and set the
1424 // skew to be 200 uS/s
1425 const chrono::nanoseconds startup_sleep1 = time_converter_.AddMonotonic(
1426 {chrono::milliseconds(95),
1427 chrono::milliseconds(95) - chrono::nanoseconds(200) * 95});
1428 // Run another 200 ms to have one logger start first.
1429 const chrono::nanoseconds startup_sleep2 = time_converter_.AddMonotonic(
1430 {chrono::milliseconds(200), chrono::milliseconds(200)});
1431 // Slew one way then the other at the same 200 uS/S slew rate. Make sure we
1432 // go far enough to cause problems if this isn't accounted for.
1433 const chrono::nanoseconds logger_run1 = time_converter_.AddMonotonic(
1434 {chrono::milliseconds(20000),
1435 chrono::milliseconds(20000) - chrono::nanoseconds(200) * 20000});
1436 const chrono::nanoseconds logger_run2 = time_converter_.AddMonotonic(
1437 {chrono::milliseconds(40000),
1438 chrono::milliseconds(40000) + chrono::nanoseconds(200) * 40000});
1439 const chrono::nanoseconds logger_run3 = time_converter_.AddMonotonic(
1440 {chrono::milliseconds(400), chrono::milliseconds(400)});
1441
Austin Schuhcde938c2020-02-02 17:30:07 -08001442 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001443 LoggerState pi2_logger = MakeLogger(pi2_);
1444
Austin Schuh87dd3832021-01-01 23:07:31 -08001445 NodeEventLoopFactory *pi1 =
1446 event_loop_factory_.GetNodeEventLoopFactory(pi1_);
Austin Schuh8bd96322020-02-13 21:18:22 -08001447 NodeEventLoopFactory *pi2 =
1448 event_loop_factory_.GetNodeEventLoopFactory(pi2_);
1449 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
1450 << pi2->realtime_now() << " distributed "
1451 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -08001452
Austin Schuh8bd96322020-02-13 21:18:22 -08001453 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
1454 << pi2->realtime_now() << " distributed "
1455 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -08001456
Austin Schuh87dd3832021-01-01 23:07:31 -08001457 event_loop_factory_.RunFor(startup_sleep1);
Austin Schuhcde938c2020-02-02 17:30:07 -08001458
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001459 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -08001460
Austin Schuh87dd3832021-01-01 23:07:31 -08001461 event_loop_factory_.RunFor(startup_sleep2);
Austin Schuhcde938c2020-02-02 17:30:07 -08001462
Austin Schuh8bd96322020-02-13 21:18:22 -08001463 {
1464 // Run pi1's logger for only part of the time.
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001465 LoggerState pi1_logger = MakeLogger(pi1_);
Austin Schuh8bd96322020-02-13 21:18:22 -08001466
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001467 StartLogger(&pi1_logger);
Austin Schuh87dd3832021-01-01 23:07:31 -08001468 event_loop_factory_.RunFor(logger_run1);
Austin Schuh8bd96322020-02-13 21:18:22 -08001469
Austin Schuh87dd3832021-01-01 23:07:31 -08001470 // Make sure we slewed time far enough so that the difference is greater
1471 // than the network delay. This confirms that if we sort incorrectly, it
1472 // would show in the results.
1473 EXPECT_LT(
1474 (pi2->monotonic_now() - pi1->monotonic_now()) - initial_pi2_offset,
1475 -event_loop_factory_.send_delay() -
1476 event_loop_factory_.network_delay());
Austin Schuh8bd96322020-02-13 21:18:22 -08001477
Austin Schuh87dd3832021-01-01 23:07:31 -08001478 event_loop_factory_.RunFor(logger_run2);
Austin Schuh8bd96322020-02-13 21:18:22 -08001479
Austin Schuh87dd3832021-01-01 23:07:31 -08001480 // And now check that we went far enough the other way to make sure we
1481 // cover both problems.
1482 EXPECT_GT(
1483 (pi2->monotonic_now() - pi1->monotonic_now()) - initial_pi2_offset,
1484 event_loop_factory_.send_delay() +
1485 event_loop_factory_.network_delay());
Austin Schuh8bd96322020-02-13 21:18:22 -08001486 }
1487
1488 // And log a bit more on pi2.
Austin Schuh87dd3832021-01-01 23:07:31 -08001489 event_loop_factory_.RunFor(logger_run3);
Austin Schuhcde938c2020-02-02 17:30:07 -08001490 }
1491
Austin Schuh287d43d2020-12-04 20:19:33 -08001492 LogReader reader(SortParts(logfiles_));
Austin Schuhcde938c2020-02-02 17:30:07 -08001493
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001494 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuhcde938c2020-02-02 17:30:07 -08001495 log_reader_factory.set_send_delay(chrono::microseconds(0));
1496
Austin Schuhcde938c2020-02-02 17:30:07 -08001497 const Node *pi1 =
1498 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1499 const Node *pi2 =
1500 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1501
Austin Schuh2f8fd752020-09-01 22:38:28 -07001502 // This sends out the fetched messages and advances time to the start of the
1503 // log file.
1504 reader.Register(&log_reader_factory);
1505
1506 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
1507 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
1508 LOG(INFO) << "now pi1 "
1509 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
1510 LOG(INFO) << "now pi2 "
1511 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
1512
Austin Schuhcde938c2020-02-02 17:30:07 -08001513 LOG(INFO) << "Done registering (pi1) "
Austin Schuh391e3172020-09-01 22:48:18 -07001514 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now()
1515 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -08001516 << log_reader_factory.GetNodeEventLoopFactory(pi1)->realtime_now();
1517 LOG(INFO) << "Done registering (pi2) "
Austin Schuh391e3172020-09-01 22:48:18 -07001518 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now()
1519 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -08001520 << log_reader_factory.GetNodeEventLoopFactory(pi2)->realtime_now();
1521
Austin Schuh07676622021-01-21 18:59:17 -08001522 EXPECT_THAT(reader.LoggedNodes(),
1523 ::testing::ElementsAre(
1524 configuration::GetNode(reader.logged_configuration(), pi1),
1525 configuration::GetNode(reader.logged_configuration(), pi2)));
Austin Schuhcde938c2020-02-02 17:30:07 -08001526
1527 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1528
1529 std::unique_ptr<EventLoop> pi1_event_loop =
1530 log_reader_factory.MakeEventLoop("test", pi1);
1531 std::unique_ptr<EventLoop> pi2_event_loop =
1532 log_reader_factory.MakeEventLoop("test", pi2);
1533
1534 int pi1_ping_count = 30;
1535 int pi2_ping_count = 30;
1536 int pi1_pong_count = 30;
1537 int pi2_pong_count = 30;
1538
1539 // Confirm that the ping value matches.
1540 pi1_event_loop->MakeWatcher(
1541 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
1542 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
1543 << pi1_event_loop->context().monotonic_remote_time << " -> "
1544 << pi1_event_loop->context().monotonic_event_time;
1545 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
1546
1547 ++pi1_ping_count;
1548 });
1549 pi2_event_loop->MakeWatcher(
1550 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
1551 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
1552 << pi2_event_loop->context().monotonic_remote_time << " -> "
1553 << pi2_event_loop->context().monotonic_event_time;
1554 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
1555
1556 ++pi2_ping_count;
1557 });
1558
1559 // Confirm that the ping and pong counts both match, and the value also
1560 // matches.
1561 pi1_event_loop->MakeWatcher(
1562 "/test", [&pi1_event_loop, &pi1_ping_count,
1563 &pi1_pong_count](const examples::Pong &pong) {
1564 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
1565 << pi1_event_loop->context().monotonic_remote_time << " -> "
1566 << pi1_event_loop->context().monotonic_event_time;
1567
1568 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
1569 ++pi1_pong_count;
1570 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
1571 });
1572 pi2_event_loop->MakeWatcher(
1573 "/test", [&pi2_event_loop, &pi2_ping_count,
1574 &pi2_pong_count](const examples::Pong &pong) {
1575 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
1576 << pi2_event_loop->context().monotonic_remote_time << " -> "
1577 << pi2_event_loop->context().monotonic_event_time;
1578
1579 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1580 ++pi2_pong_count;
1581 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1582 });
1583
1584 log_reader_factory.Run();
Austin Schuh8bd96322020-02-13 21:18:22 -08001585 EXPECT_EQ(pi1_ping_count, 6030);
1586 EXPECT_EQ(pi2_ping_count, 6030);
1587 EXPECT_EQ(pi1_pong_count, 6030);
1588 EXPECT_EQ(pi2_pong_count, 6030);
Austin Schuhcde938c2020-02-02 17:30:07 -08001589
1590 reader.Deregister();
1591}
1592
Austin Schuh5212cad2020-09-09 23:12:09 -07001593// Tests that we can sort a bunch of parts into the pre-determined sorted parts.
Austin Schuh61e973f2021-02-21 21:43:56 -08001594TEST_P(MultinodeLoggerTest, SortParts) {
Austin Schuh87dd3832021-01-01 23:07:31 -08001595 time_converter_.StartEqual();
Austin Schuh5212cad2020-09-09 23:12:09 -07001596 // Make a bunch of parts.
1597 {
1598 LoggerState pi1_logger = MakeLogger(pi1_);
1599 LoggerState pi2_logger = MakeLogger(pi2_);
1600
1601 event_loop_factory_.RunFor(chrono::milliseconds(95));
1602
1603 StartLogger(&pi1_logger);
1604 StartLogger(&pi2_logger);
1605
1606 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1607 }
1608
Austin Schuh11d43732020-09-21 17:28:30 -07001609 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
Austin Schuh3bd4c402020-11-06 18:19:06 -08001610 VerifyParts(sorted_parts);
1611}
Austin Schuh11d43732020-09-21 17:28:30 -07001612
Austin Schuh3bd4c402020-11-06 18:19:06 -08001613// Tests that we can sort a bunch of parts with an empty part. We should ignore
1614// it and remove it from the sorted list.
Austin Schuh61e973f2021-02-21 21:43:56 -08001615TEST_P(MultinodeLoggerTest, SortEmptyParts) {
Austin Schuh87dd3832021-01-01 23:07:31 -08001616 time_converter_.StartEqual();
Austin Schuh3bd4c402020-11-06 18:19:06 -08001617 // Make a bunch of parts.
1618 {
1619 LoggerState pi1_logger = MakeLogger(pi1_);
1620 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuh11d43732020-09-21 17:28:30 -07001621
Austin Schuh3bd4c402020-11-06 18:19:06 -08001622 event_loop_factory_.RunFor(chrono::milliseconds(95));
Austin Schuh11d43732020-09-21 17:28:30 -07001623
Austin Schuh3bd4c402020-11-06 18:19:06 -08001624 StartLogger(&pi1_logger);
1625 StartLogger(&pi2_logger);
Austin Schuh11d43732020-09-21 17:28:30 -07001626
Austin Schuh3bd4c402020-11-06 18:19:06 -08001627 event_loop_factory_.RunFor(chrono::milliseconds(2000));
Austin Schuh11d43732020-09-21 17:28:30 -07001628 }
1629
Austin Schuh3bd4c402020-11-06 18:19:06 -08001630 // TODO(austin): Should we flip out if the file can't open?
1631 const std::string kEmptyFile("foobarinvalidfiledoesnotexist.bfbs");
Austin Schuh11d43732020-09-21 17:28:30 -07001632
Austin Schuh3bd4c402020-11-06 18:19:06 -08001633 aos::util::WriteStringToFileOrDie(kEmptyFile, "");
1634 logfiles_.emplace_back(kEmptyFile);
Austin Schuh5212cad2020-09-09 23:12:09 -07001635
Austin Schuh3bd4c402020-11-06 18:19:06 -08001636 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1637 VerifyParts(sorted_parts, {kEmptyFile});
Austin Schuh5212cad2020-09-09 23:12:09 -07001638}
1639
Austin Schuh3bd4c402020-11-06 18:19:06 -08001640#ifdef LZMA
1641// Tests that we can sort a bunch of parts with an empty .xz file in there. The
1642// empty file should be ignored.
Austin Schuh61e973f2021-02-21 21:43:56 -08001643TEST_P(MultinodeLoggerTest, SortEmptyCompressedParts) {
Austin Schuh87dd3832021-01-01 23:07:31 -08001644 time_converter_.StartEqual();
Austin Schuh3bd4c402020-11-06 18:19:06 -08001645 // Make a bunch of parts.
1646 {
1647 LoggerState pi1_logger = MakeLogger(pi1_);
1648 LoggerState pi2_logger = MakeLogger(pi2_);
1649
1650 event_loop_factory_.RunFor(chrono::milliseconds(95));
1651
1652 StartLogger(&pi1_logger, "", true);
1653 StartLogger(&pi2_logger, "", true);
1654
1655 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1656 }
1657
1658 // TODO(austin): Should we flip out if the file can't open?
1659 const std::string kEmptyFile("foobarinvalidfiledoesnotexist.bfbs.xz");
1660
1661 AddExtension(".xz");
1662
1663 aos::util::WriteStringToFileOrDie(kEmptyFile, "");
1664 logfiles_.emplace_back(kEmptyFile);
1665
1666 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1667 VerifyParts(sorted_parts, {kEmptyFile});
1668}
1669
1670// Tests that we can sort a bunch of parts with the end missing off a compressed
1671// file. We should use the part we can read.
Austin Schuh61e973f2021-02-21 21:43:56 -08001672TEST_P(MultinodeLoggerTest, SortTruncatedCompressedParts) {
Austin Schuh87dd3832021-01-01 23:07:31 -08001673 time_converter_.StartEqual();
Austin Schuh3bd4c402020-11-06 18:19:06 -08001674 // Make a bunch of parts.
1675 {
1676 LoggerState pi1_logger = MakeLogger(pi1_);
1677 LoggerState pi2_logger = MakeLogger(pi2_);
1678
1679 event_loop_factory_.RunFor(chrono::milliseconds(95));
1680
1681 StartLogger(&pi1_logger, "", true);
1682 StartLogger(&pi2_logger, "", true);
1683
1684 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1685 }
1686
1687 // Append everything with .xz.
1688 AddExtension(".xz");
1689
1690 // Strip off the end of one of the files. Pick one with a lot of data.
1691 ::std::string compressed_contents =
Austin Schuh61e973f2021-02-21 21:43:56 -08001692 aos::util::ReadFileToStringOrDie(logfiles_[2]);
Austin Schuh3bd4c402020-11-06 18:19:06 -08001693
1694 aos::util::WriteStringToFileOrDie(
Austin Schuh61e973f2021-02-21 21:43:56 -08001695 logfiles_[2],
Austin Schuh3bd4c402020-11-06 18:19:06 -08001696 compressed_contents.substr(0, compressed_contents.size() - 100));
1697
1698 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1699 VerifyParts(sorted_parts);
1700}
1701#endif
1702
Austin Schuh01b4c352020-09-21 23:09:39 -07001703// Tests that if we remap a remapped channel, it shows up correctly.
Austin Schuh61e973f2021-02-21 21:43:56 -08001704TEST_P(MultinodeLoggerTest, RemapLoggedChannel) {
Austin Schuh87dd3832021-01-01 23:07:31 -08001705 time_converter_.StartEqual();
Austin Schuh01b4c352020-09-21 23:09:39 -07001706 {
1707 LoggerState pi1_logger = MakeLogger(pi1_);
1708 LoggerState pi2_logger = MakeLogger(pi2_);
1709
1710 event_loop_factory_.RunFor(chrono::milliseconds(95));
1711
1712 StartLogger(&pi1_logger);
1713 StartLogger(&pi2_logger);
1714
1715 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1716 }
1717
Austin Schuh287d43d2020-12-04 20:19:33 -08001718 LogReader reader(SortParts(logfiles_));
Austin Schuh01b4c352020-09-21 23:09:39 -07001719
1720 // Remap just on pi1.
1721 reader.RemapLoggedChannel<aos::timing::Report>(
1722 "/aos", configuration::GetNode(reader.configuration(), "pi1"));
1723
1724 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1725 log_reader_factory.set_send_delay(chrono::microseconds(0));
1726
1727 reader.Register(&log_reader_factory);
1728
1729 const Node *pi1 =
1730 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1731 const Node *pi2 =
1732 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1733
1734 // Confirm we can read the data on the remapped channel, just for pi1. Nothing
1735 // else should have moved.
1736 std::unique_ptr<EventLoop> pi1_event_loop =
1737 log_reader_factory.MakeEventLoop("test", pi1);
1738 pi1_event_loop->SkipTimingReport();
1739 std::unique_ptr<EventLoop> full_pi1_event_loop =
1740 log_reader_factory.MakeEventLoop("test", pi1);
1741 full_pi1_event_loop->SkipTimingReport();
1742 std::unique_ptr<EventLoop> pi2_event_loop =
1743 log_reader_factory.MakeEventLoop("test", pi2);
1744 pi2_event_loop->SkipTimingReport();
1745
1746 MessageCounter<aos::timing::Report> pi1_timing_report(pi1_event_loop.get(),
1747 "/aos");
1748 MessageCounter<aos::timing::Report> full_pi1_timing_report(
1749 full_pi1_event_loop.get(), "/pi1/aos");
1750 MessageCounter<aos::timing::Report> pi1_original_timing_report(
1751 pi1_event_loop.get(), "/original/aos");
1752 MessageCounter<aos::timing::Report> full_pi1_original_timing_report(
1753 full_pi1_event_loop.get(), "/original/pi1/aos");
1754 MessageCounter<aos::timing::Report> pi2_timing_report(pi2_event_loop.get(),
1755 "/aos");
1756
1757 log_reader_factory.Run();
1758
1759 EXPECT_EQ(pi1_timing_report.count(), 0u);
1760 EXPECT_EQ(full_pi1_timing_report.count(), 0u);
1761 EXPECT_NE(pi1_original_timing_report.count(), 0u);
1762 EXPECT_NE(full_pi1_original_timing_report.count(), 0u);
1763 EXPECT_NE(pi2_timing_report.count(), 0u);
1764
1765 reader.Deregister();
1766}
1767
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001768// Tests that we properly recreate forwarded timestamps when replaying a log.
1769// This should be enough that we can then re-run the logger and get a valid log
1770// back.
Austin Schuh61e973f2021-02-21 21:43:56 -08001771TEST_P(MultinodeLoggerTest, MessageHeader) {
Austin Schuh87dd3832021-01-01 23:07:31 -08001772 time_converter_.StartEqual();
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001773 {
1774 LoggerState pi1_logger = MakeLogger(pi1_);
1775 LoggerState pi2_logger = MakeLogger(pi2_);
1776
1777 event_loop_factory_.RunFor(chrono::milliseconds(95));
1778
1779 StartLogger(&pi1_logger);
1780 StartLogger(&pi2_logger);
1781
1782 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1783 }
1784
Austin Schuh287d43d2020-12-04 20:19:33 -08001785 LogReader reader(SortParts(logfiles_));
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001786
1787 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1788 log_reader_factory.set_send_delay(chrono::microseconds(0));
1789
1790 // This sends out the fetched messages and advances time to the start of the
1791 // log file.
1792 reader.Register(&log_reader_factory);
1793
1794 const Node *pi1 =
1795 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1796 const Node *pi2 =
1797 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1798
1799 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
1800 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
1801 LOG(INFO) << "now pi1 "
1802 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
1803 LOG(INFO) << "now pi2 "
1804 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
1805
Austin Schuh07676622021-01-21 18:59:17 -08001806 EXPECT_THAT(reader.LoggedNodes(),
1807 ::testing::ElementsAre(
1808 configuration::GetNode(reader.logged_configuration(), pi1),
1809 configuration::GetNode(reader.logged_configuration(), pi2)));
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001810
1811 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1812
1813 std::unique_ptr<EventLoop> pi1_event_loop =
1814 log_reader_factory.MakeEventLoop("test", pi1);
1815 std::unique_ptr<EventLoop> pi2_event_loop =
1816 log_reader_factory.MakeEventLoop("test", pi2);
1817
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001818 aos::Fetcher<message_bridge::Timestamp> pi1_timestamp_on_pi1_fetcher =
1819 pi1_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi1/aos");
1820 aos::Fetcher<message_bridge::Timestamp> pi1_timestamp_on_pi2_fetcher =
1821 pi2_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi1/aos");
1822
1823 aos::Fetcher<examples::Ping> ping_on_pi1_fetcher =
1824 pi1_event_loop->MakeFetcher<examples::Ping>("/test");
1825 aos::Fetcher<examples::Ping> ping_on_pi2_fetcher =
1826 pi2_event_loop->MakeFetcher<examples::Ping>("/test");
1827
1828 aos::Fetcher<message_bridge::Timestamp> pi2_timestamp_on_pi2_fetcher =
1829 pi2_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi2/aos");
1830 aos::Fetcher<message_bridge::Timestamp> pi2_timestamp_on_pi1_fetcher =
1831 pi1_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi2/aos");
1832
1833 aos::Fetcher<examples::Pong> pong_on_pi2_fetcher =
1834 pi2_event_loop->MakeFetcher<examples::Pong>("/test");
1835 aos::Fetcher<examples::Pong> pong_on_pi1_fetcher =
1836 pi1_event_loop->MakeFetcher<examples::Pong>("/test");
1837
1838 const size_t pi1_timestamp_channel = configuration::ChannelIndex(
1839 pi1_event_loop->configuration(), pi1_timestamp_on_pi1_fetcher.channel());
1840 const size_t ping_timestamp_channel = configuration::ChannelIndex(
1841 pi2_event_loop->configuration(), ping_on_pi2_fetcher.channel());
1842
1843 const size_t pi2_timestamp_channel = configuration::ChannelIndex(
1844 pi2_event_loop->configuration(), pi2_timestamp_on_pi2_fetcher.channel());
1845 const size_t pong_timestamp_channel = configuration::ChannelIndex(
1846 pi1_event_loop->configuration(), pong_on_pi1_fetcher.channel());
1847
Austin Schuh969cd602021-01-03 00:09:45 -08001848 const chrono::nanoseconds network_delay = event_loop_factory_.network_delay();
Austin Schuh816e5d62021-01-05 23:42:20 -08001849 const chrono::nanoseconds send_delay = event_loop_factory_.send_delay();
Austin Schuh969cd602021-01-03 00:09:45 -08001850
Austin Schuh61e973f2021-02-21 21:43:56 -08001851 for (std::pair<int, std::string> channel :
1852 shared()
1853 ? std::vector<
1854 std::pair<int, std::string>>{{-1,
1855 "/aos/remote_timestamps/pi2"}}
1856 : std::vector<std::pair<int, std::string>>{
1857 {pi1_timestamp_channel,
1858 "/aos/remote_timestamps/pi2/pi1/aos/"
1859 "aos-message_bridge-Timestamp"},
1860 {ping_timestamp_channel,
1861 "/aos/remote_timestamps/pi2/test/aos-examples-Ping"}}) {
1862 pi1_event_loop->MakeWatcher(
1863 channel.second,
1864 [&pi1_event_loop, &pi2_event_loop, pi1_timestamp_channel,
1865 ping_timestamp_channel, &pi1_timestamp_on_pi1_fetcher,
1866 &pi1_timestamp_on_pi2_fetcher, &ping_on_pi1_fetcher,
1867 &ping_on_pi2_fetcher, network_delay, send_delay,
1868 channel_index = channel.first](const RemoteMessage &header) {
1869 const aos::monotonic_clock::time_point header_monotonic_sent_time(
1870 chrono::nanoseconds(header.monotonic_sent_time()));
1871 const aos::realtime_clock::time_point header_realtime_sent_time(
1872 chrono::nanoseconds(header.realtime_sent_time()));
1873 const aos::monotonic_clock::time_point header_monotonic_remote_time(
1874 chrono::nanoseconds(header.monotonic_remote_time()));
1875 const aos::realtime_clock::time_point header_realtime_remote_time(
1876 chrono::nanoseconds(header.realtime_remote_time()));
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001877
Austin Schuh61e973f2021-02-21 21:43:56 -08001878 if (channel_index != -1) {
1879 ASSERT_EQ(channel_index, header.channel_index());
1880 }
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001881
Austin Schuh61e973f2021-02-21 21:43:56 -08001882 const Context *pi1_context = nullptr;
1883 const Context *pi2_context = nullptr;
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001884
Austin Schuh61e973f2021-02-21 21:43:56 -08001885 if (header.channel_index() == pi1_timestamp_channel) {
1886 ASSERT_TRUE(pi1_timestamp_on_pi1_fetcher.FetchNext());
1887 ASSERT_TRUE(pi1_timestamp_on_pi2_fetcher.FetchNext());
1888 pi1_context = &pi1_timestamp_on_pi1_fetcher.context();
1889 pi2_context = &pi1_timestamp_on_pi2_fetcher.context();
1890 } else if (header.channel_index() == ping_timestamp_channel) {
1891 ASSERT_TRUE(ping_on_pi1_fetcher.FetchNext());
1892 ASSERT_TRUE(ping_on_pi2_fetcher.FetchNext());
1893 pi1_context = &ping_on_pi1_fetcher.context();
1894 pi2_context = &ping_on_pi2_fetcher.context();
1895 } else {
1896 LOG(FATAL) << "Unknown channel " << FlatbufferToJson(&header) << " "
1897 << configuration::CleanedChannelToString(
1898 pi1_event_loop->configuration()->channels()->Get(
1899 header.channel_index()));
1900 }
Austin Schuh315b96b2020-12-11 21:21:12 -08001901
Austin Schuh61e973f2021-02-21 21:43:56 -08001902 ASSERT_TRUE(header.has_boot_uuid());
Austin Schuhcdd90272021-03-15 12:46:16 -07001903 EXPECT_EQ(UUID::FromVector(header.boot_uuid()),
1904 pi2_event_loop->boot_uuid());
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001905
Austin Schuh61e973f2021-02-21 21:43:56 -08001906 EXPECT_EQ(pi1_context->queue_index, header.remote_queue_index());
1907 EXPECT_EQ(pi2_context->remote_queue_index,
1908 header.remote_queue_index());
1909 EXPECT_EQ(pi2_context->queue_index, header.queue_index());
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001910
Austin Schuh61e973f2021-02-21 21:43:56 -08001911 EXPECT_EQ(pi2_context->monotonic_event_time,
1912 header_monotonic_sent_time);
1913 EXPECT_EQ(pi2_context->realtime_event_time,
1914 header_realtime_sent_time);
1915 EXPECT_EQ(pi2_context->realtime_remote_time,
1916 header_realtime_remote_time);
1917 EXPECT_EQ(pi2_context->monotonic_remote_time,
1918 header_monotonic_remote_time);
Austin Schuh969cd602021-01-03 00:09:45 -08001919
Austin Schuh61e973f2021-02-21 21:43:56 -08001920 EXPECT_EQ(pi1_context->realtime_event_time,
1921 header_realtime_remote_time);
1922 EXPECT_EQ(pi1_context->monotonic_event_time,
1923 header_monotonic_remote_time);
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001924
Austin Schuh61e973f2021-02-21 21:43:56 -08001925 // Time estimation isn't perfect, but we know the clocks were
1926 // identical when logged, so we know when this should have come back.
1927 // Confirm we got it when we expected.
1928 EXPECT_EQ(pi1_event_loop->context().monotonic_event_time,
1929 pi1_context->monotonic_event_time + 2 * network_delay +
1930 send_delay);
1931 });
1932 }
1933 for (std::pair<int, std::string> channel :
1934 shared()
1935 ? std::vector<
1936 std::pair<int, std::string>>{{-1,
1937 "/aos/remote_timestamps/pi1"}}
1938 : std::vector<std::pair<int, std::string>>{
1939 {pi2_timestamp_channel,
1940 "/aos/remote_timestamps/pi1/pi2/aos/"
1941 "aos-message_bridge-Timestamp"}}) {
1942 pi2_event_loop->MakeWatcher(
1943 channel.second,
1944 [&pi2_event_loop, &pi1_event_loop, pi2_timestamp_channel,
1945 pong_timestamp_channel, &pi2_timestamp_on_pi2_fetcher,
1946 &pi2_timestamp_on_pi1_fetcher, &pong_on_pi2_fetcher,
1947 &pong_on_pi1_fetcher, network_delay, send_delay,
1948 channel_index = channel.first](const RemoteMessage &header) {
1949 const aos::monotonic_clock::time_point header_monotonic_sent_time(
1950 chrono::nanoseconds(header.monotonic_sent_time()));
1951 const aos::realtime_clock::time_point header_realtime_sent_time(
1952 chrono::nanoseconds(header.realtime_sent_time()));
1953 const aos::monotonic_clock::time_point header_monotonic_remote_time(
1954 chrono::nanoseconds(header.monotonic_remote_time()));
1955 const aos::realtime_clock::time_point header_realtime_remote_time(
1956 chrono::nanoseconds(header.realtime_remote_time()));
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001957
Austin Schuh61e973f2021-02-21 21:43:56 -08001958 if (channel_index != -1) {
1959 ASSERT_EQ(channel_index, header.channel_index());
1960 }
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001961
Austin Schuh61e973f2021-02-21 21:43:56 -08001962 const Context *pi2_context = nullptr;
1963 const Context *pi1_context = nullptr;
Austin Schuh315b96b2020-12-11 21:21:12 -08001964
Austin Schuh61e973f2021-02-21 21:43:56 -08001965 if (header.channel_index() == pi2_timestamp_channel) {
1966 ASSERT_TRUE(pi2_timestamp_on_pi2_fetcher.FetchNext());
1967 ASSERT_TRUE(pi2_timestamp_on_pi1_fetcher.FetchNext());
1968 pi2_context = &pi2_timestamp_on_pi2_fetcher.context();
1969 pi1_context = &pi2_timestamp_on_pi1_fetcher.context();
1970 } else if (header.channel_index() == pong_timestamp_channel) {
1971 ASSERT_TRUE(pong_on_pi2_fetcher.FetchNext());
1972 ASSERT_TRUE(pong_on_pi1_fetcher.FetchNext());
1973 pi2_context = &pong_on_pi2_fetcher.context();
1974 pi1_context = &pong_on_pi1_fetcher.context();
1975 } else {
1976 LOG(FATAL) << "Unknown channel " << FlatbufferToJson(&header) << " "
1977 << configuration::CleanedChannelToString(
1978 pi2_event_loop->configuration()->channels()->Get(
1979 header.channel_index()));
1980 }
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001981
Austin Schuh61e973f2021-02-21 21:43:56 -08001982 ASSERT_TRUE(header.has_boot_uuid());
Austin Schuhcdd90272021-03-15 12:46:16 -07001983 EXPECT_EQ(UUID::FromVector(header.boot_uuid()),
1984 pi1_event_loop->boot_uuid());
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001985
Austin Schuh61e973f2021-02-21 21:43:56 -08001986 EXPECT_EQ(pi2_context->queue_index, header.remote_queue_index());
1987 EXPECT_EQ(pi1_context->remote_queue_index,
1988 header.remote_queue_index());
1989 EXPECT_EQ(pi1_context->queue_index, header.queue_index());
Austin Schuh969cd602021-01-03 00:09:45 -08001990
Austin Schuh61e973f2021-02-21 21:43:56 -08001991 EXPECT_EQ(pi1_context->monotonic_event_time,
1992 header_monotonic_sent_time);
1993 EXPECT_EQ(pi1_context->realtime_event_time,
1994 header_realtime_sent_time);
1995 EXPECT_EQ(pi1_context->realtime_remote_time,
1996 header_realtime_remote_time);
1997 EXPECT_EQ(pi1_context->monotonic_remote_time,
1998 header_monotonic_remote_time);
1999
2000 EXPECT_EQ(pi2_context->realtime_event_time,
2001 header_realtime_remote_time);
2002 EXPECT_EQ(pi2_context->monotonic_event_time,
2003 header_monotonic_remote_time);
2004
2005 // Time estimation isn't perfect, but we know the clocks were
2006 // identical when logged, so we know when this should have come back.
2007 // Confirm we got it when we expected.
2008 EXPECT_EQ(pi2_event_loop->context().monotonic_event_time,
2009 pi2_context->monotonic_event_time + 2 * network_delay +
2010 send_delay);
2011 });
2012 }
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07002013
2014 // And confirm we can re-create a log again, while checking the contents.
2015 {
2016 LoggerState pi1_logger = MakeLogger(
2017 configuration::GetNode(log_reader_factory.configuration(), pi1_),
2018 &log_reader_factory);
2019 LoggerState pi2_logger = MakeLogger(
2020 configuration::GetNode(log_reader_factory.configuration(), pi2_),
2021 &log_reader_factory);
2022
Austin Schuh25b46712021-01-03 00:04:38 -08002023 StartLogger(&pi1_logger, tmp_dir_ + "/relogged1");
2024 StartLogger(&pi2_logger, tmp_dir_ + "/relogged2");
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07002025
2026 log_reader_factory.Run();
2027 }
2028
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07002029 reader.Deregister();
James Kuszmaul4f106fb2021-01-05 20:53:02 -08002030
2031 // And verify that we can run the LogReader over the relogged files without
2032 // hitting any fatal errors.
2033 {
2034 LogReader relogged_reader(SortParts(
2035 MakeLogFiles(tmp_dir_ + "/relogged1", tmp_dir_ + "/relogged2")));
2036 relogged_reader.Register();
2037
2038 relogged_reader.event_loop_factory()->Run();
2039 }
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07002040}
2041
Austin Schuh315b96b2020-12-11 21:21:12 -08002042// Tests that we properly populate and extract the logger_start time by setting
2043// up a clock difference between 2 nodes and looking at the resulting parts.
Austin Schuh61e973f2021-02-21 21:43:56 -08002044TEST_P(MultinodeLoggerTest, LoggerStartTime) {
Austin Schuh87dd3832021-01-01 23:07:31 -08002045 time_converter_.AddMonotonic(
2046 {monotonic_clock::epoch(),
2047 monotonic_clock::epoch() + chrono::seconds(1000)});
Austin Schuh315b96b2020-12-11 21:21:12 -08002048 {
2049 LoggerState pi1_logger = MakeLogger(pi1_);
2050 LoggerState pi2_logger = MakeLogger(pi2_);
2051
Austin Schuh315b96b2020-12-11 21:21:12 -08002052 StartLogger(&pi1_logger);
2053 StartLogger(&pi2_logger);
2054
2055 event_loop_factory_.RunFor(chrono::milliseconds(10000));
2056 }
2057
2058 for (const LogFile &log_file : SortParts(logfiles_)) {
2059 for (const LogParts &log_part : log_file.parts) {
2060 if (log_part.node == log_file.logger_node) {
2061 EXPECT_EQ(log_part.logger_monotonic_start_time,
2062 aos::monotonic_clock::min_time);
2063 EXPECT_EQ(log_part.logger_realtime_start_time,
2064 aos::realtime_clock::min_time);
2065 } else {
2066 const chrono::seconds offset = log_file.logger_node == "pi1"
2067 ? -chrono::seconds(1000)
2068 : chrono::seconds(1000);
2069 EXPECT_EQ(log_part.logger_monotonic_start_time,
2070 log_part.monotonic_start_time + offset);
2071 EXPECT_EQ(log_part.logger_realtime_start_time,
2072 log_file.realtime_start_time +
2073 (log_part.logger_monotonic_start_time -
2074 log_file.monotonic_start_time));
2075 }
2076 }
2077 }
2078}
2079
Austin Schuh8bd96322020-02-13 21:18:22 -08002080// TODO(austin): We can write a test which recreates a logfile and confirms that
2081// we get it back. That is the ultimate test.
2082
Austin Schuh315b96b2020-12-11 21:21:12 -08002083// Tests that we properly recreate forwarded timestamps when replaying a log.
2084// This should be enough that we can then re-run the logger and get a valid log
2085// back.
Austin Schuh61e973f2021-02-21 21:43:56 -08002086TEST_P(MultinodeLoggerDeathTest, RemoteReboot) {
Austin Schuh87dd3832021-01-01 23:07:31 -08002087 time_converter_.StartEqual();
Austin Schuh315b96b2020-12-11 21:21:12 -08002088 std::string pi2_boot1;
2089 std::string pi2_boot2;
2090 {
2091 pi2_boot1 = event_loop_factory_.GetNodeEventLoopFactory(pi2_)
2092 ->boot_uuid()
Austin Schuh5e2bfb82021-03-13 22:46:55 -08002093 .ToString();
Austin Schuh315b96b2020-12-11 21:21:12 -08002094 LoggerState pi1_logger = MakeLogger(pi1_);
2095
2096 event_loop_factory_.RunFor(chrono::milliseconds(95));
2097
2098 StartLogger(&pi1_logger);
2099
2100 event_loop_factory_.RunFor(chrono::milliseconds(10000));
2101
2102 event_loop_factory_.GetNodeEventLoopFactory(pi2_)->Reboot();
2103
2104 pi2_boot2 = event_loop_factory_.GetNodeEventLoopFactory(pi2_)
2105 ->boot_uuid()
Austin Schuh5e2bfb82021-03-13 22:46:55 -08002106 .ToString();
Austin Schuh315b96b2020-12-11 21:21:12 -08002107
2108 event_loop_factory_.RunFor(chrono::milliseconds(20000));
2109 }
2110
2111 // Confirm that we refuse to replay logs with missing boot uuids.
2112 EXPECT_DEATH(
2113 {
2114 LogReader reader(SortParts(pi1_reboot_logfiles_));
2115
2116 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
2117 log_reader_factory.set_send_delay(chrono::microseconds(0));
2118
2119 // This sends out the fetched messages and advances time to the start of
2120 // the log file.
2121 reader.Register(&log_reader_factory);
2122 },
2123 absl::StrFormat("(%s|%s).*(%s|%s).*Found parts from different boots",
2124 pi2_boot1, pi2_boot2, pi2_boot2, pi2_boot1));
2125}
2126
Austin Schuhc9049732020-12-21 22:27:15 -08002127// Tests that we properly handle one direction of message_bridge being
2128// unavailable.
Austin Schuh61e973f2021-02-21 21:43:56 -08002129TEST_P(MultinodeLoggerTest, OneDirectionWithNegativeSlope) {
Austin Schuhc9049732020-12-21 22:27:15 -08002130 event_loop_factory_.GetNodeEventLoopFactory(pi1_)->Disconnect(pi2_);
Austin Schuh87dd3832021-01-01 23:07:31 -08002131 time_converter_.AddMonotonic(
2132 {monotonic_clock::epoch(),
2133 monotonic_clock::epoch() + chrono::seconds(1000)});
2134
2135 time_converter_.AddMonotonic(
2136 {chrono::milliseconds(10000),
2137 chrono::milliseconds(10000) - chrono::milliseconds(1)});
Austin Schuhc9049732020-12-21 22:27:15 -08002138 {
2139 LoggerState pi1_logger = MakeLogger(pi1_);
2140
2141 event_loop_factory_.RunFor(chrono::milliseconds(95));
2142
2143 StartLogger(&pi1_logger);
2144
2145 event_loop_factory_.RunFor(chrono::milliseconds(10000));
2146 }
2147
2148 // Confirm that we can parse the result. LogReader has enough internal CHECKs
2149 // to confirm the right thing happened.
2150 ConfirmReadable(pi1_single_direction_logfiles_);
2151}
2152
2153// Tests that we properly handle one direction of message_bridge being
2154// unavailable.
Austin Schuh61e973f2021-02-21 21:43:56 -08002155TEST_P(MultinodeLoggerTest, OneDirectionWithPositiveSlope) {
Austin Schuhc9049732020-12-21 22:27:15 -08002156 event_loop_factory_.GetNodeEventLoopFactory(pi1_)->Disconnect(pi2_);
Austin Schuh87dd3832021-01-01 23:07:31 -08002157 time_converter_.AddMonotonic(
2158 {monotonic_clock::epoch(),
2159 monotonic_clock::epoch() + chrono::seconds(500)});
2160
2161 time_converter_.AddMonotonic(
2162 {chrono::milliseconds(10000),
2163 chrono::milliseconds(10000) + chrono::milliseconds(1)});
2164 {
2165 LoggerState pi1_logger = MakeLogger(pi1_);
2166
2167 event_loop_factory_.RunFor(chrono::milliseconds(95));
2168
2169 StartLogger(&pi1_logger);
2170
2171 event_loop_factory_.RunFor(chrono::milliseconds(10000));
2172 }
2173
2174 // Confirm that we can parse the result. LogReader has enough internal CHECKs
2175 // to confirm the right thing happened.
2176 ConfirmReadable(pi1_single_direction_logfiles_);
2177}
2178
2179// Tests that we properly handle a dead node. Do this by just disconnecting it
2180// and only using one nodes of logs.
Austin Schuh61e973f2021-02-21 21:43:56 -08002181TEST_P(MultinodeLoggerTest, DeadNode) {
Austin Schuh87dd3832021-01-01 23:07:31 -08002182 event_loop_factory_.GetNodeEventLoopFactory(pi1_)->Disconnect(pi2_);
2183 event_loop_factory_.GetNodeEventLoopFactory(pi2_)->Disconnect(pi1_);
2184 time_converter_.AddMonotonic(
2185 {monotonic_clock::epoch(),
2186 monotonic_clock::epoch() + chrono::seconds(1000)});
Austin Schuhc9049732020-12-21 22:27:15 -08002187 {
2188 LoggerState pi1_logger = MakeLogger(pi1_);
2189
2190 event_loop_factory_.RunFor(chrono::milliseconds(95));
2191
2192 StartLogger(&pi1_logger);
2193
2194 event_loop_factory_.RunFor(chrono::milliseconds(10000));
2195 }
2196
2197 // Confirm that we can parse the result. LogReader has enough internal CHECKs
2198 // to confirm the right thing happened.
2199 ConfirmReadable(pi1_single_direction_logfiles_);
2200}
2201
Austin Schuhcdd90272021-03-15 12:46:16 -07002202constexpr std::string_view kCombinedConfigSha1(
Austin Schuhe61d4382021-03-31 21:33:02 -07002203 "0184681f8b83b5b9902a88ab12504c06b780907f6d156353bd958ebcf9389ef9");
Austin Schuhcdd90272021-03-15 12:46:16 -07002204constexpr std::string_view kSplitConfigSha1(
Austin Schuhe61d4382021-03-31 21:33:02 -07002205 "1020274679a8f8c15ea20a48e4a35dd59a435203e5f31a57e15355e5a6ee31f7");
Austin Schuhcdd90272021-03-15 12:46:16 -07002206
Austin Schuh61e973f2021-02-21 21:43:56 -08002207INSTANTIATE_TEST_CASE_P(
2208 All, MultinodeLoggerTest,
Austin Schuhcdd90272021-03-15 12:46:16 -07002209 ::testing::Values(Param{"multinode_pingpong_combined_config.json", true,
2210 kCombinedConfigSha1},
2211 Param{"multinode_pingpong_split_config.json", false,
2212 kSplitConfigSha1}));
Austin Schuh61e973f2021-02-21 21:43:56 -08002213
2214INSTANTIATE_TEST_CASE_P(
2215 All, MultinodeLoggerDeathTest,
Austin Schuhcdd90272021-03-15 12:46:16 -07002216 ::testing::Values(Param{"multinode_pingpong_combined_config.json", true,
2217 kCombinedConfigSha1},
2218 Param{"multinode_pingpong_split_config.json", false,
2219 kSplitConfigSha1}));
Austin Schuh61e973f2021-02-21 21:43:56 -08002220
Austin Schuha04efed2021-01-24 18:04:20 -08002221// TODO(austin): Make a log file where the remote node has no start time.
2222
Austin Schuhe309d2a2019-11-29 13:25:21 -08002223} // namespace testing
2224} // namespace logger
2225} // namespace aos