blob: 888b043683b16d1a128091965c4a414c4d607fe7 [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
153 auto *const end_timer = shm_event_loop.AddTimer([&shm_event_loop]() {
154 LOG(INFO) << "All done, quitting now";
155 shm_event_loop.Exit();
156 });
157
158 // TODO(EricS) reader.OnEnd() is not working as expected when
159 // using a channel filter.
160 // keep looking for 3 seconds if some message comes, just in case
161 size_t run_seconds = 3;
162 shm_event_loop.OnRun([&shm_event_loop, end_timer, run_seconds]() {
163 LOG(INFO) << "Quitting in: " << run_seconds;
164 end_timer->Setup(shm_event_loop.monotonic_now() +
165 std::chrono::seconds(run_seconds));
166 });
167 shm_event_loop.Run();
168 reader.Deregister();
169
170 ASSERT_TRUE(ping_fetcher.Fetch());
171 ASSERT_EQ(ping_fetcher->value(), 210);
172 ASSERT_FALSE(pong_fetcher.Fetch());
173}
174
175// Tests that ReplayChannels causes no messages to be replayed other than what
176// is included on a multi node config
177TEST_F(RealtimeMultiNodeLoggerTest, ReplayChannelsPingTest) {
178 FLAGS_override_hostname = "raspberrypi";
179 {
180 std::unique_ptr<EventLoop> logger_event_loop =
181 event_loop_factory_.MakeEventLoop(
182 "logger", configuration::GetNode(&config_.message(), "pi1"));
183
184 event_loop_factory_.RunFor(std::chrono::milliseconds(95));
185
186 Logger logger(logger_event_loop.get());
187 logger.set_separate_config(false);
188 logger.set_polling_period(std::chrono::milliseconds(100));
189
190 std::unique_ptr<MultiNodeLogNamer> namer =
191 std::make_unique<MultiNodeLogNamer>(
192 base_name_, &config_.message(), logger_event_loop.get(),
193 configuration::GetNode(&config_.message(), "pi1"));
194
195 logger.StartLogging(std::move(namer));
196 event_loop_factory_.RunFor(std::chrono::milliseconds(2000));
197 }
198
199 ReplayChannels replay_channels{{"/test", "aos.examples.Ping"}};
200 LogReader reader(logger::SortParts(logger::FindLogs(base_name_)),
201 &config_.message(), &replay_channels);
202 ShmEventLoop shm_event_loop(reader.configuration());
203 reader.Register(&shm_event_loop);
204 reader.OnEnd(shm_event_loop.node(),
205 [&shm_event_loop]() { shm_event_loop.Exit(); });
206
207 Fetcher<examples::Ping> ping_fetcher =
208 shm_event_loop.MakeFetcher<examples::Ping>("/test");
209
210 shm_event_loop.AddTimer([]() { LOG(INFO) << "Hello, World!"; })
211 ->Setup(shm_event_loop.monotonic_now(), std::chrono::seconds(1));
212
213 shm_event_loop.Run();
214 reader.Deregister();
215
216 ASSERT_TRUE(ping_fetcher.Fetch());
217 ASSERT_EQ(ping_fetcher->value(), 210);
218}
219
220// Tests that when remapping a channel included in ReplayChannels messages are
221// sent on the remapped channel
222TEST_F(RealtimeMultiNodeLoggerTest, RemappedReplayChannelsTest) {
223 FLAGS_override_hostname = "raspberrypi";
224 {
225 std::unique_ptr<EventLoop> logger_event_loop =
226 event_loop_factory_.MakeEventLoop(
227 "logger", configuration::GetNode(&config_.message(), "pi1"));
228
229 event_loop_factory_.RunFor(std::chrono::milliseconds(95));
230
231 Logger logger(logger_event_loop.get());
232 logger.set_separate_config(false);
233 logger.set_polling_period(std::chrono::milliseconds(100));
234
235 std::unique_ptr<MultiNodeLogNamer> namer =
236 std::make_unique<MultiNodeLogNamer>(
237 base_name_, &config_.message(), logger_event_loop.get(),
238 configuration::GetNode(&config_.message(), "pi1"));
239
240 logger.StartLogging(std::move(namer));
241 event_loop_factory_.RunFor(std::chrono::milliseconds(2000));
242 }
243
244 ReplayChannels replay_channels{{"/test", "aos.examples.Ping"}};
245 LogReader reader(logger::SortParts(logger::FindLogs(base_name_)),
246 &config_.message(), &replay_channels);
247 reader.RemapLoggedChannel<aos::examples::Ping>("/test", "/original");
248 ShmEventLoop shm_event_loop(reader.configuration());
249 reader.Register(&shm_event_loop);
250 reader.OnEnd(shm_event_loop.node(),
251 [&shm_event_loop]() { shm_event_loop.Exit(); });
252
253 Fetcher<examples::Ping> original_ping_fetcher =
254 shm_event_loop.MakeFetcher<examples::Ping>("/original/test");
255
256 Fetcher<examples::Ping> ping_fetcher =
257 shm_event_loop.MakeFetcher<examples::Ping>("/test");
258
259 shm_event_loop.AddTimer([]() { LOG(INFO) << "Hello, World!"; })
260 ->Setup(shm_event_loop.monotonic_now(), std::chrono::seconds(1));
261
262 shm_event_loop.Run();
263 reader.Deregister();
264
265 ASSERT_TRUE(original_ping_fetcher.Fetch());
266 ASSERT_EQ(original_ping_fetcher->value(), 210);
267 ASSERT_FALSE(ping_fetcher.Fetch());
268}
269
270// Tests that messages are not replayed when they do not exist in the
271// ReplayChannels provided to LogReader. The channels used here do not
272// exist in the log being replayed, and there's no messages on those
273// channels as well.
274TEST_F(RealtimeMultiNodeLoggerTest, DoesNotExistInReplayChannelsTest) {
275 FLAGS_override_hostname = "raspberrypi";
276 {
277 std::unique_ptr<EventLoop> logger_event_loop =
278 event_loop_factory_.MakeEventLoop(
279 "logger", configuration::GetNode(&config_.message(), "pi1"));
280
281 event_loop_factory_.RunFor(std::chrono::milliseconds(95));
282
283 Logger logger(logger_event_loop.get());
284 logger.set_separate_config(false);
285 logger.set_polling_period(std::chrono::milliseconds(100));
286 std::unique_ptr<MultiNodeLogNamer> namer =
287 std::make_unique<MultiNodeLogNamer>(
288 base_name_, &config_.message(), logger_event_loop.get(),
289 configuration::GetNode(&config_.message(), "pi1"));
290
291 logger.StartLogging(std::move(namer));
292 event_loop_factory_.RunFor(std::chrono::milliseconds(2000));
293 }
294
295 ReplayChannels replay_channels{{"/test", "aos.examples.Pong"},
296 {"/test", "fake"},
297 {"fake", "aos.examples.Ping"}};
298 LogReader reader(logger::SortParts(logger::FindLogs(base_name_)),
299 &config_.message(), &replay_channels);
300 ShmEventLoop shm_event_loop(reader.configuration());
301 reader.Register(&shm_event_loop);
302 reader.OnEnd(shm_event_loop.node(),
303 [&shm_event_loop]() { shm_event_loop.Exit(); });
304
305 Fetcher<examples::Ping> ping_fetcher =
306 shm_event_loop.MakeFetcher<examples::Ping>("/test");
307
308 auto *const end_timer = shm_event_loop.AddTimer([&shm_event_loop]() {
309 LOG(INFO) << "All done, quitting now";
310 shm_event_loop.Exit();
311 });
312
313 // TODO(#21) reader.OnEnd() is not working as expected when
314 // using replay_channels
315 // keep looking for 3 seconds if some message comes, just in case
316 size_t run_seconds = 3;
317 shm_event_loop.OnRun([&shm_event_loop, end_timer, run_seconds]() {
318 LOG(INFO) << "Quitting in: " << run_seconds;
319 end_timer->Setup(shm_event_loop.monotonic_now() +
320 std::chrono::seconds(run_seconds));
321 });
322
323 shm_event_loop.Run();
324 reader.Deregister();
325 ASSERT_FALSE(ping_fetcher.Fetch());
326}
327
328using RealtimeMultiNodeLoggerDeathTest = RealtimeMultiNodeLoggerTest;
329
330// Tests that remapping a channel not included in the replay channels passed to
331// LogReader throws an error since this would indicate the user is trying to use
332// the channel being remapped.
333TEST_F(RealtimeMultiNodeLoggerDeathTest,
334 RemapLoggedChannelNotIncludedInReplayChannels) {
335 FLAGS_override_hostname = "raspberrypi";
336 {
337 std::unique_ptr<EventLoop> logger_event_loop =
338 event_loop_factory_.MakeEventLoop(
339 "logger", configuration::GetNode(&config_.message(), "pi1"));
340
341 event_loop_factory_.RunFor(std::chrono::milliseconds(95));
342
343 Logger logger(logger_event_loop.get());
344 logger.set_separate_config(false);
345 logger.set_polling_period(std::chrono::milliseconds(100));
346
347 std::unique_ptr<MultiNodeLogNamer> namer =
348 std::make_unique<MultiNodeLogNamer>(
349 base_name_, &config_.message(), logger_event_loop.get(),
350 configuration::GetNode(&config_.message(), "pi1"));
351
352 logger.StartLogging(std::move(namer));
353 event_loop_factory_.RunFor(std::chrono::milliseconds(2000));
354 }
355
356 ReplayChannels replay_channels{{"/test", "aos.examples.Ping"}};
357 LogReader reader(logger::SortParts(logger::FindLogs(base_name_)),
358 &config_.message(), &replay_channels);
359 EXPECT_DEATH(
360 reader.RemapLoggedChannel<aos::examples::Ping>("/fake", "/original"),
361 "which is not included in the replay channels passed to LogReader");
362}
363
James Kuszmaul09632422022-05-25 15:56:19 -0700364} // namespace aos::logger::testing