blob: 8115400728833ace47441008e8b11ae4baaa1dad [file] [log] [blame]
James Kuszmaul38735e82019-12-07 16:42:06 -08001#include "aos/events/logging/logger.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -08002
3#include "aos/events/event_loop.h"
Austin Schuh01b4c352020-09-21 23:09:39 -07004#include "aos/events/message_counter.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -08005#include "aos/events/ping_lib.h"
6#include "aos/events/pong_lib.h"
7#include "aos/events/simulated_event_loop.h"
Austin Schuh0de30f32020-12-06 12:44:28 -08008#include "aos/network/remote_message_generated.h"
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07009#include "aos/network/timestamp_generated.h"
Austin Schuhc243b422020-10-11 15:35:08 -070010#include "aos/testing/tmpdir.h"
Austin Schuh2f8fd752020-09-01 22:38:28 -070011#include "aos/util/file.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -080012#include "glog/logging.h"
Austin Schuh6f3babe2020-01-26 20:34:50 -080013#include "gmock/gmock.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -080014#include "gtest/gtest.h"
15
Austin Schuh3bd4c402020-11-06 18:19:06 -080016#ifdef LZMA
17#include "aos/events/logging/lzma_encoder.h"
18#endif
19
Austin Schuhe309d2a2019-11-29 13:25:21 -080020namespace aos {
21namespace logger {
22namespace testing {
23
24namespace chrono = std::chrono;
Austin Schuh0de30f32020-12-06 12:44:28 -080025using aos::message_bridge::RemoteMessage;
Austin Schuh01b4c352020-09-21 23:09:39 -070026using aos::testing::MessageCounter;
Austin Schuhe309d2a2019-11-29 13:25:21 -080027
28class LoggerTest : public ::testing::Test {
29 public:
30 LoggerTest()
31 : config_(
32 aos::configuration::ReadConfig("aos/events/pingpong_config.json")),
33 event_loop_factory_(&config_.message()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080034 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080035 ping_(ping_event_loop_.get()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080036 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080037 pong_(pong_event_loop_.get()) {}
38
39 // Config and factory.
40 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
41 SimulatedEventLoopFactory event_loop_factory_;
42
43 // Event loop and app for Ping
44 std::unique_ptr<EventLoop> ping_event_loop_;
45 Ping ping_;
46
47 // Event loop and app for Pong
48 std::unique_ptr<EventLoop> pong_event_loop_;
49 Pong pong_;
50};
51
Brian Silverman1f345222020-09-24 21:14:48 -070052using LoggerDeathTest = LoggerTest;
53
Austin Schuhe309d2a2019-11-29 13:25:21 -080054// Tests that we can startup at all. This confirms that the channels are all in
55// the config.
56TEST_F(LoggerTest, Starts) {
Austin Schuhc243b422020-10-11 15:35:08 -070057 const ::std::string tmpdir = aos::testing::TestTmpDir();
Austin Schuh2f8fd752020-09-01 22:38:28 -070058 const ::std::string base_name = tmpdir + "/logfile";
59 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuhe309d2a2019-11-29 13:25:21 -080060 // Remove it.
61 unlink(logfile.c_str());
62
63 LOG(INFO) << "Logging data to " << logfile;
64
65 {
Austin Schuhe309d2a2019-11-29 13:25:21 -080066 std::unique_ptr<EventLoop> logger_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080067 event_loop_factory_.MakeEventLoop("logger");
Austin Schuhe309d2a2019-11-29 13:25:21 -080068
69 event_loop_factory_.RunFor(chrono::milliseconds(95));
70
Brian Silverman1f345222020-09-24 21:14:48 -070071 Logger logger(logger_event_loop.get());
72 logger.set_polling_period(std::chrono::milliseconds(100));
73 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuhe309d2a2019-11-29 13:25:21 -080074 event_loop_factory_.RunFor(chrono::milliseconds(20000));
75 }
76
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080077 // Even though it doesn't make any difference here, exercise the logic for
78 // passing in a separate config.
79 LogReader reader(logfile, &config_.message());
Austin Schuhe309d2a2019-11-29 13:25:21 -080080
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080081 // Confirm that we can remap logged channels to point to new buses.
82 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
Austin Schuhe309d2a2019-11-29 13:25:21 -080083
Austin Schuh15649d62019-12-28 16:36:38 -080084 // This sends out the fetched messages and advances time to the start of the
85 // log file.
James Kuszmaul84ff3e52020-01-03 19:48:53 -080086 reader.Register();
Austin Schuhe309d2a2019-11-29 13:25:21 -080087
Austin Schuh6f3babe2020-01-26 20:34:50 -080088 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
James Kuszmaul84ff3e52020-01-03 19:48:53 -080089
Austin Schuhe309d2a2019-11-29 13:25:21 -080090 std::unique_ptr<EventLoop> test_event_loop =
James Kuszmaul84ff3e52020-01-03 19:48:53 -080091 reader.event_loop_factory()->MakeEventLoop("log_reader");
Austin Schuhe309d2a2019-11-29 13:25:21 -080092
93 int ping_count = 10;
94 int pong_count = 10;
95
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080096 // Confirm that the ping value matches in the remapped channel location.
97 test_event_loop->MakeWatcher("/original/test",
Austin Schuhe309d2a2019-11-29 13:25:21 -080098 [&ping_count](const examples::Ping &ping) {
99 EXPECT_EQ(ping.value(), ping_count + 1);
100 ++ping_count;
101 });
102 // Confirm that the ping and pong counts both match, and the value also
103 // matches.
104 test_event_loop->MakeWatcher(
105 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
106 EXPECT_EQ(pong.value(), pong_count + 1);
107 ++pong_count;
108 EXPECT_EQ(ping_count, pong_count);
109 });
110
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800111 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
Austin Schuhe309d2a2019-11-29 13:25:21 -0800112 EXPECT_EQ(ping_count, 2010);
Austin Schuhe309d2a2019-11-29 13:25:21 -0800113}
114
Brian Silverman1f345222020-09-24 21:14:48 -0700115// Tests calling StartLogging twice.
116TEST_F(LoggerDeathTest, ExtraStart) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800117 const ::std::string tmpdir = aos::testing::TestTmpDir();
Brian Silverman1f345222020-09-24 21:14:48 -0700118 const ::std::string base_name1 = tmpdir + "/logfile1";
119 const ::std::string logfile1 = base_name1 + ".part0.bfbs";
120 const ::std::string base_name2 = tmpdir + "/logfile2";
121 const ::std::string logfile2 = base_name2 + ".part0.bfbs";
122 unlink(logfile1.c_str());
123 unlink(logfile2.c_str());
124
125 LOG(INFO) << "Logging data to " << logfile1 << " then " << logfile2;
126
127 {
128 std::unique_ptr<EventLoop> logger_event_loop =
129 event_loop_factory_.MakeEventLoop("logger");
130
131 event_loop_factory_.RunFor(chrono::milliseconds(95));
132
133 Logger logger(logger_event_loop.get());
134 logger.set_polling_period(std::chrono::milliseconds(100));
135 logger_event_loop->OnRun(
136 [base_name1, base_name2, &logger_event_loop, &logger]() {
137 logger.StartLogging(std::make_unique<LocalLogNamer>(
138 base_name1, logger_event_loop->node()));
139 EXPECT_DEATH(logger.StartLogging(std::make_unique<LocalLogNamer>(
140 base_name2, logger_event_loop->node())),
141 "Already logging");
142 });
143 event_loop_factory_.RunFor(chrono::milliseconds(20000));
144 }
145}
146
147// Tests calling StopLogging twice.
148TEST_F(LoggerDeathTest, ExtraStop) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800149 const ::std::string tmpdir = aos::testing::TestTmpDir();
Brian Silverman1f345222020-09-24 21:14:48 -0700150 const ::std::string base_name = tmpdir + "/logfile";
151 const ::std::string logfile = base_name + ".part0.bfbs";
152 // Remove it.
153 unlink(logfile.c_str());
154
155 LOG(INFO) << "Logging data to " << logfile;
156
157 {
158 std::unique_ptr<EventLoop> logger_event_loop =
159 event_loop_factory_.MakeEventLoop("logger");
160
161 event_loop_factory_.RunFor(chrono::milliseconds(95));
162
163 Logger logger(logger_event_loop.get());
164 logger.set_polling_period(std::chrono::milliseconds(100));
165 logger_event_loop->OnRun([base_name, &logger_event_loop, &logger]() {
166 logger.StartLogging(std::make_unique<LocalLogNamer>(
167 base_name, logger_event_loop->node()));
168 logger.StopLogging(aos::monotonic_clock::min_time);
169 EXPECT_DEATH(logger.StopLogging(aos::monotonic_clock::min_time),
170 "Not logging right now");
171 });
172 event_loop_factory_.RunFor(chrono::milliseconds(20000));
173 }
174}
175
176// Tests that we can startup twice.
177TEST_F(LoggerTest, StartsTwice) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800178 const ::std::string tmpdir = aos::testing::TestTmpDir();
Brian Silverman1f345222020-09-24 21:14:48 -0700179 const ::std::string base_name1 = tmpdir + "/logfile1";
180 const ::std::string logfile1 = base_name1 + ".part0.bfbs";
181 const ::std::string base_name2 = tmpdir + "/logfile2";
182 const ::std::string logfile2 = base_name2 + ".part0.bfbs";
183 unlink(logfile1.c_str());
184 unlink(logfile2.c_str());
185
186 LOG(INFO) << "Logging data to " << logfile1 << " then " << logfile2;
187
188 {
189 std::unique_ptr<EventLoop> logger_event_loop =
190 event_loop_factory_.MakeEventLoop("logger");
191
192 event_loop_factory_.RunFor(chrono::milliseconds(95));
193
194 Logger logger(logger_event_loop.get());
195 logger.set_polling_period(std::chrono::milliseconds(100));
196 logger.StartLogging(
197 std::make_unique<LocalLogNamer>(base_name1, logger_event_loop->node()));
198 event_loop_factory_.RunFor(chrono::milliseconds(10000));
199 logger.StopLogging(logger_event_loop->monotonic_now());
200 event_loop_factory_.RunFor(chrono::milliseconds(10000));
201 logger.StartLogging(
202 std::make_unique<LocalLogNamer>(base_name2, logger_event_loop->node()));
203 event_loop_factory_.RunFor(chrono::milliseconds(10000));
204 }
205
206 for (const auto &logfile :
207 {std::make_tuple(logfile1, 10), std::make_tuple(logfile2, 2010)}) {
208 SCOPED_TRACE(std::get<0>(logfile));
209 LogReader reader(std::get<0>(logfile));
210 reader.Register();
211
212 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
213
214 std::unique_ptr<EventLoop> test_event_loop =
215 reader.event_loop_factory()->MakeEventLoop("log_reader");
216
217 int ping_count = std::get<1>(logfile);
218 int pong_count = std::get<1>(logfile);
219
220 // Confirm that the ping and pong counts both match, and the value also
221 // matches.
222 test_event_loop->MakeWatcher("/test",
223 [&ping_count](const examples::Ping &ping) {
224 EXPECT_EQ(ping.value(), ping_count + 1);
225 ++ping_count;
226 });
227 test_event_loop->MakeWatcher(
228 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
229 EXPECT_EQ(pong.value(), pong_count + 1);
230 ++pong_count;
231 EXPECT_EQ(ping_count, pong_count);
232 });
233
234 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
235 EXPECT_EQ(ping_count, std::get<1>(logfile) + 1000);
236 }
237}
238
Austin Schuhfa895892020-01-07 20:07:41 -0800239// Tests that we can read and write rotated log files.
240TEST_F(LoggerTest, RotatedLogFile) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800241 const ::std::string tmpdir = aos::testing::TestTmpDir();
Austin Schuh2f8fd752020-09-01 22:38:28 -0700242 const ::std::string base_name = tmpdir + "/logfile";
243 const ::std::string logfile0 = base_name + ".part0.bfbs";
244 const ::std::string logfile1 = base_name + ".part1.bfbs";
Austin Schuhfa895892020-01-07 20:07:41 -0800245 // Remove it.
246 unlink(logfile0.c_str());
247 unlink(logfile1.c_str());
248
249 LOG(INFO) << "Logging data to " << logfile0 << " and " << logfile1;
250
251 {
Austin Schuhfa895892020-01-07 20:07:41 -0800252 std::unique_ptr<EventLoop> logger_event_loop =
253 event_loop_factory_.MakeEventLoop("logger");
254
255 event_loop_factory_.RunFor(chrono::milliseconds(95));
256
Brian Silverman1f345222020-09-24 21:14:48 -0700257 Logger logger(logger_event_loop.get());
258 logger.set_polling_period(std::chrono::milliseconds(100));
259 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuhfa895892020-01-07 20:07:41 -0800260 event_loop_factory_.RunFor(chrono::milliseconds(10000));
Austin Schuh2f8fd752020-09-01 22:38:28 -0700261 logger.Rotate();
Austin Schuhfa895892020-01-07 20:07:41 -0800262 event_loop_factory_.RunFor(chrono::milliseconds(10000));
263 }
264
Austin Schuh64fab802020-09-09 22:47:47 -0700265 {
266 // Confirm that the UUIDs match for both the parts and the logger, and the
267 // parts_index increments.
Austin Schuhadd6eb32020-11-09 21:24:26 -0800268 std::vector<SizePrefixedFlatbufferVector<LogFileHeader>> log_header;
Austin Schuh64fab802020-09-09 22:47:47 -0700269 for (std::string_view f : {logfile0, logfile1}) {
Austin Schuh3bd4c402020-11-06 18:19:06 -0800270 log_header.emplace_back(ReadHeader(f).value());
Austin Schuh64fab802020-09-09 22:47:47 -0700271 }
272
Brian Silvermanae7c0332020-09-30 16:58:23 -0700273 EXPECT_EQ(log_header[0].message().log_event_uuid()->string_view(),
274 log_header[1].message().log_event_uuid()->string_view());
Austin Schuh64fab802020-09-09 22:47:47 -0700275 EXPECT_EQ(log_header[0].message().parts_uuid()->string_view(),
276 log_header[1].message().parts_uuid()->string_view());
277
278 EXPECT_EQ(log_header[0].message().parts_index(), 0);
279 EXPECT_EQ(log_header[1].message().parts_index(), 1);
280 }
281
Austin Schuhfa895892020-01-07 20:07:41 -0800282 // Even though it doesn't make any difference here, exercise the logic for
283 // passing in a separate config.
Austin Schuh287d43d2020-12-04 20:19:33 -0800284 LogReader reader(SortParts({logfile0, logfile1}), &config_.message());
Austin Schuhfa895892020-01-07 20:07:41 -0800285
286 // Confirm that we can remap logged channels to point to new buses.
287 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
288
289 // This sends out the fetched messages and advances time to the start of the
290 // log file.
291 reader.Register();
292
Austin Schuh6f3babe2020-01-26 20:34:50 -0800293 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
Austin Schuhfa895892020-01-07 20:07:41 -0800294
295 std::unique_ptr<EventLoop> test_event_loop =
296 reader.event_loop_factory()->MakeEventLoop("log_reader");
297
298 int ping_count = 10;
299 int pong_count = 10;
300
301 // Confirm that the ping value matches in the remapped channel location.
302 test_event_loop->MakeWatcher("/original/test",
303 [&ping_count](const examples::Ping &ping) {
304 EXPECT_EQ(ping.value(), ping_count + 1);
305 ++ping_count;
306 });
307 // Confirm that the ping and pong counts both match, and the value also
308 // matches.
309 test_event_loop->MakeWatcher(
310 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
311 EXPECT_EQ(pong.value(), pong_count + 1);
312 ++pong_count;
313 EXPECT_EQ(ping_count, pong_count);
314 });
315
316 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
317 EXPECT_EQ(ping_count, 2010);
318}
319
Austin Schuh4c4e0092019-12-22 16:18:03 -0800320// Tests that a large number of messages per second doesn't overwhelm writev.
321TEST_F(LoggerTest, ManyMessages) {
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800322 const ::std::string tmpdir = aos::testing::TestTmpDir();
Austin Schuh2f8fd752020-09-01 22:38:28 -0700323 const ::std::string base_name = tmpdir + "/logfile";
324 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuh4c4e0092019-12-22 16:18:03 -0800325 // Remove the log file.
326 unlink(logfile.c_str());
327
328 LOG(INFO) << "Logging data to " << logfile;
Austin Schuh4c3b9702020-08-30 11:34:55 -0700329 ping_.set_quiet(true);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800330
331 {
Austin Schuh4c4e0092019-12-22 16:18:03 -0800332 std::unique_ptr<EventLoop> logger_event_loop =
333 event_loop_factory_.MakeEventLoop("logger");
334
335 std::unique_ptr<EventLoop> ping_spammer_event_loop =
336 event_loop_factory_.MakeEventLoop("ping_spammer");
337 aos::Sender<examples::Ping> ping_sender =
338 ping_spammer_event_loop->MakeSender<examples::Ping>("/test");
339
340 aos::TimerHandler *timer_handler =
341 ping_spammer_event_loop->AddTimer([&ping_sender]() {
342 aos::Sender<examples::Ping>::Builder builder =
343 ping_sender.MakeBuilder();
344 examples::Ping::Builder ping_builder =
345 builder.MakeBuilder<examples::Ping>();
346 CHECK(builder.Send(ping_builder.Finish()));
347 });
348
349 // 100 ms / 0.05 ms -> 2000 messages. Should be enough to crash it.
350 ping_spammer_event_loop->OnRun([&ping_spammer_event_loop, timer_handler]() {
351 timer_handler->Setup(ping_spammer_event_loop->monotonic_now(),
352 chrono::microseconds(50));
353 });
354
Brian Silverman1f345222020-09-24 21:14:48 -0700355 Logger logger(logger_event_loop.get());
356 logger.set_polling_period(std::chrono::milliseconds(100));
357 logger.StartLoggingLocalNamerOnRun(base_name);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800358
359 event_loop_factory_.RunFor(chrono::milliseconds(1000));
360 }
361}
362
Austin Schuh15649d62019-12-28 16:36:38 -0800363class MultinodeLoggerTest : public ::testing::Test {
364 public:
365 MultinodeLoggerTest()
366 : config_(aos::configuration::ReadConfig(
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800367 "aos/events/logging/multinode_pingpong_config.json")),
Austin Schuhac0771c2020-01-07 18:36:30 -0800368 event_loop_factory_(&config_.message()),
Austin Schuhcde938c2020-02-02 17:30:07 -0800369 pi1_(
370 configuration::GetNode(event_loop_factory_.configuration(), "pi1")),
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700371 pi2_(
372 configuration::GetNode(event_loop_factory_.configuration(), "pi2")),
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800373 tmp_dir_(aos::testing::TestTmpDir()),
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700374 logfile_base_(tmp_dir_ + "/multi_logfile"),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700375 logfiles_(
376 {logfile_base_ + "_pi1_data.part0.bfbs",
377 logfile_base_ + "_pi2_data/test/aos.examples.Pong.part0.bfbs",
378 logfile_base_ + "_pi2_data/test/aos.examples.Pong.part1.bfbs",
379 logfile_base_ + "_pi2_data.part0.bfbs",
380 logfile_base_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
Austin Schuh0de30f32020-12-06 12:44:28 -0800381 "aos.message_bridge.RemoteMessage.part0.bfbs",
Austin Schuh2f8fd752020-09-01 22:38:28 -0700382 logfile_base_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
Austin Schuh0de30f32020-12-06 12:44:28 -0800383 "aos.message_bridge.RemoteMessage.part1.bfbs",
Austin Schuh2f8fd752020-09-01 22:38:28 -0700384 logfile_base_ + "_timestamps/pi2/aos/remote_timestamps/pi1/"
Austin Schuh0de30f32020-12-06 12:44:28 -0800385 "aos.message_bridge.RemoteMessage.part0.bfbs",
Austin Schuh2f8fd752020-09-01 22:38:28 -0700386 logfile_base_ + "_timestamps/pi2/aos/remote_timestamps/pi1/"
Austin Schuh0de30f32020-12-06 12:44:28 -0800387 "aos.message_bridge.RemoteMessage.part1.bfbs",
Austin Schuh2f8fd752020-09-01 22:38:28 -0700388 logfile_base_ +
389 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part0.bfbs",
390 logfile_base_ +
391 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part1.bfbs",
392 logfile_base_ +
393 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part0.bfbs",
394 logfile_base_ +
395 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part1.bfbs"}),
396 structured_logfiles_{
397 std::vector<std::string>{logfiles_[0]},
398 std::vector<std::string>{logfiles_[1], logfiles_[2]},
399 std::vector<std::string>{logfiles_[3]},
400 std::vector<std::string>{logfiles_[4], logfiles_[5]},
401 std::vector<std::string>{logfiles_[6], logfiles_[7]},
402 std::vector<std::string>{logfiles_[8], logfiles_[9]},
403 std::vector<std::string>{logfiles_[10], logfiles_[11]}},
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700404 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping", pi1_)),
405 ping_(ping_event_loop_.get()),
406 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong", pi2_)),
407 pong_(pong_event_loop_.get()) {
408 // Go through and remove the logfiles if they already exist.
409 for (const auto file : logfiles_) {
410 unlink(file.c_str());
Austin Schuhc6f8f1b2020-12-02 23:23:39 -0800411 unlink((file + ".xz").c_str());
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700412 }
413
414 LOG(INFO) << "Logging data to " << logfiles_[0] << ", " << logfiles_[1]
415 << " and " << logfiles_[2];
416 }
417
418 struct LoggerState {
419 std::unique_ptr<EventLoop> event_loop;
420 std::unique_ptr<Logger> logger;
421 };
422
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700423 LoggerState MakeLogger(const Node *node,
424 SimulatedEventLoopFactory *factory = nullptr) {
425 if (factory == nullptr) {
426 factory = &event_loop_factory_;
427 }
428 return {factory->MakeEventLoop("logger", node), {}};
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700429 }
430
Austin Schuh3bd4c402020-11-06 18:19:06 -0800431 void StartLogger(LoggerState *logger, std::string logfile_base = "",
432 bool compress = false) {
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700433 if (logfile_base.empty()) {
434 logfile_base = logfile_base_;
435 }
436
Brian Silverman1f345222020-09-24 21:14:48 -0700437 logger->logger = std::make_unique<Logger>(logger->event_loop.get());
438 logger->logger->set_polling_period(std::chrono::milliseconds(100));
Austin Schuh3bd4c402020-11-06 18:19:06 -0800439 logger->event_loop->OnRun([logger, logfile_base, compress]() {
440 std::unique_ptr<MultiNodeLogNamer> namer =
441 std::make_unique<MultiNodeLogNamer>(
442 logfile_base, logger->event_loop->configuration(),
443 logger->event_loop->node());
444 if (compress) {
445#ifdef LZMA
446 namer->set_extension(".xz");
447 namer->set_encoder_factory(
448 []() { return std::make_unique<aos::logger::LzmaEncoder>(3); });
449#else
450 LOG(FATAL) << "Compression unsupported";
451#endif
452 }
453
454 logger->logger->StartLogging(std::move(namer));
Brian Silverman1f345222020-09-24 21:14:48 -0700455 });
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700456 }
Austin Schuh15649d62019-12-28 16:36:38 -0800457
Austin Schuh3bd4c402020-11-06 18:19:06 -0800458 void VerifyParts(const std::vector<LogFile> &sorted_parts,
459 const std::vector<std::string> &corrupted_parts = {}) {
460 EXPECT_EQ(sorted_parts.size(), 2u);
461
462 // Count up the number of UUIDs and make sure they are what we expect as a
463 // sanity check.
464 std::set<std::string> log_event_uuids;
465 std::set<std::string> parts_uuids;
466 std::set<std::string> both_uuids;
467
468 size_t missing_rt_count = 0;
469
470 std::vector<std::string> logger_nodes;
471 for (const LogFile &log_file : sorted_parts) {
472 EXPECT_FALSE(log_file.log_event_uuid.empty());
473 log_event_uuids.insert(log_file.log_event_uuid);
474 logger_nodes.emplace_back(log_file.logger_node);
475 both_uuids.insert(log_file.log_event_uuid);
476
477 for (const LogParts &part : log_file.parts) {
478 EXPECT_NE(part.monotonic_start_time, aos::monotonic_clock::min_time)
479 << ": " << part;
480 missing_rt_count +=
481 part.realtime_start_time == aos::realtime_clock::min_time;
482
483 EXPECT_TRUE(log_event_uuids.find(part.log_event_uuid) !=
484 log_event_uuids.end());
485 EXPECT_NE(part.node, "");
486 parts_uuids.insert(part.parts_uuid);
487 both_uuids.insert(part.parts_uuid);
488 }
489 }
490
491 // We won't have RT timestamps for 5 log files. We don't log the RT start
492 // time on remote nodes because we don't know it and would be guessing. And
493 // the log reader can actually do a better job.
494 EXPECT_EQ(missing_rt_count, 5u);
495
496 EXPECT_EQ(log_event_uuids.size(), 2u);
497 EXPECT_EQ(parts_uuids.size(), ToLogReaderVector(sorted_parts).size());
498 EXPECT_EQ(log_event_uuids.size() + parts_uuids.size(), both_uuids.size());
499
500 // Test that each list of parts is in order. Don't worry about the ordering
501 // between part file lists though.
502 // (inner vectors all need to be in order, but outer one doesn't matter).
503 EXPECT_THAT(ToLogReaderVector(sorted_parts),
504 ::testing::UnorderedElementsAreArray(structured_logfiles_));
505
506 EXPECT_THAT(logger_nodes, ::testing::UnorderedElementsAre("pi1", "pi2"));
507
508 EXPECT_NE(sorted_parts[0].realtime_start_time,
509 aos::realtime_clock::min_time);
510 EXPECT_NE(sorted_parts[1].realtime_start_time,
511 aos::realtime_clock::min_time);
512
513 EXPECT_NE(sorted_parts[0].monotonic_start_time,
514 aos::monotonic_clock::min_time);
515 EXPECT_NE(sorted_parts[1].monotonic_start_time,
516 aos::monotonic_clock::min_time);
517
518 EXPECT_THAT(sorted_parts[0].corrupted, ::testing::Eq(corrupted_parts));
519 EXPECT_THAT(sorted_parts[1].corrupted, ::testing::Eq(corrupted_parts));
520 }
521
522 void AddExtension(std::string_view extension) {
523 std::transform(logfiles_.begin(), logfiles_.end(), logfiles_.begin(),
524 [extension](const std::string &in) {
525 return absl::StrCat(in, extension);
526 });
527
528 std::transform(structured_logfiles_.begin(), structured_logfiles_.end(),
529 structured_logfiles_.begin(),
530 [extension](std::vector<std::string> in) {
531 std::transform(in.begin(), in.end(), in.begin(),
532 [extension](const std::string &in_str) {
533 return absl::StrCat(in_str, extension);
534 });
535 return in;
536 });
537 }
538
Austin Schuh15649d62019-12-28 16:36:38 -0800539 // Config and factory.
540 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
541 SimulatedEventLoopFactory event_loop_factory_;
542
Austin Schuhcde938c2020-02-02 17:30:07 -0800543 const Node *pi1_;
544 const Node *pi2_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700545
546 std::string tmp_dir_;
547 std::string logfile_base_;
Austin Schuh2f8fd752020-09-01 22:38:28 -0700548 std::vector<std::string> logfiles_;
549
550 std::vector<std::vector<std::string>> structured_logfiles_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700551
552 std::unique_ptr<EventLoop> ping_event_loop_;
553 Ping ping_;
554 std::unique_ptr<EventLoop> pong_event_loop_;
555 Pong pong_;
Austin Schuh15649d62019-12-28 16:36:38 -0800556};
557
Austin Schuh391e3172020-09-01 22:48:18 -0700558// Counts the number of messages on a channel. Returns (channel name, channel
559// type, count) for every message matching matcher()
560std::vector<std::tuple<std::string, std::string, int>> CountChannelsMatching(
Austin Schuh6f3babe2020-01-26 20:34:50 -0800561 std::string_view filename,
562 std::function<bool(const MessageHeader *)> matcher) {
563 MessageReader message_reader(filename);
564 std::vector<int> counts(
565 message_reader.log_file_header()->configuration()->channels()->size(), 0);
Austin Schuh15649d62019-12-28 16:36:38 -0800566
Austin Schuh6f3babe2020-01-26 20:34:50 -0800567 while (true) {
Austin Schuhadd6eb32020-11-09 21:24:26 -0800568 std::optional<SizePrefixedFlatbufferVector<MessageHeader>> msg =
Austin Schuh6f3babe2020-01-26 20:34:50 -0800569 message_reader.ReadMessage();
570 if (!msg) {
571 break;
572 }
573
574 if (matcher(&msg.value().message())) {
575 counts[msg.value().message().channel_index()]++;
576 }
577 }
578
Austin Schuh391e3172020-09-01 22:48:18 -0700579 std::vector<std::tuple<std::string, std::string, int>> result;
Austin Schuh6f3babe2020-01-26 20:34:50 -0800580 int channel = 0;
581 for (size_t i = 0; i < counts.size(); ++i) {
582 if (counts[i] != 0) {
Austin Schuh391e3172020-09-01 22:48:18 -0700583 const Channel *channel =
584 message_reader.log_file_header()->configuration()->channels()->Get(i);
585 result.push_back(std::make_tuple(channel->name()->str(),
586 channel->type()->str(), counts[i]));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800587 }
588 ++channel;
589 }
590
591 return result;
592}
593
594// Counts the number of messages (channel, count) for all data messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700595std::vector<std::tuple<std::string, std::string, int>> CountChannelsData(
596 std::string_view filename) {
Austin Schuh6f3babe2020-01-26 20:34:50 -0800597 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
598 if (msg->has_data()) {
599 CHECK(!msg->has_monotonic_remote_time());
600 CHECK(!msg->has_realtime_remote_time());
601 CHECK(!msg->has_remote_queue_index());
602 return true;
603 }
604 return false;
605 });
606}
607
608// Counts the number of messages (channel, count) for all timestamp messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700609std::vector<std::tuple<std::string, std::string, int>> CountChannelsTimestamp(
Austin Schuh6f3babe2020-01-26 20:34:50 -0800610 std::string_view filename) {
611 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
612 if (!msg->has_data()) {
613 CHECK(msg->has_monotonic_remote_time());
614 CHECK(msg->has_realtime_remote_time());
615 CHECK(msg->has_remote_queue_index());
616 return true;
617 }
618 return false;
619 });
620}
621
Austin Schuhcde938c2020-02-02 17:30:07 -0800622// Tests that we can write and read simple multi-node log files.
623TEST_F(MultinodeLoggerTest, SimpleMultiNode) {
Austin Schuh15649d62019-12-28 16:36:38 -0800624 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700625 LoggerState pi1_logger = MakeLogger(pi1_);
626 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuh15649d62019-12-28 16:36:38 -0800627
628 event_loop_factory_.RunFor(chrono::milliseconds(95));
629
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700630 StartLogger(&pi1_logger);
631 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800632
Austin Schuh15649d62019-12-28 16:36:38 -0800633 event_loop_factory_.RunFor(chrono::milliseconds(20000));
634 }
635
Austin Schuh6f3babe2020-01-26 20:34:50 -0800636 {
Austin Schuh64fab802020-09-09 22:47:47 -0700637 std::set<std::string> logfile_uuids;
638 std::set<std::string> parts_uuids;
639 // Confirm that we have the expected number of UUIDs for both the logfile
640 // UUIDs and parts UUIDs.
Austin Schuhadd6eb32020-11-09 21:24:26 -0800641 std::vector<SizePrefixedFlatbufferVector<LogFileHeader>> log_header;
Austin Schuh64fab802020-09-09 22:47:47 -0700642 for (std::string_view f : logfiles_) {
Austin Schuh3bd4c402020-11-06 18:19:06 -0800643 log_header.emplace_back(ReadHeader(f).value());
Brian Silvermanae7c0332020-09-30 16:58:23 -0700644 logfile_uuids.insert(log_header.back().message().log_event_uuid()->str());
Austin Schuh64fab802020-09-09 22:47:47 -0700645 parts_uuids.insert(log_header.back().message().parts_uuid()->str());
646 }
Austin Schuh15649d62019-12-28 16:36:38 -0800647
Austin Schuh64fab802020-09-09 22:47:47 -0700648 EXPECT_EQ(logfile_uuids.size(), 2u);
649 EXPECT_EQ(parts_uuids.size(), 7u);
650
651 // And confirm everything is on the correct node.
652 EXPECT_EQ(log_header[0].message().node()->name()->string_view(), "pi1");
653 EXPECT_EQ(log_header[1].message().node()->name()->string_view(), "pi2");
654 EXPECT_EQ(log_header[2].message().node()->name()->string_view(), "pi2");
655 EXPECT_EQ(log_header[3].message().node()->name()->string_view(), "pi2");
656 EXPECT_EQ(log_header[4].message().node()->name()->string_view(), "pi2");
657 EXPECT_EQ(log_header[5].message().node()->name()->string_view(), "pi2");
658 EXPECT_EQ(log_header[6].message().node()->name()->string_view(), "pi1");
659 EXPECT_EQ(log_header[7].message().node()->name()->string_view(), "pi1");
660 EXPECT_EQ(log_header[8].message().node()->name()->string_view(), "pi1");
661 EXPECT_EQ(log_header[9].message().node()->name()->string_view(), "pi1");
662 EXPECT_EQ(log_header[10].message().node()->name()->string_view(), "pi2");
663 EXPECT_EQ(log_header[11].message().node()->name()->string_view(), "pi2");
664
665 // And the parts index matches.
666 EXPECT_EQ(log_header[0].message().parts_index(), 0);
667 EXPECT_EQ(log_header[1].message().parts_index(), 0);
668 EXPECT_EQ(log_header[2].message().parts_index(), 1);
669 EXPECT_EQ(log_header[3].message().parts_index(), 0);
670 EXPECT_EQ(log_header[4].message().parts_index(), 0);
671 EXPECT_EQ(log_header[5].message().parts_index(), 1);
672 EXPECT_EQ(log_header[6].message().parts_index(), 0);
673 EXPECT_EQ(log_header[7].message().parts_index(), 1);
674 EXPECT_EQ(log_header[8].message().parts_index(), 0);
675 EXPECT_EQ(log_header[9].message().parts_index(), 1);
676 EXPECT_EQ(log_header[10].message().parts_index(), 0);
677 EXPECT_EQ(log_header[11].message().parts_index(), 1);
678 }
679
680 {
Austin Schuh391e3172020-09-01 22:48:18 -0700681 using ::testing::UnorderedElementsAre;
682
Austin Schuh6f3babe2020-01-26 20:34:50 -0800683 // Timing reports, pings
Austin Schuh2f8fd752020-09-01 22:38:28 -0700684 EXPECT_THAT(
685 CountChannelsData(logfiles_[0]),
686 UnorderedElementsAre(
687 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200),
688 std::make_tuple("/pi1/aos", "aos.timing.Report", 40),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800689 std::make_tuple("/test", "aos.examples.Ping", 2001)))
690 << " : " << logfiles_[0];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800691 // Timestamps for pong
Austin Schuh2f8fd752020-09-01 22:38:28 -0700692 EXPECT_THAT(
693 CountChannelsTimestamp(logfiles_[0]),
694 UnorderedElementsAre(
695 std::make_tuple("/test", "aos.examples.Pong", 2001),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800696 std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200)))
697 << " : " << logfiles_[0];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800698
699 // Pong data.
Austin Schuh20ac95d2020-12-05 17:24:19 -0800700 EXPECT_THAT(
701 CountChannelsData(logfiles_[1]),
702 UnorderedElementsAre(std::make_tuple("/test", "aos.examples.Pong", 91)))
703 << " : " << logfiles_[1];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700704 EXPECT_THAT(CountChannelsData(logfiles_[2]),
705 UnorderedElementsAre(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800706 std::make_tuple("/test", "aos.examples.Pong", 1910)))
707 << " : " << logfiles_[1];
Austin Schuh391e3172020-09-01 22:48:18 -0700708
Austin Schuh6f3babe2020-01-26 20:34:50 -0800709 // No timestamps
Austin Schuh20ac95d2020-12-05 17:24:19 -0800710 EXPECT_THAT(CountChannelsTimestamp(logfiles_[1]), UnorderedElementsAre())
711 << " : " << logfiles_[1];
712 EXPECT_THAT(CountChannelsTimestamp(logfiles_[2]), UnorderedElementsAre())
713 << " : " << logfiles_[2];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800714
715 // Timing reports and pongs.
Austin Schuh2f8fd752020-09-01 22:38:28 -0700716 EXPECT_THAT(
717 CountChannelsData(logfiles_[3]),
718 UnorderedElementsAre(
719 std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200),
720 std::make_tuple("/pi2/aos", "aos.timing.Report", 40),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800721 std::make_tuple("/test", "aos.examples.Pong", 2001)))
722 << " : " << logfiles_[3];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800723 // And ping timestamps.
Austin Schuh2f8fd752020-09-01 22:38:28 -0700724 EXPECT_THAT(
725 CountChannelsTimestamp(logfiles_[3]),
726 UnorderedElementsAre(
727 std::make_tuple("/test", "aos.examples.Ping", 2001),
Austin Schuh20ac95d2020-12-05 17:24:19 -0800728 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200)))
729 << " : " << logfiles_[3];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700730
731 // Timestamps from pi2 on pi1, and the other way.
Austin Schuh20ac95d2020-12-05 17:24:19 -0800732 EXPECT_THAT(CountChannelsData(logfiles_[4]), UnorderedElementsAre())
733 << " : " << logfiles_[4];
734 EXPECT_THAT(CountChannelsData(logfiles_[5]), UnorderedElementsAre())
735 << " : " << logfiles_[5];
736 EXPECT_THAT(CountChannelsData(logfiles_[6]), UnorderedElementsAre())
737 << " : " << logfiles_[6];
738 EXPECT_THAT(CountChannelsData(logfiles_[7]), UnorderedElementsAre())
739 << " : " << logfiles_[7];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700740 EXPECT_THAT(
741 CountChannelsTimestamp(logfiles_[4]),
742 UnorderedElementsAre(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800743 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 9),
744 std::make_tuple("/test", "aos.examples.Ping", 91)))
745 << " : " << logfiles_[4];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700746 EXPECT_THAT(
747 CountChannelsTimestamp(logfiles_[5]),
748 UnorderedElementsAre(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800749 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 191),
750 std::make_tuple("/test", "aos.examples.Ping", 1910)))
751 << " : " << logfiles_[5];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700752 EXPECT_THAT(CountChannelsTimestamp(logfiles_[6]),
753 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800754 "/pi2/aos", "aos.message_bridge.Timestamp", 9)))
755 << " : " << logfiles_[6];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700756 EXPECT_THAT(CountChannelsTimestamp(logfiles_[7]),
757 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800758 "/pi2/aos", "aos.message_bridge.Timestamp", 191)))
759 << " : " << logfiles_[7];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700760
761 // And then test that the remotely logged timestamp data files only have
762 // timestamps in them.
Austin Schuh20ac95d2020-12-05 17:24:19 -0800763 EXPECT_THAT(CountChannelsTimestamp(logfiles_[8]), UnorderedElementsAre())
764 << " : " << logfiles_[8];
765 EXPECT_THAT(CountChannelsTimestamp(logfiles_[9]), UnorderedElementsAre())
766 << " : " << logfiles_[9];
767 EXPECT_THAT(CountChannelsTimestamp(logfiles_[10]), UnorderedElementsAre())
768 << " : " << logfiles_[10];
769 EXPECT_THAT(CountChannelsTimestamp(logfiles_[11]), UnorderedElementsAre())
770 << " : " << logfiles_[11];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700771
772 EXPECT_THAT(CountChannelsData(logfiles_[8]),
773 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800774 "/pi1/aos", "aos.message_bridge.Timestamp", 9)))
775 << " : " << logfiles_[8];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700776 EXPECT_THAT(CountChannelsData(logfiles_[9]),
777 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800778 "/pi1/aos", "aos.message_bridge.Timestamp", 191)))
779 << " : " << logfiles_[9];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700780
781 EXPECT_THAT(CountChannelsData(logfiles_[10]),
782 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800783 "/pi2/aos", "aos.message_bridge.Timestamp", 9)))
784 << " : " << logfiles_[10];
Austin Schuh2f8fd752020-09-01 22:38:28 -0700785 EXPECT_THAT(CountChannelsData(logfiles_[11]),
786 UnorderedElementsAre(std::make_tuple(
Austin Schuh20ac95d2020-12-05 17:24:19 -0800787 "/pi2/aos", "aos.message_bridge.Timestamp", 191)))
788 << " : " << logfiles_[11];
Austin Schuh6f3babe2020-01-26 20:34:50 -0800789 }
790
Austin Schuh287d43d2020-12-04 20:19:33 -0800791 LogReader reader(SortParts(logfiles_));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800792
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700793 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuh6331ef92020-01-07 18:28:09 -0800794 log_reader_factory.set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800795
796 // This sends out the fetched messages and advances time to the start of the
797 // log file.
Austin Schuh6331ef92020-01-07 18:28:09 -0800798 reader.Register(&log_reader_factory);
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800799
Austin Schuhac0771c2020-01-07 18:36:30 -0800800 const Node *pi1 =
801 configuration::GetNode(log_reader_factory.configuration(), "pi1");
Austin Schuh6f3babe2020-01-26 20:34:50 -0800802 const Node *pi2 =
803 configuration::GetNode(log_reader_factory.configuration(), "pi2");
Austin Schuhac0771c2020-01-07 18:36:30 -0800804
Austin Schuh2f8fd752020-09-01 22:38:28 -0700805 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
806 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
807 LOG(INFO) << "now pi1 "
808 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
809 LOG(INFO) << "now pi2 "
810 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
811
Austin Schuh6f3babe2020-01-26 20:34:50 -0800812 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800813
814 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800815
Austin Schuh6f3babe2020-01-26 20:34:50 -0800816 std::unique_ptr<EventLoop> pi1_event_loop =
Austin Schuhac0771c2020-01-07 18:36:30 -0800817 log_reader_factory.MakeEventLoop("test", pi1);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800818 std::unique_ptr<EventLoop> pi2_event_loop =
819 log_reader_factory.MakeEventLoop("test", pi2);
Austin Schuh15649d62019-12-28 16:36:38 -0800820
Austin Schuh6f3babe2020-01-26 20:34:50 -0800821 int pi1_ping_count = 10;
822 int pi2_ping_count = 10;
823 int pi1_pong_count = 10;
824 int pi2_pong_count = 10;
Austin Schuh15649d62019-12-28 16:36:38 -0800825
826 // Confirm that the ping value matches.
Austin Schuh6f3babe2020-01-26 20:34:50 -0800827 pi1_event_loop->MakeWatcher(
828 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
Austin Schuh2f8fd752020-09-01 22:38:28 -0700829 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping) << " at "
Austin Schuh6f3babe2020-01-26 20:34:50 -0800830 << pi1_event_loop->context().monotonic_remote_time << " -> "
831 << pi1_event_loop->context().monotonic_event_time;
832 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
833 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
834 pi1_ping_count * chrono::milliseconds(10) +
835 monotonic_clock::epoch());
836 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
837 pi1_ping_count * chrono::milliseconds(10) +
838 realtime_clock::epoch());
839 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
840 pi1_event_loop->context().monotonic_event_time);
841 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
842 pi1_event_loop->context().realtime_event_time);
Austin Schuh15649d62019-12-28 16:36:38 -0800843
Austin Schuh6f3babe2020-01-26 20:34:50 -0800844 ++pi1_ping_count;
845 });
846 pi2_event_loop->MakeWatcher(
847 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
Austin Schuh2f8fd752020-09-01 22:38:28 -0700848 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping) << " at "
Austin Schuh6f3babe2020-01-26 20:34:50 -0800849 << pi2_event_loop->context().monotonic_remote_time << " -> "
850 << pi2_event_loop->context().monotonic_event_time;
851 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
852
853 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
854 pi2_ping_count * chrono::milliseconds(10) +
855 monotonic_clock::epoch());
856 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
857 pi2_ping_count * chrono::milliseconds(10) +
858 realtime_clock::epoch());
859 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time +
860 chrono::microseconds(150),
861 pi2_event_loop->context().monotonic_event_time);
862 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time +
863 chrono::microseconds(150),
864 pi2_event_loop->context().realtime_event_time);
865 ++pi2_ping_count;
Austin Schuh15649d62019-12-28 16:36:38 -0800866 });
867
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700868 constexpr ssize_t kQueueIndexOffset = -9;
Austin Schuh6f3babe2020-01-26 20:34:50 -0800869 // Confirm that the ping and pong counts both match, and the value also
870 // matches.
871 pi1_event_loop->MakeWatcher(
872 "/test", [&pi1_event_loop, &pi1_ping_count,
873 &pi1_pong_count](const examples::Pong &pong) {
874 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
875 << pi1_event_loop->context().monotonic_remote_time << " -> "
876 << pi1_event_loop->context().monotonic_event_time;
877
878 EXPECT_EQ(pi1_event_loop->context().remote_queue_index,
879 pi1_pong_count + kQueueIndexOffset);
880 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
881 chrono::microseconds(200) +
882 pi1_pong_count * chrono::milliseconds(10) +
883 monotonic_clock::epoch());
884 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
885 chrono::microseconds(200) +
886 pi1_pong_count * chrono::milliseconds(10) +
887 realtime_clock::epoch());
888
889 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time +
890 chrono::microseconds(150),
891 pi1_event_loop->context().monotonic_event_time);
892 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time +
893 chrono::microseconds(150),
894 pi1_event_loop->context().realtime_event_time);
895
896 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
897 ++pi1_pong_count;
898 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
899 });
900 pi2_event_loop->MakeWatcher(
901 "/test", [&pi2_event_loop, &pi2_ping_count,
902 &pi2_pong_count](const examples::Pong &pong) {
903 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
904 << pi2_event_loop->context().monotonic_remote_time << " -> "
905 << pi2_event_loop->context().monotonic_event_time;
906
907 EXPECT_EQ(pi2_event_loop->context().remote_queue_index,
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700908 pi2_pong_count + kQueueIndexOffset);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800909
910 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
911 chrono::microseconds(200) +
912 pi2_pong_count * chrono::milliseconds(10) +
913 monotonic_clock::epoch());
914 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
915 chrono::microseconds(200) +
916 pi2_pong_count * chrono::milliseconds(10) +
917 realtime_clock::epoch());
918
919 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
920 pi2_event_loop->context().monotonic_event_time);
921 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
922 pi2_event_loop->context().realtime_event_time);
923
924 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
925 ++pi2_pong_count;
926 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
927 });
928
929 log_reader_factory.Run();
930 EXPECT_EQ(pi1_ping_count, 2010);
931 EXPECT_EQ(pi2_ping_count, 2010);
932 EXPECT_EQ(pi1_pong_count, 2010);
933 EXPECT_EQ(pi2_pong_count, 2010);
Austin Schuh6331ef92020-01-07 18:28:09 -0800934
935 reader.Deregister();
Austin Schuh15649d62019-12-28 16:36:38 -0800936}
937
James Kuszmaul46d82582020-05-09 19:50:09 -0700938typedef MultinodeLoggerTest MultinodeLoggerDeathTest;
939
940// Test that if we feed the replay with a mismatched node list that we die on
941// the LogReader constructor.
942TEST_F(MultinodeLoggerDeathTest, MultiNodeBadReplayConfig) {
James Kuszmaul46d82582020-05-09 19:50:09 -0700943 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700944 LoggerState pi1_logger = MakeLogger(pi1_);
945 LoggerState pi2_logger = MakeLogger(pi2_);
James Kuszmaul46d82582020-05-09 19:50:09 -0700946
947 event_loop_factory_.RunFor(chrono::milliseconds(95));
948
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700949 StartLogger(&pi1_logger);
950 StartLogger(&pi2_logger);
James Kuszmaul46d82582020-05-09 19:50:09 -0700951
James Kuszmaul46d82582020-05-09 19:50:09 -0700952 event_loop_factory_.RunFor(chrono::milliseconds(20000));
953 }
954
955 // Test that, if we add an additional node to the replay config that the
956 // logger complains about the mismatch in number of nodes.
957 FlatbufferDetachedBuffer<Configuration> extra_nodes_config =
958 configuration::MergeWithConfig(&config_.message(), R"({
959 "nodes": [
960 {
961 "name": "extra-node"
962 }
963 ]
964 }
965 )");
966
Austin Schuh287d43d2020-12-04 20:19:33 -0800967 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
968 EXPECT_DEATH(LogReader(sorted_parts, &extra_nodes_config.message()),
James Kuszmaul46d82582020-05-09 19:50:09 -0700969 "Log file and replay config need to have matching nodes lists.");
James Kuszmaul46d82582020-05-09 19:50:09 -0700970}
971
Austin Schuhcde938c2020-02-02 17:30:07 -0800972// Tests that we can read log files where they don't start at the same monotonic
973// time.
974TEST_F(MultinodeLoggerTest, StaggeredStart) {
Austin Schuhcde938c2020-02-02 17:30:07 -0800975 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700976 LoggerState pi1_logger = MakeLogger(pi1_);
977 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuhcde938c2020-02-02 17:30:07 -0800978
979 event_loop_factory_.RunFor(chrono::milliseconds(95));
980
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700981 StartLogger(&pi1_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800982
983 event_loop_factory_.RunFor(chrono::milliseconds(200));
984
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700985 StartLogger(&pi2_logger);
986
Austin Schuhcde938c2020-02-02 17:30:07 -0800987 event_loop_factory_.RunFor(chrono::milliseconds(20000));
988 }
989
Austin Schuh287d43d2020-12-04 20:19:33 -0800990 LogReader reader(SortParts(logfiles_));
Austin Schuhcde938c2020-02-02 17:30:07 -0800991
Austin Schuh8d7e0bb2020-10-02 17:57:00 -0700992 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuhcde938c2020-02-02 17:30:07 -0800993 log_reader_factory.set_send_delay(chrono::microseconds(0));
994
995 // This sends out the fetched messages and advances time to the start of the
996 // log file.
997 reader.Register(&log_reader_factory);
998
999 const Node *pi1 =
1000 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1001 const Node *pi2 =
1002 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1003
1004 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1005
1006 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1007
1008 std::unique_ptr<EventLoop> pi1_event_loop =
1009 log_reader_factory.MakeEventLoop("test", pi1);
1010 std::unique_ptr<EventLoop> pi2_event_loop =
1011 log_reader_factory.MakeEventLoop("test", pi2);
1012
1013 int pi1_ping_count = 30;
1014 int pi2_ping_count = 30;
1015 int pi1_pong_count = 30;
1016 int pi2_pong_count = 30;
1017
1018 // Confirm that the ping value matches.
1019 pi1_event_loop->MakeWatcher(
1020 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
1021 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
1022 << pi1_event_loop->context().monotonic_remote_time << " -> "
1023 << pi1_event_loop->context().monotonic_event_time;
1024 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
1025
1026 ++pi1_ping_count;
1027 });
1028 pi2_event_loop->MakeWatcher(
1029 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
1030 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
1031 << pi2_event_loop->context().monotonic_remote_time << " -> "
1032 << pi2_event_loop->context().monotonic_event_time;
1033 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
1034
1035 ++pi2_ping_count;
1036 });
1037
1038 // Confirm that the ping and pong counts both match, and the value also
1039 // matches.
1040 pi1_event_loop->MakeWatcher(
1041 "/test", [&pi1_event_loop, &pi1_ping_count,
1042 &pi1_pong_count](const examples::Pong &pong) {
1043 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
1044 << pi1_event_loop->context().monotonic_remote_time << " -> "
1045 << pi1_event_loop->context().monotonic_event_time;
1046
1047 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
1048 ++pi1_pong_count;
1049 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
1050 });
1051 pi2_event_loop->MakeWatcher(
1052 "/test", [&pi2_event_loop, &pi2_ping_count,
1053 &pi2_pong_count](const examples::Pong &pong) {
1054 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
1055 << pi2_event_loop->context().monotonic_remote_time << " -> "
1056 << pi2_event_loop->context().monotonic_event_time;
1057
1058 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1059 ++pi2_pong_count;
1060 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1061 });
1062
1063 log_reader_factory.Run();
1064 EXPECT_EQ(pi1_ping_count, 2030);
1065 EXPECT_EQ(pi2_ping_count, 2030);
1066 EXPECT_EQ(pi1_pong_count, 2030);
1067 EXPECT_EQ(pi2_pong_count, 2030);
1068
1069 reader.Deregister();
1070}
Austin Schuh6f3babe2020-01-26 20:34:50 -08001071
Austin Schuh8bd96322020-02-13 21:18:22 -08001072// Tests that we can read log files where the monotonic clocks drift and don't
1073// match correctly. While we are here, also test that different ending times
1074// also is readable.
1075TEST_F(MultinodeLoggerTest, MismatchedClocks) {
Austin Schuhcde938c2020-02-02 17:30:07 -08001076 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001077 LoggerState pi2_logger = MakeLogger(pi2_);
1078
Austin Schuh8bd96322020-02-13 21:18:22 -08001079 NodeEventLoopFactory *pi2 =
1080 event_loop_factory_.GetNodeEventLoopFactory(pi2_);
1081 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
1082 << pi2->realtime_now() << " distributed "
1083 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -08001084
Austin Schuh8bd96322020-02-13 21:18:22 -08001085 const chrono::nanoseconds initial_pi2_offset = -chrono::seconds(1000);
1086 chrono::nanoseconds pi2_offset = initial_pi2_offset;
Austin Schuhcde938c2020-02-02 17:30:07 -08001087
Austin Schuhbe69cf32020-08-27 11:38:33 -07001088 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -08001089 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
1090 << pi2->realtime_now() << " distributed "
1091 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -08001092
Austin Schuh8bd96322020-02-13 21:18:22 -08001093 for (int i = 0; i < 95; ++i) {
1094 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -07001095 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -08001096 event_loop_factory_.RunFor(chrono::milliseconds(1));
1097 }
Austin Schuhcde938c2020-02-02 17:30:07 -08001098
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001099 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -08001100
Austin Schuh8bd96322020-02-13 21:18:22 -08001101 event_loop_factory_.RunFor(chrono::milliseconds(200));
Austin Schuhcde938c2020-02-02 17:30:07 -08001102
Austin Schuh8bd96322020-02-13 21:18:22 -08001103 {
1104 // Run pi1's logger for only part of the time.
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001105 LoggerState pi1_logger = MakeLogger(pi1_);
Austin Schuh8bd96322020-02-13 21:18:22 -08001106
James Kuszmaulbb28ef22020-05-09 22:30:38 -07001107 StartLogger(&pi1_logger);
Austin Schuh8bd96322020-02-13 21:18:22 -08001108
1109 for (int i = 0; i < 20000; ++i) {
1110 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -07001111 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -08001112 event_loop_factory_.RunFor(chrono::milliseconds(1));
1113 }
1114
1115 EXPECT_GT(pi2_offset - initial_pi2_offset,
1116 event_loop_factory_.send_delay() +
1117 event_loop_factory_.network_delay());
1118
1119 for (int i = 0; i < 40000; ++i) {
1120 pi2_offset -= chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -07001121 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -08001122 event_loop_factory_.RunFor(chrono::milliseconds(1));
1123 }
1124 }
1125
1126 // And log a bit more on pi2.
1127 event_loop_factory_.RunFor(chrono::milliseconds(400));
Austin Schuhcde938c2020-02-02 17:30:07 -08001128 }
1129
Austin Schuh287d43d2020-12-04 20:19:33 -08001130 LogReader reader(SortParts(logfiles_));
Austin Schuhcde938c2020-02-02 17:30:07 -08001131
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001132 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
Austin Schuhcde938c2020-02-02 17:30:07 -08001133 log_reader_factory.set_send_delay(chrono::microseconds(0));
1134
Austin Schuhcde938c2020-02-02 17:30:07 -08001135 const Node *pi1 =
1136 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1137 const Node *pi2 =
1138 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1139
Austin Schuh2f8fd752020-09-01 22:38:28 -07001140 // This sends out the fetched messages and advances time to the start of the
1141 // log file.
1142 reader.Register(&log_reader_factory);
1143
1144 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
1145 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
1146 LOG(INFO) << "now pi1 "
1147 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
1148 LOG(INFO) << "now pi2 "
1149 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
1150
Austin Schuhcde938c2020-02-02 17:30:07 -08001151 LOG(INFO) << "Done registering (pi1) "
Austin Schuh391e3172020-09-01 22:48:18 -07001152 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now()
1153 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -08001154 << log_reader_factory.GetNodeEventLoopFactory(pi1)->realtime_now();
1155 LOG(INFO) << "Done registering (pi2) "
Austin Schuh391e3172020-09-01 22:48:18 -07001156 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now()
1157 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -08001158 << log_reader_factory.GetNodeEventLoopFactory(pi2)->realtime_now();
1159
1160 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1161
1162 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1163
1164 std::unique_ptr<EventLoop> pi1_event_loop =
1165 log_reader_factory.MakeEventLoop("test", pi1);
1166 std::unique_ptr<EventLoop> pi2_event_loop =
1167 log_reader_factory.MakeEventLoop("test", pi2);
1168
1169 int pi1_ping_count = 30;
1170 int pi2_ping_count = 30;
1171 int pi1_pong_count = 30;
1172 int pi2_pong_count = 30;
1173
1174 // Confirm that the ping value matches.
1175 pi1_event_loop->MakeWatcher(
1176 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
1177 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
1178 << pi1_event_loop->context().monotonic_remote_time << " -> "
1179 << pi1_event_loop->context().monotonic_event_time;
1180 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
1181
1182 ++pi1_ping_count;
1183 });
1184 pi2_event_loop->MakeWatcher(
1185 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
1186 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
1187 << pi2_event_loop->context().monotonic_remote_time << " -> "
1188 << pi2_event_loop->context().monotonic_event_time;
1189 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
1190
1191 ++pi2_ping_count;
1192 });
1193
1194 // Confirm that the ping and pong counts both match, and the value also
1195 // matches.
1196 pi1_event_loop->MakeWatcher(
1197 "/test", [&pi1_event_loop, &pi1_ping_count,
1198 &pi1_pong_count](const examples::Pong &pong) {
1199 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
1200 << pi1_event_loop->context().monotonic_remote_time << " -> "
1201 << pi1_event_loop->context().monotonic_event_time;
1202
1203 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
1204 ++pi1_pong_count;
1205 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
1206 });
1207 pi2_event_loop->MakeWatcher(
1208 "/test", [&pi2_event_loop, &pi2_ping_count,
1209 &pi2_pong_count](const examples::Pong &pong) {
1210 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
1211 << pi2_event_loop->context().monotonic_remote_time << " -> "
1212 << pi2_event_loop->context().monotonic_event_time;
1213
1214 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
1215 ++pi2_pong_count;
1216 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
1217 });
1218
1219 log_reader_factory.Run();
Austin Schuh8bd96322020-02-13 21:18:22 -08001220 EXPECT_EQ(pi1_ping_count, 6030);
1221 EXPECT_EQ(pi2_ping_count, 6030);
1222 EXPECT_EQ(pi1_pong_count, 6030);
1223 EXPECT_EQ(pi2_pong_count, 6030);
Austin Schuhcde938c2020-02-02 17:30:07 -08001224
1225 reader.Deregister();
1226}
1227
Austin Schuh5212cad2020-09-09 23:12:09 -07001228// Tests that we can sort a bunch of parts into the pre-determined sorted parts.
1229TEST_F(MultinodeLoggerTest, SortParts) {
1230 // Make a bunch of parts.
1231 {
1232 LoggerState pi1_logger = MakeLogger(pi1_);
1233 LoggerState pi2_logger = MakeLogger(pi2_);
1234
1235 event_loop_factory_.RunFor(chrono::milliseconds(95));
1236
1237 StartLogger(&pi1_logger);
1238 StartLogger(&pi2_logger);
1239
1240 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1241 }
1242
Austin Schuh11d43732020-09-21 17:28:30 -07001243 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
Austin Schuh3bd4c402020-11-06 18:19:06 -08001244 VerifyParts(sorted_parts);
1245}
Austin Schuh11d43732020-09-21 17:28:30 -07001246
Austin Schuh3bd4c402020-11-06 18:19:06 -08001247// Tests that we can sort a bunch of parts with an empty part. We should ignore
1248// it and remove it from the sorted list.
1249TEST_F(MultinodeLoggerTest, SortEmptyParts) {
1250 // Make a bunch of parts.
1251 {
1252 LoggerState pi1_logger = MakeLogger(pi1_);
1253 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuh11d43732020-09-21 17:28:30 -07001254
Austin Schuh3bd4c402020-11-06 18:19:06 -08001255 event_loop_factory_.RunFor(chrono::milliseconds(95));
Austin Schuh11d43732020-09-21 17:28:30 -07001256
Austin Schuh3bd4c402020-11-06 18:19:06 -08001257 StartLogger(&pi1_logger);
1258 StartLogger(&pi2_logger);
Austin Schuh11d43732020-09-21 17:28:30 -07001259
Austin Schuh3bd4c402020-11-06 18:19:06 -08001260 event_loop_factory_.RunFor(chrono::milliseconds(2000));
Austin Schuh11d43732020-09-21 17:28:30 -07001261 }
1262
Austin Schuh3bd4c402020-11-06 18:19:06 -08001263 // TODO(austin): Should we flip out if the file can't open?
1264 const std::string kEmptyFile("foobarinvalidfiledoesnotexist.bfbs");
Austin Schuh11d43732020-09-21 17:28:30 -07001265
Austin Schuh3bd4c402020-11-06 18:19:06 -08001266 aos::util::WriteStringToFileOrDie(kEmptyFile, "");
1267 logfiles_.emplace_back(kEmptyFile);
Austin Schuh5212cad2020-09-09 23:12:09 -07001268
Austin Schuh3bd4c402020-11-06 18:19:06 -08001269 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1270 VerifyParts(sorted_parts, {kEmptyFile});
Austin Schuh5212cad2020-09-09 23:12:09 -07001271}
1272
Austin Schuh3bd4c402020-11-06 18:19:06 -08001273#ifdef LZMA
1274// Tests that we can sort a bunch of parts with an empty .xz file in there. The
1275// empty file should be ignored.
1276TEST_F(MultinodeLoggerTest, SortEmptyCompressedParts) {
1277 // Make a bunch of parts.
1278 {
1279 LoggerState pi1_logger = MakeLogger(pi1_);
1280 LoggerState pi2_logger = MakeLogger(pi2_);
1281
1282 event_loop_factory_.RunFor(chrono::milliseconds(95));
1283
1284 StartLogger(&pi1_logger, "", true);
1285 StartLogger(&pi2_logger, "", true);
1286
1287 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1288 }
1289
1290 // TODO(austin): Should we flip out if the file can't open?
1291 const std::string kEmptyFile("foobarinvalidfiledoesnotexist.bfbs.xz");
1292
1293 AddExtension(".xz");
1294
1295 aos::util::WriteStringToFileOrDie(kEmptyFile, "");
1296 logfiles_.emplace_back(kEmptyFile);
1297
1298 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1299 VerifyParts(sorted_parts, {kEmptyFile});
1300}
1301
1302// Tests that we can sort a bunch of parts with the end missing off a compressed
1303// file. We should use the part we can read.
1304TEST_F(MultinodeLoggerTest, SortTruncatedCompressedParts) {
1305 // Make a bunch of parts.
1306 {
1307 LoggerState pi1_logger = MakeLogger(pi1_);
1308 LoggerState pi2_logger = MakeLogger(pi2_);
1309
1310 event_loop_factory_.RunFor(chrono::milliseconds(95));
1311
1312 StartLogger(&pi1_logger, "", true);
1313 StartLogger(&pi2_logger, "", true);
1314
1315 event_loop_factory_.RunFor(chrono::milliseconds(2000));
1316 }
1317
1318 // Append everything with .xz.
1319 AddExtension(".xz");
1320
1321 // Strip off the end of one of the files. Pick one with a lot of data.
1322 ::std::string compressed_contents =
1323 aos::util::ReadFileToStringOrDie(logfiles_[0]);
1324
1325 aos::util::WriteStringToFileOrDie(
1326 logfiles_[0],
1327 compressed_contents.substr(0, compressed_contents.size() - 100));
1328
1329 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
1330 VerifyParts(sorted_parts);
1331}
1332#endif
1333
Austin Schuh01b4c352020-09-21 23:09:39 -07001334// Tests that if we remap a remapped channel, it shows up correctly.
1335TEST_F(MultinodeLoggerTest, RemapLoggedChannel) {
1336 {
1337 LoggerState pi1_logger = MakeLogger(pi1_);
1338 LoggerState pi2_logger = MakeLogger(pi2_);
1339
1340 event_loop_factory_.RunFor(chrono::milliseconds(95));
1341
1342 StartLogger(&pi1_logger);
1343 StartLogger(&pi2_logger);
1344
1345 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1346 }
1347
Austin Schuh287d43d2020-12-04 20:19:33 -08001348 LogReader reader(SortParts(logfiles_));
Austin Schuh01b4c352020-09-21 23:09:39 -07001349
1350 // Remap just on pi1.
1351 reader.RemapLoggedChannel<aos::timing::Report>(
1352 "/aos", configuration::GetNode(reader.configuration(), "pi1"));
1353
1354 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1355 log_reader_factory.set_send_delay(chrono::microseconds(0));
1356
1357 reader.Register(&log_reader_factory);
1358
1359 const Node *pi1 =
1360 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1361 const Node *pi2 =
1362 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1363
1364 // Confirm we can read the data on the remapped channel, just for pi1. Nothing
1365 // else should have moved.
1366 std::unique_ptr<EventLoop> pi1_event_loop =
1367 log_reader_factory.MakeEventLoop("test", pi1);
1368 pi1_event_loop->SkipTimingReport();
1369 std::unique_ptr<EventLoop> full_pi1_event_loop =
1370 log_reader_factory.MakeEventLoop("test", pi1);
1371 full_pi1_event_loop->SkipTimingReport();
1372 std::unique_ptr<EventLoop> pi2_event_loop =
1373 log_reader_factory.MakeEventLoop("test", pi2);
1374 pi2_event_loop->SkipTimingReport();
1375
1376 MessageCounter<aos::timing::Report> pi1_timing_report(pi1_event_loop.get(),
1377 "/aos");
1378 MessageCounter<aos::timing::Report> full_pi1_timing_report(
1379 full_pi1_event_loop.get(), "/pi1/aos");
1380 MessageCounter<aos::timing::Report> pi1_original_timing_report(
1381 pi1_event_loop.get(), "/original/aos");
1382 MessageCounter<aos::timing::Report> full_pi1_original_timing_report(
1383 full_pi1_event_loop.get(), "/original/pi1/aos");
1384 MessageCounter<aos::timing::Report> pi2_timing_report(pi2_event_loop.get(),
1385 "/aos");
1386
1387 log_reader_factory.Run();
1388
1389 EXPECT_EQ(pi1_timing_report.count(), 0u);
1390 EXPECT_EQ(full_pi1_timing_report.count(), 0u);
1391 EXPECT_NE(pi1_original_timing_report.count(), 0u);
1392 EXPECT_NE(full_pi1_original_timing_report.count(), 0u);
1393 EXPECT_NE(pi2_timing_report.count(), 0u);
1394
1395 reader.Deregister();
1396}
1397
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001398// Tests that we properly recreate forwarded timestamps when replaying a log.
1399// This should be enough that we can then re-run the logger and get a valid log
1400// back.
1401TEST_F(MultinodeLoggerTest, MessageHeader) {
1402 {
1403 LoggerState pi1_logger = MakeLogger(pi1_);
1404 LoggerState pi2_logger = MakeLogger(pi2_);
1405
1406 event_loop_factory_.RunFor(chrono::milliseconds(95));
1407
1408 StartLogger(&pi1_logger);
1409 StartLogger(&pi2_logger);
1410
1411 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1412 }
1413
Austin Schuh287d43d2020-12-04 20:19:33 -08001414 LogReader reader(SortParts(logfiles_));
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001415
1416 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1417 log_reader_factory.set_send_delay(chrono::microseconds(0));
1418
1419 // This sends out the fetched messages and advances time to the start of the
1420 // log file.
1421 reader.Register(&log_reader_factory);
1422
1423 const Node *pi1 =
1424 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1425 const Node *pi2 =
1426 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1427
1428 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
1429 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
1430 LOG(INFO) << "now pi1 "
1431 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
1432 LOG(INFO) << "now pi2 "
1433 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
1434
1435 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
1436
1437 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
1438
1439 std::unique_ptr<EventLoop> pi1_event_loop =
1440 log_reader_factory.MakeEventLoop("test", pi1);
1441 std::unique_ptr<EventLoop> pi2_event_loop =
1442 log_reader_factory.MakeEventLoop("test", pi2);
1443
Austin Schuh0de30f32020-12-06 12:44:28 -08001444 MessageCounter<RemoteMessage> pi1_original_message_header_counter(
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001445 pi1_event_loop.get(), "/original/aos/remote_timestamps/pi2");
Austin Schuh0de30f32020-12-06 12:44:28 -08001446 MessageCounter<RemoteMessage> pi2_original_message_header_counter(
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001447 pi2_event_loop.get(), "/original/aos/remote_timestamps/pi1");
1448
1449 aos::Fetcher<message_bridge::Timestamp> pi1_timestamp_on_pi1_fetcher =
1450 pi1_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi1/aos");
1451 aos::Fetcher<message_bridge::Timestamp> pi1_timestamp_on_pi2_fetcher =
1452 pi2_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi1/aos");
1453
1454 aos::Fetcher<examples::Ping> ping_on_pi1_fetcher =
1455 pi1_event_loop->MakeFetcher<examples::Ping>("/test");
1456 aos::Fetcher<examples::Ping> ping_on_pi2_fetcher =
1457 pi2_event_loop->MakeFetcher<examples::Ping>("/test");
1458
1459 aos::Fetcher<message_bridge::Timestamp> pi2_timestamp_on_pi2_fetcher =
1460 pi2_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi2/aos");
1461 aos::Fetcher<message_bridge::Timestamp> pi2_timestamp_on_pi1_fetcher =
1462 pi1_event_loop->MakeFetcher<message_bridge::Timestamp>("/pi2/aos");
1463
1464 aos::Fetcher<examples::Pong> pong_on_pi2_fetcher =
1465 pi2_event_loop->MakeFetcher<examples::Pong>("/test");
1466 aos::Fetcher<examples::Pong> pong_on_pi1_fetcher =
1467 pi1_event_loop->MakeFetcher<examples::Pong>("/test");
1468
1469 const size_t pi1_timestamp_channel = configuration::ChannelIndex(
1470 pi1_event_loop->configuration(), pi1_timestamp_on_pi1_fetcher.channel());
1471 const size_t ping_timestamp_channel = configuration::ChannelIndex(
1472 pi2_event_loop->configuration(), ping_on_pi2_fetcher.channel());
1473
1474 const size_t pi2_timestamp_channel = configuration::ChannelIndex(
1475 pi2_event_loop->configuration(), pi2_timestamp_on_pi2_fetcher.channel());
1476 const size_t pong_timestamp_channel = configuration::ChannelIndex(
1477 pi1_event_loop->configuration(), pong_on_pi1_fetcher.channel());
1478
1479 pi1_event_loop->MakeWatcher(
1480 "/aos/remote_timestamps/pi2",
1481 [&pi1_event_loop, pi1_timestamp_channel, ping_timestamp_channel,
1482 &pi1_timestamp_on_pi1_fetcher, &pi1_timestamp_on_pi2_fetcher,
1483 &ping_on_pi1_fetcher,
Austin Schuh0de30f32020-12-06 12:44:28 -08001484 &ping_on_pi2_fetcher](const RemoteMessage &header) {
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001485 const aos::monotonic_clock::time_point header_monotonic_sent_time(
1486 chrono::nanoseconds(header.monotonic_sent_time()));
1487 const aos::realtime_clock::time_point header_realtime_sent_time(
1488 chrono::nanoseconds(header.realtime_sent_time()));
1489 const aos::monotonic_clock::time_point header_monotonic_remote_time(
1490 chrono::nanoseconds(header.monotonic_remote_time()));
1491 const aos::realtime_clock::time_point header_realtime_remote_time(
1492 chrono::nanoseconds(header.realtime_remote_time()));
1493
1494 const Context *pi1_context = nullptr;
1495 const Context *pi2_context = nullptr;
1496
1497 if (header.channel_index() == pi1_timestamp_channel) {
1498 ASSERT_TRUE(pi1_timestamp_on_pi1_fetcher.FetchNext());
1499 ASSERT_TRUE(pi1_timestamp_on_pi2_fetcher.FetchNext());
1500 pi1_context = &pi1_timestamp_on_pi1_fetcher.context();
1501 pi2_context = &pi1_timestamp_on_pi2_fetcher.context();
1502 } else if (header.channel_index() == ping_timestamp_channel) {
1503 ASSERT_TRUE(ping_on_pi1_fetcher.FetchNext());
1504 ASSERT_TRUE(ping_on_pi2_fetcher.FetchNext());
1505 pi1_context = &ping_on_pi1_fetcher.context();
1506 pi2_context = &ping_on_pi2_fetcher.context();
1507 } else {
1508 LOG(FATAL) << "Unknown channel " << FlatbufferToJson(&header) << " "
1509 << configuration::CleanedChannelToString(
1510 pi1_event_loop->configuration()->channels()->Get(
1511 header.channel_index()));
1512 }
1513
1514 EXPECT_EQ(pi1_context->queue_index, header.remote_queue_index());
1515 EXPECT_EQ(pi2_context->remote_queue_index, header.remote_queue_index());
1516 EXPECT_EQ(pi2_context->queue_index, header.queue_index());
1517
1518 EXPECT_EQ(pi2_context->monotonic_event_time,
1519 header_monotonic_sent_time);
1520 EXPECT_EQ(pi2_context->realtime_event_time, header_realtime_sent_time);
1521 EXPECT_EQ(pi2_context->realtime_remote_time,
1522 header_realtime_remote_time);
1523 EXPECT_EQ(pi2_context->monotonic_remote_time,
1524 header_monotonic_remote_time);
1525
1526 EXPECT_EQ(pi1_context->realtime_event_time,
1527 header_realtime_remote_time);
1528 EXPECT_EQ(pi1_context->monotonic_event_time,
1529 header_monotonic_remote_time);
1530 });
1531 pi2_event_loop->MakeWatcher(
1532 "/aos/remote_timestamps/pi1",
1533 [&pi2_event_loop, pi2_timestamp_channel, pong_timestamp_channel,
1534 &pi2_timestamp_on_pi2_fetcher, &pi2_timestamp_on_pi1_fetcher,
1535 &pong_on_pi2_fetcher,
Austin Schuh0de30f32020-12-06 12:44:28 -08001536 &pong_on_pi1_fetcher](const RemoteMessage &header) {
Austin Schuh8d7e0bb2020-10-02 17:57:00 -07001537 const aos::monotonic_clock::time_point header_monotonic_sent_time(
1538 chrono::nanoseconds(header.monotonic_sent_time()));
1539 const aos::realtime_clock::time_point header_realtime_sent_time(
1540 chrono::nanoseconds(header.realtime_sent_time()));
1541 const aos::monotonic_clock::time_point header_monotonic_remote_time(
1542 chrono::nanoseconds(header.monotonic_remote_time()));
1543 const aos::realtime_clock::time_point header_realtime_remote_time(
1544 chrono::nanoseconds(header.realtime_remote_time()));
1545
1546 const Context *pi2_context = nullptr;
1547 const Context *pi1_context = nullptr;
1548
1549 if (header.channel_index() == pi2_timestamp_channel) {
1550 ASSERT_TRUE(pi2_timestamp_on_pi2_fetcher.FetchNext());
1551 ASSERT_TRUE(pi2_timestamp_on_pi1_fetcher.FetchNext());
1552 pi2_context = &pi2_timestamp_on_pi2_fetcher.context();
1553 pi1_context = &pi2_timestamp_on_pi1_fetcher.context();
1554 } else if (header.channel_index() == pong_timestamp_channel) {
1555 ASSERT_TRUE(pong_on_pi2_fetcher.FetchNext());
1556 ASSERT_TRUE(pong_on_pi1_fetcher.FetchNext());
1557 pi2_context = &pong_on_pi2_fetcher.context();
1558 pi1_context = &pong_on_pi1_fetcher.context();
1559 } else {
1560 LOG(FATAL) << "Unknown channel " << FlatbufferToJson(&header) << " "
1561 << configuration::CleanedChannelToString(
1562 pi2_event_loop->configuration()->channels()->Get(
1563 header.channel_index()));
1564 }
1565
1566 EXPECT_EQ(pi2_context->queue_index, header.remote_queue_index());
1567 EXPECT_EQ(pi1_context->remote_queue_index, header.remote_queue_index());
1568 EXPECT_EQ(pi1_context->queue_index, header.queue_index());
1569
1570 EXPECT_EQ(pi1_context->monotonic_event_time,
1571 header_monotonic_sent_time);
1572 EXPECT_EQ(pi1_context->realtime_event_time, header_realtime_sent_time);
1573 EXPECT_EQ(pi1_context->realtime_remote_time,
1574 header_realtime_remote_time);
1575 EXPECT_EQ(pi1_context->monotonic_remote_time,
1576 header_monotonic_remote_time);
1577
1578 EXPECT_EQ(pi2_context->realtime_event_time,
1579 header_realtime_remote_time);
1580 EXPECT_EQ(pi2_context->monotonic_event_time,
1581 header_monotonic_remote_time);
1582 });
1583
1584 // And confirm we can re-create a log again, while checking the contents.
1585 {
1586 LoggerState pi1_logger = MakeLogger(
1587 configuration::GetNode(log_reader_factory.configuration(), pi1_),
1588 &log_reader_factory);
1589 LoggerState pi2_logger = MakeLogger(
1590 configuration::GetNode(log_reader_factory.configuration(), pi2_),
1591 &log_reader_factory);
1592
1593 StartLogger(&pi1_logger, "relogged");
1594 StartLogger(&pi2_logger, "relogged");
1595
1596 log_reader_factory.Run();
1597 }
1598
1599 EXPECT_EQ(pi2_original_message_header_counter.count(), 0u);
1600 EXPECT_EQ(pi1_original_message_header_counter.count(), 0u);
1601
1602 reader.Deregister();
1603}
1604
Austin Schuh8bd96322020-02-13 21:18:22 -08001605// TODO(austin): We can write a test which recreates a logfile and confirms that
1606// we get it back. That is the ultimate test.
1607
Austin Schuhe309d2a2019-11-29 13:25:21 -08001608} // namespace testing
1609} // namespace logger
1610} // namespace aos