blob: d96d4c692d29c7554f51694176907598abd4c43a [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
62 LogReader reader(logfile);
63
64 LOG(INFO) << "Config " << FlatbufferToJson(reader.configuration());
Austin Schuhfd960622020-01-01 13:22:55 -080065 EXPECT_EQ(reader.node(), nullptr);
Austin Schuhe309d2a2019-11-29 13:25:21 -080066
Austin Schuh15649d62019-12-28 16:36:38 -080067 // This sends out the fetched messages and advances time to the start of the
68 // log file.
James Kuszmaul84ff3e52020-01-03 19:48:53 -080069 reader.Register();
Austin Schuhe309d2a2019-11-29 13:25:21 -080070
James Kuszmaul84ff3e52020-01-03 19:48:53 -080071 EXPECT_EQ(reader.node(), nullptr);
72
73 EXPECT_EQ(reader.event_loop_factory()->node(), nullptr);
Austin Schuh0bf5b9e2019-12-30 18:16:09 -080074
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
81 // Confirm that the ping value matches.
82 test_event_loop->MakeWatcher("/test",
83 [&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 Schuh4c4e0092019-12-22 16:18:03 -0800100// Tests that a large number of messages per second doesn't overwhelm writev.
101TEST_F(LoggerTest, ManyMessages) {
102 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
103 const ::std::string logfile = tmpdir + "/logfile.bfbs";
104 // Remove the log file.
105 unlink(logfile.c_str());
106
107 LOG(INFO) << "Logging data to " << logfile;
108
109 {
110 DetachedBufferWriter writer(logfile);
111 std::unique_ptr<EventLoop> logger_event_loop =
112 event_loop_factory_.MakeEventLoop("logger");
113
114 std::unique_ptr<EventLoop> ping_spammer_event_loop =
115 event_loop_factory_.MakeEventLoop("ping_spammer");
116 aos::Sender<examples::Ping> ping_sender =
117 ping_spammer_event_loop->MakeSender<examples::Ping>("/test");
118
119 aos::TimerHandler *timer_handler =
120 ping_spammer_event_loop->AddTimer([&ping_sender]() {
121 aos::Sender<examples::Ping>::Builder builder =
122 ping_sender.MakeBuilder();
123 examples::Ping::Builder ping_builder =
124 builder.MakeBuilder<examples::Ping>();
125 CHECK(builder.Send(ping_builder.Finish()));
126 });
127
128 // 100 ms / 0.05 ms -> 2000 messages. Should be enough to crash it.
129 ping_spammer_event_loop->OnRun([&ping_spammer_event_loop, timer_handler]() {
130 timer_handler->Setup(ping_spammer_event_loop->monotonic_now(),
131 chrono::microseconds(50));
132 });
133
134 Logger logger(&writer, logger_event_loop.get(),
135 std::chrono::milliseconds(100));
136
137 event_loop_factory_.RunFor(chrono::milliseconds(1000));
138 }
139}
140
Austin Schuh15649d62019-12-28 16:36:38 -0800141class MultinodeLoggerTest : public ::testing::Test {
142 public:
143 MultinodeLoggerTest()
144 : config_(aos::configuration::ReadConfig(
145 "aos/events/multinode_pingpong_config.json")),
146 event_loop_factory_(&config_.message(), "pi1"),
147 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping")),
148 ping_(ping_event_loop_.get()) {}
149
150 // Config and factory.
151 aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
152 SimulatedEventLoopFactory event_loop_factory_;
153
154 // Event loop and app for Ping
155 std::unique_ptr<EventLoop> ping_event_loop_;
156 Ping ping_;
157};
158
159// Tests that we can startup at all in a multinode configuration.
160TEST_F(MultinodeLoggerTest, MultiNode) {
161 constexpr chrono::seconds kTimeOffset = chrono::seconds(10000);
162 constexpr uint32_t kQueueIndexOffset = 1024;
163 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
164 const ::std::string logfile = tmpdir + "/multi_logfile.bfbs";
165 // Remove it.
166 unlink(logfile.c_str());
167
168 LOG(INFO) << "Logging data to " << logfile;
169
170 {
171 std::unique_ptr<EventLoop> pong_event_loop =
172 event_loop_factory_.MakeEventLoop("pong");
173
174 std::unique_ptr<aos::RawSender> pong_sender(
175 pong_event_loop->MakeRawSender(aos::configuration::GetChannel(
176 pong_event_loop->configuration(), "/test", "aos.examples.Pong",
177 pong_event_loop->name(), pong_event_loop->node())));
178
179 // Ok, let's fake a remote node. We use the fancy raw sender Send
180 // method that message_gateway will use to do that.
181 int pong_count = 0;
182 pong_event_loop->MakeWatcher(
183 "/test", [&pong_event_loop, &pong_count, &pong_sender,
184 kTimeOffset](const examples::Ping &ping) {
185 flatbuffers::FlatBufferBuilder fbb;
186 examples::Pong::Builder pong_builder(fbb);
187 pong_builder.add_value(ping.value());
188 pong_builder.add_initial_send_time(ping.send_time());
189 fbb.Finish(pong_builder.Finish());
190
191 pong_sender->Send(fbb.GetBufferPointer(), fbb.GetSize(),
192 pong_event_loop->monotonic_now() + kTimeOffset,
193 pong_event_loop->realtime_now() + kTimeOffset,
194 kQueueIndexOffset + pong_count);
195 ++pong_count;
196 });
197
198 DetachedBufferWriter writer(logfile);
199 std::unique_ptr<EventLoop> logger_event_loop =
200 event_loop_factory_.MakeEventLoop("logger");
201
202 event_loop_factory_.RunFor(chrono::milliseconds(95));
203
204 Logger logger(&writer, logger_event_loop.get(),
205 std::chrono::milliseconds(100));
206 event_loop_factory_.RunFor(chrono::milliseconds(20000));
207 }
208
209 LogReader reader(logfile);
210
211 // TODO(austin): Also replay as pi2 or pi3 and make sure we see the pong
212 // messages. This won't work today yet until the log reading code gets
213 // significantly better.
Austin Schuh15649d62019-12-28 16:36:38 -0800214
215 // This sends out the fetched messages and advances time to the start of the
216 // log file.
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800217 reader.Register();
218
219 ASSERT_NE(reader.node(), nullptr);
220 EXPECT_EQ(reader.node()->name()->string_view(), "pi1");
221
222 reader.event_loop_factory()->set_send_delay(chrono::microseconds(0));
Austin Schuh15649d62019-12-28 16:36:38 -0800223
224 std::unique_ptr<EventLoop> test_event_loop =
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800225 reader.event_loop_factory()->MakeEventLoop("test");
Austin Schuh15649d62019-12-28 16:36:38 -0800226
227 int ping_count = 10;
228 int pong_count = 10;
229
230 // Confirm that the ping value matches.
231 test_event_loop->MakeWatcher("/test",
232 [&ping_count](const examples::Ping &ping) {
233 EXPECT_EQ(ping.value(), ping_count + 1);
234 ++ping_count;
235 });
236 // Confirm that the ping and pong counts both match, and the value also
237 // matches.
238 test_event_loop->MakeWatcher(
239 "/test", [&test_event_loop, &ping_count, &pong_count,
240 kTimeOffset](const examples::Pong &pong) {
241 EXPECT_EQ(test_event_loop->context().remote_queue_index,
242 pong_count + kQueueIndexOffset);
243 EXPECT_EQ(test_event_loop->context().monotonic_remote_time,
244 test_event_loop->monotonic_now() + kTimeOffset);
245 EXPECT_EQ(test_event_loop->context().realtime_remote_time,
246 test_event_loop->realtime_now() + kTimeOffset);
247
248 EXPECT_EQ(pong.value(), pong_count + 1);
249 ++pong_count;
250 EXPECT_EQ(ping_count, pong_count);
251 });
252
James Kuszmaul84ff3e52020-01-03 19:48:53 -0800253 reader.event_loop_factory()->RunFor(std::chrono::seconds(100));
Austin Schuh15649d62019-12-28 16:36:38 -0800254 EXPECT_EQ(ping_count, 2010);
255 EXPECT_EQ(pong_count, 2010);
Austin Schuh15649d62019-12-28 16:36:38 -0800256}
257
Austin Schuhe309d2a2019-11-29 13:25:21 -0800258} // namespace testing
259} // namespace logger
260} // namespace aos