blob: a7b8b7ddd722f7c71e4935906d72528c754a25d7 [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_; }
44 void reset_used() { used_ = false; }
45
46 TestLogImplementation() : used_(false) {}
47
48 bool used_;
49};
50class LoggingTest : public ::testing::Test {
51 protected:
52 AssertionResult WasAnythingLogged() {
53 if (log_implementation->used()) {
Tyler Chatow4b471e12020-01-05 20:19:36 -080054 return AssertionSuccess() << "read message '"
55 << log_implementation->message().message << "'";
Brian Silvermanf665d692013-02-17 22:11:39 -080056 }
57 return AssertionFailure();
58 }
59 AssertionResult WasLogged(log_level level, const std::string message) {
60 if (!log_implementation->used()) {
61 return AssertionFailure() << "nothing was logged";
62 }
63 if (log_implementation->message().level != level) {
Tyler Chatow4b471e12020-01-05 20:19:36 -080064 return AssertionFailure() << "a message with level "
65 << log_str(log_implementation->message().level)
66 << " was logged instead of " << log_str(level);
Brian Silvermanf665d692013-02-17 22:11:39 -080067 }
68 internal::Context *context = internal::Context::Get();
69 if (log_implementation->message().source != context->source) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070070 AOS_LOG(FATAL, "got a message from %" PRIu32 ", but we're %" PRIu32 "\n",
71 static_cast<uint32_t>(log_implementation->message().source),
72 static_cast<uint32_t>(context->source));
Brian Silvermanf665d692013-02-17 22:11:39 -080073 }
Austin Schuhaebbc342015-01-25 02:25:13 -080074 if (log_implementation->message().name_length != context->name_size ||
75 memcmp(log_implementation->message().name, context->name,
Tyler Chatow4b471e12020-01-05 20:19:36 -080076 context->name_size) != 0) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070077 AOS_LOG(FATAL, "got a message from %.*s, but we're %s\n",
78 static_cast<int>(log_implementation->message().name_length),
79 log_implementation->message().name, context->name);
Brian Silvermanf665d692013-02-17 22:11:39 -080080 }
Tyler Chatow4b471e12020-01-05 20:19:36 -080081 if (strstr(log_implementation->message().message, message.c_str()) ==
82 NULL) {
83 return AssertionFailure()
84 << "got a message of '" << log_implementation->message().message
85 << "' but expected it to contain '" << message << "'";
Brian Silvermanf665d692013-02-17 22:11:39 -080086 }
87
88 return AssertionSuccess() << log_implementation->message().message;
89 }
90
91 private:
Brian Silvermancb5da1f2015-12-05 22:19:58 -050092 void SetUp() override {
Brian Silvermanf665d692013-02-17 22:11:39 -080093 static bool first = true;
94 if (first) {
95 first = false;
96
97 Init();
Tyler Chatow4b471e12020-01-05 20:19:36 -080098 SetImplementation(log_implementation = new TestLogImplementation());
Brian Silvermanf665d692013-02-17 22:11:39 -080099 }
100
101 log_implementation->reset_used();
102 }
Tyler Chatow4b471e12020-01-05 20:19:36 -0800103 void TearDown() override { Cleanup(); }
Brian Silvermanf665d692013-02-17 22:11:39 -0800104
105 static TestLogImplementation *log_implementation;
106};
107TestLogImplementation *LoggingTest::log_implementation(NULL);
108typedef LoggingTest LoggingDeathTest;
109
110// Tests both basic logging functionality and that the test setup works
111// correctly.
112TEST_F(LoggingTest, Basic) {
113 EXPECT_FALSE(WasAnythingLogged());
Austin Schuhf257f3c2019-10-27 21:00:43 -0700114 AOS_LOG(INFO, "test log 1\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800115 EXPECT_TRUE(WasLogged(INFO, "test log 1\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700116 AOS_LOG(INFO, "test log 1.5\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800117 // there's a subtle typo on purpose...
118 EXPECT_FALSE(WasLogged(INFO, "test log 15\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700119 AOS_LOG(ERROR, "test log 2=%d\n", 55);
Brian Silvermanf665d692013-02-17 22:11:39 -0800120 EXPECT_TRUE(WasLogged(ERROR, "test log 2=55\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700121 AOS_LOG(ERROR, "test log 3\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800122 EXPECT_FALSE(WasLogged(WARNING, "test log 3\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700123 AOS_LOG(WARNING, "test log 4\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800124 EXPECT_TRUE(WasAnythingLogged());
125}
126TEST_F(LoggingTest, Cork) {
127 static const int begin_line = __LINE__;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700128 AOS_LOG_CORK("first part ");
129 AOS_LOG_CORK("second part (=%d) ", 19);
Brian Silvermanf665d692013-02-17 22:11:39 -0800130 EXPECT_FALSE(WasAnythingLogged());
Austin Schuhf257f3c2019-10-27 21:00:43 -0700131 AOS_LOG_CORK("third part ");
Brian Silvermanf665d692013-02-17 22:11:39 -0800132 static const int end_line = __LINE__;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700133 AOS_LOG_UNCORK(WARNING, "last part %d\n", 5);
Brian Silvermanf665d692013-02-17 22:11:39 -0800134 std::stringstream expected;
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500135 expected << "implementations_test.cc: ";
Brian Silvermanf665d692013-02-17 22:11:39 -0800136 expected << (begin_line + 1);
137 expected << "-";
138 expected << (end_line + 1);
139 expected << ": ";
Brian Silvermanc0a0d112013-09-19 21:08:49 -0700140 expected << __func__;
Brian Silvermanf665d692013-02-17 22:11:39 -0800141 expected << ": first part second part (=19) third part last part 5\n";
142 EXPECT_TRUE(WasLogged(WARNING, expected.str()));
143}
144
Brian Silvermanf665d692013-02-17 22:11:39 -0800145TEST_F(LoggingDeathTest, Fatal) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700146 ASSERT_EXIT(AOS_LOG(FATAL, "this should crash it\n"),
147 ::testing::KilledBySignal(SIGABRT), "this should crash it");
Brian Silvermanf665d692013-02-17 22:11:39 -0800148}
Brian Silvermanfe457de2014-05-26 22:04:08 -0700149
150TEST_F(LoggingDeathTest, PCHECK) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700151 EXPECT_DEATH(AOS_PCHECK(fprintf(stdin, "nope")),
Brian Silvermanfe457de2014-05-26 22:04:08 -0700152 ".*fprintf\\(stdin, \"nope\"\\).*failed.*");
153}
154
Austin Schuhf257f3c2019-10-27 21:00:43 -0700155TEST_F(LoggingTest, PCHECK) { EXPECT_EQ(7, AOS_PCHECK(printf("abc123\n"))); }
Brian Silvermanf665d692013-02-17 22:11:39 -0800156
157TEST_F(LoggingTest, PrintfDirectives) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700158 AOS_LOG(INFO, "test log %%1 %%d\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800159 EXPECT_TRUE(WasLogged(INFO, "test log %1 %d\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700160 AOS_LOG_DYNAMIC(WARNING, "test log %%2 %%f\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800161 EXPECT_TRUE(WasLogged(WARNING, "test log %2 %f\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700162 AOS_LOG_CORK("log 3 part %%1 %%d ");
163 AOS_LOG_UNCORK(DEBUG, "log 3 part %%2 %%f\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800164 EXPECT_TRUE(WasLogged(DEBUG, "log 3 part %1 %d log 3 part %2 %f\n"));
165}
166
167TEST_F(LoggingTest, Timing) {
168 // For writing only.
Tyler Chatow4b471e12020-01-05 20:19:36 -0800169 // static const long kTimingCycles = 5000000;
Brian Silvermanf665d692013-02-17 22:11:39 -0800170 static const long kTimingCycles = 5000;
171
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800172 monotonic_clock::time_point start = monotonic_clock::now();
Brian Silvermanf665d692013-02-17 22:11:39 -0800173 for (long i = 0; i < kTimingCycles; ++i) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700174 AOS_LOG(INFO, "a\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800175 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800176 monotonic_clock::time_point end = monotonic_clock::now();
177 auto diff = end - start;
Brian Silverman41abe012014-02-08 18:25:02 -0800178 printf("short message took %" PRId64 " nsec for %ld\n",
Alex Perrycb7da4b2019-08-28 19:35:56 -0700179 static_cast<int64_t>(
180 chrono::duration_cast<chrono::nanoseconds>(diff).count()),
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800181 kTimingCycles);
Brian Silvermanf665d692013-02-17 22:11:39 -0800182
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800183 start = monotonic_clock::now();
Brian Silvermanf665d692013-02-17 22:11:39 -0800184 for (long i = 0; i < kTimingCycles; ++i) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700185 AOS_LOG(INFO, "something longer than just \"a\" to log to test timing\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800186 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800187 end = monotonic_clock::now();
Brian Silvermanf665d692013-02-17 22:11:39 -0800188 diff = end - start;
Brian Silverman41abe012014-02-08 18:25:02 -0800189 printf("long message took %" PRId64 " nsec for %ld\n",
Alex Perrycb7da4b2019-08-28 19:35:56 -0700190 static_cast<int64_t>(
191 chrono::duration_cast<chrono::nanoseconds>(diff).count()),
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800192 kTimingCycles);
Brian Silvermanf665d692013-02-17 22:11:39 -0800193}
194
Brian Silverman54a368e2015-02-14 20:05:33 -0500195TEST(LoggingPrintFormatTest, Time) {
196 char buffer[1024];
197
198 // Easy ones.
199 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
200 AOS_TIME_ARGS(2, 0)));
201 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
202 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
203 AOS_TIME_ARGS(2, 1)));
204 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
205
206 // This one should be exact.
207 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
208 AOS_TIME_ARGS(2, 1000)));
209 EXPECT_EQ("0000000002.000001s", ::std::string(buffer));
210
211 // Make sure rounding works correctly.
212 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
213 AOS_TIME_ARGS(2, 999)));
Austin Schuh648b3612017-11-20 01:02:24 -0800214 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
Brian Silverman54a368e2015-02-14 20:05:33 -0500215 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
216 AOS_TIME_ARGS(2, 500)));
Austin Schuh648b3612017-11-20 01:02:24 -0800217 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
Brian Silverman54a368e2015-02-14 20:05:33 -0500218 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
219 AOS_TIME_ARGS(2, 499)));
220 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
221
222 // This used to result in "0000000001.099500s".
223 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
224 AOS_TIME_ARGS(1, 995000000)));
225 EXPECT_EQ("0000000001.995000s", ::std::string(buffer));
Austin Schuh648b3612017-11-20 01:02:24 -0800226
227 // This used to result in "0000000001.099500s".
228 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
229 AOS_TIME_ARGS(1, 999999999)));
230 EXPECT_EQ("0000000001.999999s", ::std::string(buffer));
Brian Silverman54a368e2015-02-14 20:05:33 -0500231}
232
233TEST(LoggingPrintFormatTest, Base) {
234 char buffer[1024];
235
236 static const ::std::string kExpected1 =
237 "name(971)(01678): ERROR at 0000000001.995000s: ";
238 ASSERT_GT(sizeof(buffer), kExpected1.size());
239 ASSERT_EQ(
240 kExpected1.size(),
241 static_cast<size_t>(snprintf(
242 buffer, sizeof(buffer), AOS_LOGGING_BASE_FORMAT,
243 AOS_LOGGING_BASE_ARGS(4, "name", 971, 1678, ERROR, 1, 995000000))));
244 EXPECT_EQ(kExpected1, ::std::string(buffer));
245}
246
Brian Silvermanf665d692013-02-17 22:11:39 -0800247} // namespace testing
248} // namespace logging
249} // namespace aos