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