blob: 3b10f9de585752ac2f7a5e3d97282f90c6cdc40f [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;
Austin Schuh4c3b9702020-08-30 11:34:55 -0700174 ping_.set_quiet(true);
Austin Schuh4c4e0092019-12-22 16:18:03 -0800175
176 {
177 DetachedBufferWriter writer(logfile);
178 std::unique_ptr<EventLoop> logger_event_loop =
179 event_loop_factory_.MakeEventLoop("logger");
180
181 std::unique_ptr<EventLoop> ping_spammer_event_loop =
182 event_loop_factory_.MakeEventLoop("ping_spammer");
183 aos::Sender<examples::Ping> ping_sender =
184 ping_spammer_event_loop->MakeSender<examples::Ping>("/test");
185
186 aos::TimerHandler *timer_handler =
187 ping_spammer_event_loop->AddTimer([&ping_sender]() {
188 aos::Sender<examples::Ping>::Builder builder =
189 ping_sender.MakeBuilder();
190 examples::Ping::Builder ping_builder =
191 builder.MakeBuilder<examples::Ping>();
192 CHECK(builder.Send(ping_builder.Finish()));
193 });
194
195 // 100 ms / 0.05 ms -> 2000 messages. Should be enough to crash it.
196 ping_spammer_event_loop->OnRun([&ping_spammer_event_loop, timer_handler]() {
197 timer_handler->Setup(ping_spammer_event_loop->monotonic_now(),
198 chrono::microseconds(50));
199 });
200
201 Logger logger(&writer, logger_event_loop.get(),
202 std::chrono::milliseconds(100));
203
204 event_loop_factory_.RunFor(chrono::milliseconds(1000));
205 }
206}
207
Austin Schuh15649d62019-12-28 16:36:38 -0800208class MultinodeLoggerTest : public ::testing::Test {
209 public:
210 MultinodeLoggerTest()
211 : config_(aos::configuration::ReadConfig(
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800212 "aos/events/logging/multinode_pingpong_config.json")),
Austin Schuhac0771c2020-01-07 18:36:30 -0800213 event_loop_factory_(&config_.message()),
Austin Schuhcde938c2020-02-02 17:30:07 -0800214 pi1_(
215 configuration::GetNode(event_loop_factory_.configuration(), "pi1")),
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700216 pi2_(
217 configuration::GetNode(event_loop_factory_.configuration(), "pi2")),
218 tmp_dir_(getenv("TEST_TMPDIR")),
219 logfile_base_(tmp_dir_ + "/multi_logfile"),
220 logfiles_({logfile_base_ + "_pi1_data.bfbs",
221 logfile_base_ + "_pi2_data/test/aos.examples.Pong.bfbs",
222 logfile_base_ + "_pi2_data.bfbs"}),
223 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping", pi1_)),
224 ping_(ping_event_loop_.get()),
225 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong", pi2_)),
226 pong_(pong_event_loop_.get()) {
227 // Go through and remove the logfiles if they already exist.
228 for (const auto file : logfiles_) {
229 unlink(file.c_str());
230 }
231
232 LOG(INFO) << "Logging data to " << logfiles_[0] << ", " << logfiles_[1]
233 << " and " << logfiles_[2];
234 }
235
236 struct LoggerState {
237 std::unique_ptr<EventLoop> event_loop;
238 std::unique_ptr<Logger> logger;
239 };
240
241 LoggerState MakeLogger(const Node *node) {
242 return {event_loop_factory_.MakeEventLoop("logger", node), {}};
243 }
244
245 void StartLogger(LoggerState *logger) {
246 logger->logger = std::make_unique<Logger>(
247 std::make_unique<MultiNodeLogNamer>(logfile_base_,
248 logger->event_loop->configuration(),
249 logger->event_loop->node()),
250 logger->event_loop.get(), chrono::milliseconds(100));
251 }
Austin Schuh15649d62019-12-28 16:36:38 -0800252
253 // Config and factory.
254 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
255 SimulatedEventLoopFactory event_loop_factory_;
256
Austin Schuhcde938c2020-02-02 17:30:07 -0800257 const Node *pi1_;
258 const Node *pi2_;
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700259
260 std::string tmp_dir_;
261 std::string logfile_base_;
262 std::array<std::string, 3> logfiles_;
263
264 std::unique_ptr<EventLoop> ping_event_loop_;
265 Ping ping_;
266 std::unique_ptr<EventLoop> pong_event_loop_;
267 Pong pong_;
Austin Schuh15649d62019-12-28 16:36:38 -0800268};
269
Austin Schuh391e3172020-09-01 22:48:18 -0700270// Counts the number of messages on a channel. Returns (channel name, channel
271// type, count) for every message matching matcher()
272std::vector<std::tuple<std::string, std::string, int>> CountChannelsMatching(
Austin Schuh6f3babe2020-01-26 20:34:50 -0800273 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
Austin Schuh391e3172020-09-01 22:48:18 -0700291 std::vector<std::tuple<std::string, std::string, int>> result;
Austin Schuh6f3babe2020-01-26 20:34:50 -0800292 int channel = 0;
293 for (size_t i = 0; i < counts.size(); ++i) {
294 if (counts[i] != 0) {
Austin Schuh391e3172020-09-01 22:48:18 -0700295 const Channel *channel =
296 message_reader.log_file_header()->configuration()->channels()->Get(i);
297 result.push_back(std::make_tuple(channel->name()->str(),
298 channel->type()->str(), counts[i]));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800299 }
300 ++channel;
301 }
302
303 return result;
304}
305
306// Counts the number of messages (channel, count) for all data messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700307std::vector<std::tuple<std::string, std::string, int>> CountChannelsData(
308 std::string_view filename) {
Austin Schuh6f3babe2020-01-26 20:34:50 -0800309 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
310 if (msg->has_data()) {
311 CHECK(!msg->has_monotonic_remote_time());
312 CHECK(!msg->has_realtime_remote_time());
313 CHECK(!msg->has_remote_queue_index());
314 return true;
315 }
316 return false;
317 });
318}
319
320// Counts the number of messages (channel, count) for all timestamp messages.
Austin Schuh391e3172020-09-01 22:48:18 -0700321std::vector<std::tuple<std::string, std::string, int>> CountChannelsTimestamp(
Austin Schuh6f3babe2020-01-26 20:34:50 -0800322 std::string_view filename) {
323 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
324 if (!msg->has_data()) {
325 CHECK(msg->has_monotonic_remote_time());
326 CHECK(msg->has_realtime_remote_time());
327 CHECK(msg->has_remote_queue_index());
328 return true;
329 }
330 return false;
331 });
332}
333
Austin Schuhcde938c2020-02-02 17:30:07 -0800334// Tests that we can write and read simple multi-node log files.
335TEST_F(MultinodeLoggerTest, SimpleMultiNode) {
Austin Schuh15649d62019-12-28 16:36:38 -0800336 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700337 LoggerState pi1_logger = MakeLogger(pi1_);
338 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuh15649d62019-12-28 16:36:38 -0800339
340 event_loop_factory_.RunFor(chrono::milliseconds(95));
341
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700342 StartLogger(&pi1_logger);
343 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800344
Austin Schuh15649d62019-12-28 16:36:38 -0800345 event_loop_factory_.RunFor(chrono::milliseconds(20000));
346 }
347
Austin Schuh6f3babe2020-01-26 20:34:50 -0800348 {
349 // Confirm that the headers are all for the correct nodes.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700350 FlatbufferVector<LogFileHeader> logheader1 = ReadHeader(logfiles_[0]);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800351 EXPECT_EQ(logheader1.message().node()->name()->string_view(), "pi1");
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700352 FlatbufferVector<LogFileHeader> logheader2 = ReadHeader(logfiles_[1]);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800353 EXPECT_EQ(logheader2.message().node()->name()->string_view(), "pi2");
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700354 FlatbufferVector<LogFileHeader> logheader3 = ReadHeader(logfiles_[2]);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800355 EXPECT_EQ(logheader3.message().node()->name()->string_view(), "pi2");
Austin Schuh15649d62019-12-28 16:36:38 -0800356
Austin Schuh391e3172020-09-01 22:48:18 -0700357 using ::testing::UnorderedElementsAre;
358
Austin Schuh6f3babe2020-01-26 20:34:50 -0800359 // Timing reports, pings
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700360 EXPECT_THAT(CountChannelsData(logfiles_[0]),
Austin Schuh391e3172020-09-01 22:48:18 -0700361 UnorderedElementsAre(
362 std::make_tuple("/pi1/aos", "aos.timing.Report", 40),
363 std::make_tuple("/test", "aos.examples.Ping", 2001)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800364 // Timestamps for pong
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700365 EXPECT_THAT(CountChannelsTimestamp(logfiles_[0]),
Austin Schuh391e3172020-09-01 22:48:18 -0700366 UnorderedElementsAre(
367 std::make_tuple("/test", "aos.examples.Pong", 2001)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800368
369 // Pong data.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700370 EXPECT_THAT(CountChannelsData(logfiles_[1]),
Austin Schuh391e3172020-09-01 22:48:18 -0700371 UnorderedElementsAre(
372 std::make_tuple("/test", "aos.examples.Pong", 2001)));
373
Austin Schuh6f3babe2020-01-26 20:34:50 -0800374 // No timestamps
Austin Schuh391e3172020-09-01 22:48:18 -0700375 EXPECT_THAT(CountChannelsTimestamp(logfiles_[1]), UnorderedElementsAre());
Austin Schuh6f3babe2020-01-26 20:34:50 -0800376
377 // Timing reports and pongs.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700378 EXPECT_THAT(CountChannelsData(logfiles_[2]),
Austin Schuh391e3172020-09-01 22:48:18 -0700379 UnorderedElementsAre(
380 std::make_tuple("/pi2/aos", "aos.timing.Report", 40),
381 std::make_tuple("/test", "aos.examples.Pong", 2001)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800382 // And ping timestamps.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700383 EXPECT_THAT(CountChannelsTimestamp(logfiles_[2]),
Austin Schuh391e3172020-09-01 22:48:18 -0700384 UnorderedElementsAre(
385 std::make_tuple("/test", "aos.examples.Ping", 2001)));
Austin Schuh6f3babe2020-01-26 20:34:50 -0800386 }
387
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700388 LogReader reader({std::vector<std::string>{logfiles_[0]},
389 std::vector<std::string>{logfiles_[2]}});
Austin Schuh6f3babe2020-01-26 20:34:50 -0800390
Austin Schuhac0771c2020-01-07 18:36:30 -0800391 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
Austin Schuh6331ef92020-01-07 18:28:09 -0800392 log_reader_factory.set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800393
394 // This sends out the fetched messages and advances time to the start of the
395 // log file.
Austin Schuh6331ef92020-01-07 18:28:09 -0800396 reader.Register(&log_reader_factory);
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800397
Austin Schuhac0771c2020-01-07 18:36:30 -0800398 const Node *pi1 =
399 configuration::GetNode(log_reader_factory.configuration(), "pi1");
Austin Schuh6f3babe2020-01-26 20:34:50 -0800400 const Node *pi2 =
401 configuration::GetNode(log_reader_factory.configuration(), "pi2");
Austin Schuhac0771c2020-01-07 18:36:30 -0800402
Austin Schuh6f3babe2020-01-26 20:34:50 -0800403 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800404
405 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800406
Austin Schuh6f3babe2020-01-26 20:34:50 -0800407 std::unique_ptr<EventLoop> pi1_event_loop =
Austin Schuhac0771c2020-01-07 18:36:30 -0800408 log_reader_factory.MakeEventLoop("test", pi1);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800409 std::unique_ptr<EventLoop> pi2_event_loop =
410 log_reader_factory.MakeEventLoop("test", pi2);
Austin Schuh15649d62019-12-28 16:36:38 -0800411
Austin Schuh6f3babe2020-01-26 20:34:50 -0800412 int pi1_ping_count = 10;
413 int pi2_ping_count = 10;
414 int pi1_pong_count = 10;
415 int pi2_pong_count = 10;
Austin Schuh15649d62019-12-28 16:36:38 -0800416
417 // Confirm that the ping value matches.
Austin Schuh6f3babe2020-01-26 20:34:50 -0800418 pi1_event_loop->MakeWatcher(
419 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
420 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
421 << pi1_event_loop->context().monotonic_remote_time << " -> "
422 << pi1_event_loop->context().monotonic_event_time;
423 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
424 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
425 pi1_ping_count * chrono::milliseconds(10) +
426 monotonic_clock::epoch());
427 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
428 pi1_ping_count * chrono::milliseconds(10) +
429 realtime_clock::epoch());
430 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
431 pi1_event_loop->context().monotonic_event_time);
432 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
433 pi1_event_loop->context().realtime_event_time);
Austin Schuh15649d62019-12-28 16:36:38 -0800434
Austin Schuh6f3babe2020-01-26 20:34:50 -0800435 ++pi1_ping_count;
436 });
437 pi2_event_loop->MakeWatcher(
438 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
439 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
440 << pi2_event_loop->context().monotonic_remote_time << " -> "
441 << pi2_event_loop->context().monotonic_event_time;
442 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
443
444 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
445 pi2_ping_count * chrono::milliseconds(10) +
446 monotonic_clock::epoch());
447 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
448 pi2_ping_count * chrono::milliseconds(10) +
449 realtime_clock::epoch());
450 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time +
451 chrono::microseconds(150),
452 pi2_event_loop->context().monotonic_event_time);
453 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time +
454 chrono::microseconds(150),
455 pi2_event_loop->context().realtime_event_time);
456 ++pi2_ping_count;
Austin Schuh15649d62019-12-28 16:36:38 -0800457 });
458
Austin Schuh6f3babe2020-01-26 20:34:50 -0800459 constexpr ssize_t kQueueIndexOffset = 0;
460 // Confirm that the ping and pong counts both match, and the value also
461 // matches.
462 pi1_event_loop->MakeWatcher(
463 "/test", [&pi1_event_loop, &pi1_ping_count,
464 &pi1_pong_count](const examples::Pong &pong) {
465 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
466 << pi1_event_loop->context().monotonic_remote_time << " -> "
467 << pi1_event_loop->context().monotonic_event_time;
468
469 EXPECT_EQ(pi1_event_loop->context().remote_queue_index,
470 pi1_pong_count + kQueueIndexOffset);
471 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
472 chrono::microseconds(200) +
473 pi1_pong_count * chrono::milliseconds(10) +
474 monotonic_clock::epoch());
475 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
476 chrono::microseconds(200) +
477 pi1_pong_count * chrono::milliseconds(10) +
478 realtime_clock::epoch());
479
480 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time +
481 chrono::microseconds(150),
482 pi1_event_loop->context().monotonic_event_time);
483 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time +
484 chrono::microseconds(150),
485 pi1_event_loop->context().realtime_event_time);
486
487 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
488 ++pi1_pong_count;
489 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
490 });
491 pi2_event_loop->MakeWatcher(
492 "/test", [&pi2_event_loop, &pi2_ping_count,
493 &pi2_pong_count](const examples::Pong &pong) {
494 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
495 << pi2_event_loop->context().monotonic_remote_time << " -> "
496 << pi2_event_loop->context().monotonic_event_time;
497
498 EXPECT_EQ(pi2_event_loop->context().remote_queue_index,
499 pi2_pong_count + kQueueIndexOffset - 9);
500
501 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
502 chrono::microseconds(200) +
503 pi2_pong_count * chrono::milliseconds(10) +
504 monotonic_clock::epoch());
505 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
506 chrono::microseconds(200) +
507 pi2_pong_count * chrono::milliseconds(10) +
508 realtime_clock::epoch());
509
510 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
511 pi2_event_loop->context().monotonic_event_time);
512 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
513 pi2_event_loop->context().realtime_event_time);
514
515 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
516 ++pi2_pong_count;
517 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
518 });
519
520 log_reader_factory.Run();
521 EXPECT_EQ(pi1_ping_count, 2010);
522 EXPECT_EQ(pi2_ping_count, 2010);
523 EXPECT_EQ(pi1_pong_count, 2010);
524 EXPECT_EQ(pi2_pong_count, 2010);
Austin Schuh6331ef92020-01-07 18:28:09 -0800525
526 reader.Deregister();
Austin Schuh15649d62019-12-28 16:36:38 -0800527}
528
James Kuszmaul46d82582020-05-09 19:50:09 -0700529typedef MultinodeLoggerTest MultinodeLoggerDeathTest;
530
531// Test that if we feed the replay with a mismatched node list that we die on
532// the LogReader constructor.
533TEST_F(MultinodeLoggerDeathTest, MultiNodeBadReplayConfig) {
James Kuszmaul46d82582020-05-09 19:50:09 -0700534 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700535 LoggerState pi1_logger = MakeLogger(pi1_);
536 LoggerState pi2_logger = MakeLogger(pi2_);
James Kuszmaul46d82582020-05-09 19:50:09 -0700537
538 event_loop_factory_.RunFor(chrono::milliseconds(95));
539
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700540 StartLogger(&pi1_logger);
541 StartLogger(&pi2_logger);
James Kuszmaul46d82582020-05-09 19:50:09 -0700542
James Kuszmaul46d82582020-05-09 19:50:09 -0700543 event_loop_factory_.RunFor(chrono::milliseconds(20000));
544 }
545
546 // Test that, if we add an additional node to the replay config that the
547 // logger complains about the mismatch in number of nodes.
548 FlatbufferDetachedBuffer<Configuration> extra_nodes_config =
549 configuration::MergeWithConfig(&config_.message(), R"({
550 "nodes": [
551 {
552 "name": "extra-node"
553 }
554 ]
555 }
556 )");
557
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700558 EXPECT_DEATH(LogReader({std::vector<std::string>{logfiles_[0]},
559 std::vector<std::string>{logfiles_[2]}},
James Kuszmaul46d82582020-05-09 19:50:09 -0700560 &extra_nodes_config.message()),
561 "Log file and replay config need to have matching nodes lists.");
562 ;
563}
564
Austin Schuhcde938c2020-02-02 17:30:07 -0800565// Tests that we can read log files where they don't start at the same monotonic
566// time.
567TEST_F(MultinodeLoggerTest, StaggeredStart) {
Austin Schuhcde938c2020-02-02 17:30:07 -0800568 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700569 LoggerState pi1_logger = MakeLogger(pi1_);
570 LoggerState pi2_logger = MakeLogger(pi2_);
Austin Schuhcde938c2020-02-02 17:30:07 -0800571
572 event_loop_factory_.RunFor(chrono::milliseconds(95));
573
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700574 StartLogger(&pi1_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800575
576 event_loop_factory_.RunFor(chrono::milliseconds(200));
577
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700578 StartLogger(&pi2_logger);
579
Austin Schuhcde938c2020-02-02 17:30:07 -0800580 event_loop_factory_.RunFor(chrono::milliseconds(20000));
581 }
582
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700583 LogReader reader({std::vector<std::string>{logfiles_[0]},
584 std::vector<std::string>{logfiles_[2]}});
Austin Schuhcde938c2020-02-02 17:30:07 -0800585
586 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
587 log_reader_factory.set_send_delay(chrono::microseconds(0));
588
589 // This sends out the fetched messages and advances time to the start of the
590 // log file.
591 reader.Register(&log_reader_factory);
592
593 const Node *pi1 =
594 configuration::GetNode(log_reader_factory.configuration(), "pi1");
595 const Node *pi2 =
596 configuration::GetNode(log_reader_factory.configuration(), "pi2");
597
598 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
599
600 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
601
602 std::unique_ptr<EventLoop> pi1_event_loop =
603 log_reader_factory.MakeEventLoop("test", pi1);
604 std::unique_ptr<EventLoop> pi2_event_loop =
605 log_reader_factory.MakeEventLoop("test", pi2);
606
607 int pi1_ping_count = 30;
608 int pi2_ping_count = 30;
609 int pi1_pong_count = 30;
610 int pi2_pong_count = 30;
611
612 // Confirm that the ping value matches.
613 pi1_event_loop->MakeWatcher(
614 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
615 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
616 << pi1_event_loop->context().monotonic_remote_time << " -> "
617 << pi1_event_loop->context().monotonic_event_time;
618 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
619
620 ++pi1_ping_count;
621 });
622 pi2_event_loop->MakeWatcher(
623 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
624 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
625 << pi2_event_loop->context().monotonic_remote_time << " -> "
626 << pi2_event_loop->context().monotonic_event_time;
627 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
628
629 ++pi2_ping_count;
630 });
631
632 // Confirm that the ping and pong counts both match, and the value also
633 // matches.
634 pi1_event_loop->MakeWatcher(
635 "/test", [&pi1_event_loop, &pi1_ping_count,
636 &pi1_pong_count](const examples::Pong &pong) {
637 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
638 << pi1_event_loop->context().monotonic_remote_time << " -> "
639 << pi1_event_loop->context().monotonic_event_time;
640
641 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
642 ++pi1_pong_count;
643 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
644 });
645 pi2_event_loop->MakeWatcher(
646 "/test", [&pi2_event_loop, &pi2_ping_count,
647 &pi2_pong_count](const examples::Pong &pong) {
648 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
649 << pi2_event_loop->context().monotonic_remote_time << " -> "
650 << pi2_event_loop->context().monotonic_event_time;
651
652 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
653 ++pi2_pong_count;
654 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
655 });
656
657 log_reader_factory.Run();
658 EXPECT_EQ(pi1_ping_count, 2030);
659 EXPECT_EQ(pi2_ping_count, 2030);
660 EXPECT_EQ(pi1_pong_count, 2030);
661 EXPECT_EQ(pi2_pong_count, 2030);
662
663 reader.Deregister();
664}
Austin Schuh6f3babe2020-01-26 20:34:50 -0800665
Austin Schuh8bd96322020-02-13 21:18:22 -0800666// Tests that we can read log files where the monotonic clocks drift and don't
667// match correctly. While we are here, also test that different ending times
668// also is readable.
669TEST_F(MultinodeLoggerTest, MismatchedClocks) {
Austin Schuhcde938c2020-02-02 17:30:07 -0800670 {
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700671 LoggerState pi2_logger = MakeLogger(pi2_);
672
Austin Schuh8bd96322020-02-13 21:18:22 -0800673 NodeEventLoopFactory *pi2 =
674 event_loop_factory_.GetNodeEventLoopFactory(pi2_);
675 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
676 << pi2->realtime_now() << " distributed "
677 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -0800678
Austin Schuh8bd96322020-02-13 21:18:22 -0800679 const chrono::nanoseconds initial_pi2_offset = -chrono::seconds(1000);
680 chrono::nanoseconds pi2_offset = initial_pi2_offset;
Austin Schuhcde938c2020-02-02 17:30:07 -0800681
Austin Schuhbe69cf32020-08-27 11:38:33 -0700682 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800683 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
684 << pi2->realtime_now() << " distributed "
685 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -0800686
Austin Schuh8bd96322020-02-13 21:18:22 -0800687 for (int i = 0; i < 95; ++i) {
688 pi2_offset += chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -0700689 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800690 event_loop_factory_.RunFor(chrono::milliseconds(1));
691 }
Austin Schuhcde938c2020-02-02 17:30:07 -0800692
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700693 StartLogger(&pi2_logger);
Austin Schuhcde938c2020-02-02 17:30:07 -0800694
Austin Schuh8bd96322020-02-13 21:18:22 -0800695 event_loop_factory_.RunFor(chrono::milliseconds(200));
Austin Schuhcde938c2020-02-02 17:30:07 -0800696
Austin Schuh8bd96322020-02-13 21:18:22 -0800697 {
698 // Run pi1's logger for only part of the time.
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700699 LoggerState pi1_logger = MakeLogger(pi1_);
Austin Schuh8bd96322020-02-13 21:18:22 -0800700
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700701 StartLogger(&pi1_logger);
Austin Schuh8bd96322020-02-13 21:18:22 -0800702
703 for (int i = 0; i < 20000; ++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 EXPECT_GT(pi2_offset - initial_pi2_offset,
710 event_loop_factory_.send_delay() +
711 event_loop_factory_.network_delay());
712
713 for (int i = 0; i < 40000; ++i) {
714 pi2_offset -= chrono::nanoseconds(200);
Austin Schuhbe69cf32020-08-27 11:38:33 -0700715 pi2->SetDistributedOffset(-pi2_offset, 1.0);
Austin Schuh8bd96322020-02-13 21:18:22 -0800716 event_loop_factory_.RunFor(chrono::milliseconds(1));
717 }
718 }
719
720 // And log a bit more on pi2.
721 event_loop_factory_.RunFor(chrono::milliseconds(400));
Austin Schuhcde938c2020-02-02 17:30:07 -0800722 }
723
James Kuszmaulbb28ef22020-05-09 22:30:38 -0700724 LogReader reader({std::vector<std::string>{logfiles_[0]},
725 std::vector<std::string>{logfiles_[2]}});
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
Austin Schuhcde938c2020-02-02 17:30:07 -0800734 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 LOG(INFO) << "Done registering (pi1) "
Austin Schuh391e3172020-09-01 22:48:18 -0700740 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now()
741 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -0800742 << log_reader_factory.GetNodeEventLoopFactory(pi1)->realtime_now();
743 LOG(INFO) << "Done registering (pi2) "
Austin Schuh391e3172020-09-01 22:48:18 -0700744 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now()
745 << " "
Austin Schuhcde938c2020-02-02 17:30:07 -0800746 << log_reader_factory.GetNodeEventLoopFactory(pi2)->realtime_now();
747
748 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
749
750 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
751
752 std::unique_ptr<EventLoop> pi1_event_loop =
753 log_reader_factory.MakeEventLoop("test", pi1);
754 std::unique_ptr<EventLoop> pi2_event_loop =
755 log_reader_factory.MakeEventLoop("test", pi2);
756
757 int pi1_ping_count = 30;
758 int pi2_ping_count = 30;
759 int pi1_pong_count = 30;
760 int pi2_pong_count = 30;
761
762 // Confirm that the ping value matches.
763 pi1_event_loop->MakeWatcher(
764 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
765 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
766 << pi1_event_loop->context().monotonic_remote_time << " -> "
767 << pi1_event_loop->context().monotonic_event_time;
768 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
769
770 ++pi1_ping_count;
771 });
772 pi2_event_loop->MakeWatcher(
773 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
774 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
775 << pi2_event_loop->context().monotonic_remote_time << " -> "
776 << pi2_event_loop->context().monotonic_event_time;
777 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
778
779 ++pi2_ping_count;
780 });
781
782 // Confirm that the ping and pong counts both match, and the value also
783 // matches.
784 pi1_event_loop->MakeWatcher(
785 "/test", [&pi1_event_loop, &pi1_ping_count,
786 &pi1_pong_count](const examples::Pong &pong) {
787 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
788 << pi1_event_loop->context().monotonic_remote_time << " -> "
789 << pi1_event_loop->context().monotonic_event_time;
790
791 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
792 ++pi1_pong_count;
793 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
794 });
795 pi2_event_loop->MakeWatcher(
796 "/test", [&pi2_event_loop, &pi2_ping_count,
797 &pi2_pong_count](const examples::Pong &pong) {
798 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
799 << pi2_event_loop->context().monotonic_remote_time << " -> "
800 << pi2_event_loop->context().monotonic_event_time;
801
802 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
803 ++pi2_pong_count;
804 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
805 });
806
807 log_reader_factory.Run();
Austin Schuh8bd96322020-02-13 21:18:22 -0800808 EXPECT_EQ(pi1_ping_count, 6030);
809 EXPECT_EQ(pi2_ping_count, 6030);
810 EXPECT_EQ(pi1_pong_count, 6030);
811 EXPECT_EQ(pi2_pong_count, 6030);
Austin Schuhcde938c2020-02-02 17:30:07 -0800812
813 reader.Deregister();
814}
815
Austin Schuh8bd96322020-02-13 21:18:22 -0800816// TODO(austin): We can write a test which recreates a logfile and confirms that
817// we get it back. That is the ultimate test.
818
Austin Schuhe309d2a2019-11-29 13:25:21 -0800819} // namespace testing
820} // namespace logger
821} // namespace aos