blob: 62d5f1e8cfece218b4cc481b10d9baba68659b06 [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
Austin Schuh99f7c6a2024-06-25 22:07:44 -070010#include "absl/log/check.h"
11#include "absl/log/log.h"
Brian Silvermanf665d692013-02-17 22:11:39 -080012#include "gtest/gtest.h"
13
Philipp Schrader790cb542023-07-05 21:06:52 -070014#include "aos/logging/printf_formats.h"
15#include "aos/time/time.h"
16
Tyler Chatow4b471e12020-01-05 20:19:36 -080017using ::testing::AssertionFailure;
Brian Silvermanf665d692013-02-17 22:11:39 -080018using ::testing::AssertionResult;
19using ::testing::AssertionSuccess;
Brian Silvermanf665d692013-02-17 22:11:39 -080020
Stephan Pleinesf63bde82024-01-13 15:59:33 -080021namespace aos::logging::testing {
Brian Silvermanf665d692013-02-17 22:11:39 -080022
Austin Schuhf2a50ba2016-12-24 16:16:26 -080023namespace chrono = ::std::chrono;
24
Alex Perrycb7da4b2019-08-28 19:35:56 -070025class TestLogImplementation : public LogImplementation {
26 virtual ::aos::monotonic_clock::time_point monotonic_now() const {
27 return ::aos::monotonic_clock::now();
28 }
29
Austin Schuhad9e5eb2021-11-19 20:33:55 -080030 std::string_view MyName() override {
31 internal::Context *context = internal::Context::Get();
32 return context->MyName();
33 }
34
Alex Perrycb7da4b2019-08-28 19:35:56 -070035 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0))) void DoLog(
36 log_level level, const char *format, va_list ap) override {
Austin Schuhad9e5eb2021-11-19 20:33:55 -080037 internal::FillInMessage(level, MyName(), monotonic_now(), format, ap,
38 &message_);
Brian Silvermanf665d692013-02-17 22:11:39 -080039
Brian Silvermanfe457de2014-05-26 22:04:08 -070040 if (level == FATAL) {
41 internal::PrintMessage(stderr, message_);
42 abort();
43 }
44
Brian Silvermanf665d692013-02-17 22:11:39 -080045 used_ = true;
46 }
47
48 LogMessage message_;
49
50 public:
51 const LogMessage &message() { return message_; }
52 bool used() { return used_; }
Brian Silvermanf665d692013-02-17 22:11:39 -080053
Austin Schuha0c41ba2020-09-10 22:59:14 -070054 bool used_ = false;
Brian Silvermanf665d692013-02-17 22:11:39 -080055};
56class LoggingTest : public ::testing::Test {
57 protected:
58 AssertionResult WasAnythingLogged() {
59 if (log_implementation->used()) {
Tyler Chatow4b471e12020-01-05 20:19:36 -080060 return AssertionSuccess() << "read message '"
61 << log_implementation->message().message << "'";
Brian Silvermanf665d692013-02-17 22:11:39 -080062 }
63 return AssertionFailure();
64 }
65 AssertionResult WasLogged(log_level level, const std::string message) {
66 if (!log_implementation->used()) {
67 return AssertionFailure() << "nothing was logged";
68 }
69 if (log_implementation->message().level != level) {
Tyler Chatow4b471e12020-01-05 20:19:36 -080070 return AssertionFailure() << "a message with level "
71 << log_str(log_implementation->message().level)
72 << " was logged instead of " << log_str(level);
Brian Silvermanf665d692013-02-17 22:11:39 -080073 }
74 internal::Context *context = internal::Context::Get();
75 if (log_implementation->message().source != context->source) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070076 AOS_LOG(FATAL, "got a message from %" PRIu32 ", but we're %" PRIu32 "\n",
77 static_cast<uint32_t>(log_implementation->message().source),
78 static_cast<uint32_t>(context->source));
Brian Silvermanf665d692013-02-17 22:11:39 -080079 }
Austin Schuhad9e5eb2021-11-19 20:33:55 -080080 if (log_implementation->message().name_length != context->MyName().size() ||
81 memcmp(log_implementation->message().name, context->MyName().data(),
82 context->MyName().size()) != 0) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070083 AOS_LOG(FATAL, "got a message from %.*s, but we're %s\n",
84 static_cast<int>(log_implementation->message().name_length),
Austin Schuhad9e5eb2021-11-19 20:33:55 -080085 log_implementation->message().name,
86 std::string(context->MyName()).c_str());
Brian Silvermanf665d692013-02-17 22:11:39 -080087 }
Tyler Chatow4b471e12020-01-05 20:19:36 -080088 if (strstr(log_implementation->message().message, message.c_str()) ==
89 NULL) {
90 return AssertionFailure()
91 << "got a message of '" << log_implementation->message().message
92 << "' but expected it to contain '" << message << "'";
Brian Silvermanf665d692013-02-17 22:11:39 -080093 }
94
95 return AssertionSuccess() << log_implementation->message().message;
96 }
97
98 private:
Brian Silvermancb5da1f2015-12-05 22:19:58 -050099 void SetUp() override {
Austin Schuha0c41ba2020-09-10 22:59:14 -0700100 log_implementation = std::make_shared<TestLogImplementation>();
101 SetImplementation(log_implementation);
Brian Silvermanf665d692013-02-17 22:11:39 -0800102 }
Austin Schuha0c41ba2020-09-10 22:59:14 -0700103 void TearDown() override {
104 SetImplementation(nullptr);
Austin Schuha0c41ba2020-09-10 22:59:14 -0700105 internal::Context::DeleteNow();
106 CHECK_EQ(log_implementation.use_count(), 1);
107 log_implementation.reset();
108 }
Brian Silvermanf665d692013-02-17 22:11:39 -0800109
Austin Schuha0c41ba2020-09-10 22:59:14 -0700110 std::shared_ptr<TestLogImplementation> log_implementation;
Brian Silvermanf665d692013-02-17 22:11:39 -0800111};
Brian Silvermanf665d692013-02-17 22:11:39 -0800112typedef LoggingTest LoggingDeathTest;
113
114// Tests both basic logging functionality and that the test setup works
115// correctly.
116TEST_F(LoggingTest, Basic) {
117 EXPECT_FALSE(WasAnythingLogged());
Austin Schuhf257f3c2019-10-27 21:00:43 -0700118 AOS_LOG(INFO, "test log 1\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800119 EXPECT_TRUE(WasLogged(INFO, "test log 1\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700120 AOS_LOG(INFO, "test log 1.5\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800121 // there's a subtle typo on purpose...
122 EXPECT_FALSE(WasLogged(INFO, "test log 15\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700123 AOS_LOG(ERROR, "test log 2=%d\n", 55);
Brian Silvermanf665d692013-02-17 22:11:39 -0800124 EXPECT_TRUE(WasLogged(ERROR, "test log 2=55\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700125 AOS_LOG(ERROR, "test log 3\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800126 EXPECT_FALSE(WasLogged(WARNING, "test log 3\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700127 AOS_LOG(WARNING, "test log 4\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800128 EXPECT_TRUE(WasAnythingLogged());
129}
Brian Silvermanf665d692013-02-17 22:11:39 -0800130
Brian Silvermanf665d692013-02-17 22:11:39 -0800131TEST_F(LoggingDeathTest, Fatal) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700132 ASSERT_EXIT(AOS_LOG(FATAL, "this should crash it\n"),
133 ::testing::KilledBySignal(SIGABRT), "this should crash it");
Brian Silvermanf665d692013-02-17 22:11:39 -0800134}
Brian Silvermanfe457de2014-05-26 22:04:08 -0700135
136TEST_F(LoggingDeathTest, PCHECK) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700137 EXPECT_DEATH(AOS_PCHECK(fprintf(stdin, "nope")),
Brian Silvermanfe457de2014-05-26 22:04:08 -0700138 ".*fprintf\\(stdin, \"nope\"\\).*failed.*");
139}
140
Austin Schuhf257f3c2019-10-27 21:00:43 -0700141TEST_F(LoggingTest, PCHECK) { EXPECT_EQ(7, AOS_PCHECK(printf("abc123\n"))); }
Brian Silvermanf665d692013-02-17 22:11:39 -0800142
143TEST_F(LoggingTest, PrintfDirectives) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700144 AOS_LOG(INFO, "test log %%1 %%d\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800145 EXPECT_TRUE(WasLogged(INFO, "test log %1 %d\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700146 AOS_LOG_DYNAMIC(WARNING, "test log %%2 %%f\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800147 EXPECT_TRUE(WasLogged(WARNING, "test log %2 %f\n"));
Brian Silvermanf665d692013-02-17 22:11:39 -0800148}
149
150TEST_F(LoggingTest, Timing) {
151 // For writing only.
Tyler Chatow4b471e12020-01-05 20:19:36 -0800152 // static const long kTimingCycles = 5000000;
Brian Silvermanf665d692013-02-17 22:11:39 -0800153 static const long kTimingCycles = 5000;
154
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800155 monotonic_clock::time_point start = monotonic_clock::now();
Brian Silvermanf665d692013-02-17 22:11:39 -0800156 for (long i = 0; i < kTimingCycles; ++i) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700157 AOS_LOG(INFO, "a\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800158 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800159 monotonic_clock::time_point end = monotonic_clock::now();
160 auto diff = end - start;
Brian Silverman41abe012014-02-08 18:25:02 -0800161 printf("short message took %" PRId64 " nsec for %ld\n",
Alex Perrycb7da4b2019-08-28 19:35:56 -0700162 static_cast<int64_t>(
163 chrono::duration_cast<chrono::nanoseconds>(diff).count()),
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800164 kTimingCycles);
Brian Silvermanf665d692013-02-17 22:11:39 -0800165
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800166 start = monotonic_clock::now();
Brian Silvermanf665d692013-02-17 22:11:39 -0800167 for (long i = 0; i < kTimingCycles; ++i) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700168 AOS_LOG(INFO, "something longer than just \"a\" to log to test timing\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800169 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800170 end = monotonic_clock::now();
Brian Silvermanf665d692013-02-17 22:11:39 -0800171 diff = end - start;
Brian Silverman41abe012014-02-08 18:25:02 -0800172 printf("long message took %" PRId64 " nsec for %ld\n",
Alex Perrycb7da4b2019-08-28 19:35:56 -0700173 static_cast<int64_t>(
174 chrono::duration_cast<chrono::nanoseconds>(diff).count()),
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800175 kTimingCycles);
Brian Silvermanf665d692013-02-17 22:11:39 -0800176}
177
Brian Silverman54a368e2015-02-14 20:05:33 -0500178TEST(LoggingPrintFormatTest, Time) {
179 char buffer[1024];
180
181 // Easy ones.
182 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
183 AOS_TIME_ARGS(2, 0)));
184 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
185 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
186 AOS_TIME_ARGS(2, 1)));
187 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
188
189 // This one should be exact.
190 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
191 AOS_TIME_ARGS(2, 1000)));
192 EXPECT_EQ("0000000002.000001s", ::std::string(buffer));
193
194 // Make sure rounding works correctly.
195 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
196 AOS_TIME_ARGS(2, 999)));
Austin Schuh648b3612017-11-20 01:02:24 -0800197 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
Brian Silverman54a368e2015-02-14 20:05:33 -0500198 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
199 AOS_TIME_ARGS(2, 500)));
Austin Schuh648b3612017-11-20 01:02:24 -0800200 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
Brian Silverman54a368e2015-02-14 20:05:33 -0500201 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
202 AOS_TIME_ARGS(2, 499)));
203 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
204
205 // This used to result in "0000000001.099500s".
206 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
207 AOS_TIME_ARGS(1, 995000000)));
208 EXPECT_EQ("0000000001.995000s", ::std::string(buffer));
Austin Schuh648b3612017-11-20 01:02:24 -0800209
210 // This used to result in "0000000001.099500s".
211 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
212 AOS_TIME_ARGS(1, 999999999)));
213 EXPECT_EQ("0000000001.999999s", ::std::string(buffer));
Brian Silverman54a368e2015-02-14 20:05:33 -0500214}
215
216TEST(LoggingPrintFormatTest, Base) {
217 char buffer[1024];
218
219 static const ::std::string kExpected1 =
220 "name(971)(01678): ERROR at 0000000001.995000s: ";
221 ASSERT_GT(sizeof(buffer), kExpected1.size());
222 ASSERT_EQ(
223 kExpected1.size(),
224 static_cast<size_t>(snprintf(
225 buffer, sizeof(buffer), AOS_LOGGING_BASE_FORMAT,
226 AOS_LOGGING_BASE_ARGS(4, "name", 971, 1678, ERROR, 1, 995000000))));
227 EXPECT_EQ(kExpected1, ::std::string(buffer));
228}
229
Tyler Chatow67ddb032020-01-12 14:30:04 -0800230TEST(ScopedLogRestorerTest, RestoreTest) {
Austin Schuha0c41ba2020-09-10 22:59:14 -0700231 SetImplementation(std::make_shared<StreamLogImplementation>(stdout));
232 LogImplementation *curr_impl = GetImplementation().get();
Tyler Chatow67ddb032020-01-12 14:30:04 -0800233
Austin Schuhad9e5eb2021-11-19 20:33:55 -0800234 std::string name = "name";
Tyler Chatow67ddb032020-01-12 14:30:04 -0800235 {
236 ScopedLogRestorer log_restorer;
237
Austin Schuhad9e5eb2021-11-19 20:33:55 -0800238 log_restorer.Swap(std::make_shared<CallbackLogImplementation>(
239 [](const LogMessage &) {}, &name));
Austin Schuha0c41ba2020-09-10 22:59:14 -0700240 ASSERT_NE(curr_impl, GetImplementation().get());
Tyler Chatow67ddb032020-01-12 14:30:04 -0800241 }
242
Austin Schuha0c41ba2020-09-10 22:59:14 -0700243 ASSERT_EQ(curr_impl, GetImplementation().get());
Tyler Chatow67ddb032020-01-12 14:30:04 -0800244}
245
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800246} // namespace aos::logging::testing