blob: 2accf35bc6f7992ef0dcfeafa91b24cad30fc65a [file] [log] [blame]
Brian Silvermanfe457de2014-05-26 22:04:08 -07001#include <inttypes.h>
2
Austin Schuhf2a50ba2016-12-24 16:16:26 -08003#include <chrono>
4#include <string>
5
Brian Silvermanf665d692013-02-17 22:11:39 -08006#include "gtest/gtest.h"
7
John Park33858a32018-09-28 23:05:48 -07008#include "aos/logging/implementations.h"
9#include "aos/time/time.h"
10#include "aos/logging/printf_formats.h"
Brian Silvermanf665d692013-02-17 22:11:39 -080011
12using ::testing::AssertionResult;
13using ::testing::AssertionSuccess;
14using ::testing::AssertionFailure;
15
16namespace aos {
17namespace logging {
18namespace testing {
19
Austin Schuhf2a50ba2016-12-24 16:16:26 -080020namespace chrono = ::std::chrono;
21
Brian Silvermancb5da1f2015-12-05 22:19:58 -050022class TestLogImplementation : public SimpleLogImplementation {
Brian Silvermanf7986142014-04-21 17:42:35 -070023 __attribute__((format(GOOD_PRINTF_FORMAT_TYPE, 3, 0)))
Brian Silvermancb5da1f2015-12-05 22:19:58 -050024 void DoLog(log_level level, const char *format, va_list ap) override {
Austin Schuh82c0c822019-05-27 19:55:20 -070025 internal::FillInMessage(level, monotonic_now(), format, ap, &message_);
Brian Silvermanf665d692013-02-17 22:11:39 -080026
Brian Silvermanfe457de2014-05-26 22:04:08 -070027 if (level == FATAL) {
28 internal::PrintMessage(stderr, message_);
29 abort();
30 }
31
Brian Silvermanf665d692013-02-17 22:11:39 -080032 used_ = true;
33 }
34
35 LogMessage message_;
36
37 public:
38 const LogMessage &message() { return message_; }
39 bool used() { return used_; }
40 void reset_used() { used_ = false; }
41
42 TestLogImplementation() : used_(false) {}
43
44 bool used_;
45};
46class LoggingTest : public ::testing::Test {
47 protected:
48 AssertionResult WasAnythingLogged() {
49 if (log_implementation->used()) {
50 return AssertionSuccess() << "read message '" <<
51 log_implementation->message().message << "'";
52 }
53 return AssertionFailure();
54 }
55 AssertionResult WasLogged(log_level level, const std::string message) {
56 if (!log_implementation->used()) {
57 return AssertionFailure() << "nothing was logged";
58 }
59 if (log_implementation->message().level != level) {
60 return AssertionFailure() << "a message with level " <<
61 log_str(log_implementation->message().level) <<
62 " was logged instead of " << log_str(level);
63 }
64 internal::Context *context = internal::Context::Get();
65 if (log_implementation->message().source != context->source) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070066 AOS_LOG(FATAL, "got a message from %" PRIu32 ", but we're %" PRIu32 "\n",
67 static_cast<uint32_t>(log_implementation->message().source),
68 static_cast<uint32_t>(context->source));
Brian Silvermanf665d692013-02-17 22:11:39 -080069 }
Austin Schuhaebbc342015-01-25 02:25:13 -080070 if (log_implementation->message().name_length != context->name_size ||
71 memcmp(log_implementation->message().name, context->name,
72 context->name_size) !=
Brian Silvermanf0bb8372014-04-30 15:58:55 -070073 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 }
78 if (strstr(log_implementation->message().message, message.c_str())
79 == NULL) {
80 return AssertionFailure() << "got a message of '" <<
81 log_implementation->message().message <<
82 "' but expected it to contain '" << message << "'";
83 }
84
85 return AssertionSuccess() << log_implementation->message().message;
86 }
87
88 private:
Brian Silvermancb5da1f2015-12-05 22:19:58 -050089 void SetUp() override {
Brian Silvermanf665d692013-02-17 22:11:39 -080090 static bool first = true;
91 if (first) {
92 first = false;
93
94 Init();
Brian Silvermanf665d692013-02-17 22:11:39 -080095 AddImplementation(log_implementation = new TestLogImplementation());
96 }
97
98 log_implementation->reset_used();
99 }
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500100 void TearDown() override {
Brian Silvermanf665d692013-02-17 22:11:39 -0800101 Cleanup();
102 }
103
104 static TestLogImplementation *log_implementation;
105};
106TestLogImplementation *LoggingTest::log_implementation(NULL);
107typedef LoggingTest LoggingDeathTest;
108
109// Tests both basic logging functionality and that the test setup works
110// correctly.
111TEST_F(LoggingTest, Basic) {
112 EXPECT_FALSE(WasAnythingLogged());
Austin Schuhf257f3c2019-10-27 21:00:43 -0700113 AOS_LOG(INFO, "test log 1\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800114 EXPECT_TRUE(WasLogged(INFO, "test log 1\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700115 AOS_LOG(INFO, "test log 1.5\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800116 // there's a subtle typo on purpose...
117 EXPECT_FALSE(WasLogged(INFO, "test log 15\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700118 AOS_LOG(ERROR, "test log 2=%d\n", 55);
Brian Silvermanf665d692013-02-17 22:11:39 -0800119 EXPECT_TRUE(WasLogged(ERROR, "test log 2=55\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700120 AOS_LOG(ERROR, "test log 3\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800121 EXPECT_FALSE(WasLogged(WARNING, "test log 3\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700122 AOS_LOG(WARNING, "test log 4\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800123 EXPECT_TRUE(WasAnythingLogged());
124}
125TEST_F(LoggingTest, Cork) {
126 static const int begin_line = __LINE__;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700127 AOS_LOG_CORK("first part ");
128 AOS_LOG_CORK("second part (=%d) ", 19);
Brian Silvermanf665d692013-02-17 22:11:39 -0800129 EXPECT_FALSE(WasAnythingLogged());
Austin Schuhf257f3c2019-10-27 21:00:43 -0700130 AOS_LOG_CORK("third part ");
Brian Silvermanf665d692013-02-17 22:11:39 -0800131 static const int end_line = __LINE__;
Austin Schuhf257f3c2019-10-27 21:00:43 -0700132 AOS_LOG_UNCORK(WARNING, "last part %d\n", 5);
Brian Silvermanf665d692013-02-17 22:11:39 -0800133 std::stringstream expected;
Brian Silvermancb5da1f2015-12-05 22:19:58 -0500134 expected << "implementations_test.cc: ";
Brian Silvermanf665d692013-02-17 22:11:39 -0800135 expected << (begin_line + 1);
136 expected << "-";
137 expected << (end_line + 1);
138 expected << ": ";
Brian Silvermanc0a0d112013-09-19 21:08:49 -0700139 expected << __func__;
Brian Silvermanf665d692013-02-17 22:11:39 -0800140 expected << ": first part second part (=19) third part last part 5\n";
141 EXPECT_TRUE(WasLogged(WARNING, expected.str()));
142}
143
Brian Silvermanf665d692013-02-17 22:11:39 -0800144TEST_F(LoggingDeathTest, Fatal) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700145 ASSERT_EXIT(AOS_LOG(FATAL, "this should crash it\n"),
146 ::testing::KilledBySignal(SIGABRT), "this should crash it");
Brian Silvermanf665d692013-02-17 22:11:39 -0800147}
Brian Silvermanfe457de2014-05-26 22:04:08 -0700148
149TEST_F(LoggingDeathTest, PCHECK) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700150 EXPECT_DEATH(AOS_PCHECK(fprintf(stdin, "nope")),
Brian Silvermanfe457de2014-05-26 22:04:08 -0700151 ".*fprintf\\(stdin, \"nope\"\\).*failed.*");
152}
153
Austin Schuhf257f3c2019-10-27 21:00:43 -0700154TEST_F(LoggingTest, PCHECK) { EXPECT_EQ(7, AOS_PCHECK(printf("abc123\n"))); }
Brian Silvermanf665d692013-02-17 22:11:39 -0800155
156TEST_F(LoggingTest, PrintfDirectives) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700157 AOS_LOG(INFO, "test log %%1 %%d\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800158 EXPECT_TRUE(WasLogged(INFO, "test log %1 %d\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700159 AOS_LOG_DYNAMIC(WARNING, "test log %%2 %%f\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800160 EXPECT_TRUE(WasLogged(WARNING, "test log %2 %f\n"));
Austin Schuhf257f3c2019-10-27 21:00:43 -0700161 AOS_LOG_CORK("log 3 part %%1 %%d ");
162 AOS_LOG_UNCORK(DEBUG, "log 3 part %%2 %%f\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800163 EXPECT_TRUE(WasLogged(DEBUG, "log 3 part %1 %d log 3 part %2 %f\n"));
164}
165
166TEST_F(LoggingTest, Timing) {
167 // For writing only.
168 //static const long kTimingCycles = 5000000;
169 static const long kTimingCycles = 5000;
170
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800171 monotonic_clock::time_point start = monotonic_clock::now();
Brian Silvermanf665d692013-02-17 22:11:39 -0800172 for (long i = 0; i < kTimingCycles; ++i) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700173 AOS_LOG(INFO, "a\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800174 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800175 monotonic_clock::time_point end = monotonic_clock::now();
176 auto diff = end - start;
Brian Silverman41abe012014-02-08 18:25:02 -0800177 printf("short message took %" PRId64 " nsec for %ld\n",
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800178 chrono::duration_cast<chrono::nanoseconds>(diff).count(),
179 kTimingCycles);
Brian Silvermanf665d692013-02-17 22:11:39 -0800180
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800181 start = monotonic_clock::now();
Brian Silvermanf665d692013-02-17 22:11:39 -0800182 for (long i = 0; i < kTimingCycles; ++i) {
Austin Schuhf257f3c2019-10-27 21:00:43 -0700183 AOS_LOG(INFO, "something longer than just \"a\" to log to test timing\n");
Brian Silvermanf665d692013-02-17 22:11:39 -0800184 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800185 end = monotonic_clock::now();
Brian Silvermanf665d692013-02-17 22:11:39 -0800186 diff = end - start;
Brian Silverman41abe012014-02-08 18:25:02 -0800187 printf("long message took %" PRId64 " nsec for %ld\n",
Austin Schuhf2a50ba2016-12-24 16:16:26 -0800188 chrono::duration_cast<chrono::nanoseconds>(diff).count(),
189 kTimingCycles);
Brian Silvermanf665d692013-02-17 22:11:39 -0800190}
191
Brian Silverman54a368e2015-02-14 20:05:33 -0500192TEST(LoggingPrintFormatTest, Time) {
193 char buffer[1024];
194
195 // Easy ones.
196 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
197 AOS_TIME_ARGS(2, 0)));
198 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
199 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
200 AOS_TIME_ARGS(2, 1)));
201 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
202
203 // This one should be exact.
204 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
205 AOS_TIME_ARGS(2, 1000)));
206 EXPECT_EQ("0000000002.000001s", ::std::string(buffer));
207
208 // Make sure rounding works correctly.
209 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
210 AOS_TIME_ARGS(2, 999)));
Austin Schuh648b3612017-11-20 01:02:24 -0800211 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
Brian Silverman54a368e2015-02-14 20:05:33 -0500212 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
213 AOS_TIME_ARGS(2, 500)));
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, 499)));
217 EXPECT_EQ("0000000002.000000s", ::std::string(buffer));
218
219 // This used to result in "0000000001.099500s".
220 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
221 AOS_TIME_ARGS(1, 995000000)));
222 EXPECT_EQ("0000000001.995000s", ::std::string(buffer));
Austin Schuh648b3612017-11-20 01:02:24 -0800223
224 // This used to result in "0000000001.099500s".
225 ASSERT_EQ(18, snprintf(buffer, sizeof(buffer), AOS_TIME_FORMAT,
226 AOS_TIME_ARGS(1, 999999999)));
227 EXPECT_EQ("0000000001.999999s", ::std::string(buffer));
Brian Silverman54a368e2015-02-14 20:05:33 -0500228}
229
230TEST(LoggingPrintFormatTest, Base) {
231 char buffer[1024];
232
233 static const ::std::string kExpected1 =
234 "name(971)(01678): ERROR at 0000000001.995000s: ";
235 ASSERT_GT(sizeof(buffer), kExpected1.size());
236 ASSERT_EQ(
237 kExpected1.size(),
238 static_cast<size_t>(snprintf(
239 buffer, sizeof(buffer), AOS_LOGGING_BASE_FORMAT,
240 AOS_LOGGING_BASE_ARGS(4, "name", 971, 1678, ERROR, 1, 995000000))));
241 EXPECT_EQ(kExpected1, ::std::string(buffer));
242}
243
Brian Silvermanf665d692013-02-17 22:11:39 -0800244} // namespace testing
245} // namespace logging
246} // namespace aos