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