blob: 84a1bed611cef2cddbb42449acf18581d77c5445 [file] [log] [blame]
Tyler Chatow4b471e12020-01-05 20:19:36 -08001#include "aos/logging/implementations.h"
2
Brian Silvermanfe457de2014-05-26 22:04:08 -07003#include <inttypes.h>
4
Austin Schuhf2a50ba2016-12-24 16:16:26 -08005#include <chrono>
6#include <string>
7
Tyler Chatow4b471e12020-01-05 20:19:36 -08008#include "aos/logging/printf_formats.h"
9#include "aos/time/time.h"
Brian Silvermanf665d692013-02-17 22:11:39 -080010#include "gtest/gtest.h"
11
Tyler Chatow4b471e12020-01-05 20:19:36 -080012using ::testing::AssertionFailure;
Brian Silvermanf665d692013-02-17 22:11:39 -080013using ::testing::AssertionResult;
14using ::testing::AssertionSuccess;
Brian Silvermanf665d692013-02-17 22:11:39 -080015
16namespace aos {
17namespace logging {
18namespace testing {
19
Austin Schuhf2a50ba2016-12-24 16:16:26 -080020namespace chrono = ::std::chrono;
21
Alex Perrycb7da4b2019-08-28 19:35:56 -070022class TestLogImplementation : public LogImplementation {
23 virtual ::aos::monotonic_clock::time_point monotonic_now() const {
24 return ::aos::monotonic_clock::now();
25 }
26
27 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0))) void DoLog(
28 log_level level, const char *format, va_list ap) override {
Austin Schuh82c0c822019-05-27 19:55:20 -070029 internal::FillInMessage(level, monotonic_now(), format, ap, &message_);
Brian Silvermanf665d692013-02-17 22:11:39 -080030
Brian Silvermanfe457de2014-05-26 22:04:08 -070031 if (level == FATAL) {
32 internal::PrintMessage(stderr, message_);
33 abort();
34 }
35
Brian Silvermanf665d692013-02-17 22:11:39 -080036 used_ = true;
37 }
38
39 LogMessage message_;
40
41 public:
42 const LogMessage &message() { return message_; }
43 bool used() { return used_; }
Brian Silvermanf665d692013-02-17 22:11:39 -080044
Austin Schuha0c41ba2020-09-10 22:59:14 -070045 bool used_ = false;
Brian Silvermanf665d692013-02-17 22:11:39 -080046};
47class LoggingTest : public ::testing::Test {
48 protected:
49 AssertionResult WasAnythingLogged() {
50 if (log_implementation->used()) {
Tyler Chatow4b471e12020-01-05 20:19:36 -080051 return AssertionSuccess() << "read message '"
52 << log_implementation->message().message << "'";
Brian Silvermanf665d692013-02-17 22:11:39 -080053 }
54 return AssertionFailure();
55 }
56 AssertionResult WasLogged(log_level level, const std::string message) {
57 if (!log_implementation->used()) {
58 return AssertionFailure() << "nothing was logged";
59 }
60 if (log_implementation->message().level != level) {
Tyler Chatow4b471e12020-01-05 20:19:36 -080061 return AssertionFailure() << "a message with level "
62 << log_str(log_implementation->message().level)
63 << " was logged instead of " << log_str(level);
Brian Silvermanf665d692013-02-17 22:11:39 -080064 }
65 internal::Context *context = internal::Context::Get();
66 if (log_implementation->message().source != context->source) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070067 AOS_LOG(FATAL, "got a message from %" PRIu32 ", but we're %" PRIu32 "\n",
68 static_cast<uint32_t>(log_implementation->message().source),
69 static_cast<uint32_t>(context->source));
Brian Silvermanf665d692013-02-17 22:11:39 -080070 }
Austin Schuhaebbc342015-01-25 02:25:13 -080071 if (log_implementation->message().name_length != context->name_size ||
72 memcmp(log_implementation->message().name, context->name,
Tyler Chatow4b471e12020-01-05 20:19:36 -080073 context->name_size) != 0) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070074 AOS_LOG(FATAL, "got a message from %.*s, but we're %s\n",
75 static_cast<int>(log_implementation->message().name_length),
76 log_implementation->message().name, context->name);
Brian Silvermanf665d692013-02-17 22:11:39 -080077 }
Tyler Chatow4b471e12020-01-05 20:19:36 -080078 if (strstr(log_implementation->message().message, message.c_str()) ==
79 NULL) {
80 return AssertionFailure()
81 << "got a message of '" << log_implementation->message().message
82 << "' but expected it to contain '" << message << "'";
Brian Silvermanf665d692013-02-17 22:11:39 -080083 }
84
85 return AssertionSuccess() << log_implementation->message().message;
86 }
87
88 private:
Brian Silvermancb5da1f2015-12-05 22:19:58 -050089 void SetUp() override {
Austin Schuha0c41ba2020-09-10 22:59:14 -070090 log_implementation = std::make_shared<TestLogImplementation>();
91 SetImplementation(log_implementation);
Brian Silvermanf665d692013-02-17 22:11:39 -080092 }
Austin Schuha0c41ba2020-09-10 22:59:14 -070093 void TearDown() override {
94 SetImplementation(nullptr);
95 Cleanup();
96 internal::Context::DeleteNow();
97 CHECK_EQ(log_implementation.use_count(), 1);
98 log_implementation.reset();
99 }
Brian Silvermanf665d692013-02-17 22:11:39 -0800100
Austin Schuha0c41ba2020-09-10 22:59:14 -0700101 std::shared_ptr<TestLogImplementation> log_implementation;
Brian Silvermanf665d692013-02-17 22:11:39 -0800102};
Brian Silvermanf665d692013-02-17 22:11:39 -0800103typedef LoggingTest LoggingDeathTest;
104
105// Tests both basic logging functionality and that the test setup works
106// correctly.
107TEST_F(LoggingTest, Basic) {
108 EXPECT_FALSE(WasAnythingLogged());
Austin Schuhf257f3c2019-10-27 21:00:43 -0700109 AOS_LOG(INFO, "test log 1\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800110 EXPECT_TRUE(WasLogged(INFO, "test log 1\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700111 AOS_LOG(INFO, "test log 1.5\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800112 // there's a subtle typo on purpose...
113 EXPECT_FALSE(WasLogged(INFO, "test log 15\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700114 AOS_LOG(ERROR, "test log 2=%d\n", 55);
Brian Silvermanf665d692013-02-17 22:11:39 -0800115 EXPECT_TRUE(WasLogged(ERROR, "test log 2=55\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700116 AOS_LOG(ERROR, "test log 3\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800117 EXPECT_FALSE(WasLogged(WARNING, "test log 3\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700118 AOS_LOG(WARNING, "test log 4\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800119 EXPECT_TRUE(WasAnythingLogged());
120}
121TEST_F(LoggingTest, Cork) {
122 static const int begin_line = __LINE__;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700123 AOS_LOG_CORK("first part ");
124 AOS_LOG_CORK("second part (=%d) ", 19);
Brian Silvermanf665d692013-02-17 22:11:39 -0800125 EXPECT_FALSE(WasAnythingLogged());
Austin Schuhf257f3c2019-10-27 21:00:43 -0700126 AOS_LOG_CORK("third part ");
Brian Silvermanf665d692013-02-17 22:11:39 -0800127 static const int end_line = __LINE__;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700128 AOS_LOG_UNCORK(WARNING, "last part %d\n", 5);
Brian Silvermanf665d692013-02-17 22:11:39 -0800129 std::stringstream expected;
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500130 expected << "implementations_test.cc: ";
Brian Silvermanf665d692013-02-17 22:11:39 -0800131 expected << (begin_line + 1);
132 expected << "-";
133 expected << (end_line + 1);
134 expected << ": ";
Brian Silvermanc0a0d112013-09-19 21:08:49 -0700135 expected << __func__;
Brian Silvermanf665d692013-02-17 22:11:39 -0800136 expected << ": first part second part (=19) third part last part 5\n";
137 EXPECT_TRUE(WasLogged(WARNING, expected.str()));
138}
139
Brian Silvermanf665d692013-02-17 22:11:39 -0800140TEST_F(LoggingDeathTest, Fatal) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700141 ASSERT_EXIT(AOS_LOG(FATAL, "this should crash it\n"),
142 ::testing::KilledBySignal(SIGABRT), "this should crash it");
Brian Silvermanf665d692013-02-17 22:11:39 -0800143}
Brian Silvermanfe457de2014-05-26 22:04:08 -0700144
145TEST_F(LoggingDeathTest, PCHECK) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700146 EXPECT_DEATH(AOS_PCHECK(fprintf(stdin, "nope")),
Brian Silvermanfe457de2014-05-26 22:04:08 -0700147 ".*fprintf\\(stdin, \"nope\"\\).*failed.*");
148}
149
Austin Schuhf257f3c2019-10-27 21:00:43 -0700150TEST_F(LoggingTest, PCHECK) { EXPECT_EQ(7, AOS_PCHECK(printf("abc123\n"))); }
Brian Silvermanf665d692013-02-17 22:11:39 -0800151
152TEST_F(LoggingTest, PrintfDirectives) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700153 AOS_LOG(INFO, "test log %%1 %%d\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800154 EXPECT_TRUE(WasLogged(INFO, "test log %1 %d\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700155 AOS_LOG_DYNAMIC(WARNING, "test log %%2 %%f\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800156 EXPECT_TRUE(WasLogged(WARNING, "test log %2 %f\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700157 AOS_LOG_CORK("log 3 part %%1 %%d ");
158 AOS_LOG_UNCORK(DEBUG, "log 3 part %%2 %%f\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800159 EXPECT_TRUE(WasLogged(DEBUG, "log 3 part %1 %d log 3 part %2 %f\n"));
160}
161
162TEST_F(LoggingTest, Timing) {
163 // For writing only.
Tyler Chatow4b471e12020-01-05 20:19:36 -0800164 // static const long kTimingCycles = 5000000;
Brian Silvermanf665d692013-02-17 22:11:39 -0800165 static const long kTimingCycles = 5000;
166
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800167 monotonic_clock::time_point start = monotonic_clock::now();
Brian Silvermanf665d692013-02-17 22:11:39 -0800168 for (long i = 0; i < kTimingCycles; ++i) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700169 AOS_LOG(INFO, "a\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800170 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800171 monotonic_clock::time_point end = monotonic_clock::now();
172 auto diff = end - start;
Brian Silverman41abe012014-02-08 18:25:02 -0800173 printf("short message took %" PRId64 " nsec for %ld\n",
Alex Perrycb7da4b2019-08-28 19:35:56 -0700174 static_cast<int64_t>(
175 chrono::duration_cast<chrono::nanoseconds>(diff).count()),
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800176 kTimingCycles);
Brian Silvermanf665d692013-02-17 22:11:39 -0800177
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800178 start = monotonic_clock::now();
Brian Silvermanf665d692013-02-17 22:11:39 -0800179 for (long i = 0; i < kTimingCycles; ++i) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700180 AOS_LOG(INFO, "something longer than just \"a\" to log to test timing\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800181 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800182 end = monotonic_clock::now();
Brian Silvermanf665d692013-02-17 22:11:39 -0800183 diff = end - start;
Brian Silverman41abe012014-02-08 18:25:02 -0800184 printf("long message took %" PRId64 " nsec for %ld\n",
Alex Perrycb7da4b2019-08-28 19:35:56 -0700185 static_cast<int64_t>(
186 chrono::duration_cast<chrono::nanoseconds>(diff).count()),
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800187 kTimingCycles);
Brian Silvermanf665d692013-02-17 22:11:39 -0800188}
189
Brian Silverman54a368e2015-02-14 20:05:33 -0500190TEST(LoggingPrintFormatTest, Time) {
191 char buffer[1024];
192
193 // Easy ones.
194 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
195 AOS_TIME_ARGS(2, 0)));
196 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
197 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
198 AOS_TIME_ARGS(2, 1)));
199 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
200
201 // This one should be exact.
202 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
203 AOS_TIME_ARGS(2, 1000)));
204 EXPECT_EQ("0000000002.000001s", ::std::string(buffer));
205
206 // Make sure rounding works correctly.
207 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
208 AOS_TIME_ARGS(2, 999)));
Austin Schuh648b3612017-11-20 01:02:24 -0800209 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
Brian Silverman54a368e2015-02-14 20:05:33 -0500210 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
211 AOS_TIME_ARGS(2, 500)));
Austin Schuh648b3612017-11-20 01:02:24 -0800212 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
Brian Silverman54a368e2015-02-14 20:05:33 -0500213 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
214 AOS_TIME_ARGS(2, 499)));
215 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
216
217 // This used to result in "0000000001.099500s".
218 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
219 AOS_TIME_ARGS(1, 995000000)));
220 EXPECT_EQ("0000000001.995000s", ::std::string(buffer));
Austin Schuh648b3612017-11-20 01:02:24 -0800221
222 // This used to result in "0000000001.099500s".
223 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
224 AOS_TIME_ARGS(1, 999999999)));
225 EXPECT_EQ("0000000001.999999s", ::std::string(buffer));
Brian Silverman54a368e2015-02-14 20:05:33 -0500226}
227
228TEST(LoggingPrintFormatTest, Base) {
229 char buffer[1024];
230
231 static const ::std::string kExpected1 =
232 "name(971)(01678): ERROR at 0000000001.995000s: ";
233 ASSERT_GT(sizeof(buffer), kExpected1.size());
234 ASSERT_EQ(
235 kExpected1.size(),
236 static_cast<size_t>(snprintf(
237 buffer, sizeof(buffer), AOS_LOGGING_BASE_FORMAT,
238 AOS_LOGGING_BASE_ARGS(4, "name", 971, 1678, ERROR, 1, 995000000))));
239 EXPECT_EQ(kExpected1, ::std::string(buffer));
240}
241
Tyler Chatow67ddb032020-01-12 14:30:04 -0800242TEST(ScopedLogRestorerTest, RestoreTest) {
Austin Schuha0c41ba2020-09-10 22:59:14 -0700243 SetImplementation(std::make_shared<StreamLogImplementation>(stdout));
244 LogImplementation *curr_impl = GetImplementation().get();
Tyler Chatow67ddb032020-01-12 14:30:04 -0800245
246 {
247 ScopedLogRestorer log_restorer;
248
Austin Schuha0c41ba2020-09-10 22:59:14 -0700249 log_restorer.Swap(
250 std::make_shared<CallbackLogImplementation>([](const LogMessage &) {}));
251 ASSERT_NE(curr_impl, GetImplementation().get());
Tyler Chatow67ddb032020-01-12 14:30:04 -0800252 }
253
Austin Schuha0c41ba2020-09-10 22:59:14 -0700254 ASSERT_EQ(curr_impl, GetImplementation().get());
Tyler Chatow67ddb032020-01-12 14:30:04 -0800255}
256
Brian Silvermanf665d692013-02-17 22:11:39 -0800257} // namespace testing
258} // namespace logging
259} // namespace aos