blob: 55d0eccdb56a2db90314c1bc912711ad76eb893c [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"
8#include "gtest/gtest.h"
9
10namespace aos {
11namespace logger {
12namespace testing {
13
14namespace chrono = std::chrono;
15
16class LoggerTest : public ::testing::Test {
17 public:
18 LoggerTest()
19 : config_(
20 aos::configuration::ReadConfig("aos/events/pingpong_config.json")),
21 event_loop_factory_(&config_.message()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080022 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080023 ping_(ping_event_loop_.get()),
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080024 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong")),
Austin Schuhe309d2a2019-11-29 13:25:21 -080025 pong_(pong_event_loop_.get()) {}
26
27 // Config and factory.
28 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
29 SimulatedEventLoopFactory event_loop_factory_;
30
31 // Event loop and app for Ping
32 std::unique_ptr<EventLoop> ping_event_loop_;
33 Ping ping_;
34
35 // Event loop and app for Pong
36 std::unique_ptr<EventLoop> pong_event_loop_;
37 Pong pong_;
38};
39
40// Tests that we can startup at all. This confirms that the channels are all in
41// the config.
42TEST_F(LoggerTest, Starts) {
43 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
44 const ::std::string logfile = tmpdir + "/logfile.bfbs";
45 // Remove it.
46 unlink(logfile.c_str());
47
48 LOG(INFO) << "Logging data to " << logfile;
49
50 {
51 DetachedBufferWriter writer(logfile);
52 std::unique_ptr<EventLoop> logger_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080053 event_loop_factory_.MakeEventLoop("logger");
Austin Schuhe309d2a2019-11-29 13:25:21 -080054
55 event_loop_factory_.RunFor(chrono::milliseconds(95));
56
57 Logger logger(&writer, logger_event_loop.get(),
58 std::chrono::milliseconds(100));
59 event_loop_factory_.RunFor(chrono::milliseconds(20000));
60 }
61
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080062 // Even though it doesn't make any difference here, exercise the logic for
63 // passing in a separate config.
64 LogReader reader(logfile, &config_.message());
Austin Schuhe309d2a2019-11-29 13:25:21 -080065
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080066 // Confirm that we can remap logged channels to point to new buses.
67 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
Austin Schuhe309d2a2019-11-29 13:25:21 -080068
Austin Schuh15649d62019-12-28 16:36:38 -080069 // This sends out the fetched messages and advances time to the start of the
70 // log file.
James Kuszmaul84ff3e52020-01-03 19:48:53 -080071 reader.Register();
Austin Schuhe309d2a2019-11-29 13:25:21 -080072
James Kuszmaul84ff3e52020-01-03 19:48:53 -080073 EXPECT_EQ(reader.node(), nullptr);
74
Austin Schuhe309d2a2019-11-29 13:25:21 -080075 std::unique_ptr<EventLoop> test_event_loop =
James Kuszmaul84ff3e52020-01-03 19:48:53 -080076 reader.event_loop_factory()->MakeEventLoop("log_reader");
Austin Schuhe309d2a2019-11-29 13:25:21 -080077
78 int ping_count = 10;
79 int pong_count = 10;
80
James Kuszmaulc7bbb3e2020-01-03 20:01:00 -080081 // Confirm that the ping value matches in the remapped channel location.
82 test_event_loop->MakeWatcher("/original/test",
Austin Schuhe309d2a2019-11-29 13:25:21 -080083 [&ping_count](const examples::Ping &ping) {
84 EXPECT_EQ(ping.value(), ping_count + 1);
85 ++ping_count;
86 });
87 // Confirm that the ping and pong counts both match, and the value also
88 // matches.
89 test_event_loop->MakeWatcher(
90 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
91 EXPECT_EQ(pong.value(), pong_count + 1);
92 ++pong_count;
93 EXPECT_EQ(ping_count, pong_count);
94 });
95
James Kuszmaul84ff3e52020-01-03 19:48:53 -080096 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
Austin Schuhe309d2a2019-11-29 13:25:21 -080097 EXPECT_EQ(ping_count, 2010);
Austin Schuhe309d2a2019-11-29 13:25:21 -080098}
99
Austin Schuhfa895892020-01-07 20:07:41 -0800100// Tests that we can read and write rotated log files.
101TEST_F(LoggerTest, RotatedLogFile) {
102 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
103 const ::std::string logfile0 = tmpdir + "/logfile0.bfbs";
104 const ::std::string logfile1 = tmpdir + "/logfile1.bfbs";
105 // Remove it.
106 unlink(logfile0.c_str());
107 unlink(logfile1.c_str());
108
109 LOG(INFO) << "Logging data to " << logfile0 << " and " << logfile1;
110
111 {
112 DetachedBufferWriter writer0(logfile0);
113 DetachedBufferWriter writer1(logfile1);
114 std::unique_ptr<EventLoop> logger_event_loop =
115 event_loop_factory_.MakeEventLoop("logger");
116
117 event_loop_factory_.RunFor(chrono::milliseconds(95));
118
119 Logger logger(&writer0, logger_event_loop.get(),
120 std::chrono::milliseconds(100));
121 event_loop_factory_.RunFor(chrono::milliseconds(10000));
122 logger.Rotate(&writer1);
123 event_loop_factory_.RunFor(chrono::milliseconds(10000));
124 }
125
126 // Even though it doesn't make any difference here, exercise the logic for
127 // passing in a separate config.
128 LogReader reader(std::vector<std::string>{logfile0, logfile1},
129 &config_.message());
130
131 // Confirm that we can remap logged channels to point to new buses.
132 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
133
134 // This sends out the fetched messages and advances time to the start of the
135 // log file.
136 reader.Register();
137
138 EXPECT_EQ(reader.node(), nullptr);
139
140 std::unique_ptr<EventLoop> test_event_loop =
141 reader.event_loop_factory()->MakeEventLoop("log_reader");
142
143 int ping_count = 10;
144 int pong_count = 10;
145
146 // Confirm that the ping value matches in the remapped channel location.
147 test_event_loop->MakeWatcher("/original/test",
148 [&ping_count](const examples::Ping &ping) {
149 EXPECT_EQ(ping.value(), ping_count + 1);
150 ++ping_count;
151 });
152 // Confirm that the ping and pong counts both match, and the value also
153 // matches.
154 test_event_loop->MakeWatcher(
155 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
156 EXPECT_EQ(pong.value(), pong_count + 1);
157 ++pong_count;
158 EXPECT_EQ(ping_count, pong_count);
159 });
160
161 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
162 EXPECT_EQ(ping_count, 2010);
163}
164
Austin Schuh4c4e0092019-12-22 16:18:03 -0800165// Tests that a large number of messages per second doesn't overwhelm writev.
166TEST_F(LoggerTest, ManyMessages) {
167 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
168 const ::std::string logfile = tmpdir + "/logfile.bfbs";
169 // Remove the log file.
170 unlink(logfile.c_str());
171
172 LOG(INFO) << "Logging data to " << logfile;
173
174 {
175 DetachedBufferWriter writer(logfile);
176 std::unique_ptr<EventLoop> logger_event_loop =
177 event_loop_factory_.MakeEventLoop("logger");
178
179 std::unique_ptr<EventLoop> ping_spammer_event_loop =
180 event_loop_factory_.MakeEventLoop("ping_spammer");
181 aos::Sender<examples::Ping> ping_sender =
182 ping_spammer_event_loop->MakeSender<examples::Ping>("/test");
183
184 aos::TimerHandler *timer_handler =
185 ping_spammer_event_loop->AddTimer([&ping_sender]() {
186 aos::Sender<examples::Ping>::Builder builder =
187 ping_sender.MakeBuilder();
188 examples::Ping::Builder ping_builder =
189 builder.MakeBuilder<examples::Ping>();
190 CHECK(builder.Send(ping_builder.Finish()));
191 });
192
193 // 100 ms / 0.05 ms -> 2000 messages. Should be enough to crash it.
194 ping_spammer_event_loop->OnRun([&ping_spammer_event_loop, timer_handler]() {
195 timer_handler->Setup(ping_spammer_event_loop->monotonic_now(),
196 chrono::microseconds(50));
197 });
198
199 Logger logger(&writer, logger_event_loop.get(),
200 std::chrono::milliseconds(100));
201
202 event_loop_factory_.RunFor(chrono::milliseconds(1000));
203 }
204}
205
Austin Schuh15649d62019-12-28 16:36:38 -0800206class MultinodeLoggerTest : public ::testing::Test {
207 public:
208 MultinodeLoggerTest()
209 : config_(aos::configuration::ReadConfig(
Austin Schuhe84c3ed2019-12-14 15:29:48 -0800210 "aos/events/logging/multinode_pingpong_config.json")),
Austin Schuhac0771c2020-01-07 18:36:30 -0800211 event_loop_factory_(&config_.message()),
212 ping_event_loop_(event_loop_factory_.MakeEventLoop(
213 "ping", configuration::GetNode(event_loop_factory_.configuration(),
214 "pi1"))),
Austin Schuh15649d62019-12-28 16:36:38 -0800215 ping_(ping_event_loop_.get()) {}
216
217 // Config and factory.
218 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
219 SimulatedEventLoopFactory event_loop_factory_;
220
221 // Event loop and app for Ping
222 std::unique_ptr<EventLoop> ping_event_loop_;
223 Ping ping_;
224};
225
226// Tests that we can startup at all in a multinode configuration.
227TEST_F(MultinodeLoggerTest, MultiNode) {
228 constexpr chrono::seconds kTimeOffset = chrono::seconds(10000);
229 constexpr uint32_t kQueueIndexOffset = 1024;
230 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
231 const ::std::string logfile = tmpdir + "/multi_logfile.bfbs";
232 // Remove it.
233 unlink(logfile.c_str());
234
235 LOG(INFO) << "Logging data to " << logfile;
236
237 {
Austin Schuhac0771c2020-01-07 18:36:30 -0800238 const Node *pi1 =
239 configuration::GetNode(event_loop_factory_.configuration(), "pi1");
Austin Schuh15649d62019-12-28 16:36:38 -0800240 std::unique_ptr<EventLoop> pong_event_loop =
Austin Schuhac0771c2020-01-07 18:36:30 -0800241 event_loop_factory_.MakeEventLoop("pong", pi1);
Austin Schuh15649d62019-12-28 16:36:38 -0800242
243 std::unique_ptr<aos::RawSender> pong_sender(
244 pong_event_loop->MakeRawSender(aos::configuration::GetChannel(
245 pong_event_loop->configuration(), "/test", "aos.examples.Pong",
246 pong_event_loop->name(), pong_event_loop->node())));
247
248 // Ok, let's fake a remote node. We use the fancy raw sender Send
249 // method that message_gateway will use to do that.
250 int pong_count = 0;
251 pong_event_loop->MakeWatcher(
252 "/test", [&pong_event_loop, &pong_count, &pong_sender,
253 kTimeOffset](const examples::Ping &ping) {
254 flatbuffers::FlatBufferBuilder fbb;
255 examples::Pong::Builder pong_builder(fbb);
256 pong_builder.add_value(ping.value());
257 pong_builder.add_initial_send_time(ping.send_time());
258 fbb.Finish(pong_builder.Finish());
259
260 pong_sender->Send(fbb.GetBufferPointer(), fbb.GetSize(),
261 pong_event_loop->monotonic_now() + kTimeOffset,
262 pong_event_loop->realtime_now() + kTimeOffset,
263 kQueueIndexOffset + pong_count);
264 ++pong_count;
265 });
266
267 DetachedBufferWriter writer(logfile);
268 std::unique_ptr<EventLoop> logger_event_loop =
Austin Schuhac0771c2020-01-07 18:36:30 -0800269 event_loop_factory_.MakeEventLoop("logger", pi1);
Austin Schuh15649d62019-12-28 16:36:38 -0800270
271 event_loop_factory_.RunFor(chrono::milliseconds(95));
272
273 Logger logger(&writer, logger_event_loop.get(),
274 std::chrono::milliseconds(100));
275 event_loop_factory_.RunFor(chrono::milliseconds(20000));
276 }
277
278 LogReader reader(logfile);
279
280 // TODO(austin): Also replay as pi2 or pi3 and make sure we see the pong
281 // messages. This won't work today yet until the log reading code gets
282 // significantly better.
Austin Schuhac0771c2020-01-07 18:36:30 -0800283 SimulatedEventLoopFactory log_reader_factory(reader.logged_configuration());
Austin Schuh6331ef92020-01-07 18:28:09 -0800284 log_reader_factory.set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800285
286 // This sends out the fetched messages and advances time to the start of the
287 // log file.
Austin Schuh6331ef92020-01-07 18:28:09 -0800288 reader.Register(&log_reader_factory);
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800289
Austin Schuhac0771c2020-01-07 18:36:30 -0800290 const Node *pi1 =
291 configuration::GetNode(log_reader_factory.configuration(), "pi1");
292
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800293 ASSERT_NE(reader.node(), nullptr);
294 EXPECT_EQ(reader.node()->name()->string_view(), "pi1");
295
296 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800297
298 std::unique_ptr<EventLoop> test_event_loop =
Austin Schuhac0771c2020-01-07 18:36:30 -0800299 log_reader_factory.MakeEventLoop("test", pi1);
Austin Schuh15649d62019-12-28 16:36:38 -0800300
301 int ping_count = 10;
302 int pong_count = 10;
303
304 // Confirm that the ping value matches.
305 test_event_loop->MakeWatcher("/test",
306 [&ping_count](const examples::Ping &ping) {
307 EXPECT_EQ(ping.value(), ping_count + 1);
308 ++ping_count;
309 });
310 // Confirm that the ping and pong counts both match, and the value also
311 // matches.
312 test_event_loop->MakeWatcher(
313 "/test", [&test_event_loop, &ping_count, &pong_count,
314 kTimeOffset](const examples::Pong &pong) {
315 EXPECT_EQ(test_event_loop->context().remote_queue_index,
316 pong_count + kQueueIndexOffset);
317 EXPECT_EQ(test_event_loop->context().monotonic_remote_time,
318 test_event_loop->monotonic_now() + kTimeOffset);
319 EXPECT_EQ(test_event_loop->context().realtime_remote_time,
320 test_event_loop->realtime_now() + kTimeOffset);
321
322 EXPECT_EQ(pong.value(), pong_count + 1);
323 ++pong_count;
324 EXPECT_EQ(ping_count, pong_count);
325 });
326
Austin Schuh6331ef92020-01-07 18:28:09 -0800327 log_reader_factory.RunFor(std::chrono::seconds(100));
Austin Schuh15649d62019-12-28 16:36:38 -0800328 EXPECT_EQ(ping_count, 2010);
329 EXPECT_EQ(pong_count, 2010);
Austin Schuh6331ef92020-01-07 18:28:09 -0800330
331 reader.Deregister();
Austin Schuh15649d62019-12-28 16:36:38 -0800332}
333
Austin Schuhe309d2a2019-11-29 13:25:21 -0800334} // namespace testing
335} // namespace logger
336} // namespace aos