blob: b894bf74e973159d976f9d10770677a92e729903 [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")),
215 pi2_(configuration::GetNode(event_loop_factory_.configuration(),
216 "pi2")) {}
Austin Schuh15649d62019-12-28 16:36:38 -0800217
218 // Config and factory.
219 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
220 SimulatedEventLoopFactory event_loop_factory_;
221
Austin Schuhcde938c2020-02-02 17:30:07 -0800222 const Node *pi1_;
223 const Node *pi2_;
Austin Schuh15649d62019-12-28 16:36:38 -0800224};
225
Austin Schuh6f3babe2020-01-26 20:34:50 -0800226// Counts the number of messages on a channel (returns channel, count) for every
227// message matching matcher()
228std::vector<std::pair<int, int>> CountChannelsMatching(
229 std::string_view filename,
230 std::function<bool(const MessageHeader *)> matcher) {
231 MessageReader message_reader(filename);
232 std::vector<int> counts(
233 message_reader.log_file_header()->configuration()->channels()->size(), 0);
Austin Schuh15649d62019-12-28 16:36:38 -0800234
Austin Schuh6f3babe2020-01-26 20:34:50 -0800235 while (true) {
236 std::optional<FlatbufferVector<MessageHeader>> msg =
237 message_reader.ReadMessage();
238 if (!msg) {
239 break;
240 }
241
242 if (matcher(&msg.value().message())) {
243 counts[msg.value().message().channel_index()]++;
244 }
245 }
246
247 std::vector<std::pair<int, int>> result;
248 int channel = 0;
249 for (size_t i = 0; i < counts.size(); ++i) {
250 if (counts[i] != 0) {
251 result.push_back(std::make_pair(channel, counts[i]));
252 }
253 ++channel;
254 }
255
256 return result;
257}
258
259// Counts the number of messages (channel, count) for all data messages.
260std::vector<std::pair<int, int>> CountChannelsData(std::string_view filename) {
261 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
262 if (msg->has_data()) {
263 CHECK(!msg->has_monotonic_remote_time());
264 CHECK(!msg->has_realtime_remote_time());
265 CHECK(!msg->has_remote_queue_index());
266 return true;
267 }
268 return false;
269 });
270}
271
272// Counts the number of messages (channel, count) for all timestamp messages.
273std::vector<std::pair<int, int>> CountChannelsTimestamp(
274 std::string_view filename) {
275 return CountChannelsMatching(filename, [](const MessageHeader *msg) {
276 if (!msg->has_data()) {
277 CHECK(msg->has_monotonic_remote_time());
278 CHECK(msg->has_realtime_remote_time());
279 CHECK(msg->has_remote_queue_index());
280 return true;
281 }
282 return false;
283 });
284}
285
Austin Schuhcde938c2020-02-02 17:30:07 -0800286// Tests that we can write and read simple multi-node log files.
287TEST_F(MultinodeLoggerTest, SimpleMultiNode) {
Austin Schuh6f3babe2020-01-26 20:34:50 -0800288 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
289 const ::std::string logfile_base = tmpdir + "/multi_logfile";
290 const ::std::string logfile1 = logfile_base + "_pi1_data.bfbs";
291 const ::std::string logfile2 =
292 logfile_base + "_pi2_data/test/aos.examples.Pong.bfbs";
293 const ::std::string logfile3 = logfile_base + "_pi2_data.bfbs";
294
295 // Remove them.
296 unlink(logfile1.c_str());
297 unlink(logfile2.c_str());
298 unlink(logfile3.c_str());
299
300 LOG(INFO) << "Logging data to " << logfile1 << ", " << logfile2 << " and "
301 << logfile3;
Austin Schuh15649d62019-12-28 16:36:38 -0800302
303 {
Austin Schuhcde938c2020-02-02 17:30:07 -0800304 std::unique_ptr<EventLoop> ping_event_loop =
305 event_loop_factory_.MakeEventLoop("ping", pi1_);
306 Ping ping(ping_event_loop.get());
307 std::unique_ptr<EventLoop> pong_event_loop =
308 event_loop_factory_.MakeEventLoop("pong", pi2_);
309 Pong pong(pong_event_loop.get());
Austin Schuh15649d62019-12-28 16:36:38 -0800310
Austin Schuh6f3babe2020-01-26 20:34:50 -0800311 std::unique_ptr<EventLoop> pi1_logger_event_loop =
Austin Schuhcde938c2020-02-02 17:30:07 -0800312 event_loop_factory_.MakeEventLoop("logger", pi1_);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800313 std::unique_ptr<LogNamer> pi1_log_namer =
314 std::make_unique<MultiNodeLogNamer>(
315 logfile_base, pi1_logger_event_loop->configuration(),
316 pi1_logger_event_loop->node());
317
318 std::unique_ptr<EventLoop> pi2_logger_event_loop =
Austin Schuhcde938c2020-02-02 17:30:07 -0800319 event_loop_factory_.MakeEventLoop("logger", pi2_);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800320 std::unique_ptr<LogNamer> pi2_log_namer =
321 std::make_unique<MultiNodeLogNamer>(
322 logfile_base, pi2_logger_event_loop->configuration(),
323 pi2_logger_event_loop->node());
Austin Schuh15649d62019-12-28 16:36:38 -0800324
325 event_loop_factory_.RunFor(chrono::milliseconds(95));
326
Austin Schuh6f3babe2020-01-26 20:34:50 -0800327 Logger pi1_logger(std::move(pi1_log_namer), pi1_logger_event_loop.get(),
Austin Schuh8bd96322020-02-13 21:18:22 -0800328 chrono::milliseconds(100));
Austin Schuhcde938c2020-02-02 17:30:07 -0800329
Austin Schuh6f3babe2020-01-26 20:34:50 -0800330 Logger pi2_logger(std::move(pi2_log_namer), pi2_logger_event_loop.get(),
Austin Schuh8bd96322020-02-13 21:18:22 -0800331 chrono::milliseconds(100));
Austin Schuh15649d62019-12-28 16:36:38 -0800332 event_loop_factory_.RunFor(chrono::milliseconds(20000));
333 }
334
Austin Schuh6f3babe2020-01-26 20:34:50 -0800335 {
336 // Confirm that the headers are all for the correct nodes.
337 FlatbufferVector<LogFileHeader> logheader1 = ReadHeader(logfile1);
338 EXPECT_EQ(logheader1.message().node()->name()->string_view(), "pi1");
339 FlatbufferVector<LogFileHeader> logheader2 = ReadHeader(logfile2);
340 EXPECT_EQ(logheader2.message().node()->name()->string_view(), "pi2");
341 FlatbufferVector<LogFileHeader> logheader3 = ReadHeader(logfile3);
342 EXPECT_EQ(logheader3.message().node()->name()->string_view(), "pi2");
Austin Schuh15649d62019-12-28 16:36:38 -0800343
Austin Schuh6f3babe2020-01-26 20:34:50 -0800344 // Timing reports, pings
345 EXPECT_THAT(CountChannelsData(logfile1),
Austin Schuhcde938c2020-02-02 17:30:07 -0800346 ::testing::ElementsAre(::testing::Pair(1, 40),
Austin Schuh6f3babe2020-01-26 20:34:50 -0800347 ::testing::Pair(4, 2001)));
348 // Timestamps for pong
349 EXPECT_THAT(CountChannelsTimestamp(logfile1),
350 ::testing::ElementsAre(::testing::Pair(5, 2001)));
351
352 // Pong data.
353 EXPECT_THAT(CountChannelsData(logfile2),
354 ::testing::ElementsAre(::testing::Pair(5, 2001)));
355 // No timestamps
356 EXPECT_THAT(CountChannelsTimestamp(logfile2), ::testing::ElementsAre());
357
358 // Timing reports and pongs.
359 EXPECT_THAT(CountChannelsData(logfile3),
Austin Schuhcde938c2020-02-02 17:30:07 -0800360 ::testing::ElementsAre(::testing::Pair(3, 40),
Austin Schuh6f3babe2020-01-26 20:34:50 -0800361 ::testing::Pair(5, 2001)));
362 // And ping timestamps.
363 EXPECT_THAT(CountChannelsTimestamp(logfile3),
364 ::testing::ElementsAre(::testing::Pair(4, 2001)));
365 }
366
Austin Schuhcde938c2020-02-02 17:30:07 -0800367 LogReader reader(
368 {std::vector<std::string>{logfile1}, std::vector<std::string>{logfile3}});
Austin Schuh6f3babe2020-01-26 20:34:50 -0800369
Austin Schuhac0771c2020-01-07 18:36:30 -0800370 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
Austin Schuh6331ef92020-01-07 18:28:09 -0800371 log_reader_factory.set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800372
373 // This sends out the fetched messages and advances time to the start of the
374 // log file.
Austin Schuh6331ef92020-01-07 18:28:09 -0800375 reader.Register(&log_reader_factory);
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800376
Austin Schuhac0771c2020-01-07 18:36:30 -0800377 const Node *pi1 =
378 configuration::GetNode(log_reader_factory.configuration(), "pi1");
Austin Schuh6f3babe2020-01-26 20:34:50 -0800379 const Node *pi2 =
380 configuration::GetNode(log_reader_factory.configuration(), "pi2");
Austin Schuhac0771c2020-01-07 18:36:30 -0800381
Austin Schuh6f3babe2020-01-26 20:34:50 -0800382 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800383
384 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800385
Austin Schuh6f3babe2020-01-26 20:34:50 -0800386 std::unique_ptr<EventLoop> pi1_event_loop =
Austin Schuhac0771c2020-01-07 18:36:30 -0800387 log_reader_factory.MakeEventLoop("test", pi1);
Austin Schuh6f3babe2020-01-26 20:34:50 -0800388 std::unique_ptr<EventLoop> pi2_event_loop =
389 log_reader_factory.MakeEventLoop("test", pi2);
Austin Schuh15649d62019-12-28 16:36:38 -0800390
Austin Schuh6f3babe2020-01-26 20:34:50 -0800391 int pi1_ping_count = 10;
392 int pi2_ping_count = 10;
393 int pi1_pong_count = 10;
394 int pi2_pong_count = 10;
Austin Schuh15649d62019-12-28 16:36:38 -0800395
396 // Confirm that the ping value matches.
Austin Schuh6f3babe2020-01-26 20:34:50 -0800397 pi1_event_loop->MakeWatcher(
398 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
399 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
400 << pi1_event_loop->context().monotonic_remote_time << " -> "
401 << pi1_event_loop->context().monotonic_event_time;
402 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
403 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
404 pi1_ping_count * chrono::milliseconds(10) +
405 monotonic_clock::epoch());
406 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
407 pi1_ping_count * chrono::milliseconds(10) +
408 realtime_clock::epoch());
409 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
410 pi1_event_loop->context().monotonic_event_time);
411 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
412 pi1_event_loop->context().realtime_event_time);
Austin Schuh15649d62019-12-28 16:36:38 -0800413
Austin Schuh6f3babe2020-01-26 20:34:50 -0800414 ++pi1_ping_count;
415 });
416 pi2_event_loop->MakeWatcher(
417 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
418 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
419 << pi2_event_loop->context().monotonic_remote_time << " -> "
420 << pi2_event_loop->context().monotonic_event_time;
421 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
422
423 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
424 pi2_ping_count * chrono::milliseconds(10) +
425 monotonic_clock::epoch());
426 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
427 pi2_ping_count * chrono::milliseconds(10) +
428 realtime_clock::epoch());
429 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time +
430 chrono::microseconds(150),
431 pi2_event_loop->context().monotonic_event_time);
432 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time +
433 chrono::microseconds(150),
434 pi2_event_loop->context().realtime_event_time);
435 ++pi2_ping_count;
Austin Schuh15649d62019-12-28 16:36:38 -0800436 });
437
Austin Schuh6f3babe2020-01-26 20:34:50 -0800438 constexpr ssize_t kQueueIndexOffset = 0;
439 // Confirm that the ping and pong counts both match, and the value also
440 // matches.
441 pi1_event_loop->MakeWatcher(
442 "/test", [&pi1_event_loop, &pi1_ping_count,
443 &pi1_pong_count](const examples::Pong &pong) {
444 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
445 << pi1_event_loop->context().monotonic_remote_time << " -> "
446 << pi1_event_loop->context().monotonic_event_time;
447
448 EXPECT_EQ(pi1_event_loop->context().remote_queue_index,
449 pi1_pong_count + kQueueIndexOffset);
450 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time,
451 chrono::microseconds(200) +
452 pi1_pong_count * chrono::milliseconds(10) +
453 monotonic_clock::epoch());
454 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time,
455 chrono::microseconds(200) +
456 pi1_pong_count * chrono::milliseconds(10) +
457 realtime_clock::epoch());
458
459 EXPECT_EQ(pi1_event_loop->context().monotonic_remote_time +
460 chrono::microseconds(150),
461 pi1_event_loop->context().monotonic_event_time);
462 EXPECT_EQ(pi1_event_loop->context().realtime_remote_time +
463 chrono::microseconds(150),
464 pi1_event_loop->context().realtime_event_time);
465
466 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
467 ++pi1_pong_count;
468 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
469 });
470 pi2_event_loop->MakeWatcher(
471 "/test", [&pi2_event_loop, &pi2_ping_count,
472 &pi2_pong_count](const examples::Pong &pong) {
473 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
474 << pi2_event_loop->context().monotonic_remote_time << " -> "
475 << pi2_event_loop->context().monotonic_event_time;
476
477 EXPECT_EQ(pi2_event_loop->context().remote_queue_index,
478 pi2_pong_count + kQueueIndexOffset - 9);
479
480 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
481 chrono::microseconds(200) +
482 pi2_pong_count * chrono::milliseconds(10) +
483 monotonic_clock::epoch());
484 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
485 chrono::microseconds(200) +
486 pi2_pong_count * chrono::milliseconds(10) +
487 realtime_clock::epoch());
488
489 EXPECT_EQ(pi2_event_loop->context().monotonic_remote_time,
490 pi2_event_loop->context().monotonic_event_time);
491 EXPECT_EQ(pi2_event_loop->context().realtime_remote_time,
492 pi2_event_loop->context().realtime_event_time);
493
494 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
495 ++pi2_pong_count;
496 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
497 });
498
499 log_reader_factory.Run();
500 EXPECT_EQ(pi1_ping_count, 2010);
501 EXPECT_EQ(pi2_ping_count, 2010);
502 EXPECT_EQ(pi1_pong_count, 2010);
503 EXPECT_EQ(pi2_pong_count, 2010);
Austin Schuh6331ef92020-01-07 18:28:09 -0800504
505 reader.Deregister();
Austin Schuh15649d62019-12-28 16:36:38 -0800506}
507
James Kuszmaul46d82582020-05-09 19:50:09 -0700508typedef MultinodeLoggerTest MultinodeLoggerDeathTest;
509
510// Test that if we feed the replay with a mismatched node list that we die on
511// the LogReader constructor.
512TEST_F(MultinodeLoggerDeathTest, MultiNodeBadReplayConfig) {
513 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
514 const ::std::string logfile_base = tmpdir + "/multi_logfile";
515 const ::std::string logfile1 = logfile_base + "_pi1_data.bfbs";
516 const ::std::string logfile2 =
517 logfile_base + "_pi2_data/test/aos.examples.Pong.bfbs";
518 const ::std::string logfile3 = logfile_base + "_pi2_data.bfbs";
519
520 // Remove them.
521 unlink(logfile1.c_str());
522 unlink(logfile2.c_str());
523 unlink(logfile3.c_str());
524
525 LOG(INFO) << "Logging data to " << logfile1 << ", " << logfile2 << " and "
526 << logfile3;
527
528 {
529 std::unique_ptr<EventLoop> ping_event_loop =
530 event_loop_factory_.MakeEventLoop("ping", pi1_);
531 Ping ping(ping_event_loop.get());
532 std::unique_ptr<EventLoop> pong_event_loop =
533 event_loop_factory_.MakeEventLoop("pong", pi2_);
534 Pong pong(pong_event_loop.get());
535
536 std::unique_ptr<EventLoop> pi1_logger_event_loop =
537 event_loop_factory_.MakeEventLoop("logger", pi1_);
538 std::unique_ptr<LogNamer> pi1_log_namer =
539 std::make_unique<MultiNodeLogNamer>(
540 logfile_base, pi1_logger_event_loop->configuration(),
541 pi1_logger_event_loop->node());
542
543 std::unique_ptr<EventLoop> pi2_logger_event_loop =
544 event_loop_factory_.MakeEventLoop("logger", pi2_);
545 std::unique_ptr<LogNamer> pi2_log_namer =
546 std::make_unique<MultiNodeLogNamer>(
547 logfile_base, pi2_logger_event_loop->configuration(),
548 pi2_logger_event_loop->node());
549
550 event_loop_factory_.RunFor(chrono::milliseconds(95));
551
552 Logger pi1_logger(std::move(pi1_log_namer), pi1_logger_event_loop.get(),
553 chrono::milliseconds(100));
554
555 Logger pi2_logger(std::move(pi2_log_namer), pi2_logger_event_loop.get(),
556 chrono::milliseconds(100));
557 event_loop_factory_.RunFor(chrono::milliseconds(20000));
558 }
559
560 // Test that, if we add an additional node to the replay config that the
561 // logger complains about the mismatch in number of nodes.
562 FlatbufferDetachedBuffer<Configuration> extra_nodes_config =
563 configuration::MergeWithConfig(&config_.message(), R"({
564 "nodes": [
565 {
566 "name": "extra-node"
567 }
568 ]
569 }
570 )");
571
572 EXPECT_DEATH(LogReader({std::vector<std::string>{logfile1},
573 std::vector<std::string>{logfile3}},
574 &extra_nodes_config.message()),
575 "Log file and replay config need to have matching nodes lists.");
576 ;
577}
578
Austin Schuhcde938c2020-02-02 17:30:07 -0800579// Tests that we can read log files where they don't start at the same monotonic
580// time.
581TEST_F(MultinodeLoggerTest, StaggeredStart) {
582 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
583 const ::std::string logfile_base = tmpdir + "/multi_logfile";
584 const ::std::string logfile1 = logfile_base + "_pi1_data.bfbs";
585 const ::std::string logfile2 =
586 logfile_base + "_pi2_data/test/aos.examples.Pong.bfbs";
587 const ::std::string logfile3 = logfile_base + "_pi2_data.bfbs";
588
589 // Remove them.
590 unlink(logfile1.c_str());
591 unlink(logfile2.c_str());
592 unlink(logfile3.c_str());
593
594 LOG(INFO) << "Logging data to " << logfile1 << " and " << logfile3;
595
596 {
597 std::unique_ptr<EventLoop> ping_event_loop =
598 event_loop_factory_.MakeEventLoop("ping", pi1_);
599 Ping ping(ping_event_loop.get());
600 std::unique_ptr<EventLoop> pong_event_loop =
601 event_loop_factory_.MakeEventLoop("pong", pi2_);
602 Pong pong(pong_event_loop.get());
603
604 std::unique_ptr<EventLoop> pi1_logger_event_loop =
605 event_loop_factory_.MakeEventLoop("logger", pi1_);
606 std::unique_ptr<LogNamer> pi1_log_namer =
607 std::make_unique<MultiNodeLogNamer>(
608 logfile_base, pi1_logger_event_loop->configuration(),
609 pi1_logger_event_loop->node());
610
611 std::unique_ptr<EventLoop> pi2_logger_event_loop =
612 event_loop_factory_.MakeEventLoop("logger", pi2_);
613 std::unique_ptr<LogNamer> pi2_log_namer =
614 std::make_unique<MultiNodeLogNamer>(
615 logfile_base, pi2_logger_event_loop->configuration(),
616 pi2_logger_event_loop->node());
617
618 event_loop_factory_.RunFor(chrono::milliseconds(95));
619
620 Logger pi1_logger(std::move(pi1_log_namer), pi1_logger_event_loop.get(),
Austin Schuh8bd96322020-02-13 21:18:22 -0800621 chrono::milliseconds(100));
Austin Schuhcde938c2020-02-02 17:30:07 -0800622
623 event_loop_factory_.RunFor(chrono::milliseconds(200));
624
625 Logger pi2_logger(std::move(pi2_log_namer), pi2_logger_event_loop.get(),
Austin Schuh8bd96322020-02-13 21:18:22 -0800626 chrono::milliseconds(100));
Austin Schuhcde938c2020-02-02 17:30:07 -0800627 event_loop_factory_.RunFor(chrono::milliseconds(20000));
628 }
629
630 LogReader reader(
631 {std::vector<std::string>{logfile1}, std::vector<std::string>{logfile3}});
632
633 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
634 log_reader_factory.set_send_delay(chrono::microseconds(0));
635
636 // This sends out the fetched messages and advances time to the start of the
637 // log file.
638 reader.Register(&log_reader_factory);
639
640 const Node *pi1 =
641 configuration::GetNode(log_reader_factory.configuration(), "pi1");
642 const Node *pi2 =
643 configuration::GetNode(log_reader_factory.configuration(), "pi2");
644
645 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
646
647 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
648
649 std::unique_ptr<EventLoop> pi1_event_loop =
650 log_reader_factory.MakeEventLoop("test", pi1);
651 std::unique_ptr<EventLoop> pi2_event_loop =
652 log_reader_factory.MakeEventLoop("test", pi2);
653
654 int pi1_ping_count = 30;
655 int pi2_ping_count = 30;
656 int pi1_pong_count = 30;
657 int pi2_pong_count = 30;
658
659 // Confirm that the ping value matches.
660 pi1_event_loop->MakeWatcher(
661 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
662 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
663 << pi1_event_loop->context().monotonic_remote_time << " -> "
664 << pi1_event_loop->context().monotonic_event_time;
665 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
666
667 ++pi1_ping_count;
668 });
669 pi2_event_loop->MakeWatcher(
670 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
671 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
672 << pi2_event_loop->context().monotonic_remote_time << " -> "
673 << pi2_event_loop->context().monotonic_event_time;
674 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
675
676 ++pi2_ping_count;
677 });
678
679 // Confirm that the ping and pong counts both match, and the value also
680 // matches.
681 pi1_event_loop->MakeWatcher(
682 "/test", [&pi1_event_loop, &pi1_ping_count,
683 &pi1_pong_count](const examples::Pong &pong) {
684 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
685 << pi1_event_loop->context().monotonic_remote_time << " -> "
686 << pi1_event_loop->context().monotonic_event_time;
687
688 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
689 ++pi1_pong_count;
690 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
691 });
692 pi2_event_loop->MakeWatcher(
693 "/test", [&pi2_event_loop, &pi2_ping_count,
694 &pi2_pong_count](const examples::Pong &pong) {
695 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
696 << pi2_event_loop->context().monotonic_remote_time << " -> "
697 << pi2_event_loop->context().monotonic_event_time;
698
699 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
700 ++pi2_pong_count;
701 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
702 });
703
704 log_reader_factory.Run();
705 EXPECT_EQ(pi1_ping_count, 2030);
706 EXPECT_EQ(pi2_ping_count, 2030);
707 EXPECT_EQ(pi1_pong_count, 2030);
708 EXPECT_EQ(pi2_pong_count, 2030);
709
710 reader.Deregister();
711}
Austin Schuh6f3babe2020-01-26 20:34:50 -0800712
Austin Schuh8bd96322020-02-13 21:18:22 -0800713// Tests that we can read log files where the monotonic clocks drift and don't
714// match correctly. While we are here, also test that different ending times
715// also is readable.
716TEST_F(MultinodeLoggerTest, MismatchedClocks) {
Austin Schuhcde938c2020-02-02 17:30:07 -0800717 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
718 const ::std::string logfile_base = tmpdir + "/multi_logfile";
719 const ::std::string logfile1 = logfile_base + "_pi1_data.bfbs";
720 const ::std::string logfile2 =
721 logfile_base + "_pi2_data/test/aos.examples.Pong.bfbs";
722 const ::std::string logfile3 = logfile_base + "_pi2_data.bfbs";
723
724 // Remove them.
725 unlink(logfile1.c_str());
726 unlink(logfile2.c_str());
727 unlink(logfile3.c_str());
728
729 LOG(INFO) << "Logging data to " << logfile1 << " and " << logfile3;
730
731 {
Austin Schuh8bd96322020-02-13 21:18:22 -0800732 NodeEventLoopFactory *pi2 =
733 event_loop_factory_.GetNodeEventLoopFactory(pi2_);
734 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
735 << pi2->realtime_now() << " distributed "
736 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -0800737
Austin Schuh8bd96322020-02-13 21:18:22 -0800738 const chrono::nanoseconds initial_pi2_offset = -chrono::seconds(1000);
739 chrono::nanoseconds pi2_offset = initial_pi2_offset;
Austin Schuhcde938c2020-02-02 17:30:07 -0800740
Austin Schuh8bd96322020-02-13 21:18:22 -0800741 pi2->SetDistributedOffset(pi2_offset);
742 LOG(INFO) << "pi2 times: " << pi2->monotonic_now() << " "
743 << pi2->realtime_now() << " distributed "
744 << pi2->ToDistributedClock(pi2->monotonic_now());
Austin Schuhcde938c2020-02-02 17:30:07 -0800745
Austin Schuh8bd96322020-02-13 21:18:22 -0800746 std::unique_ptr<EventLoop> ping_event_loop =
747 event_loop_factory_.MakeEventLoop("ping", pi1_);
748 Ping ping(ping_event_loop.get());
749 std::unique_ptr<EventLoop> pong_event_loop =
750 event_loop_factory_.MakeEventLoop("pong", pi2_);
751 Pong pong(pong_event_loop.get());
Austin Schuhcde938c2020-02-02 17:30:07 -0800752
Austin Schuh8bd96322020-02-13 21:18:22 -0800753 std::unique_ptr<EventLoop> pi2_logger_event_loop =
754 event_loop_factory_.MakeEventLoop("logger", pi2_);
755 std::unique_ptr<LogNamer> pi2_log_namer =
756 std::make_unique<MultiNodeLogNamer>(
757 logfile_base, pi2_logger_event_loop->configuration(),
758 pi2_logger_event_loop->node());
Austin Schuhcde938c2020-02-02 17:30:07 -0800759
Austin Schuh8bd96322020-02-13 21:18:22 -0800760 for (int i = 0; i < 95; ++i) {
761 pi2_offset += chrono::nanoseconds(200);
762 pi2->SetDistributedOffset(pi2_offset);
763 event_loop_factory_.RunFor(chrono::milliseconds(1));
764 }
Austin Schuhcde938c2020-02-02 17:30:07 -0800765
Austin Schuh8bd96322020-02-13 21:18:22 -0800766 Logger pi2_logger(std::move(pi2_log_namer), pi2_logger_event_loop.get(),
767 chrono::milliseconds(100));
Austin Schuhcde938c2020-02-02 17:30:07 -0800768
Austin Schuh8bd96322020-02-13 21:18:22 -0800769 event_loop_factory_.RunFor(chrono::milliseconds(200));
Austin Schuhcde938c2020-02-02 17:30:07 -0800770
Austin Schuh8bd96322020-02-13 21:18:22 -0800771 {
772 // Run pi1's logger for only part of the time.
773 std::unique_ptr<EventLoop> pi1_logger_event_loop =
774 event_loop_factory_.MakeEventLoop("logger", pi1_);
775 std::unique_ptr<LogNamer> pi1_log_namer =
776 std::make_unique<MultiNodeLogNamer>(
777 logfile_base, pi1_logger_event_loop->configuration(),
778 pi1_logger_event_loop->node());
779
780 Logger pi1_logger(std::move(pi1_log_namer), pi1_logger_event_loop.get(),
781 chrono::milliseconds(100));
782
783 for (int i = 0; i < 20000; ++i) {
784 pi2_offset += chrono::nanoseconds(200);
785 pi2->SetDistributedOffset(pi2_offset);
786 event_loop_factory_.RunFor(chrono::milliseconds(1));
787 }
788
789 EXPECT_GT(pi2_offset - initial_pi2_offset,
790 event_loop_factory_.send_delay() +
791 event_loop_factory_.network_delay());
792
793 for (int i = 0; i < 40000; ++i) {
794 pi2_offset -= chrono::nanoseconds(200);
795 pi2->SetDistributedOffset(pi2_offset);
796 event_loop_factory_.RunFor(chrono::milliseconds(1));
797 }
798 }
799
800 // And log a bit more on pi2.
801 event_loop_factory_.RunFor(chrono::milliseconds(400));
Austin Schuhcde938c2020-02-02 17:30:07 -0800802 }
803
804 LogReader reader(
805 {std::vector<std::string>{logfile1}, std::vector<std::string>{logfile3}});
806
807 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
808 log_reader_factory.set_send_delay(chrono::microseconds(0));
809
810 // This sends out the fetched messages and advances time to the start of the
811 // log file.
812 reader.Register(&log_reader_factory);
813
814
815 const Node *pi1 =
816 configuration::GetNode(log_reader_factory.configuration(), "pi1");
817 const Node *pi2 =
818 configuration::GetNode(log_reader_factory.configuration(), "pi2");
819
820 LOG(INFO) << "Done registering (pi1) "
821 << log_reader_factory.GetNodeEventLoopFactory(pi1)->monotonic_now() << " "
822 << log_reader_factory.GetNodeEventLoopFactory(pi1)->realtime_now();
823 LOG(INFO) << "Done registering (pi2) "
824 << log_reader_factory.GetNodeEventLoopFactory(pi2)->monotonic_now() << " "
825 << log_reader_factory.GetNodeEventLoopFactory(pi2)->realtime_now();
826
827 EXPECT_THAT(reader.Nodes(), ::testing::ElementsAre(pi1, pi2));
828
829 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
830
831 std::unique_ptr<EventLoop> pi1_event_loop =
832 log_reader_factory.MakeEventLoop("test", pi1);
833 std::unique_ptr<EventLoop> pi2_event_loop =
834 log_reader_factory.MakeEventLoop("test", pi2);
835
836 int pi1_ping_count = 30;
837 int pi2_ping_count = 30;
838 int pi1_pong_count = 30;
839 int pi2_pong_count = 30;
840
841 // Confirm that the ping value matches.
842 pi1_event_loop->MakeWatcher(
843 "/test", [&pi1_ping_count, &pi1_event_loop](const examples::Ping &ping) {
844 VLOG(1) << "Pi1 ping " << FlatbufferToJson(&ping)
845 << pi1_event_loop->context().monotonic_remote_time << " -> "
846 << pi1_event_loop->context().monotonic_event_time;
847 EXPECT_EQ(ping.value(), pi1_ping_count + 1);
848
849 ++pi1_ping_count;
850 });
851 pi2_event_loop->MakeWatcher(
852 "/test", [&pi2_ping_count, &pi2_event_loop](const examples::Ping &ping) {
853 VLOG(1) << "Pi2 ping " << FlatbufferToJson(&ping)
854 << pi2_event_loop->context().monotonic_remote_time << " -> "
855 << pi2_event_loop->context().monotonic_event_time;
856 EXPECT_EQ(ping.value(), pi2_ping_count + 1);
857
858 ++pi2_ping_count;
859 });
860
861 // Confirm that the ping and pong counts both match, and the value also
862 // matches.
863 pi1_event_loop->MakeWatcher(
864 "/test", [&pi1_event_loop, &pi1_ping_count,
865 &pi1_pong_count](const examples::Pong &pong) {
866 VLOG(1) << "Pi1 pong " << FlatbufferToJson(&pong) << " at "
867 << pi1_event_loop->context().monotonic_remote_time << " -> "
868 << pi1_event_loop->context().monotonic_event_time;
869
870 EXPECT_EQ(pong.value(), pi1_pong_count + 1);
871 ++pi1_pong_count;
872 EXPECT_EQ(pi1_ping_count, pi1_pong_count);
873 });
874 pi2_event_loop->MakeWatcher(
875 "/test", [&pi2_event_loop, &pi2_ping_count,
876 &pi2_pong_count](const examples::Pong &pong) {
877 VLOG(1) << "Pi2 pong " << FlatbufferToJson(&pong) << " at "
878 << pi2_event_loop->context().monotonic_remote_time << " -> "
879 << pi2_event_loop->context().monotonic_event_time;
880
881 EXPECT_EQ(pong.value(), pi2_pong_count + 1);
882 ++pi2_pong_count;
883 EXPECT_EQ(pi2_ping_count, pi2_pong_count);
884 });
885
886 log_reader_factory.Run();
Austin Schuh8bd96322020-02-13 21:18:22 -0800887 EXPECT_EQ(pi1_ping_count, 6030);
888 EXPECT_EQ(pi2_ping_count, 6030);
889 EXPECT_EQ(pi1_pong_count, 6030);
890 EXPECT_EQ(pi2_pong_count, 6030);
Austin Schuhcde938c2020-02-02 17:30:07 -0800891
892 reader.Deregister();
893}
894
Austin Schuh8bd96322020-02-13 21:18:22 -0800895// TODO(austin): We can write a test which recreates a logfile and confirms that
896// we get it back. That is the ultimate test.
897
Austin Schuhe309d2a2019-11-29 13:25:21 -0800898} // namespace testing
899} // namespace logger
900} // namespace aos