blob: c62710178b5664237a29a54ff5018fb1447b48c3 [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
66 // TODO(austin): Figure out what the API needs to look like. How do we replay
67 // the data that was fetched before it all starts? How do we set the starting
68 // time from the log file? Probably need to let the reader do more if it
69 // knows about the factory.
70 SimulatedEventLoopFactory log_reader_factory(reader.configuration());
71 std::unique_ptr<EventLoop> reader_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080072 log_reader_factory.MakeEventLoop("log_reader");
Austin Schuhe309d2a2019-11-29 13:25:21 -080073
74 reader.Register(reader_event_loop.get());
75
76 // Capture monotonic start time in OnRun and offset from there? Let the user
77 // configure the factory if they want time to match?
78 /*
79 log_reader_factory.InitializeTime(log_reader.monotonic_start_time(),
80 log_reader.realtime_start_time());
81 */
82 std::unique_ptr<EventLoop> test_event_loop =
Austin Schuh5f1cc5c2019-12-01 18:01:11 -080083 log_reader_factory.MakeEventLoop("log_reader");
Austin Schuhe309d2a2019-11-29 13:25:21 -080084
85 int ping_count = 10;
86 int pong_count = 10;
87
88 // Confirm that the ping value matches.
89 test_event_loop->MakeWatcher("/test",
90 [&ping_count](const examples::Ping &ping) {
91 EXPECT_EQ(ping.value(), ping_count + 1);
92 ++ping_count;
93 });
94 // Confirm that the ping and pong counts both match, and the value also
95 // matches.
96 test_event_loop->MakeWatcher(
97 "/test", [&pong_count, &ping_count](const examples::Pong &pong) {
98 EXPECT_EQ(pong.value(), pong_count + 1);
99 ++pong_count;
100 EXPECT_EQ(ping_count, pong_count);
101 });
102
103 log_reader_factory.RunFor(std::chrono::seconds(100));
104 EXPECT_EQ(ping_count, 2010);
105
106 reader.Deregister();
107}
108
Austin Schuh4c4e0092019-12-22 16:18:03 -0800109// Tests that a large number of messages per second doesn't overwhelm writev.
110TEST_F(LoggerTest, ManyMessages) {
111 const ::std::string tmpdir(getenv("TEST_TMPDIR"));
112 const ::std::string logfile = tmpdir + "/logfile.bfbs";
113 // Remove the log file.
114 unlink(logfile.c_str());
115
116 LOG(INFO) << "Logging data to " << logfile;
117
118 {
119 DetachedBufferWriter writer(logfile);
120 std::unique_ptr<EventLoop> logger_event_loop =
121 event_loop_factory_.MakeEventLoop("logger");
122
123 std::unique_ptr<EventLoop> ping_spammer_event_loop =
124 event_loop_factory_.MakeEventLoop("ping_spammer");
125 aos::Sender<examples::Ping> ping_sender =
126 ping_spammer_event_loop->MakeSender<examples::Ping>("/test");
127
128 aos::TimerHandler *timer_handler =
129 ping_spammer_event_loop->AddTimer([&ping_sender]() {
130 aos::Sender<examples::Ping>::Builder builder =
131 ping_sender.MakeBuilder();
132 examples::Ping::Builder ping_builder =
133 builder.MakeBuilder<examples::Ping>();
134 CHECK(builder.Send(ping_builder.Finish()));
135 });
136
137 // 100 ms / 0.05 ms -> 2000 messages. Should be enough to crash it.
138 ping_spammer_event_loop->OnRun([&ping_spammer_event_loop, timer_handler]() {
139 timer_handler->Setup(ping_spammer_event_loop->monotonic_now(),
140 chrono::microseconds(50));
141 });
142
143 Logger logger(&writer, logger_event_loop.get(),
144 std::chrono::milliseconds(100));
145
146 event_loop_factory_.RunFor(chrono::milliseconds(1000));
147 }
148}
149
Austin Schuhe309d2a2019-11-29 13:25:21 -0800150} // namespace testing
151} // namespace logger
152} // namespace aos