blob: 08fdc7b613fec3acff4df05d2f75732a64139760 [file] [log] [blame]
Tyler Chatow4b471e12020-01-05 20:19:36 -08001#include "aos/logging/implementations.h"
2
Stephan Pleines0960c262024-05-31 20:29:24 -07003#include <signal.h>
4#include <stdlib.h>
5
Austin Schuhf2a50ba2016-12-24 16:16:26 -08006#include <chrono>
Tyler Chatowbf0609c2021-07-31 16:13:27 -07007#include <cinttypes>
Austin Schuhf2a50ba2016-12-24 16:16:26 -08008#include <string>
9
Brian Silverman1463c092020-10-30 17:28:24 -070010#include "glog/logging.h"
Brian Silvermanf665d692013-02-17 22:11:39 -080011#include "gtest/gtest.h"
12
Philipp Schrader790cb542023-07-05 21:06:52 -070013#include "aos/logging/printf_formats.h"
14#include "aos/time/time.h"
15
Tyler Chatow4b471e12020-01-05 20:19:36 -080016using ::testing::AssertionFailure;
Brian Silvermanf665d692013-02-17 22:11:39 -080017using ::testing::AssertionResult;
18using ::testing::AssertionSuccess;
Brian Silvermanf665d692013-02-17 22:11:39 -080019
Stephan Pleinesf63bde82024-01-13 15:59:33 -080020namespace aos::logging::testing {
Brian Silvermanf665d692013-02-17 22:11:39 -080021
Austin Schuhf2a50ba2016-12-24 16:16:26 -080022namespace chrono = ::std::chrono;
23
Alex Perrycb7da4b2019-08-28 19:35:56 -070024class TestLogImplementation : public LogImplementation {
25 virtual ::aos::monotonic_clock::time_point monotonic_now() const {
26 return ::aos::monotonic_clock::now();
27 }
28
Austin Schuhad9e5eb2021-11-19 20:33:55 -080029 std::string_view MyName() override {
30 internal::Context *context = internal::Context::Get();
31 return context->MyName();
32 }
33
Alex Perrycb7da4b2019-08-28 19:35:56 -070034 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0))) void DoLog(
35 log_level level, const char *format, va_list ap) override {
Austin Schuhad9e5eb2021-11-19 20:33:55 -080036 internal::FillInMessage(level, MyName(), monotonic_now(), format, ap,
37 &message_);
Brian Silvermanf665d692013-02-17 22:11:39 -080038
Brian Silvermanfe457de2014-05-26 22:04:08 -070039 if (level == FATAL) {
40 internal::PrintMessage(stderr, message_);
41 abort();
42 }
43
Brian Silvermanf665d692013-02-17 22:11:39 -080044 used_ = true;
45 }
46
47 LogMessage message_;
48
49 public:
50 const LogMessage &message() { return message_; }
51 bool used() { return used_; }
Brian Silvermanf665d692013-02-17 22:11:39 -080052
Austin Schuha0c41ba2020-09-10 22:59:14 -070053 bool used_ = false;
Brian Silvermanf665d692013-02-17 22:11:39 -080054};
55class LoggingTest : public ::testing::Test {
56 protected:
57 AssertionResult WasAnythingLogged() {
58 if (log_implementation->used()) {
Tyler Chatow4b471e12020-01-05 20:19:36 -080059 return AssertionSuccess() << "read message '"
60 << log_implementation->message().message << "'";
Brian Silvermanf665d692013-02-17 22:11:39 -080061 }
62 return AssertionFailure();
63 }
64 AssertionResult WasLogged(log_level level, const std::string message) {
65 if (!log_implementation->used()) {
66 return AssertionFailure() << "nothing was logged";
67 }
68 if (log_implementation->message().level != level) {
Tyler Chatow4b471e12020-01-05 20:19:36 -080069 return AssertionFailure() << "a message with level "
70 << log_str(log_implementation->message().level)
71 << " was logged instead of " << log_str(level);
Brian Silvermanf665d692013-02-17 22:11:39 -080072 }
73 internal::Context *context = internal::Context::Get();
74 if (log_implementation->message().source != context->source) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070075 AOS_LOG(FATAL, "got a message from %" PRIu32 ", but we're %" PRIu32 "\n",
76 static_cast<uint32_t>(log_implementation->message().source),
77 static_cast<uint32_t>(context->source));
Brian Silvermanf665d692013-02-17 22:11:39 -080078 }
Austin Schuhad9e5eb2021-11-19 20:33:55 -080079 if (log_implementation->message().name_length != context->MyName().size() ||
80 memcmp(log_implementation->message().name, context->MyName().data(),
81 context->MyName().size()) != 0) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070082 AOS_LOG(FATAL, "got a message from %.*s, but we're %s\n",
83 static_cast<int>(log_implementation->message().name_length),
Austin Schuhad9e5eb2021-11-19 20:33:55 -080084 log_implementation->message().name,
85 std::string(context->MyName()).c_str());
Brian Silvermanf665d692013-02-17 22:11:39 -080086 }
Tyler Chatow4b471e12020-01-05 20:19:36 -080087 if (strstr(log_implementation->message().message, message.c_str()) ==
88 NULL) {
89 return AssertionFailure()
90 << "got a message of '" << log_implementation->message().message
91 << "' but expected it to contain '" << message << "'";
Brian Silvermanf665d692013-02-17 22:11:39 -080092 }
93
94 return AssertionSuccess() << log_implementation->message().message;
95 }
96
97 private:
Brian Silvermancb5da1f2015-12-05 22:19:58 -050098 void SetUp() override {
Austin Schuha0c41ba2020-09-10 22:59:14 -070099 log_implementation = std::make_shared<TestLogImplementation>();
100 SetImplementation(log_implementation);
Brian Silvermanf665d692013-02-17 22:11:39 -0800101 }
Austin Schuha0c41ba2020-09-10 22:59:14 -0700102 void TearDown() override {
103 SetImplementation(nullptr);
Austin Schuha0c41ba2020-09-10 22:59:14 -0700104 internal::Context::DeleteNow();
105 CHECK_EQ(log_implementation.use_count(), 1);
106 log_implementation.reset();
107 }
Brian Silvermanf665d692013-02-17 22:11:39 -0800108
Austin Schuha0c41ba2020-09-10 22:59:14 -0700109 std::shared_ptr<TestLogImplementation> log_implementation;
Brian Silvermanf665d692013-02-17 22:11:39 -0800110};
Brian Silvermanf665d692013-02-17 22:11:39 -0800111typedef LoggingTest LoggingDeathTest;
112
113// Tests both basic logging functionality and that the test setup works
114// correctly.
115TEST_F(LoggingTest, Basic) {
116 EXPECT_FALSE(WasAnythingLogged());
Austin Schuhf257f3c2019-10-27 21:00:43 -0700117 AOS_LOG(INFO, "test log 1\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800118 EXPECT_TRUE(WasLogged(INFO, "test log 1\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700119 AOS_LOG(INFO, "test log 1.5\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800120 // there's a subtle typo on purpose...
121 EXPECT_FALSE(WasLogged(INFO, "test log 15\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700122 AOS_LOG(ERROR, "test log 2=%d\n", 55);
Brian Silvermanf665d692013-02-17 22:11:39 -0800123 EXPECT_TRUE(WasLogged(ERROR, "test log 2=55\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700124 AOS_LOG(ERROR, "test log 3\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800125 EXPECT_FALSE(WasLogged(WARNING, "test log 3\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700126 AOS_LOG(WARNING, "test log 4\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800127 EXPECT_TRUE(WasAnythingLogged());
128}
Brian Silvermanf665d692013-02-17 22:11:39 -0800129
Brian Silvermanf665d692013-02-17 22:11:39 -0800130TEST_F(LoggingDeathTest, Fatal) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700131 ASSERT_EXIT(AOS_LOG(FATAL, "this should crash it\n"),
132 ::testing::KilledBySignal(SIGABRT), "this should crash it");
Brian Silvermanf665d692013-02-17 22:11:39 -0800133}
Brian Silvermanfe457de2014-05-26 22:04:08 -0700134
135TEST_F(LoggingDeathTest, PCHECK) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700136 EXPECT_DEATH(AOS_PCHECK(fprintf(stdin, "nope")),
Brian Silvermanfe457de2014-05-26 22:04:08 -0700137 ".*fprintf\\(stdin, \"nope\"\\).*failed.*");
138}
139
Austin Schuhf257f3c2019-10-27 21:00:43 -0700140TEST_F(LoggingTest, PCHECK) { EXPECT_EQ(7, AOS_PCHECK(printf("abc123\n"))); }
Brian Silvermanf665d692013-02-17 22:11:39 -0800141
142TEST_F(LoggingTest, PrintfDirectives) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700143 AOS_LOG(INFO, "test log %%1 %%d\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800144 EXPECT_TRUE(WasLogged(INFO, "test log %1 %d\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700145 AOS_LOG_DYNAMIC(WARNING, "test log %%2 %%f\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800146 EXPECT_TRUE(WasLogged(WARNING, "test log %2 %f\n"));
Brian Silvermanf665d692013-02-17 22:11:39 -0800147}
148
149TEST_F(LoggingTest, Timing) {
150 // For writing only.
Tyler Chatow4b471e12020-01-05 20:19:36 -0800151 // static const long kTimingCycles = 5000000;
Brian Silvermanf665d692013-02-17 22:11:39 -0800152 static const long kTimingCycles = 5000;
153
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800154 monotonic_clock::time_point start = monotonic_clock::now();
Brian Silvermanf665d692013-02-17 22:11:39 -0800155 for (long i = 0; i < kTimingCycles; ++i) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700156 AOS_LOG(INFO, "a\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800157 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800158 monotonic_clock::time_point end = monotonic_clock::now();
159 auto diff = end - start;
Brian Silverman41abe012014-02-08 18:25:02 -0800160 printf("short message took %" PRId64 " nsec for %ld\n",
Alex Perrycb7da4b2019-08-28 19:35:56 -0700161 static_cast<int64_t>(
162 chrono::duration_cast<chrono::nanoseconds>(diff).count()),
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800163 kTimingCycles);
Brian Silvermanf665d692013-02-17 22:11:39 -0800164
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800165 start = monotonic_clock::now();
Brian Silvermanf665d692013-02-17 22:11:39 -0800166 for (long i = 0; i < kTimingCycles; ++i) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700167 AOS_LOG(INFO, "something longer than just \"a\" to log to test timing\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800168 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800169 end = monotonic_clock::now();
Brian Silvermanf665d692013-02-17 22:11:39 -0800170 diff = end - start;
Brian Silverman41abe012014-02-08 18:25:02 -0800171 printf("long message took %" PRId64 " nsec for %ld\n",
Alex Perrycb7da4b2019-08-28 19:35:56 -0700172 static_cast<int64_t>(
173 chrono::duration_cast<chrono::nanoseconds>(diff).count()),
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800174 kTimingCycles);
Brian Silvermanf665d692013-02-17 22:11:39 -0800175}
176
Brian Silverman54a368e2015-02-14 20:05:33 -0500177TEST(LoggingPrintFormatTest, Time) {
178 char buffer[1024];
179
180 // Easy ones.
181 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
182 AOS_TIME_ARGS(2, 0)));
183 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
184 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
185 AOS_TIME_ARGS(2, 1)));
186 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
187
188 // This one should be exact.
189 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
190 AOS_TIME_ARGS(2, 1000)));
191 EXPECT_EQ("0000000002.000001s", ::std::string(buffer));
192
193 // Make sure rounding works correctly.
194 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
195 AOS_TIME_ARGS(2, 999)));
Austin Schuh648b3612017-11-20 01:02:24 -0800196 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
Brian Silverman54a368e2015-02-14 20:05:33 -0500197 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
198 AOS_TIME_ARGS(2, 500)));
Austin Schuh648b3612017-11-20 01:02:24 -0800199 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
Brian Silverman54a368e2015-02-14 20:05:33 -0500200 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
201 AOS_TIME_ARGS(2, 499)));
202 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
203
204 // This used to result in "0000000001.099500s".
205 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
206 AOS_TIME_ARGS(1, 995000000)));
207 EXPECT_EQ("0000000001.995000s", ::std::string(buffer));
Austin Schuh648b3612017-11-20 01:02:24 -0800208
209 // This used to result in "0000000001.099500s".
210 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
211 AOS_TIME_ARGS(1, 999999999)));
212 EXPECT_EQ("0000000001.999999s", ::std::string(buffer));
Brian Silverman54a368e2015-02-14 20:05:33 -0500213}
214
215TEST(LoggingPrintFormatTest, Base) {
216 char buffer[1024];
217
218 static const ::std::string kExpected1 =
219 "name(971)(01678): ERROR at 0000000001.995000s: ";
220 ASSERT_GT(sizeof(buffer), kExpected1.size());
221 ASSERT_EQ(
222 kExpected1.size(),
223 static_cast<size_t>(snprintf(
224 buffer, sizeof(buffer), AOS_LOGGING_BASE_FORMAT,
225 AOS_LOGGING_BASE_ARGS(4, "name", 971, 1678, ERROR, 1, 995000000))));
226 EXPECT_EQ(kExpected1, ::std::string(buffer));
227}
228
Tyler Chatow67ddb032020-01-12 14:30:04 -0800229TEST(ScopedLogRestorerTest, RestoreTest) {
Austin Schuha0c41ba2020-09-10 22:59:14 -0700230 SetImplementation(std::make_shared<StreamLogImplementation>(stdout));
231 LogImplementation *curr_impl = GetImplementation().get();
Tyler Chatow67ddb032020-01-12 14:30:04 -0800232
Austin Schuhad9e5eb2021-11-19 20:33:55 -0800233 std::string name = "name";
Tyler Chatow67ddb032020-01-12 14:30:04 -0800234 {
235 ScopedLogRestorer log_restorer;
236
Austin Schuhad9e5eb2021-11-19 20:33:55 -0800237 log_restorer.Swap(std::make_shared<CallbackLogImplementation>(
238 [](const LogMessage &) {}, &name));
Austin Schuha0c41ba2020-09-10 22:59:14 -0700239 ASSERT_NE(curr_impl, GetImplementation().get());
Tyler Chatow67ddb032020-01-12 14:30:04 -0800240 }
241
Austin Schuha0c41ba2020-09-10 22:59:14 -0700242 ASSERT_EQ(curr_impl, GetImplementation().get());
Tyler Chatow67ddb032020-01-12 14:30:04 -0800243}
244
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800245} // namespace aos::logging::testing