blob: 3d97c05cdd6f43e680d8f97e3a8bcbe82cbe4743 [file] [log] [blame]
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -05001#include "aos/testing/test_logging.h"
Brian Silvermanf665d692013-02-17 22:11:39 -08002
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -05003#include <stdio.h>
4
5#include <vector>
Brian Silvermanf665d692013-02-17 22:11:39 -08006
Brian Silvermanb3616972013-03-05 19:58:10 -08007#include "gtest/gtest.h"
8
John Park33858a32018-09-28 23:05:48 -07009#include "aos/logging/implementations.h"
10#include "aos/mutex/mutex.h"
John Parkb5e47302020-01-08 19:58:18 -080011#include "absl/base/call_once.h"
Brian Silvermanb3616972013-03-05 19:58:10 -080012
13using ::aos::logging::LogMessage;
brians343bc112013-02-10 01:53:46 +000014
15namespace aos {
brians343bc112013-02-10 01:53:46 +000016namespace testing {
Brian Silvermanb3616972013-03-05 19:58:10 -080017namespace {
18
Brian Silvermanbe858a12014-04-30 17:37:28 -070019class TestLogImplementation : public logging::HandleMessageLogImplementation {
Brian Silvermanb3616972013-03-05 19:58:10 -080020 public:
21 const ::std::vector<LogMessage> &messages() { return messages_; }
22
Austin Schuh82c0c822019-05-27 19:55:20 -070023 // Sets the current thread's time to be monotonic_now for logging.
24 void MockTime(::aos::monotonic_clock::time_point monotonic_now) {
25 mock_time_ = true;
26 monotonic_now_ = monotonic_now;
27 }
28
29 // Clears any mock time for the current thread.
30 void UnMockTime() { mock_time_ = false; }
31
32 ::aos::monotonic_clock::time_point monotonic_now() const override {
33 if (mock_time_) {
34 return monotonic_now_;
35 }
36 return ::aos::monotonic_clock::now();
37 }
38
Brian Silvermanb3616972013-03-05 19:58:10 -080039 // This class has to be a singleton so that everybody can get access to the
40 // same instance to read out the messages etc.
41 static TestLogImplementation *GetInstance() {
John Parkb5e47302020-01-08 19:58:18 -080042 static absl::once_flag once;
43 absl::call_once(once, CreateInstance);
44 return instance;
Brian Silvermanb3616972013-03-05 19:58:10 -080045 }
46
47 // Clears out all of the messages already recorded.
48 void ClearMessages() {
Brian Silverman459d37a2015-03-29 18:00:30 -040049 ::aos::MutexLocker locker(&messages_mutex_);
Brian Silvermanb3616972013-03-05 19:58:10 -080050 messages_.clear();
51 }
52
53 // Prints out all of the messages (like when a test fails).
54 void PrintAllMessages() {
Brian Silverman459d37a2015-03-29 18:00:30 -040055 ::aos::MutexLocker locker(&messages_mutex_);
Brian Silvermanb3616972013-03-05 19:58:10 -080056 for (auto it = messages_.begin(); it != messages_.end(); ++it) {
57 logging::internal::PrintMessage(stdout, *it);
58 }
59 }
60
Philipp Schradere41ed9d2015-03-15 22:57:13 +000061 void SetOutputFile(const char *filename) {
62 if (strcmp("-", filename) != 0) {
63 FILE *newfile = fopen(filename, "w");
64
65 if (newfile) {
66 output_file_ = newfile;
67 }
68 }
69 }
70
Austin Schuh1bf8a212019-05-26 22:13:14 -070071 bool fill_type_cache() override { return false; }
72
Philipp Schradere41ed9d2015-03-15 22:57:13 +000073 void PrintMessagesAsTheyComeIn() { print_as_messages_come_in_ = true; }
74
Brian Silvermanb3616972013-03-05 19:58:10 -080075 private:
John Parkb5e47302020-01-08 19:58:18 -080076 static TestLogImplementation *instance;
Brian Silvermanb3616972013-03-05 19:58:10 -080077 TestLogImplementation() {}
Philipp Schradere41ed9d2015-03-15 22:57:13 +000078 ~TestLogImplementation() {
79 if (output_file_ != stdout) {
80 fclose(output_file_);
81 }
82 }
Brian Silvermanb3616972013-03-05 19:58:10 -080083
John Parkb5e47302020-01-08 19:58:18 -080084 static void CreateInstance() {
85 instance = new TestLogImplementation();
Brian Silvermanb3616972013-03-05 19:58:10 -080086 }
87
Brian Silvermanbe858a12014-04-30 17:37:28 -070088 virtual void HandleMessage(const LogMessage &message) override {
Brian Silverman459d37a2015-03-29 18:00:30 -040089 ::aos::MutexLocker locker(&messages_mutex_);
Philipp Schradere41ed9d2015-03-15 22:57:13 +000090 if (message.level == FATAL || print_as_messages_come_in_) {
91 logging::internal::PrintMessage(output_file_, message);
Brian Silvermanb3616972013-03-05 19:58:10 -080092 }
93
94 messages_.push_back(message);
95 }
96
97 ::std::vector<LogMessage> messages_;
Philipp Schradere41ed9d2015-03-15 22:57:13 +000098 bool print_as_messages_come_in_ = false;
99 FILE *output_file_ = stdout;
Brian Silverman459d37a2015-03-29 18:00:30 -0400100 ::aos::Mutex messages_mutex_;
Austin Schuh82c0c822019-05-27 19:55:20 -0700101
102 // Thread local storage for mock time. This is thread local because if
103 // someone spawns a thread and goes to town in parallel with a simulated event
104 // loop, we want to just print the actual monotonic clock out.
105 static thread_local bool mock_time_;
106 static thread_local ::aos::monotonic_clock::time_point monotonic_now_;
Brian Silvermanb3616972013-03-05 19:58:10 -0800107};
108
John Parkb5e47302020-01-08 19:58:18 -0800109TestLogImplementation *TestLogImplementation::instance;
110
Austin Schuh82c0c822019-05-27 19:55:20 -0700111thread_local bool TestLogImplementation::mock_time_ = false;
112thread_local ::aos::monotonic_clock::time_point
113 TestLogImplementation::monotonic_now_ = ::aos::monotonic_clock::min_time;
114
Brian Silvermanb3616972013-03-05 19:58:10 -0800115class MyTestEventListener : public ::testing::EmptyTestEventListener {
Austin Schuh82c0c822019-05-27 19:55:20 -0700116 virtual void OnTestStart(const ::testing::TestInfo & /*test_info*/) {
Brian Silvermanb3616972013-03-05 19:58:10 -0800117 TestLogImplementation::GetInstance()->ClearMessages();
118 }
119 virtual void OnTestEnd(const ::testing::TestInfo &test_info) {
120 if (test_info.result()->Failed()) {
Philipp Schradere41ed9d2015-03-15 22:57:13 +0000121 printf("Test %s failed. Use '--print-logs' to see all log messages.\n",
Brian Silvermanb3616972013-03-05 19:58:10 -0800122 test_info.name());
Brian Silvermanb3616972013-03-05 19:58:10 -0800123 }
124 }
Brian Silvermanb91a37d2013-03-09 17:54:30 -0800125
126 virtual void OnTestPartResult( const ::testing::TestPartResult &result) {
127 if (result.failed()) {
128 const char *failure_type = "unknown";
129 switch (result.type()) {
130 case ::testing::TestPartResult::Type::kNonFatalFailure:
131 failure_type = "EXPECT";
132 break;
133 case ::testing::TestPartResult::Type::kFatalFailure:
134 failure_type = "ASSERT";
135 break;
136 case ::testing::TestPartResult::Type::kSuccess:
137 break;
138 }
139 log_do(ERROR, "%s: %d: gtest %s failure\n%s\n",
140 result.file_name(),
141 result.line_number(),
142 failure_type,
143 result.message());
144 }
145 }
Brian Silvermanb3616972013-03-05 19:58:10 -0800146};
147
148void *DoEnableTestLogging() {
149 logging::Init();
Tyler Chatow4b471e12020-01-05 20:19:36 -0800150 logging::SetImplementation(TestLogImplementation::GetInstance());
Brian Silvermanb3616972013-03-05 19:58:10 -0800151
152 ::testing::UnitTest::GetInstance()->listeners().Append(
153 new MyTestEventListener());
154
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -0500155 return nullptr;
Brian Silvermanb3616972013-03-05 19:58:10 -0800156}
157
John Parkb5e47302020-01-08 19:58:18 -0800158static absl::once_flag enable_test_logging_once;
Brian Silvermanb3616972013-03-05 19:58:10 -0800159
160} // namespace
brians343bc112013-02-10 01:53:46 +0000161
Brian Silvermanb3616972013-03-05 19:58:10 -0800162void EnableTestLogging() {
John Parkb5e47302020-01-08 19:58:18 -0800163 absl::call_once(enable_test_logging_once, DoEnableTestLogging);
Brian Silvermanb3616972013-03-05 19:58:10 -0800164}
165
Philipp Schradere41ed9d2015-03-15 22:57:13 +0000166void SetLogFileName(const char* filename) {
167 TestLogImplementation::GetInstance()->SetOutputFile(filename);
168}
169
170void ForcePrintLogsDuringTests() {
171 TestLogImplementation::GetInstance()->PrintMessagesAsTheyComeIn();
172}
173
Austin Schuh82c0c822019-05-27 19:55:20 -0700174void MockTime(::aos::monotonic_clock::time_point monotonic_now) {
175 TestLogImplementation::GetInstance()->MockTime(monotonic_now);
176}
177void UnMockTime() {
178 TestLogImplementation::GetInstance()->UnMockTime();
179}
180
brians343bc112013-02-10 01:53:46 +0000181} // namespace testing
brians343bc112013-02-10 01:53:46 +0000182} // namespace aos