blob: 8c7751e84239af215cbb3def68e7d17264454c39 [file] [log] [blame]
Philipp Schrader790cb542023-07-05 21:06:52 -07001#include "gtest/gtest.h"
2
James Kuszmaul09632422022-05-25 15:56:19 -07003#include "aos/events/logging/log_reader.h"
4#include "aos/events/logging/log_writer.h"
5#include "aos/events/ping_lib.h"
Eric Schmiedebergb38477e2022-12-02 16:08:04 -07006#include "aos/events/pong_lib.h"
James Kuszmaul09632422022-05-25 15:56:19 -07007#include "aos/events/shm_event_loop.h"
8#include "aos/json_to_flatbuffer.h"
9#include "aos/testing/path.h"
10#include "aos/testing/tmpdir.h"
James Kuszmaul09632422022-05-25 15:56:19 -070011
Eric Schmiedebergb38477e2022-12-02 16:08:04 -070012DECLARE_string(override_hostname);
13
James Kuszmaul09632422022-05-25 15:56:19 -070014namespace aos::logger::testing {
15
16class RealtimeLoggerTest : public ::testing::Test {
17 protected:
18 RealtimeLoggerTest()
19 : shm_dir_(aos::testing::TestTmpDir() + "/aos"),
20 config_file_(
21 aos::testing::ArtifactPath("aos/events/pingpong_config.json")),
22 config_(aos::configuration::ReadConfig(config_file_)),
23 event_loop_factory_(&config_.message()),
24 ping_event_loop_(event_loop_factory_.MakeEventLoop("ping")),
Eric Schmiedebergb38477e2022-12-02 16:08:04 -070025 pong_event_loop_(event_loop_factory_.MakeEventLoop("pong")),
26 ping_(ping_event_loop_.get()),
27 pong_(pong_event_loop_.get()),
28 tmpdir_(aos::testing::TestTmpDir()),
29 base_name_(tmpdir_ + "/logfile/") {
James Kuszmaul09632422022-05-25 15:56:19 -070030 FLAGS_shm_base = shm_dir_;
31
Eric Schmiedebergb38477e2022-12-02 16:08:04 -070032 // Nuke the shm and log dirs, to ensure we aren't being affected by any
33 // preexisting tests.
James Kuszmaul09632422022-05-25 15:56:19 -070034 aos::util::UnlinkRecursive(shm_dir_);
Eric Schmiedebergb38477e2022-12-02 16:08:04 -070035 aos::util::UnlinkRecursive(base_name_);
36 }
37
38 gflags::FlagSaver flag_saver_;
39 std::string shm_dir_;
40
41 const std::string config_file_;
42 const aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
43
44 // Factory and Ping class to generate a test logfile.
45 SimulatedEventLoopFactory event_loop_factory_;
46 std::unique_ptr<EventLoop> ping_event_loop_;
47 std::unique_ptr<EventLoop> pong_event_loop_;
48 Ping ping_;
49 Pong pong_;
50 const std::string tmpdir_;
51 const std::string base_name_;
52};
53
54class RealtimeMultiNodeLoggerTest : public ::testing::Test {
55 protected:
56 RealtimeMultiNodeLoggerTest()
57 : shm_dir_(aos::testing::TestTmpDir() + "/aos"),
58 config_file_(aos::testing::ArtifactPath(
59 "aos/events/logging/multinode_pingpong_combined_config.json")),
60 config_(aos::configuration::ReadConfig(config_file_)),
61 event_loop_factory_(&config_.message()),
62 ping_event_loop_(event_loop_factory_.MakeEventLoop(
63 "pi1", configuration::GetNode(&config_.message(), "pi1"))),
64 ping_(ping_event_loop_.get()),
65 tmpdir_(aos::testing::TestTmpDir()),
66 base_name_(tmpdir_ + "/logfile/") {
67 FLAGS_shm_base = shm_dir_;
68
69 // Nuke the shm and log dirs, to ensure we aren't being affected by any
70 // preexisting tests.
71 aos::util::UnlinkRecursive(shm_dir_);
72 aos::util::UnlinkRecursive(base_name_);
James Kuszmaul09632422022-05-25 15:56:19 -070073 }
74
75 gflags::FlagSaver flag_saver_;
76 std::string shm_dir_;
77
78 const std::string config_file_;
79 const aos::FlatbufferDetachedBuffer<aos::Configuration> config_;
80
81 // Factory and Ping class to generate a test logfile.
82 SimulatedEventLoopFactory event_loop_factory_;
83 std::unique_ptr<EventLoop> ping_event_loop_;
84 Ping ping_;
Eric Schmiedebergb38477e2022-12-02 16:08:04 -070085 const std::string tmpdir_;
86 const std::string base_name_;
James Kuszmaul09632422022-05-25 15:56:19 -070087};
88
89TEST_F(RealtimeLoggerTest, RealtimeReplay) {
James Kuszmaul09632422022-05-25 15:56:19 -070090 {
91 std::unique_ptr<EventLoop> logger_event_loop =
92 event_loop_factory_.MakeEventLoop("logger");
93
94 event_loop_factory_.RunFor(std::chrono::milliseconds(95));
95
96 Logger logger(logger_event_loop.get());
97 logger.set_separate_config(false);
98 logger.set_polling_period(std::chrono::milliseconds(100));
Eric Schmiedebergb38477e2022-12-02 16:08:04 -070099 logger.StartLoggingOnRun(base_name_);
James Kuszmaul09632422022-05-25 15:56:19 -0700100 event_loop_factory_.RunFor(std::chrono::milliseconds(2000));
101 }
102
Eric Schmiedebergb38477e2022-12-02 16:08:04 -0700103 LogReader reader(logger::SortParts(logger::FindLogs(base_name_)));
James Kuszmaul09632422022-05-25 15:56:19 -0700104 ShmEventLoop shm_event_loop(reader.configuration());
105 reader.Register(&shm_event_loop);
106 reader.OnEnd(shm_event_loop.node(),
107 [&shm_event_loop]() { shm_event_loop.Exit(); });
108
109 Fetcher<examples::Ping> ping_fetcher =
110 shm_event_loop.MakeFetcher<examples::Ping>("/test");
111
112 shm_event_loop.AddTimer([]() { LOG(INFO) << "Hello, World!"; })
Philipp Schradera6712522023-07-05 20:25:11 -0700113 ->Schedule(shm_event_loop.monotonic_now(), std::chrono::seconds(1));
James Kuszmaul09632422022-05-25 15:56:19 -0700114
115 shm_event_loop.Run();
116 reader.Deregister();
117
118 ASSERT_TRUE(ping_fetcher.Fetch());
119 ASSERT_EQ(ping_fetcher->value(), 210);
120}
Eric Schmiedebergb38477e2022-12-02 16:08:04 -0700121
122// Tests that ReplayChannels causes no messages to be replayed other than what
123// is included on a single node config
124TEST_F(RealtimeLoggerTest, SingleNodeReplayChannels) {
125 {
126 std::unique_ptr<EventLoop> logger_event_loop =
127 event_loop_factory_.MakeEventLoop("logger");
128
129 event_loop_factory_.RunFor(std::chrono::milliseconds(95));
130
131 Logger logger(logger_event_loop.get());
132 logger.set_separate_config(false);
133 logger.set_polling_period(std::chrono::milliseconds(100));
134 logger.StartLoggingOnRun(base_name_);
135 event_loop_factory_.RunFor(std::chrono::milliseconds(2000));
136 }
137
138 ReplayChannels replay_channels{{"/test", "aos.examples.Ping"}};
139 LogReader reader(logger::SortParts(logger::FindLogs(base_name_)),
140 &config_.message(), &replay_channels);
141 ShmEventLoop shm_event_loop(reader.configuration());
142 reader.Register(&shm_event_loop);
143 reader.OnEnd(shm_event_loop.node(),
144 [&shm_event_loop]() { shm_event_loop.Exit(); });
145
146 Fetcher<examples::Ping> ping_fetcher =
147 shm_event_loop.MakeFetcher<examples::Ping>("/test");
148 Fetcher<examples::Pong> pong_fetcher =
149 shm_event_loop.MakeFetcher<examples::Pong>("/test");
150
151 shm_event_loop.AddTimer([]() { LOG(INFO) << "Hello, World!"; })
Philipp Schradera6712522023-07-05 20:25:11 -0700152 ->Schedule(shm_event_loop.monotonic_now(), std::chrono::seconds(1));
Eric Schmiedebergb38477e2022-12-02 16:08:04 -0700153
Naman Guptac87b3102023-02-28 14:42:02 -0800154 // End timer should not be called in this case, it should automatically quit
155 // the event loop and check for number of fetches messages
156 // This is added to make sure OnEnd is called consistently
157 // When OnEnd is not called after finishing of the log, this will eventually
158 // quit due to the end timer but will report a failure
Eric Schmiedebergb38477e2022-12-02 16:08:04 -0700159 size_t run_seconds = 3;
Naman Guptac87b3102023-02-28 14:42:02 -0800160 auto *const end_timer =
161 shm_event_loop.AddTimer([&shm_event_loop, run_seconds]() {
162 shm_event_loop.Exit();
163 FAIL() << "OnEnd wasn't called on log end so quitting after "
164 << run_seconds << " seconds.";
165 });
Eric Schmiedebergb38477e2022-12-02 16:08:04 -0700166 shm_event_loop.OnRun([&shm_event_loop, end_timer, run_seconds]() {
167 LOG(INFO) << "Quitting in: " << run_seconds;
Philipp Schradera6712522023-07-05 20:25:11 -0700168 end_timer->Schedule(shm_event_loop.monotonic_now() +
169 std::chrono::seconds(run_seconds));
Eric Schmiedebergb38477e2022-12-02 16:08:04 -0700170 });
Naman Guptac87b3102023-02-28 14:42:02 -0800171
Eric Schmiedebergb38477e2022-12-02 16:08:04 -0700172 shm_event_loop.Run();
173 reader.Deregister();
174
175 ASSERT_TRUE(ping_fetcher.Fetch());
176 ASSERT_EQ(ping_fetcher->value(), 210);
177 ASSERT_FALSE(pong_fetcher.Fetch());
178}
179
180// Tests that ReplayChannels causes no messages to be replayed other than what
181// is included on a multi node config
182TEST_F(RealtimeMultiNodeLoggerTest, ReplayChannelsPingTest) {
183 FLAGS_override_hostname = "raspberrypi";
184 {
185 std::unique_ptr<EventLoop> logger_event_loop =
186 event_loop_factory_.MakeEventLoop(
187 "logger", configuration::GetNode(&config_.message(), "pi1"));
188
189 event_loop_factory_.RunFor(std::chrono::milliseconds(95));
190
191 Logger logger(logger_event_loop.get());
192 logger.set_separate_config(false);
193 logger.set_polling_period(std::chrono::milliseconds(100));
194
Alexei Strots01395492023-03-20 13:59:56 -0700195 std::unique_ptr<MultiNodeFilesLogNamer> namer =
196 std::make_unique<MultiNodeFilesLogNamer>(
Eric Schmiedebergb38477e2022-12-02 16:08:04 -0700197 base_name_, &config_.message(), logger_event_loop.get(),
198 configuration::GetNode(&config_.message(), "pi1"));
199
200 logger.StartLogging(std::move(namer));
201 event_loop_factory_.RunFor(std::chrono::milliseconds(2000));
202 }
203
204 ReplayChannels replay_channels{{"/test", "aos.examples.Ping"}};
205 LogReader reader(logger::SortParts(logger::FindLogs(base_name_)),
206 &config_.message(), &replay_channels);
207 ShmEventLoop shm_event_loop(reader.configuration());
208 reader.Register(&shm_event_loop);
209 reader.OnEnd(shm_event_loop.node(),
210 [&shm_event_loop]() { shm_event_loop.Exit(); });
211
212 Fetcher<examples::Ping> ping_fetcher =
213 shm_event_loop.MakeFetcher<examples::Ping>("/test");
214
215 shm_event_loop.AddTimer([]() { LOG(INFO) << "Hello, World!"; })
Philipp Schradera6712522023-07-05 20:25:11 -0700216 ->Schedule(shm_event_loop.monotonic_now(), std::chrono::seconds(1));
Eric Schmiedebergb38477e2022-12-02 16:08:04 -0700217
218 shm_event_loop.Run();
219 reader.Deregister();
220
221 ASSERT_TRUE(ping_fetcher.Fetch());
222 ASSERT_EQ(ping_fetcher->value(), 210);
223}
224
225// Tests that when remapping a channel included in ReplayChannels messages are
226// sent on the remapped channel
227TEST_F(RealtimeMultiNodeLoggerTest, RemappedReplayChannelsTest) {
228 FLAGS_override_hostname = "raspberrypi";
229 {
230 std::unique_ptr<EventLoop> logger_event_loop =
231 event_loop_factory_.MakeEventLoop(
232 "logger", configuration::GetNode(&config_.message(), "pi1"));
233
234 event_loop_factory_.RunFor(std::chrono::milliseconds(95));
235
236 Logger logger(logger_event_loop.get());
237 logger.set_separate_config(false);
238 logger.set_polling_period(std::chrono::milliseconds(100));
239
Alexei Strots01395492023-03-20 13:59:56 -0700240 std::unique_ptr<MultiNodeFilesLogNamer> namer =
241 std::make_unique<MultiNodeFilesLogNamer>(
Eric Schmiedebergb38477e2022-12-02 16:08:04 -0700242 base_name_, &config_.message(), logger_event_loop.get(),
243 configuration::GetNode(&config_.message(), "pi1"));
244
245 logger.StartLogging(std::move(namer));
246 event_loop_factory_.RunFor(std::chrono::milliseconds(2000));
247 }
248
249 ReplayChannels replay_channels{{"/test", "aos.examples.Ping"}};
250 LogReader reader(logger::SortParts(logger::FindLogs(base_name_)),
251 &config_.message(), &replay_channels);
252 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
253 ShmEventLoop shm_event_loop(reader.configuration());
254 reader.Register(&shm_event_loop);
255 reader.OnEnd(shm_event_loop.node(),
256 [&shm_event_loop]() { shm_event_loop.Exit(); });
257
258 Fetcher<examples::Ping> original_ping_fetcher =
259 shm_event_loop.MakeFetcher<examples::Ping>("/original/test");
260
261 Fetcher<examples::Ping> ping_fetcher =
262 shm_event_loop.MakeFetcher<examples::Ping>("/test");
263
264 shm_event_loop.AddTimer([]() { LOG(INFO) << "Hello, World!"; })
Philipp Schradera6712522023-07-05 20:25:11 -0700265 ->Schedule(shm_event_loop.monotonic_now(), std::chrono::seconds(1));
Eric Schmiedebergb38477e2022-12-02 16:08:04 -0700266
267 shm_event_loop.Run();
268 reader.Deregister();
269
270 ASSERT_TRUE(original_ping_fetcher.Fetch());
271 ASSERT_EQ(original_ping_fetcher->value(), 210);
272 ASSERT_FALSE(ping_fetcher.Fetch());
273}
274
275// Tests that messages are not replayed when they do not exist in the
276// ReplayChannels provided to LogReader. The channels used here do not
277// exist in the log being replayed, and there's no messages on those
278// channels as well.
279TEST_F(RealtimeMultiNodeLoggerTest, DoesNotExistInReplayChannelsTest) {
280 FLAGS_override_hostname = "raspberrypi";
281 {
282 std::unique_ptr<EventLoop> logger_event_loop =
283 event_loop_factory_.MakeEventLoop(
284 "logger", configuration::GetNode(&config_.message(), "pi1"));
285
286 event_loop_factory_.RunFor(std::chrono::milliseconds(95));
287
288 Logger logger(logger_event_loop.get());
289 logger.set_separate_config(false);
290 logger.set_polling_period(std::chrono::milliseconds(100));
Alexei Strots01395492023-03-20 13:59:56 -0700291 std::unique_ptr<MultiNodeFilesLogNamer> namer =
292 std::make_unique<MultiNodeFilesLogNamer>(
Eric Schmiedebergb38477e2022-12-02 16:08:04 -0700293 base_name_, &config_.message(), logger_event_loop.get(),
294 configuration::GetNode(&config_.message(), "pi1"));
295
296 logger.StartLogging(std::move(namer));
297 event_loop_factory_.RunFor(std::chrono::milliseconds(2000));
298 }
299
300 ReplayChannels replay_channels{{"/test", "aos.examples.Pong"},
301 {"/test", "fake"},
302 {"fake", "aos.examples.Ping"}};
303 LogReader reader(logger::SortParts(logger::FindLogs(base_name_)),
304 &config_.message(), &replay_channels);
305 ShmEventLoop shm_event_loop(reader.configuration());
306 reader.Register(&shm_event_loop);
307 reader.OnEnd(shm_event_loop.node(),
308 [&shm_event_loop]() { shm_event_loop.Exit(); });
309
310 Fetcher<examples::Ping> ping_fetcher =
311 shm_event_loop.MakeFetcher<examples::Ping>("/test");
312
313 auto *const end_timer = shm_event_loop.AddTimer([&shm_event_loop]() {
314 LOG(INFO) << "All done, quitting now";
315 shm_event_loop.Exit();
316 });
317
318 // TODO(#21) reader.OnEnd() is not working as expected when
319 // using replay_channels
320 // keep looking for 3 seconds if some message comes, just in case
321 size_t run_seconds = 3;
322 shm_event_loop.OnRun([&shm_event_loop, end_timer, run_seconds]() {
323 LOG(INFO) << "Quitting in: " << run_seconds;
Philipp Schradera6712522023-07-05 20:25:11 -0700324 end_timer->Schedule(shm_event_loop.monotonic_now() +
325 std::chrono::seconds(run_seconds));
Eric Schmiedebergb38477e2022-12-02 16:08:04 -0700326 });
327
328 shm_event_loop.Run();
329 reader.Deregister();
330 ASSERT_FALSE(ping_fetcher.Fetch());
331}
332
333using RealtimeMultiNodeLoggerDeathTest = RealtimeMultiNodeLoggerTest;
334
335// Tests that remapping a channel not included in the replay channels passed to
336// LogReader throws an error since this would indicate the user is trying to use
337// the channel being remapped.
338TEST_F(RealtimeMultiNodeLoggerDeathTest,
339 RemapLoggedChannelNotIncludedInReplayChannels) {
340 FLAGS_override_hostname = "raspberrypi";
341 {
342 std::unique_ptr<EventLoop> logger_event_loop =
343 event_loop_factory_.MakeEventLoop(
344 "logger", configuration::GetNode(&config_.message(), "pi1"));
345
346 event_loop_factory_.RunFor(std::chrono::milliseconds(95));
347
348 Logger logger(logger_event_loop.get());
349 logger.set_separate_config(false);
350 logger.set_polling_period(std::chrono::milliseconds(100));
351
Alexei Strots01395492023-03-20 13:59:56 -0700352 std::unique_ptr<MultiNodeFilesLogNamer> namer =
353 std::make_unique<MultiNodeFilesLogNamer>(
Eric Schmiedebergb38477e2022-12-02 16:08:04 -0700354 base_name_, &config_.message(), logger_event_loop.get(),
355 configuration::GetNode(&config_.message(), "pi1"));
356
357 logger.StartLogging(std::move(namer));
358 event_loop_factory_.RunFor(std::chrono::milliseconds(2000));
359 }
360
361 ReplayChannels replay_channels{{"/test", "aos.examples.Ping"}};
362 LogReader reader(logger::SortParts(logger::FindLogs(base_name_)),
363 &config_.message(), &replay_channels);
364 EXPECT_DEATH(
365 reader.RemapLoggedChannel<aos::examples::Ping>("/fake", "/original"),
366 "which is not included in the replay channels passed to LogReader");
367}
368
James Kuszmaul09632422022-05-25 15:56:19 -0700369} // namespace aos::logger::testing