blob: d4b6424ef2cd9b8925492b7bcd117a15c1a80dbe [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 Schuh2f8fd752020-09-01 22:38:28 -07008#include "aos/util/file.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -08009#include "glog/logging.h"
Austin Schuh6f3babe2020-01-26 20:34:50 -080010#include "gmock/gmock.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -080011#include "gtest/gtest.h"
12
13namespace aos {
14namespace logger {
15namespace testing {
16
17namespace chrono = std::chrono;
Austin Schuh01b4c352020-09-21 23:09:39 -070018using aos::testing::MessageCounter;
Austin Schuhe309d2a2019-11-29 13:25:21 -080019
20class LoggerTest : public ::testing::Test {
21 public:
22 LoggerTest()
23 : config_(
24 aos::configuration::ReadConfig("aos/events/pingpong_config.json")),
25 event_loop_factory_(&config_.message()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080026 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080027 ping_(ping_event_loop_.get()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080028 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080029 pong_(pong_event_loop_.get()) {}
30
31 // Config and factory.
32 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
33 SimulatedEventLoopFactory event_loop_factory_;
34
35 // Event loop and app for Ping
36 std::unique_ptr<EventLoop> ping_event_loop_;
37 Ping ping_;
38
39 // Event loop and app for Pong
40 std::unique_ptr<EventLoop> pong_event_loop_;
41 Pong pong_;
42};
43
44// Tests that we can startup at all. This confirms that the channels are all in
45// the config.
46TEST_F(LoggerTest, Starts) {
47 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
Austin Schuh2f8fd752020-09-01 22:38:28 -070048 const ::std::string base_name = tmpdir + "/logfile";
49 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuhe309d2a2019-11-29 13:25:21 -080050 // Remove it.
51 unlink(logfile.c_str());
52
53 LOG(INFO) << "Logging data to " << logfile;
54
55 {
Austin Schuhe309d2a2019-11-29 13:25:21 -080056 std::unique_ptr<EventLoop> logger_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080057 event_loop_factory_.MakeEventLoop("logger");
Austin Schuhe309d2a2019-11-29 13:25:21 -080058
59 event_loop_factory_.RunFor(chrono::milliseconds(95));
60
Austin Schuh2f8fd752020-09-01 22:38:28 -070061 Logger logger(base_name, logger_event_loop.get(),
Austin Schuhe309d2a2019-11-29 13:25:21 -080062 std::chrono::milliseconds(100));
63 event_loop_factory_.RunFor(chrono::milliseconds(20000));
64 }
65
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080066 // Even though it doesn't make any difference here, exercise the logic for
67 // passing in a separate config.
68 LogReader reader(logfile, &config_.message());
Austin Schuhe309d2a2019-11-29 13:25:21 -080069
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080070 // Confirm that we can remap logged channels to point to new buses.
71 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
Austin Schuhe309d2a2019-11-29 13:25:21 -080072
Austin Schuh15649d62019-12-28 16:36:38 -080073 // This sends out the fetched messages and advances time to the start of the
74 // log file.
James Kuszmaul84ff3e52020-01-03 19:48:53 -080075 reader.Register();
Austin Schuhe309d2a2019-11-29 13:25:21 -080076
Austin Schuh6f3babe2020-01-26 20:34:50 -080077 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
James Kuszmaul84ff3e52020-01-03 19:48:53 -080078
Austin Schuhe309d2a2019-11-29 13:25:21 -080079 std::unique_ptr<EventLoop> test_event_loop =
James Kuszmaul84ff3e52020-01-03 19:48:53 -080080 reader.event_loop_factory()->MakeEventLoop("log_reader");
Austin Schuhe309d2a2019-11-29 13:25:21 -080081
82 int ping_count = 10;
83 int pong_count = 10;
84
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080085 // Confirm that the ping value matches in the remapped channel location.
86 test_event_loop->MakeWatcher("/original/test",
Austin Schuhe309d2a2019-11-29 13:25:21 -080087 [&ping_count](const examples::Ping &ping) {
88 EXPECT_EQ(ping.value(), ping_count + 1);
89 ++ping_count;
90 });
91 // Confirm that the ping and pong counts both match, and the value also
92 // matches.
93 test_event_loop->MakeWatcher(
94 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
95 EXPECT_EQ(pong.value(), pong_count + 1);
96 ++pong_count;
97 EXPECT_EQ(ping_count, pong_count);
98 });
99
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800100 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
Austin Schuhe309d2a2019-11-29 13:25:21 -0800101 EXPECT_EQ(ping_count, 2010);
Austin Schuhe309d2a2019-11-29 13:25:21 -0800102}
103
Austin Schuhfa895892020-01-07 20:07:41 -0800104// Tests that we can read and write rotated log files.
105TEST_F(LoggerTest, RotatedLogFile) {
106 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
Austin Schuh2f8fd752020-09-01 22:38:28 -0700107 const ::std::string base_name = tmpdir + "/logfile";
108 const ::std::string logfile0 = base_name + ".part0.bfbs";
109 const ::std::string logfile1 = base_name + ".part1.bfbs";
Austin Schuhfa895892020-01-07 20:07:41 -0800110 // Remove it.
111 unlink(logfile0.c_str());
112 unlink(logfile1.c_str());
113
114 LOG(INFO) << "Logging data to " << logfile0 << " and " << logfile1;
115
116 {
Austin Schuhfa895892020-01-07 20:07:41 -0800117 std::unique_ptr<EventLoop> logger_event_loop =
118 event_loop_factory_.MakeEventLoop("logger");
119
120 event_loop_factory_.RunFor(chrono::milliseconds(95));
121
Austin Schuh2f8fd752020-09-01 22:38:28 -0700122 Logger logger(
123 std::make_unique<LocalLogNamer>(base_name, logger_event_loop->node()),
124 logger_event_loop.get(), std::chrono::milliseconds(100));
Austin Schuhfa895892020-01-07 20:07:41 -0800125 event_loop_factory_.RunFor(chrono::milliseconds(10000));
Austin Schuh2f8fd752020-09-01 22:38:28 -0700126 logger.Rotate();
Austin Schuhfa895892020-01-07 20:07:41 -0800127 event_loop_factory_.RunFor(chrono::milliseconds(10000));
128 }
129
Austin Schuh64fab802020-09-09 22:47:47 -0700130 {
131 // Confirm that the UUIDs match for both the parts and the logger, and the
132 // parts_index increments.
133 std::vector<FlatbufferVector<LogFileHeader>> log_header;
134 for (std::string_view f : {logfile0, logfile1}) {
135 log_header.emplace_back(ReadHeader(f));
136 }
137
138 EXPECT_EQ(log_header[0].message().logger_uuid()->string_view(),
139 log_header[1].message().logger_uuid()->string_view());
140 EXPECT_EQ(log_header[0].message().parts_uuid()->string_view(),
141 log_header[1].message().parts_uuid()->string_view());
142
143 EXPECT_EQ(log_header[0].message().parts_index(), 0);
144 EXPECT_EQ(log_header[1].message().parts_index(), 1);
145 }
146
Austin Schuhfa895892020-01-07 20:07:41 -0800147 // Even though it doesn't make any difference here, exercise the logic for
148 // passing in a separate config.
149 LogReader reader(std::vector<std::string>{logfile0, logfile1},
150 &config_.message());
151
152 // Confirm that we can remap logged channels to point to new buses.
153 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
154
155 // This sends out the fetched messages and advances time to the start of the
156 // log file.
157 reader.Register();
158
Austin Schuh6f3babe2020-01-26 20:34:50 -0800159 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
Austin Schuhfa895892020-01-07 20:07:41 -0800160
161 std::unique_ptr<EventLoop> test_event_loop =
162 reader.event_loop_factory()->MakeEventLoop("log_reader");
163
164 int ping_count = 10;
165 int pong_count = 10;
166
167 // Confirm that the ping value matches in the remapped channel location.
168 test_event_loop->MakeWatcher("/original/test",
169 [&ping_count](const examples::Ping &ping) {
170 EXPECT_EQ(ping.value(), ping_count + 1);
171 ++ping_count;
172 });
173 // Confirm that the ping and pong counts both match, and the value also
174 // matches.
175 test_event_loop->MakeWatcher(
176 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
177 EXPECT_EQ(pong.value(), pong_count + 1);
178 ++pong_count;
179 EXPECT_EQ(ping_count, pong_count);
180 });
181
182 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
183 EXPECT_EQ(ping_count, 2010);
184}
185
Austin Schuh4c4e0092019-12-22 16:18:03 -0800186// Tests that a large number of messages per second doesn't overwhelm writev.
187TEST_F(LoggerTest, ManyMessages) {
188 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
Austin Schuh2f8fd752020-09-01 22:38:28 -0700189 const ::std::string base_name = tmpdir + "/logfile";
190 const ::std::string logfile = base_name + ".part0.bfbs";
Austin Schuh4c4e0092019-12-22 16:18:03 -0800191 // Remove the log file.
192 unlink(logfile.c_str());
193
194 LOG(INFO) << "Logging data to " << logfile;
Austin Schuh4c3b9702020-08-30 11:34:55 -0700195 ping_.set_quiet(true);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800196
197 {
Austin Schuh4c4e0092019-12-22 16:18:03 -0800198 std::unique_ptr<EventLoop> logger_event_loop =
199 event_loop_factory_.MakeEventLoop("logger");
200
201 std::unique_ptr<EventLoop> ping_spammer_event_loop =
202 event_loop_factory_.MakeEventLoop("ping_spammer");
203 aos::Sender<examples::Ping> ping_sender =
204 ping_spammer_event_loop->MakeSender<examples::Ping>("/test");
205
206 aos::TimerHandler *timer_handler =
207 ping_spammer_event_loop->AddTimer([&ping_sender]() {
208 aos::Sender<examples::Ping>::Builder builder =
209 ping_sender.MakeBuilder();
210 examples::Ping::Builder ping_builder =
211 builder.MakeBuilder<examples::Ping>();
212 CHECK(builder.Send(ping_builder.Finish()));
213 });
214
215 // 100 ms / 0.05 ms -> 2000 messages. Should be enough to crash it.
216 ping_spammer_event_loop->OnRun([&ping_spammer_event_loop, timer_handler]() {
217 timer_handler->Setup(ping_spammer_event_loop->monotonic_now(),
218 chrono::microseconds(50));
219 });
220
Austin Schuh2f8fd752020-09-01 22:38:28 -0700221 Logger logger(base_name, logger_event_loop.get(),
Austin Schuh4c4e0092019-12-22 16:18:03 -0800222 std::chrono::milliseconds(100));
223
224 event_loop_factory_.RunFor(chrono::milliseconds(1000));
225 }
226}
227
Austin Schuh15649d62019-12-28 16:36:38 -0800228class MultinodeLoggerTest : public ::testing::Test {
229 public:
230 MultinodeLoggerTest()
231 : config_(aos::configuration::ReadConfig(
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800232 "aos/events/logging/multinode_pingpong_config.json")),
Austin Schuhac0771c2020-01-07 18:36:30 -0800233 event_loop_factory_(&config_.message()),
Austin Schuhcde938c2020-02-02 17:30:07 -0800234 pi1_(
235 configuration::GetNode(event_loop_factory_.configuration(), "pi1")),
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700236 pi2_(
237 configuration::GetNode(event_loop_factory_.configuration(), "pi2")),
238 tmp_dir_(getenv("TEST_TMPDIR")),
239 logfile_base_(tmp_dir_ + "/multi_logfile"),
Austin Schuh2f8fd752020-09-01 22:38:28 -0700240 logfiles_(
241 {logfile_base_ + "_pi1_data.part0.bfbs",
242 logfile_base_ + "_pi2_data/test/aos.examples.Pong.part0.bfbs",
243 logfile_base_ + "_pi2_data/test/aos.examples.Pong.part1.bfbs",
244 logfile_base_ + "_pi2_data.part0.bfbs",
245 logfile_base_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
246 "aos.logger.MessageHeader.part0.bfbs",
247 logfile_base_ + "_timestamps/pi1/aos/remote_timestamps/pi2/"
248 "aos.logger.MessageHeader.part1.bfbs",
249 logfile_base_ + "_timestamps/pi2/aos/remote_timestamps/pi1/"
250 "aos.logger.MessageHeader.part0.bfbs",
251 logfile_base_ + "_timestamps/pi2/aos/remote_timestamps/pi1/"
252 "aos.logger.MessageHeader.part1.bfbs",
253 logfile_base_ +
254 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part0.bfbs",
255 logfile_base_ +
256 "_pi1_data/pi1/aos/aos.message_bridge.Timestamp.part1.bfbs",
257 logfile_base_ +
258 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part0.bfbs",
259 logfile_base_ +
260 "_pi2_data/pi2/aos/aos.message_bridge.Timestamp.part1.bfbs"}),
261 structured_logfiles_{
262 std::vector<std::string>{logfiles_[0]},
263 std::vector<std::string>{logfiles_[1], logfiles_[2]},
264 std::vector<std::string>{logfiles_[3]},
265 std::vector<std::string>{logfiles_[4], logfiles_[5]},
266 std::vector<std::string>{logfiles_[6], logfiles_[7]},
267 std::vector<std::string>{logfiles_[8], logfiles_[9]},
268 std::vector<std::string>{logfiles_[10], logfiles_[11]}},
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700269 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping", pi1_)),
270 ping_(ping_event_loop_.get()),
271 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong", pi2_)),
272 pong_(pong_event_loop_.get()) {
273 // Go through and remove the logfiles if they already exist.
274 for (const auto file : logfiles_) {
275 unlink(file.c_str());
276 }
277
278 LOG(INFO) << "Logging data to " << logfiles_[0] << ", " << logfiles_[1]
279 << " and " << logfiles_[2];
280 }
281
282 struct LoggerState {
283 std::unique_ptr<EventLoop> event_loop;
284 std::unique_ptr<Logger> logger;
285 };
286
287 LoggerState MakeLogger(const Node *node) {
288 return {event_loop_factory_.MakeEventLoop("logger", node), {}};
289 }
290
291 void StartLogger(LoggerState *logger) {
292 logger->logger = std::make_unique<Logger>(
293 std::make_unique<MultiNodeLogNamer>(logfile_base_,
294 logger->event_loop->configuration(),
295 logger->event_loop->node()),
296 logger->event_loop.get(), chrono::milliseconds(100));
297 }
Austin Schuh15649d62019-12-28 16:36:38 -0800298
299 // Config and factory.
300 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
301 SimulatedEventLoopFactory event_loop_factory_;
302
Austin Schuhcde938c2020-02-02 17:30:07 -0800303 const Node *pi1_;
304 const Node *pi2_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700305
306 std::string tmp_dir_;
307 std::string logfile_base_;
Austin Schuh2f8fd752020-09-01 22:38:28 -0700308 std::vector<std::string> logfiles_;
309
310 std::vector<std::vector<std::string>> structured_logfiles_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700311
312 std::unique_ptr<EventLoop> ping_event_loop_;
313 Ping ping_;
314 std::unique_ptr<EventLoop> pong_event_loop_;
315 Pong pong_;
Austin Schuh15649d62019-12-28 16:36:38 -0800316};
317
Austin Schuh391e3172020-09-01 22:48:18 -0700318// Counts the number of messages on a channel. Returns (channel name, channel
319// type, count) for every message matching matcher()
320std::vector<std::tuple<std::string, std::string, int>> CountChannelsMatching(
Austin Schuh6f3babe2020-01-26 20:34:50 -0800321 std::string_view filename,
322 std::function<bool(const MessageHeader *)> matcher) {
323 MessageReader message_reader(filename);
324 std::vector<int> counts(
325 message_reader.log_file_header()->configuration()->channels()->size(), 0);
Austin Schuh15649d62019-12-28 16:36:38 -0800326
Austin Schuh6f3babe2020-01-26 20:34:50 -0800327 while (true) {
328 std::optional<FlatbufferVector<MessageHeader>> msg =
329 message_reader.ReadMessage();
330 if (!msg) {
331 break;
332 }
333
334 if (matcher(&msg.value().message())) {
335 counts[msg.value().message().channel_index()]++;
336 }
337 }
338
Austin Schuh391e3172020-09-01 22:48:18 -0700339 std::vector<std::tuple<std::string, std::string, int>> result;
Austin Schuh6f3babe2020-01-26 20:34:50 -0800340 int channel = 0;
341 for (size_t i = 0; i < counts.size(); ++i) {
342 if (counts[i] != 0) {
Austin Schuh391e3172020-09-01 22:48:18 -0700343 const Channel *channel =
344 message_reader.log_file_header()->configuration()->channels()->Get(i);
345 result.push_back(std::make_tuple(channel->name()->str(),
346 channel->type()->str(), counts[i]));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800347 }
348 ++channel;
349 }
350
351 return result;
352}
353
354// Counts the number of messages (channel, count) for all data messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700355std::vector<std::tuple<std::string, std::string, int>> CountChannelsData(
356 std::string_view filename) {
Austin Schuh6f3babe2020-01-26 20:34:50 -0800357 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
358 if (msg->has_data()) {
359 CHECK(!msg->has_monotonic_remote_time());
360 CHECK(!msg->has_realtime_remote_time());
361 CHECK(!msg->has_remote_queue_index());
362 return true;
363 }
364 return false;
365 });
366}
367
368// Counts the number of messages (channel, count) for all timestamp messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700369std::vector<std::tuple<std::string, std::string, int>> CountChannelsTimestamp(
Austin Schuh6f3babe2020-01-26 20:34:50 -0800370 std::string_view filename) {
371 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
372 if (!msg->has_data()) {
373 CHECK(msg->has_monotonic_remote_time());
374 CHECK(msg->has_realtime_remote_time());
375 CHECK(msg->has_remote_queue_index());
376 return true;
377 }
378 return false;
379 });
380}
381
Austin Schuhcde938c2020-02-02 17:30:07 -0800382// Tests that we can write and read simple multi-node log files.
383TEST_F(MultinodeLoggerTest, SimpleMultiNode) {
Austin Schuh15649d62019-12-28 16:36:38 -0800384 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700385 LoggerState pi1_logger = MakeLogger(pi1_);
386 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuh15649d62019-12-28 16:36:38 -0800387
388 event_loop_factory_.RunFor(chrono::milliseconds(95));
389
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700390 StartLogger(&pi1_logger);
391 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800392
Austin Schuh15649d62019-12-28 16:36:38 -0800393 event_loop_factory_.RunFor(chrono::milliseconds(20000));
394 }
395
Austin Schuh6f3babe2020-01-26 20:34:50 -0800396 {
Austin Schuh64fab802020-09-09 22:47:47 -0700397 std::set<std::string> logfile_uuids;
398 std::set<std::string> parts_uuids;
399 // Confirm that we have the expected number of UUIDs for both the logfile
400 // UUIDs and parts UUIDs.
401 std::vector<FlatbufferVector<LogFileHeader>> log_header;
402 for (std::string_view f : logfiles_) {
403 log_header.emplace_back(ReadHeader(f));
404 logfile_uuids.insert(log_header.back().message().logger_uuid()->str());
405 parts_uuids.insert(log_header.back().message().parts_uuid()->str());
406 }
Austin Schuh15649d62019-12-28 16:36:38 -0800407
Austin Schuh64fab802020-09-09 22:47:47 -0700408 EXPECT_EQ(logfile_uuids.size(), 2u);
409 EXPECT_EQ(parts_uuids.size(), 7u);
410
411 // And confirm everything is on the correct node.
412 EXPECT_EQ(log_header[0].message().node()->name()->string_view(), "pi1");
413 EXPECT_EQ(log_header[1].message().node()->name()->string_view(), "pi2");
414 EXPECT_EQ(log_header[2].message().node()->name()->string_view(), "pi2");
415 EXPECT_EQ(log_header[3].message().node()->name()->string_view(), "pi2");
416 EXPECT_EQ(log_header[4].message().node()->name()->string_view(), "pi2");
417 EXPECT_EQ(log_header[5].message().node()->name()->string_view(), "pi2");
418 EXPECT_EQ(log_header[6].message().node()->name()->string_view(), "pi1");
419 EXPECT_EQ(log_header[7].message().node()->name()->string_view(), "pi1");
420 EXPECT_EQ(log_header[8].message().node()->name()->string_view(), "pi1");
421 EXPECT_EQ(log_header[9].message().node()->name()->string_view(), "pi1");
422 EXPECT_EQ(log_header[10].message().node()->name()->string_view(), "pi2");
423 EXPECT_EQ(log_header[11].message().node()->name()->string_view(), "pi2");
424
425 // And the parts index matches.
426 EXPECT_EQ(log_header[0].message().parts_index(), 0);
427 EXPECT_EQ(log_header[1].message().parts_index(), 0);
428 EXPECT_EQ(log_header[2].message().parts_index(), 1);
429 EXPECT_EQ(log_header[3].message().parts_index(), 0);
430 EXPECT_EQ(log_header[4].message().parts_index(), 0);
431 EXPECT_EQ(log_header[5].message().parts_index(), 1);
432 EXPECT_EQ(log_header[6].message().parts_index(), 0);
433 EXPECT_EQ(log_header[7].message().parts_index(), 1);
434 EXPECT_EQ(log_header[8].message().parts_index(), 0);
435 EXPECT_EQ(log_header[9].message().parts_index(), 1);
436 EXPECT_EQ(log_header[10].message().parts_index(), 0);
437 EXPECT_EQ(log_header[11].message().parts_index(), 1);
438 }
439
440 {
Austin Schuh391e3172020-09-01 22:48:18 -0700441 using ::testing::UnorderedElementsAre;
442
Austin Schuh6f3babe2020-01-26 20:34:50 -0800443 // Timing reports, pings
Austin Schuh2f8fd752020-09-01 22:38:28 -0700444 EXPECT_THAT(
445 CountChannelsData(logfiles_[0]),
446 UnorderedElementsAre(
447 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200),
448 std::make_tuple("/pi1/aos", "aos.timing.Report", 40),
449 std::make_tuple("/test", "aos.examples.Ping", 2001)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800450 // Timestamps for pong
Austin Schuh2f8fd752020-09-01 22:38:28 -0700451 EXPECT_THAT(
452 CountChannelsTimestamp(logfiles_[0]),
453 UnorderedElementsAre(
454 std::make_tuple("/test", "aos.examples.Pong", 2001),
455 std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800456
457 // Pong data.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700458 EXPECT_THAT(CountChannelsData(logfiles_[1]),
Austin Schuh391e3172020-09-01 22:48:18 -0700459 UnorderedElementsAre(
Austin Schuh2f8fd752020-09-01 22:38:28 -0700460 std::make_tuple("/test", "aos.examples.Pong", 101)));
461 EXPECT_THAT(CountChannelsData(logfiles_[2]),
462 UnorderedElementsAre(
463 std::make_tuple("/test", "aos.examples.Pong", 1900)));
Austin Schuh391e3172020-09-01 22:48:18 -0700464
Austin Schuh6f3babe2020-01-26 20:34:50 -0800465 // No timestamps
Austin Schuh391e3172020-09-01 22:48:18 -0700466 EXPECT_THAT(CountChannelsTimestamp(logfiles_[1]), UnorderedElementsAre());
Austin Schuh2f8fd752020-09-01 22:38:28 -0700467 EXPECT_THAT(CountChannelsTimestamp(logfiles_[2]), UnorderedElementsAre());
Austin Schuh6f3babe2020-01-26 20:34:50 -0800468
469 // Timing reports and pongs.
Austin Schuh2f8fd752020-09-01 22:38:28 -0700470 EXPECT_THAT(
471 CountChannelsData(logfiles_[3]),
472 UnorderedElementsAre(
473 std::make_tuple("/pi2/aos", "aos.message_bridge.Timestamp", 200),
474 std::make_tuple("/pi2/aos", "aos.timing.Report", 40),
475 std::make_tuple("/test", "aos.examples.Pong", 2001)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800476 // And ping timestamps.
Austin Schuh2f8fd752020-09-01 22:38:28 -0700477 EXPECT_THAT(
478 CountChannelsTimestamp(logfiles_[3]),
479 UnorderedElementsAre(
480 std::make_tuple("/test", "aos.examples.Ping", 2001),
481 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 200)));
482
483 // Timestamps from pi2 on pi1, and the other way.
484 EXPECT_THAT(CountChannelsData(logfiles_[4]), UnorderedElementsAre());
485 EXPECT_THAT(CountChannelsData(logfiles_[5]), UnorderedElementsAre());
486 EXPECT_THAT(CountChannelsData(logfiles_[6]), UnorderedElementsAre());
487 EXPECT_THAT(CountChannelsData(logfiles_[7]), UnorderedElementsAre());
488 EXPECT_THAT(
489 CountChannelsTimestamp(logfiles_[4]),
490 UnorderedElementsAre(
491 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 10),
492 std::make_tuple("/test", "aos.examples.Ping", 101)));
493 EXPECT_THAT(
494 CountChannelsTimestamp(logfiles_[5]),
495 UnorderedElementsAre(
496 std::make_tuple("/pi1/aos", "aos.message_bridge.Timestamp", 190),
497 std::make_tuple("/test", "aos.examples.Ping", 1900)));
498 EXPECT_THAT(CountChannelsTimestamp(logfiles_[6]),
499 UnorderedElementsAre(std::make_tuple(
500 "/pi2/aos", "aos.message_bridge.Timestamp", 10)));
501 EXPECT_THAT(CountChannelsTimestamp(logfiles_[7]),
502 UnorderedElementsAre(std::make_tuple(
503 "/pi2/aos", "aos.message_bridge.Timestamp", 190)));
504
505 // And then test that the remotely logged timestamp data files only have
506 // timestamps in them.
507 EXPECT_THAT(CountChannelsTimestamp(logfiles_[8]), UnorderedElementsAre());
508 EXPECT_THAT(CountChannelsTimestamp(logfiles_[9]), UnorderedElementsAre());
509 EXPECT_THAT(CountChannelsTimestamp(logfiles_[10]), UnorderedElementsAre());
510 EXPECT_THAT(CountChannelsTimestamp(logfiles_[11]), UnorderedElementsAre());
511
512 EXPECT_THAT(CountChannelsData(logfiles_[8]),
513 UnorderedElementsAre(std::make_tuple(
514 "/pi1/aos", "aos.message_bridge.Timestamp", 10)));
515 EXPECT_THAT(CountChannelsData(logfiles_[9]),
516 UnorderedElementsAre(std::make_tuple(
517 "/pi1/aos", "aos.message_bridge.Timestamp", 190)));
518
519 EXPECT_THAT(CountChannelsData(logfiles_[10]),
520 UnorderedElementsAre(std::make_tuple(
521 "/pi2/aos", "aos.message_bridge.Timestamp", 10)));
522 EXPECT_THAT(CountChannelsData(logfiles_[11]),
523 UnorderedElementsAre(std::make_tuple(
524 "/pi2/aos", "aos.message_bridge.Timestamp", 190)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800525 }
526
Austin Schuh2f8fd752020-09-01 22:38:28 -0700527 LogReader reader(structured_logfiles_);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800528
Austin Schuhac0771c2020-01-07 18:36:30 -0800529 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
Austin Schuh6331ef92020-01-07 18:28:09 -0800530 log_reader_factory.set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800531
532 // This sends out the fetched messages and advances time to the start of the
533 // log file.
Austin Schuh6331ef92020-01-07 18:28:09 -0800534 reader.Register(&log_reader_factory);
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800535
Austin Schuhac0771c2020-01-07 18:36:30 -0800536 const Node *pi1 =
537 configuration::GetNode(log_reader_factory.configuration(), "pi1");
Austin Schuh6f3babe2020-01-26 20:34:50 -0800538 const Node *pi2 =
539 configuration::GetNode(log_reader_factory.configuration(), "pi2");
Austin Schuhac0771c2020-01-07 18:36:30 -0800540
Austin Schuh2f8fd752020-09-01 22:38:28 -0700541 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
542 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
543 LOG(INFO) << "now pi1 "
544 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
545 LOG(INFO) << "now pi2 "
546 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
547
Austin Schuh6f3babe2020-01-26 20:34:50 -0800548 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800549
550 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800551
Austin Schuh6f3babe2020-01-26 20:34:50 -0800552 std::unique_ptr<EventLoop> pi1_event_loop =
Austin Schuhac0771c2020-01-07 18:36:30 -0800553 log_reader_factory.MakeEventLoop("test", pi1);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800554 std::unique_ptr<EventLoop> pi2_event_loop =
555 log_reader_factory.MakeEventLoop("test", pi2);
Austin Schuh15649d62019-12-28 16:36:38 -0800556
Austin Schuh6f3babe2020-01-26 20:34:50 -0800557 int pi1_ping_count = 10;
558 int pi2_ping_count = 10;
559 int pi1_pong_count = 10;
560 int pi2_pong_count = 10;
Austin Schuh15649d62019-12-28 16:36:38 -0800561
562 // Confirm that the ping value matches.
Austin Schuh6f3babe2020-01-26 20:34:50 -0800563 pi1_event_loop->MakeWatcher(
564 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
Austin Schuh2f8fd752020-09-01 22:38:28 -0700565 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping) << " at "
Austin Schuh6f3babe2020-01-26 20:34:50 -0800566 << pi1_event_loop->context().monotonic_remote_time << " -> "
567 << pi1_event_loop->context().monotonic_event_time;
568 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
569 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
570 pi1_ping_count * chrono::milliseconds(10) +
571 monotonic_clock::epoch());
572 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
573 pi1_ping_count * chrono::milliseconds(10) +
574 realtime_clock::epoch());
575 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
576 pi1_event_loop->context().monotonic_event_time);
577 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
578 pi1_event_loop->context().realtime_event_time);
Austin Schuh15649d62019-12-28 16:36:38 -0800579
Austin Schuh6f3babe2020-01-26 20:34:50 -0800580 ++pi1_ping_count;
581 });
582 pi2_event_loop->MakeWatcher(
583 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
Austin Schuh2f8fd752020-09-01 22:38:28 -0700584 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping) << " at "
Austin Schuh6f3babe2020-01-26 20:34:50 -0800585 << pi2_event_loop->context().monotonic_remote_time << " -> "
586 << pi2_event_loop->context().monotonic_event_time;
587 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
588
589 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
590 pi2_ping_count * chrono::milliseconds(10) +
591 monotonic_clock::epoch());
592 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
593 pi2_ping_count * chrono::milliseconds(10) +
594 realtime_clock::epoch());
595 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time +
596 chrono::microseconds(150),
597 pi2_event_loop->context().monotonic_event_time);
598 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time +
599 chrono::microseconds(150),
600 pi2_event_loop->context().realtime_event_time);
601 ++pi2_ping_count;
Austin Schuh15649d62019-12-28 16:36:38 -0800602 });
603
Austin Schuh6f3babe2020-01-26 20:34:50 -0800604 constexpr ssize_t kQueueIndexOffset = 0;
605 // Confirm that the ping and pong counts both match, and the value also
606 // matches.
607 pi1_event_loop->MakeWatcher(
608 "/test", [&pi1_event_loop, &pi1_ping_count,
609 &pi1_pong_count](const examples::Pong &pong) {
610 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
611 << pi1_event_loop->context().monotonic_remote_time << " -> "
612 << pi1_event_loop->context().monotonic_event_time;
613
614 EXPECT_EQ(pi1_event_loop->context().remote_queue_index,
615 pi1_pong_count + kQueueIndexOffset);
616 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
617 chrono::microseconds(200) +
618 pi1_pong_count * chrono::milliseconds(10) +
619 monotonic_clock::epoch());
620 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
621 chrono::microseconds(200) +
622 pi1_pong_count * chrono::milliseconds(10) +
623 realtime_clock::epoch());
624
625 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time +
626 chrono::microseconds(150),
627 pi1_event_loop->context().monotonic_event_time);
628 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time +
629 chrono::microseconds(150),
630 pi1_event_loop->context().realtime_event_time);
631
632 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
633 ++pi1_pong_count;
634 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
635 });
636 pi2_event_loop->MakeWatcher(
637 "/test", [&pi2_event_loop, &pi2_ping_count,
638 &pi2_pong_count](const examples::Pong &pong) {
639 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
640 << pi2_event_loop->context().monotonic_remote_time << " -> "
641 << pi2_event_loop->context().monotonic_event_time;
642
643 EXPECT_EQ(pi2_event_loop->context().remote_queue_index,
644 pi2_pong_count + kQueueIndexOffset - 9);
645
646 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
647 chrono::microseconds(200) +
648 pi2_pong_count * chrono::milliseconds(10) +
649 monotonic_clock::epoch());
650 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
651 chrono::microseconds(200) +
652 pi2_pong_count * chrono::milliseconds(10) +
653 realtime_clock::epoch());
654
655 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
656 pi2_event_loop->context().monotonic_event_time);
657 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
658 pi2_event_loop->context().realtime_event_time);
659
660 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
661 ++pi2_pong_count;
662 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
663 });
664
665 log_reader_factory.Run();
666 EXPECT_EQ(pi1_ping_count, 2010);
667 EXPECT_EQ(pi2_ping_count, 2010);
668 EXPECT_EQ(pi1_pong_count, 2010);
669 EXPECT_EQ(pi2_pong_count, 2010);
Austin Schuh6331ef92020-01-07 18:28:09 -0800670
671 reader.Deregister();
Austin Schuh15649d62019-12-28 16:36:38 -0800672}
673
James Kuszmaul46d82582020-05-09 19:50:09 -0700674typedef MultinodeLoggerTest MultinodeLoggerDeathTest;
675
676// Test that if we feed the replay with a mismatched node list that we die on
677// the LogReader constructor.
678TEST_F(MultinodeLoggerDeathTest, MultiNodeBadReplayConfig) {
James Kuszmaul46d82582020-05-09 19:50:09 -0700679 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700680 LoggerState pi1_logger = MakeLogger(pi1_);
681 LoggerState pi2_logger = MakeLogger(pi2_);
James Kuszmaul46d82582020-05-09 19:50:09 -0700682
683 event_loop_factory_.RunFor(chrono::milliseconds(95));
684
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700685 StartLogger(&pi1_logger);
686 StartLogger(&pi2_logger);
James Kuszmaul46d82582020-05-09 19:50:09 -0700687
James Kuszmaul46d82582020-05-09 19:50:09 -0700688 event_loop_factory_.RunFor(chrono::milliseconds(20000));
689 }
690
691 // Test that, if we add an additional node to the replay config that the
692 // logger complains about the mismatch in number of nodes.
693 FlatbufferDetachedBuffer<Configuration> extra_nodes_config =
694 configuration::MergeWithConfig(&config_.message(), R"({
695 "nodes": [
696 {
697 "name": "extra-node"
698 }
699 ]
700 }
701 )");
702
Austin Schuh2f8fd752020-09-01 22:38:28 -0700703 EXPECT_DEATH(LogReader(structured_logfiles_, &extra_nodes_config.message()),
James Kuszmaul46d82582020-05-09 19:50:09 -0700704 "Log file and replay config need to have matching nodes lists.");
James Kuszmaul46d82582020-05-09 19:50:09 -0700705}
706
Austin Schuhcde938c2020-02-02 17:30:07 -0800707// Tests that we can read log files where they don't start at the same monotonic
708// time.
709TEST_F(MultinodeLoggerTest, StaggeredStart) {
Austin Schuhcde938c2020-02-02 17:30:07 -0800710 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700711 LoggerState pi1_logger = MakeLogger(pi1_);
712 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuhcde938c2020-02-02 17:30:07 -0800713
714 event_loop_factory_.RunFor(chrono::milliseconds(95));
715
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700716 StartLogger(&pi1_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800717
718 event_loop_factory_.RunFor(chrono::milliseconds(200));
719
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700720 StartLogger(&pi2_logger);
721
Austin Schuhcde938c2020-02-02 17:30:07 -0800722 event_loop_factory_.RunFor(chrono::milliseconds(20000));
723 }
724
Austin Schuh2f8fd752020-09-01 22:38:28 -0700725 LogReader reader(structured_logfiles_);
Austin Schuhcde938c2020-02-02 17:30:07 -0800726
727 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
728 log_reader_factory.set_send_delay(chrono::microseconds(0));
729
730 // This sends out the fetched messages and advances time to the start of the
731 // log file.
732 reader.Register(&log_reader_factory);
733
734 const Node *pi1 =
735 configuration::GetNode(log_reader_factory.configuration(), "pi1");
736 const Node *pi2 =
737 configuration::GetNode(log_reader_factory.configuration(), "pi2");
738
739 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
740
741 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
742
743 std::unique_ptr<EventLoop> pi1_event_loop =
744 log_reader_factory.MakeEventLoop("test", pi1);
745 std::unique_ptr<EventLoop> pi2_event_loop =
746 log_reader_factory.MakeEventLoop("test", pi2);
747
748 int pi1_ping_count = 30;
749 int pi2_ping_count = 30;
750 int pi1_pong_count = 30;
751 int pi2_pong_count = 30;
752
753 // Confirm that the ping value matches.
754 pi1_event_loop->MakeWatcher(
755 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
756 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
757 << pi1_event_loop->context().monotonic_remote_time << " -> "
758 << pi1_event_loop->context().monotonic_event_time;
759 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
760
761 ++pi1_ping_count;
762 });
763 pi2_event_loop->MakeWatcher(
764 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
765 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
766 << pi2_event_loop->context().monotonic_remote_time << " -> "
767 << pi2_event_loop->context().monotonic_event_time;
768 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
769
770 ++pi2_ping_count;
771 });
772
773 // Confirm that the ping and pong counts both match, and the value also
774 // matches.
775 pi1_event_loop->MakeWatcher(
776 "/test", [&pi1_event_loop, &pi1_ping_count,
777 &pi1_pong_count](const examples::Pong &pong) {
778 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
779 << pi1_event_loop->context().monotonic_remote_time << " -> "
780 << pi1_event_loop->context().monotonic_event_time;
781
782 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
783 ++pi1_pong_count;
784 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
785 });
786 pi2_event_loop->MakeWatcher(
787 "/test", [&pi2_event_loop, &pi2_ping_count,
788 &pi2_pong_count](const examples::Pong &pong) {
789 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
790 << pi2_event_loop->context().monotonic_remote_time << " -> "
791 << pi2_event_loop->context().monotonic_event_time;
792
793 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
794 ++pi2_pong_count;
795 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
796 });
797
798 log_reader_factory.Run();
799 EXPECT_EQ(pi1_ping_count, 2030);
800 EXPECT_EQ(pi2_ping_count, 2030);
801 EXPECT_EQ(pi1_pong_count, 2030);
802 EXPECT_EQ(pi2_pong_count, 2030);
803
804 reader.Deregister();
805}
Austin Schuh6f3babe2020-01-26 20:34:50 -0800806
Austin Schuh8bd96322020-02-13 21:18:22 -0800807// Tests that we can read log files where the monotonic clocks drift and don't
808// match correctly. While we are here, also test that different ending times
809// also is readable.
810TEST_F(MultinodeLoggerTest, MismatchedClocks) {
Austin Schuhcde938c2020-02-02 17:30:07 -0800811 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700812 LoggerState pi2_logger = MakeLogger(pi2_);
813
Austin Schuh8bd96322020-02-13 21:18:22 -0800814 NodeEventLoopFactory *pi2 =
815 event_loop_factory_.GetNodeEventLoopFactory(pi2_);
816 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
817 << pi2->realtime_now() << " distributed "
818 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -0800819
Austin Schuh8bd96322020-02-13 21:18:22 -0800820 const chrono::nanoseconds initial_pi2_offset = -chrono::seconds(1000);
821 chrono::nanoseconds pi2_offset = initial_pi2_offset;
Austin Schuhcde938c2020-02-02 17:30:07 -0800822
Austin Schuhbe69cf32020-08-27 11:38:33 -0700823 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800824 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
825 << pi2->realtime_now() << " distributed "
826 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -0800827
Austin Schuh8bd96322020-02-13 21:18:22 -0800828 for (int i = 0; i < 95; ++i) {
829 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -0700830 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800831 event_loop_factory_.RunFor(chrono::milliseconds(1));
832 }
Austin Schuhcde938c2020-02-02 17:30:07 -0800833
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700834 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800835
Austin Schuh8bd96322020-02-13 21:18:22 -0800836 event_loop_factory_.RunFor(chrono::milliseconds(200));
Austin Schuhcde938c2020-02-02 17:30:07 -0800837
Austin Schuh8bd96322020-02-13 21:18:22 -0800838 {
839 // Run pi1's logger for only part of the time.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700840 LoggerState pi1_logger = MakeLogger(pi1_);
Austin Schuh8bd96322020-02-13 21:18:22 -0800841
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700842 StartLogger(&pi1_logger);
Austin Schuh8bd96322020-02-13 21:18:22 -0800843
844 for (int i = 0; i < 20000; ++i) {
845 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -0700846 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800847 event_loop_factory_.RunFor(chrono::milliseconds(1));
848 }
849
850 EXPECT_GT(pi2_offset - initial_pi2_offset,
851 event_loop_factory_.send_delay() +
852 event_loop_factory_.network_delay());
853
854 for (int i = 0; i < 40000; ++i) {
855 pi2_offset -= chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -0700856 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800857 event_loop_factory_.RunFor(chrono::milliseconds(1));
858 }
859 }
860
861 // And log a bit more on pi2.
862 event_loop_factory_.RunFor(chrono::milliseconds(400));
Austin Schuhcde938c2020-02-02 17:30:07 -0800863 }
864
Austin Schuh2f8fd752020-09-01 22:38:28 -0700865 LogReader reader(structured_logfiles_);
Austin Schuhcde938c2020-02-02 17:30:07 -0800866
867 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
868 log_reader_factory.set_send_delay(chrono::microseconds(0));
869
Austin Schuhcde938c2020-02-02 17:30:07 -0800870 const Node *pi1 =
871 configuration::GetNode(log_reader_factory.configuration(), "pi1");
872 const Node *pi2 =
873 configuration::GetNode(log_reader_factory.configuration(), "pi2");
874
Austin Schuh2f8fd752020-09-01 22:38:28 -0700875 // This sends out the fetched messages and advances time to the start of the
876 // log file.
877 reader.Register(&log_reader_factory);
878
879 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi1) << " pi1";
880 LOG(INFO) << "Start time " << reader.monotonic_start_time(pi2) << " pi2";
881 LOG(INFO) << "now pi1 "
882 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now();
883 LOG(INFO) << "now pi2 "
884 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now();
885
Austin Schuhcde938c2020-02-02 17:30:07 -0800886 LOG(INFO) << "Done registering (pi1) "
Austin Schuh391e3172020-09-01 22:48:18 -0700887 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now()
888 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -0800889 << log_reader_factory.GetNodeEventLoopFactory(pi1)->realtime_now();
890 LOG(INFO) << "Done registering (pi2) "
Austin Schuh391e3172020-09-01 22:48:18 -0700891 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now()
892 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -0800893 << log_reader_factory.GetNodeEventLoopFactory(pi2)->realtime_now();
894
895 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
896
897 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
898
899 std::unique_ptr<EventLoop> pi1_event_loop =
900 log_reader_factory.MakeEventLoop("test", pi1);
901 std::unique_ptr<EventLoop> pi2_event_loop =
902 log_reader_factory.MakeEventLoop("test", pi2);
903
904 int pi1_ping_count = 30;
905 int pi2_ping_count = 30;
906 int pi1_pong_count = 30;
907 int pi2_pong_count = 30;
908
909 // Confirm that the ping value matches.
910 pi1_event_loop->MakeWatcher(
911 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
912 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
913 << pi1_event_loop->context().monotonic_remote_time << " -> "
914 << pi1_event_loop->context().monotonic_event_time;
915 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
916
917 ++pi1_ping_count;
918 });
919 pi2_event_loop->MakeWatcher(
920 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
921 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
922 << pi2_event_loop->context().monotonic_remote_time << " -> "
923 << pi2_event_loop->context().monotonic_event_time;
924 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
925
926 ++pi2_ping_count;
927 });
928
929 // Confirm that the ping and pong counts both match, and the value also
930 // matches.
931 pi1_event_loop->MakeWatcher(
932 "/test", [&pi1_event_loop, &pi1_ping_count,
933 &pi1_pong_count](const examples::Pong &pong) {
934 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
935 << pi1_event_loop->context().monotonic_remote_time << " -> "
936 << pi1_event_loop->context().monotonic_event_time;
937
938 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
939 ++pi1_pong_count;
940 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
941 });
942 pi2_event_loop->MakeWatcher(
943 "/test", [&pi2_event_loop, &pi2_ping_count,
944 &pi2_pong_count](const examples::Pong &pong) {
945 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
946 << pi2_event_loop->context().monotonic_remote_time << " -> "
947 << pi2_event_loop->context().monotonic_event_time;
948
949 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
950 ++pi2_pong_count;
951 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
952 });
953
954 log_reader_factory.Run();
Austin Schuh8bd96322020-02-13 21:18:22 -0800955 EXPECT_EQ(pi1_ping_count, 6030);
956 EXPECT_EQ(pi2_ping_count, 6030);
957 EXPECT_EQ(pi1_pong_count, 6030);
958 EXPECT_EQ(pi2_pong_count, 6030);
Austin Schuhcde938c2020-02-02 17:30:07 -0800959
960 reader.Deregister();
961}
962
Austin Schuh5212cad2020-09-09 23:12:09 -0700963// Tests that we can sort a bunch of parts into the pre-determined sorted parts.
964TEST_F(MultinodeLoggerTest, SortParts) {
965 // Make a bunch of parts.
966 {
967 LoggerState pi1_logger = MakeLogger(pi1_);
968 LoggerState pi2_logger = MakeLogger(pi2_);
969
970 event_loop_factory_.RunFor(chrono::milliseconds(95));
971
972 StartLogger(&pi1_logger);
973 StartLogger(&pi2_logger);
974
975 event_loop_factory_.RunFor(chrono::milliseconds(2000));
976 }
977
Austin Schuh11d43732020-09-21 17:28:30 -0700978 const std::vector<LogFile> sorted_parts = SortParts(logfiles_);
979
980 EXPECT_EQ(sorted_parts.size(), 2u);
981
982 // Count up the number of UUIDs and make sure they are what we expect as a
983 // sanity check.
984 std::set<std::string> logger_uuids;
985 std::set<std::string> parts_uuids;
986 std::set<std::string> both_uuids;
987
988 size_t missing_rt_count = 0;
989
990 for (const LogFile &log_file : sorted_parts) {
991 EXPECT_FALSE(log_file.logger_uuid.empty());
992 logger_uuids.insert(log_file.logger_uuid);
993 both_uuids.insert(log_file.logger_uuid);
994
995 for (const LogParts &part : log_file.parts) {
996 EXPECT_NE(part.monotonic_start_time, aos::monotonic_clock::min_time)
997 << ": " << part;
998 missing_rt_count += part.realtime_start_time == aos::realtime_clock::min_time;
999
1000 EXPECT_TRUE(logger_uuids.find(part.logger_uuid) != logger_uuids.end());
1001 EXPECT_NE(part.node, "");
1002 parts_uuids.insert(part.parts_uuid);
1003 both_uuids.insert(part.parts_uuid);
1004 }
1005 }
1006
1007 // We won't have RT timestamps for 5 log files. We don't log the RT start
1008 // time on remote nodes because we don't know it and would be guessing. And
1009 // the log reader can actually do a better job.
1010 EXPECT_EQ(missing_rt_count, 5u);
1011
1012 EXPECT_EQ(logger_uuids.size(), 2u);
1013 EXPECT_EQ(parts_uuids.size(), ToLogReaderVector(sorted_parts).size());
1014 EXPECT_EQ(logger_uuids.size() + parts_uuids.size(), both_uuids.size());
Austin Schuh5212cad2020-09-09 23:12:09 -07001015
1016 // Test that each list of parts is in order. Don't worry about the ordering
1017 // between part file lists though.
1018 // (inner vectors all need to be in order, but outer one doesn't matter).
Austin Schuh11d43732020-09-21 17:28:30 -07001019 EXPECT_THAT(ToLogReaderVector(sorted_parts),
Austin Schuh5212cad2020-09-09 23:12:09 -07001020 ::testing::UnorderedElementsAreArray(structured_logfiles_));
1021}
1022
Austin Schuh01b4c352020-09-21 23:09:39 -07001023// Tests that if we remap a remapped channel, it shows up correctly.
1024TEST_F(MultinodeLoggerTest, RemapLoggedChannel) {
1025 {
1026 LoggerState pi1_logger = MakeLogger(pi1_);
1027 LoggerState pi2_logger = MakeLogger(pi2_);
1028
1029 event_loop_factory_.RunFor(chrono::milliseconds(95));
1030
1031 StartLogger(&pi1_logger);
1032 StartLogger(&pi2_logger);
1033
1034 event_loop_factory_.RunFor(chrono::milliseconds(20000));
1035 }
1036
1037 LogReader reader(structured_logfiles_);
1038
1039 // Remap just on pi1.
1040 reader.RemapLoggedChannel<aos::timing::Report>(
1041 "/aos", configuration::GetNode(reader.configuration(), "pi1"));
1042
1043 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
1044 log_reader_factory.set_send_delay(chrono::microseconds(0));
1045
1046 reader.Register(&log_reader_factory);
1047
1048 const Node *pi1 =
1049 configuration::GetNode(log_reader_factory.configuration(), "pi1");
1050 const Node *pi2 =
1051 configuration::GetNode(log_reader_factory.configuration(), "pi2");
1052
1053 // Confirm we can read the data on the remapped channel, just for pi1. Nothing
1054 // else should have moved.
1055 std::unique_ptr<EventLoop> pi1_event_loop =
1056 log_reader_factory.MakeEventLoop("test", pi1);
1057 pi1_event_loop->SkipTimingReport();
1058 std::unique_ptr<EventLoop> full_pi1_event_loop =
1059 log_reader_factory.MakeEventLoop("test", pi1);
1060 full_pi1_event_loop->SkipTimingReport();
1061 std::unique_ptr<EventLoop> pi2_event_loop =
1062 log_reader_factory.MakeEventLoop("test", pi2);
1063 pi2_event_loop->SkipTimingReport();
1064
1065 MessageCounter<aos::timing::Report> pi1_timing_report(pi1_event_loop.get(),
1066 "/aos");
1067 MessageCounter<aos::timing::Report> full_pi1_timing_report(
1068 full_pi1_event_loop.get(), "/pi1/aos");
1069 MessageCounter<aos::timing::Report> pi1_original_timing_report(
1070 pi1_event_loop.get(), "/original/aos");
1071 MessageCounter<aos::timing::Report> full_pi1_original_timing_report(
1072 full_pi1_event_loop.get(), "/original/pi1/aos");
1073 MessageCounter<aos::timing::Report> pi2_timing_report(pi2_event_loop.get(),
1074 "/aos");
1075
1076 log_reader_factory.Run();
1077
1078 EXPECT_EQ(pi1_timing_report.count(), 0u);
1079 EXPECT_EQ(full_pi1_timing_report.count(), 0u);
1080 EXPECT_NE(pi1_original_timing_report.count(), 0u);
1081 EXPECT_NE(full_pi1_original_timing_report.count(), 0u);
1082 EXPECT_NE(pi2_timing_report.count(), 0u);
1083
1084 reader.Deregister();
1085}
1086
Austin Schuh8bd96322020-02-13 21:18:22 -08001087// TODO(austin): We can write a test which recreates a logfile and confirms that
1088// we get it back. That is the ultimate test.
1089
Austin Schuhe309d2a2019-11-29 13:25:21 -08001090} // namespace testing
1091} // namespace logger
1092} // namespace aos