blob: b6a30cb40b75a32458ec2bef28df5c43a3c04cf6 [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"
4#include "aos/events/ping_lib.h"
5#include "aos/events/pong_lib.h"
6#include "aos/events/simulated_event_loop.h"
7#include "glog/logging.h"
Austin Schuh6f3babe2020-01-26 20:34:50 -08008#include "gmock/gmock.h"
Austin Schuhe309d2a2019-11-29 13:25:21 -08009#include "gtest/gtest.h"
10
11namespace aos {
12namespace logger {
13namespace testing {
14
15namespace chrono = std::chrono;
16
17class LoggerTest : public ::testing::Test {
18 public:
19 LoggerTest()
20 : config_(
21 aos::configuration::ReadConfig("aos/events/pingpong_config.json")),
22 event_loop_factory_(&config_.message()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080023 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080024 ping_(ping_event_loop_.get()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080025 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080026 pong_(pong_event_loop_.get()) {}
27
28 // Config and factory.
29 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
30 SimulatedEventLoopFactory event_loop_factory_;
31
32 // Event loop and app for Ping
33 std::unique_ptr<EventLoop> ping_event_loop_;
34 Ping ping_;
35
36 // Event loop and app for Pong
37 std::unique_ptr<EventLoop> pong_event_loop_;
38 Pong pong_;
39};
40
41// Tests that we can startup at all. This confirms that the channels are all in
42// the config.
43TEST_F(LoggerTest, Starts) {
44 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
45 const ::std::string logfile = tmpdir + "/logfile.bfbs";
46 // Remove it.
47 unlink(logfile.c_str());
48
49 LOG(INFO) << "Logging data to " << logfile;
50
51 {
52 DetachedBufferWriter writer(logfile);
53 std::unique_ptr<EventLoop> logger_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080054 event_loop_factory_.MakeEventLoop("logger");
Austin Schuhe309d2a2019-11-29 13:25:21 -080055
56 event_loop_factory_.RunFor(chrono::milliseconds(95));
57
58 Logger logger(&writer, logger_event_loop.get(),
59 std::chrono::milliseconds(100));
60 event_loop_factory_.RunFor(chrono::milliseconds(20000));
61 }
62
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080063 // Even though it doesn't make any difference here, exercise the logic for
64 // passing in a separate config.
65 LogReader reader(logfile, &config_.message());
Austin Schuhe309d2a2019-11-29 13:25:21 -080066
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080067 // Confirm that we can remap logged channels to point to new buses.
68 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
Austin Schuhe309d2a2019-11-29 13:25:21 -080069
Austin Schuh15649d62019-12-28 16:36:38 -080070 // This sends out the fetched messages and advances time to the start of the
71 // log file.
James Kuszmaul84ff3e52020-01-03 19:48:53 -080072 reader.Register();
Austin Schuhe309d2a2019-11-29 13:25:21 -080073
Austin Schuh6f3babe2020-01-26 20:34:50 -080074 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
James Kuszmaul84ff3e52020-01-03 19:48:53 -080075
Austin Schuhe309d2a2019-11-29 13:25:21 -080076 std::unique_ptr<EventLoop> test_event_loop =
James Kuszmaul84ff3e52020-01-03 19:48:53 -080077 reader.event_loop_factory()->MakeEventLoop("log_reader");
Austin Schuhe309d2a2019-11-29 13:25:21 -080078
79 int ping_count = 10;
80 int pong_count = 10;
81
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080082 // Confirm that the ping value matches in the remapped channel location.
83 test_event_loop->MakeWatcher("/original/test",
Austin Schuhe309d2a2019-11-29 13:25:21 -080084 [&ping_count](const examples::Ping &ping) {
85 EXPECT_EQ(ping.value(), ping_count + 1);
86 ++ping_count;
87 });
88 // Confirm that the ping and pong counts both match, and the value also
89 // matches.
90 test_event_loop->MakeWatcher(
91 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
92 EXPECT_EQ(pong.value(), pong_count + 1);
93 ++pong_count;
94 EXPECT_EQ(ping_count, pong_count);
95 });
96
James Kuszmaul84ff3e52020-01-03 19:48:53 -080097 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
Austin Schuhe309d2a2019-11-29 13:25:21 -080098 EXPECT_EQ(ping_count, 2010);
Austin Schuhe309d2a2019-11-29 13:25:21 -080099}
100
Austin Schuhfa895892020-01-07 20:07:41 -0800101// Tests that we can read and write rotated log files.
102TEST_F(LoggerTest, RotatedLogFile) {
103 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
104 const ::std::string logfile0 = tmpdir + "/logfile0.bfbs";
105 const ::std::string logfile1 = tmpdir + "/logfile1.bfbs";
106 // Remove it.
107 unlink(logfile0.c_str());
108 unlink(logfile1.c_str());
109
110 LOG(INFO) << "Logging data to " << logfile0 << " and " << logfile1;
111
112 {
113 DetachedBufferWriter writer0(logfile0);
114 DetachedBufferWriter writer1(logfile1);
115 std::unique_ptr<EventLoop> logger_event_loop =
116 event_loop_factory_.MakeEventLoop("logger");
117
118 event_loop_factory_.RunFor(chrono::milliseconds(95));
119
120 Logger logger(&writer0, logger_event_loop.get(),
121 std::chrono::milliseconds(100));
122 event_loop_factory_.RunFor(chrono::milliseconds(10000));
123 logger.Rotate(&writer1);
124 event_loop_factory_.RunFor(chrono::milliseconds(10000));
125 }
126
127 // Even though it doesn't make any difference here, exercise the logic for
128 // passing in a separate config.
129 LogReader reader(std::vector<std::string>{logfile0, logfile1},
130 &config_.message());
131
132 // Confirm that we can remap logged channels to point to new buses.
133 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
134
135 // This sends out the fetched messages and advances time to the start of the
136 // log file.
137 reader.Register();
138
Austin Schuh6f3babe2020-01-26 20:34:50 -0800139 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(nullptr));
Austin Schuhfa895892020-01-07 20:07:41 -0800140
141 std::unique_ptr<EventLoop> test_event_loop =
142 reader.event_loop_factory()->MakeEventLoop("log_reader");
143
144 int ping_count = 10;
145 int pong_count = 10;
146
147 // Confirm that the ping value matches in the remapped channel location.
148 test_event_loop->MakeWatcher("/original/test",
149 [&ping_count](const examples::Ping &ping) {
150 EXPECT_EQ(ping.value(), ping_count + 1);
151 ++ping_count;
152 });
153 // Confirm that the ping and pong counts both match, and the value also
154 // matches.
155 test_event_loop->MakeWatcher(
156 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
157 EXPECT_EQ(pong.value(), pong_count + 1);
158 ++pong_count;
159 EXPECT_EQ(ping_count, pong_count);
160 });
161
162 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
163 EXPECT_EQ(ping_count, 2010);
164}
165
Austin Schuh4c4e0092019-12-22 16:18:03 -0800166// Tests that a large number of messages per second doesn't overwhelm writev.
167TEST_F(LoggerTest, ManyMessages) {
168 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
169 const ::std::string logfile = tmpdir + "/logfile.bfbs";
170 // Remove the log file.
171 unlink(logfile.c_str());
172
173 LOG(INFO) << "Logging data to " << logfile;
174
175 {
176 DetachedBufferWriter writer(logfile);
177 std::unique_ptr<EventLoop> logger_event_loop =
178 event_loop_factory_.MakeEventLoop("logger");
179
180 std::unique_ptr<EventLoop> ping_spammer_event_loop =
181 event_loop_factory_.MakeEventLoop("ping_spammer");
182 aos::Sender<examples::Ping> ping_sender =
183 ping_spammer_event_loop->MakeSender<examples::Ping>("/test");
184
185 aos::TimerHandler *timer_handler =
186 ping_spammer_event_loop->AddTimer([&ping_sender]() {
187 aos::Sender<examples::Ping>::Builder builder =
188 ping_sender.MakeBuilder();
189 examples::Ping::Builder ping_builder =
190 builder.MakeBuilder<examples::Ping>();
191 CHECK(builder.Send(ping_builder.Finish()));
192 });
193
194 // 100 ms / 0.05 ms -> 2000 messages. Should be enough to crash it.
195 ping_spammer_event_loop->OnRun([&ping_spammer_event_loop, timer_handler]() {
196 timer_handler->Setup(ping_spammer_event_loop->monotonic_now(),
197 chrono::microseconds(50));
198 });
199
200 Logger logger(&writer, logger_event_loop.get(),
201 std::chrono::milliseconds(100));
202
203 event_loop_factory_.RunFor(chrono::milliseconds(1000));
204 }
205}
206
Austin Schuh15649d62019-12-28 16:36:38 -0800207class MultinodeLoggerTest : public ::testing::Test {
208 public:
209 MultinodeLoggerTest()
210 : config_(aos::configuration::ReadConfig(
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800211 "aos/events/logging/multinode_pingpong_config.json")),
Austin Schuhac0771c2020-01-07 18:36:30 -0800212 event_loop_factory_(&config_.message()),
Austin Schuhcde938c2020-02-02 17:30:07 -0800213 pi1_(
214 configuration::GetNode(event_loop_factory_.configuration(), "pi1")),
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700215 pi2_(
216 configuration::GetNode(event_loop_factory_.configuration(), "pi2")),
217 tmp_dir_(getenv("TEST_TMPDIR")),
218 logfile_base_(tmp_dir_ + "/multi_logfile"),
219 logfiles_({logfile_base_ + "_pi1_data.bfbs",
220 logfile_base_ + "_pi2_data/test/aos.examples.Pong.bfbs",
221 logfile_base_ + "_pi2_data.bfbs"}),
222 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping", pi1_)),
223 ping_(ping_event_loop_.get()),
224 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong", pi2_)),
225 pong_(pong_event_loop_.get()) {
226 // Go through and remove the logfiles if they already exist.
227 for (const auto file : logfiles_) {
228 unlink(file.c_str());
229 }
230
231 LOG(INFO) << "Logging data to " << logfiles_[0] << ", " << logfiles_[1]
232 << " and " << logfiles_[2];
233 }
234
235 struct LoggerState {
236 std::unique_ptr<EventLoop> event_loop;
237 std::unique_ptr<Logger> logger;
238 };
239
240 LoggerState MakeLogger(const Node *node) {
241 return {event_loop_factory_.MakeEventLoop("logger", node), {}};
242 }
243
244 void StartLogger(LoggerState *logger) {
245 logger->logger = std::make_unique<Logger>(
246 std::make_unique<MultiNodeLogNamer>(logfile_base_,
247 logger->event_loop->configuration(),
248 logger->event_loop->node()),
249 logger->event_loop.get(), chrono::milliseconds(100));
250 }
Austin Schuh15649d62019-12-28 16:36:38 -0800251
252 // Config and factory.
253 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
254 SimulatedEventLoopFactory event_loop_factory_;
255
Austin Schuhcde938c2020-02-02 17:30:07 -0800256 const Node *pi1_;
257 const Node *pi2_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700258
259 std::string tmp_dir_;
260 std::string logfile_base_;
261 std::array<std::string, 3> logfiles_;
262
263 std::unique_ptr<EventLoop> ping_event_loop_;
264 Ping ping_;
265 std::unique_ptr<EventLoop> pong_event_loop_;
266 Pong pong_;
Austin Schuh15649d62019-12-28 16:36:38 -0800267};
268
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700269
Austin Schuh6f3babe2020-01-26 20:34:50 -0800270// Counts the number of messages on a channel (returns channel, count) for every
271// message matching matcher()
272std::vector<std::pair<int, int>> CountChannelsMatching(
273 std::string_view filename,
274 std::function<bool(const MessageHeader *)> matcher) {
275 MessageReader message_reader(filename);
276 std::vector<int> counts(
277 message_reader.log_file_header()->configuration()->channels()->size(), 0);
Austin Schuh15649d62019-12-28 16:36:38 -0800278
Austin Schuh6f3babe2020-01-26 20:34:50 -0800279 while (true) {
280 std::optional<FlatbufferVector<MessageHeader>> msg =
281 message_reader.ReadMessage();
282 if (!msg) {
283 break;
284 }
285
286 if (matcher(&msg.value().message())) {
287 counts[msg.value().message().channel_index()]++;
288 }
289 }
290
291 std::vector<std::pair<int, int>> result;
292 int channel = 0;
293 for (size_t i = 0; i < counts.size(); ++i) {
294 if (counts[i] != 0) {
295 result.push_back(std::make_pair(channel, counts[i]));
296 }
297 ++channel;
298 }
299
300 return result;
301}
302
303// Counts the number of messages (channel, count) for all data messages.
304std::vector<std::pair<int, int>> CountChannelsData(std::string_view filename) {
305 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
306 if (msg->has_data()) {
307 CHECK(!msg->has_monotonic_remote_time());
308 CHECK(!msg->has_realtime_remote_time());
309 CHECK(!msg->has_remote_queue_index());
310 return true;
311 }
312 return false;
313 });
314}
315
316// Counts the number of messages (channel, count) for all timestamp messages.
317std::vector<std::pair<int, int>> CountChannelsTimestamp(
318 std::string_view filename) {
319 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
320 if (!msg->has_data()) {
321 CHECK(msg->has_monotonic_remote_time());
322 CHECK(msg->has_realtime_remote_time());
323 CHECK(msg->has_remote_queue_index());
324 return true;
325 }
326 return false;
327 });
328}
329
Austin Schuhcde938c2020-02-02 17:30:07 -0800330// Tests that we can write and read simple multi-node log files.
331TEST_F(MultinodeLoggerTest, SimpleMultiNode) {
Austin Schuh15649d62019-12-28 16:36:38 -0800332 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700333 LoggerState pi1_logger = MakeLogger(pi1_);
334 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuh15649d62019-12-28 16:36:38 -0800335
336 event_loop_factory_.RunFor(chrono::milliseconds(95));
337
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700338 StartLogger(&pi1_logger);
339 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800340
Austin Schuh15649d62019-12-28 16:36:38 -0800341 event_loop_factory_.RunFor(chrono::milliseconds(20000));
342 }
343
Austin Schuh6f3babe2020-01-26 20:34:50 -0800344 {
345 // Confirm that the headers are all for the correct nodes.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700346 FlatbufferVector<LogFileHeader> logheader1 = ReadHeader(logfiles_[0]);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800347 EXPECT_EQ(logheader1.message().node()->name()->string_view(), "pi1");
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700348 FlatbufferVector<LogFileHeader> logheader2 = ReadHeader(logfiles_[1]);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800349 EXPECT_EQ(logheader2.message().node()->name()->string_view(), "pi2");
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700350 FlatbufferVector<LogFileHeader> logheader3 = ReadHeader(logfiles_[2]);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800351 EXPECT_EQ(logheader3.message().node()->name()->string_view(), "pi2");
Austin Schuh15649d62019-12-28 16:36:38 -0800352
Austin Schuh6f3babe2020-01-26 20:34:50 -0800353 // Timing reports, pings
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700354 EXPECT_THAT(CountChannelsData(logfiles_[0]),
Austin Schuhcde938c2020-02-02 17:30:07 -0800355 ::testing::ElementsAre(::testing::Pair(1, 40),
Austin Schuh6f3babe2020-01-26 20:34:50 -0800356 ::testing::Pair(4, 2001)));
357 // Timestamps for pong
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700358 EXPECT_THAT(CountChannelsTimestamp(logfiles_[0]),
Austin Schuh6f3babe2020-01-26 20:34:50 -0800359 ::testing::ElementsAre(::testing::Pair(5, 2001)));
360
361 // Pong data.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700362 EXPECT_THAT(CountChannelsData(logfiles_[1]),
Austin Schuh6f3babe2020-01-26 20:34:50 -0800363 ::testing::ElementsAre(::testing::Pair(5, 2001)));
364 // No timestamps
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700365 EXPECT_THAT(CountChannelsTimestamp(logfiles_[1]), ::testing::ElementsAre());
Austin Schuh6f3babe2020-01-26 20:34:50 -0800366
367 // Timing reports and pongs.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700368 EXPECT_THAT(CountChannelsData(logfiles_[2]),
Austin Schuhcde938c2020-02-02 17:30:07 -0800369 ::testing::ElementsAre(::testing::Pair(3, 40),
Austin Schuh6f3babe2020-01-26 20:34:50 -0800370 ::testing::Pair(5, 2001)));
371 // And ping timestamps.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700372 EXPECT_THAT(CountChannelsTimestamp(logfiles_[2]),
Austin Schuh6f3babe2020-01-26 20:34:50 -0800373 ::testing::ElementsAre(::testing::Pair(4, 2001)));
374 }
375
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700376 LogReader reader({std::vector<std::string>{logfiles_[0]},
377 std::vector<std::string>{logfiles_[2]}});
Austin Schuh6f3babe2020-01-26 20:34:50 -0800378
Austin Schuhac0771c2020-01-07 18:36:30 -0800379 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
Austin Schuh6331ef92020-01-07 18:28:09 -0800380 log_reader_factory.set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800381
382 // This sends out the fetched messages and advances time to the start of the
383 // log file.
Austin Schuh6331ef92020-01-07 18:28:09 -0800384 reader.Register(&log_reader_factory);
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800385
Austin Schuhac0771c2020-01-07 18:36:30 -0800386 const Node *pi1 =
387 configuration::GetNode(log_reader_factory.configuration(), "pi1");
Austin Schuh6f3babe2020-01-26 20:34:50 -0800388 const Node *pi2 =
389 configuration::GetNode(log_reader_factory.configuration(), "pi2");
Austin Schuhac0771c2020-01-07 18:36:30 -0800390
Austin Schuh6f3babe2020-01-26 20:34:50 -0800391 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800392
393 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800394
Austin Schuh6f3babe2020-01-26 20:34:50 -0800395 std::unique_ptr<EventLoop> pi1_event_loop =
Austin Schuhac0771c2020-01-07 18:36:30 -0800396 log_reader_factory.MakeEventLoop("test", pi1);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800397 std::unique_ptr<EventLoop> pi2_event_loop =
398 log_reader_factory.MakeEventLoop("test", pi2);
Austin Schuh15649d62019-12-28 16:36:38 -0800399
Austin Schuh6f3babe2020-01-26 20:34:50 -0800400 int pi1_ping_count = 10;
401 int pi2_ping_count = 10;
402 int pi1_pong_count = 10;
403 int pi2_pong_count = 10;
Austin Schuh15649d62019-12-28 16:36:38 -0800404
405 // Confirm that the ping value matches.
Austin Schuh6f3babe2020-01-26 20:34:50 -0800406 pi1_event_loop->MakeWatcher(
407 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
408 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
409 << pi1_event_loop->context().monotonic_remote_time << " -> "
410 << pi1_event_loop->context().monotonic_event_time;
411 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
412 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
413 pi1_ping_count * chrono::milliseconds(10) +
414 monotonic_clock::epoch());
415 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
416 pi1_ping_count * chrono::milliseconds(10) +
417 realtime_clock::epoch());
418 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
419 pi1_event_loop->context().monotonic_event_time);
420 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
421 pi1_event_loop->context().realtime_event_time);
Austin Schuh15649d62019-12-28 16:36:38 -0800422
Austin Schuh6f3babe2020-01-26 20:34:50 -0800423 ++pi1_ping_count;
424 });
425 pi2_event_loop->MakeWatcher(
426 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
427 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
428 << pi2_event_loop->context().monotonic_remote_time << " -> "
429 << pi2_event_loop->context().monotonic_event_time;
430 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
431
432 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
433 pi2_ping_count * chrono::milliseconds(10) +
434 monotonic_clock::epoch());
435 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
436 pi2_ping_count * chrono::milliseconds(10) +
437 realtime_clock::epoch());
438 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time +
439 chrono::microseconds(150),
440 pi2_event_loop->context().monotonic_event_time);
441 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time +
442 chrono::microseconds(150),
443 pi2_event_loop->context().realtime_event_time);
444 ++pi2_ping_count;
Austin Schuh15649d62019-12-28 16:36:38 -0800445 });
446
Austin Schuh6f3babe2020-01-26 20:34:50 -0800447 constexpr ssize_t kQueueIndexOffset = 0;
448 // Confirm that the ping and pong counts both match, and the value also
449 // matches.
450 pi1_event_loop->MakeWatcher(
451 "/test", [&pi1_event_loop, &pi1_ping_count,
452 &pi1_pong_count](const examples::Pong &pong) {
453 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
454 << pi1_event_loop->context().monotonic_remote_time << " -> "
455 << pi1_event_loop->context().monotonic_event_time;
456
457 EXPECT_EQ(pi1_event_loop->context().remote_queue_index,
458 pi1_pong_count + kQueueIndexOffset);
459 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
460 chrono::microseconds(200) +
461 pi1_pong_count * chrono::milliseconds(10) +
462 monotonic_clock::epoch());
463 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
464 chrono::microseconds(200) +
465 pi1_pong_count * chrono::milliseconds(10) +
466 realtime_clock::epoch());
467
468 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time +
469 chrono::microseconds(150),
470 pi1_event_loop->context().monotonic_event_time);
471 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time +
472 chrono::microseconds(150),
473 pi1_event_loop->context().realtime_event_time);
474
475 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
476 ++pi1_pong_count;
477 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
478 });
479 pi2_event_loop->MakeWatcher(
480 "/test", [&pi2_event_loop, &pi2_ping_count,
481 &pi2_pong_count](const examples::Pong &pong) {
482 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
483 << pi2_event_loop->context().monotonic_remote_time << " -> "
484 << pi2_event_loop->context().monotonic_event_time;
485
486 EXPECT_EQ(pi2_event_loop->context().remote_queue_index,
487 pi2_pong_count + kQueueIndexOffset - 9);
488
489 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
490 chrono::microseconds(200) +
491 pi2_pong_count * chrono::milliseconds(10) +
492 monotonic_clock::epoch());
493 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
494 chrono::microseconds(200) +
495 pi2_pong_count * chrono::milliseconds(10) +
496 realtime_clock::epoch());
497
498 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
499 pi2_event_loop->context().monotonic_event_time);
500 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
501 pi2_event_loop->context().realtime_event_time);
502
503 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
504 ++pi2_pong_count;
505 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
506 });
507
508 log_reader_factory.Run();
509 EXPECT_EQ(pi1_ping_count, 2010);
510 EXPECT_EQ(pi2_ping_count, 2010);
511 EXPECT_EQ(pi1_pong_count, 2010);
512 EXPECT_EQ(pi2_pong_count, 2010);
Austin Schuh6331ef92020-01-07 18:28:09 -0800513
514 reader.Deregister();
Austin Schuh15649d62019-12-28 16:36:38 -0800515}
516
James Kuszmaul46d82582020-05-09 19:50:09 -0700517typedef MultinodeLoggerTest MultinodeLoggerDeathTest;
518
519// Test that if we feed the replay with a mismatched node list that we die on
520// the LogReader constructor.
521TEST_F(MultinodeLoggerDeathTest, MultiNodeBadReplayConfig) {
James Kuszmaul46d82582020-05-09 19:50:09 -0700522 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700523 LoggerState pi1_logger = MakeLogger(pi1_);
524 LoggerState pi2_logger = MakeLogger(pi2_);
James Kuszmaul46d82582020-05-09 19:50:09 -0700525
526 event_loop_factory_.RunFor(chrono::milliseconds(95));
527
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700528 StartLogger(&pi1_logger);
529 StartLogger(&pi2_logger);
James Kuszmaul46d82582020-05-09 19:50:09 -0700530
James Kuszmaul46d82582020-05-09 19:50:09 -0700531 event_loop_factory_.RunFor(chrono::milliseconds(20000));
532 }
533
534 // Test that, if we add an additional node to the replay config that the
535 // logger complains about the mismatch in number of nodes.
536 FlatbufferDetachedBuffer<Configuration> extra_nodes_config =
537 configuration::MergeWithConfig(&config_.message(), R"({
538 "nodes": [
539 {
540 "name": "extra-node"
541 }
542 ]
543 }
544 )");
545
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700546 EXPECT_DEATH(LogReader({std::vector<std::string>{logfiles_[0]},
547 std::vector<std::string>{logfiles_[2]}},
James Kuszmaul46d82582020-05-09 19:50:09 -0700548 &extra_nodes_config.message()),
549 "Log file and replay config need to have matching nodes lists.");
550 ;
551}
552
Austin Schuhcde938c2020-02-02 17:30:07 -0800553// Tests that we can read log files where they don't start at the same monotonic
554// time.
555TEST_F(MultinodeLoggerTest, StaggeredStart) {
Austin Schuhcde938c2020-02-02 17:30:07 -0800556 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700557 LoggerState pi1_logger = MakeLogger(pi1_);
558 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuhcde938c2020-02-02 17:30:07 -0800559
560 event_loop_factory_.RunFor(chrono::milliseconds(95));
561
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700562 StartLogger(&pi1_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800563
564 event_loop_factory_.RunFor(chrono::milliseconds(200));
565
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700566 StartLogger(&pi2_logger);
567
Austin Schuhcde938c2020-02-02 17:30:07 -0800568 event_loop_factory_.RunFor(chrono::milliseconds(20000));
569 }
570
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700571 LogReader reader({std::vector<std::string>{logfiles_[0]},
572 std::vector<std::string>{logfiles_[2]}});
Austin Schuhcde938c2020-02-02 17:30:07 -0800573
574 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
575 log_reader_factory.set_send_delay(chrono::microseconds(0));
576
577 // This sends out the fetched messages and advances time to the start of the
578 // log file.
579 reader.Register(&log_reader_factory);
580
581 const Node *pi1 =
582 configuration::GetNode(log_reader_factory.configuration(), "pi1");
583 const Node *pi2 =
584 configuration::GetNode(log_reader_factory.configuration(), "pi2");
585
586 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
587
588 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
589
590 std::unique_ptr<EventLoop> pi1_event_loop =
591 log_reader_factory.MakeEventLoop("test", pi1);
592 std::unique_ptr<EventLoop> pi2_event_loop =
593 log_reader_factory.MakeEventLoop("test", pi2);
594
595 int pi1_ping_count = 30;
596 int pi2_ping_count = 30;
597 int pi1_pong_count = 30;
598 int pi2_pong_count = 30;
599
600 // Confirm that the ping value matches.
601 pi1_event_loop->MakeWatcher(
602 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
603 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
604 << pi1_event_loop->context().monotonic_remote_time << " -> "
605 << pi1_event_loop->context().monotonic_event_time;
606 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
607
608 ++pi1_ping_count;
609 });
610 pi2_event_loop->MakeWatcher(
611 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
612 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
613 << pi2_event_loop->context().monotonic_remote_time << " -> "
614 << pi2_event_loop->context().monotonic_event_time;
615 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
616
617 ++pi2_ping_count;
618 });
619
620 // Confirm that the ping and pong counts both match, and the value also
621 // matches.
622 pi1_event_loop->MakeWatcher(
623 "/test", [&pi1_event_loop, &pi1_ping_count,
624 &pi1_pong_count](const examples::Pong &pong) {
625 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
626 << pi1_event_loop->context().monotonic_remote_time << " -> "
627 << pi1_event_loop->context().monotonic_event_time;
628
629 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
630 ++pi1_pong_count;
631 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
632 });
633 pi2_event_loop->MakeWatcher(
634 "/test", [&pi2_event_loop, &pi2_ping_count,
635 &pi2_pong_count](const examples::Pong &pong) {
636 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
637 << pi2_event_loop->context().monotonic_remote_time << " -> "
638 << pi2_event_loop->context().monotonic_event_time;
639
640 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
641 ++pi2_pong_count;
642 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
643 });
644
645 log_reader_factory.Run();
646 EXPECT_EQ(pi1_ping_count, 2030);
647 EXPECT_EQ(pi2_ping_count, 2030);
648 EXPECT_EQ(pi1_pong_count, 2030);
649 EXPECT_EQ(pi2_pong_count, 2030);
650
651 reader.Deregister();
652}
Austin Schuh6f3babe2020-01-26 20:34:50 -0800653
Austin Schuh8bd96322020-02-13 21:18:22 -0800654// Tests that we can read log files where the monotonic clocks drift and don't
655// match correctly. While we are here, also test that different ending times
656// also is readable.
657TEST_F(MultinodeLoggerTest, MismatchedClocks) {
Austin Schuhcde938c2020-02-02 17:30:07 -0800658 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700659 LoggerState pi2_logger = MakeLogger(pi2_);
660
Austin Schuh8bd96322020-02-13 21:18:22 -0800661 NodeEventLoopFactory *pi2 =
662 event_loop_factory_.GetNodeEventLoopFactory(pi2_);
663 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
664 << pi2->realtime_now() << " distributed "
665 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -0800666
Austin Schuh8bd96322020-02-13 21:18:22 -0800667 const chrono::nanoseconds initial_pi2_offset = -chrono::seconds(1000);
668 chrono::nanoseconds pi2_offset = initial_pi2_offset;
Austin Schuhcde938c2020-02-02 17:30:07 -0800669
Austin Schuhbe69cf32020-08-27 11:38:33 -0700670 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800671 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
672 << pi2->realtime_now() << " distributed "
673 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -0800674
Austin Schuhcde938c2020-02-02 17:30:07 -0800675
Austin Schuh8bd96322020-02-13 21:18:22 -0800676 for (int i = 0; i < 95; ++i) {
677 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -0700678 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800679 event_loop_factory_.RunFor(chrono::milliseconds(1));
680 }
Austin Schuhcde938c2020-02-02 17:30:07 -0800681
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700682
683 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800684
Austin Schuh8bd96322020-02-13 21:18:22 -0800685 event_loop_factory_.RunFor(chrono::milliseconds(200));
Austin Schuhcde938c2020-02-02 17:30:07 -0800686
Austin Schuh8bd96322020-02-13 21:18:22 -0800687 {
688 // Run pi1's logger for only part of the time.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700689 LoggerState pi1_logger = MakeLogger(pi1_);
Austin Schuh8bd96322020-02-13 21:18:22 -0800690
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700691 StartLogger(&pi1_logger);
Austin Schuh8bd96322020-02-13 21:18:22 -0800692
693 for (int i = 0; i < 20000; ++i) {
694 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -0700695 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800696 event_loop_factory_.RunFor(chrono::milliseconds(1));
697 }
698
699 EXPECT_GT(pi2_offset - initial_pi2_offset,
700 event_loop_factory_.send_delay() +
701 event_loop_factory_.network_delay());
702
703 for (int i = 0; i < 40000; ++i) {
704 pi2_offset -= chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -0700705 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800706 event_loop_factory_.RunFor(chrono::milliseconds(1));
707 }
708 }
709
710 // And log a bit more on pi2.
711 event_loop_factory_.RunFor(chrono::milliseconds(400));
Austin Schuhcde938c2020-02-02 17:30:07 -0800712 }
713
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700714 LogReader reader({std::vector<std::string>{logfiles_[0]},
715 std::vector<std::string>{logfiles_[2]}});
Austin Schuhcde938c2020-02-02 17:30:07 -0800716
717 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
718 log_reader_factory.set_send_delay(chrono::microseconds(0));
719
720 // This sends out the fetched messages and advances time to the start of the
721 // log file.
722 reader.Register(&log_reader_factory);
723
724
725 const Node *pi1 =
726 configuration::GetNode(log_reader_factory.configuration(), "pi1");
727 const Node *pi2 =
728 configuration::GetNode(log_reader_factory.configuration(), "pi2");
729
730 LOG(INFO) << "Done registering (pi1) "
731 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now() << " "
732 << log_reader_factory.GetNodeEventLoopFactory(pi1)->realtime_now();
733 LOG(INFO) << "Done registering (pi2) "
734 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now() << " "
735 << log_reader_factory.GetNodeEventLoopFactory(pi2)->realtime_now();
736
737 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
738
739 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
740
741 std::unique_ptr<EventLoop> pi1_event_loop =
742 log_reader_factory.MakeEventLoop("test", pi1);
743 std::unique_ptr<EventLoop> pi2_event_loop =
744 log_reader_factory.MakeEventLoop("test", pi2);
745
746 int pi1_ping_count = 30;
747 int pi2_ping_count = 30;
748 int pi1_pong_count = 30;
749 int pi2_pong_count = 30;
750
751 // Confirm that the ping value matches.
752 pi1_event_loop->MakeWatcher(
753 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
754 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
755 << pi1_event_loop->context().monotonic_remote_time << " -> "
756 << pi1_event_loop->context().monotonic_event_time;
757 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
758
759 ++pi1_ping_count;
760 });
761 pi2_event_loop->MakeWatcher(
762 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
763 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
764 << pi2_event_loop->context().monotonic_remote_time << " -> "
765 << pi2_event_loop->context().monotonic_event_time;
766 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
767
768 ++pi2_ping_count;
769 });
770
771 // Confirm that the ping and pong counts both match, and the value also
772 // matches.
773 pi1_event_loop->MakeWatcher(
774 "/test", [&pi1_event_loop, &pi1_ping_count,
775 &pi1_pong_count](const examples::Pong &pong) {
776 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
777 << pi1_event_loop->context().monotonic_remote_time << " -> "
778 << pi1_event_loop->context().monotonic_event_time;
779
780 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
781 ++pi1_pong_count;
782 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
783 });
784 pi2_event_loop->MakeWatcher(
785 "/test", [&pi2_event_loop, &pi2_ping_count,
786 &pi2_pong_count](const examples::Pong &pong) {
787 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
788 << pi2_event_loop->context().monotonic_remote_time << " -> "
789 << pi2_event_loop->context().monotonic_event_time;
790
791 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
792 ++pi2_pong_count;
793 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
794 });
795
796 log_reader_factory.Run();
Austin Schuh8bd96322020-02-13 21:18:22 -0800797 EXPECT_EQ(pi1_ping_count, 6030);
798 EXPECT_EQ(pi2_ping_count, 6030);
799 EXPECT_EQ(pi1_pong_count, 6030);
800 EXPECT_EQ(pi2_pong_count, 6030);
Austin Schuhcde938c2020-02-02 17:30:07 -0800801
802 reader.Deregister();
803}
804
Austin Schuh8bd96322020-02-13 21:18:22 -0800805// TODO(austin): We can write a test which recreates a logfile and confirms that
806// we get it back. That is the ultimate test.
807
Austin Schuhe309d2a2019-11-29 13:25:21 -0800808} // namespace testing
809} // namespace logger
810} // namespace aos