blob: 77bc4e9aab9bc230fc0000dcf57cc360b517514f [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
Austin Schuha0c41ba2020-09-10 22:59:14 -07009#include "absl/base/call_once.h"
Brian Silvermanb47f5552020-10-01 15:08:14 -070010
John Park33858a32018-09-28 23:05:48 -070011#include "aos/logging/implementations.h"
12#include "aos/mutex/mutex.h"
Brian Silvermanb47f5552020-10-01 15:08:14 -070013#include "aos/thread_local.h"
Brian Silvermanb3616972013-03-05 19:58:10 -080014
15using ::aos::logging::LogMessage;
brians343bc112013-02-10 01:53:46 +000016
17namespace aos {
brians343bc112013-02-10 01:53:46 +000018namespace testing {
Brian Silvermanb3616972013-03-05 19:58:10 -080019namespace {
20
Brian Silvermanbe858a12014-04-30 17:37:28 -070021class TestLogImplementation : public logging::HandleMessageLogImplementation {
Brian Silvermanb3616972013-03-05 19:58:10 -080022 public:
23 const ::std::vector<LogMessage> &messages() { return messages_; }
24
Austin Schuh82c0c822019-05-27 19:55:20 -070025 // Sets the current thread's time to be monotonic_now for logging.
26 void MockTime(::aos::monotonic_clock::time_point monotonic_now) {
27 mock_time_ = true;
28 monotonic_now_ = monotonic_now;
29 }
30
31 // Clears any mock time for the current thread.
32 void UnMockTime() { mock_time_ = false; }
33
34 ::aos::monotonic_clock::time_point monotonic_now() const override {
35 if (mock_time_) {
36 return monotonic_now_;
37 }
38 return ::aos::monotonic_clock::now();
39 }
40
Brian Silvermanb3616972013-03-05 19:58:10 -080041 // This class has to be a singleton so that everybody can get access to the
42 // same instance to read out the messages etc.
Austin Schuha0c41ba2020-09-10 22:59:14 -070043 static std::shared_ptr<TestLogImplementation> GetInstance() {
44 static std::shared_ptr<TestLogImplementation> instance =
45 std::make_unique<TestLogImplementation>();
John Parkb5e47302020-01-08 19:58:18 -080046 return instance;
Brian Silvermanb3616972013-03-05 19:58:10 -080047 }
48
49 // Clears out all of the messages already recorded.
50 void ClearMessages() {
Brian Silverman459d37a2015-03-29 18:00:30 -040051 ::aos::MutexLocker locker(&messages_mutex_);
Brian Silvermanb3616972013-03-05 19:58:10 -080052 messages_.clear();
53 }
54
55 // Prints out all of the messages (like when a test fails).
56 void PrintAllMessages() {
Brian Silverman459d37a2015-03-29 18:00:30 -040057 ::aos::MutexLocker locker(&messages_mutex_);
Brian Silvermanb3616972013-03-05 19:58:10 -080058 for (auto it = messages_.begin(); it != messages_.end(); ++it) {
59 logging::internal::PrintMessage(stdout, *it);
60 }
61 }
62
Philipp Schradere41ed9d2015-03-15 22:57:13 +000063 void SetOutputFile(const char *filename) {
64 if (strcmp("-", filename) != 0) {
65 FILE *newfile = fopen(filename, "w");
66
67 if (newfile) {
68 output_file_ = newfile;
69 }
70 }
71 }
72
Austin Schuh1bf8a212019-05-26 22:13:14 -070073 bool fill_type_cache() override { return false; }
74
Philipp Schradere41ed9d2015-03-15 22:57:13 +000075 void PrintMessagesAsTheyComeIn() { print_as_messages_come_in_ = true; }
76
Austin Schuha0c41ba2020-09-10 22:59:14 -070077 // Don't call these from outside this class.
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
Austin Schuha0c41ba2020-09-10 22:59:14 -070084 private:
Brian Silvermanbe858a12014-04-30 17:37:28 -070085 virtual void HandleMessage(const LogMessage &message) override {
Brian Silverman459d37a2015-03-29 18:00:30 -040086 ::aos::MutexLocker locker(&messages_mutex_);
Philipp Schradere41ed9d2015-03-15 22:57:13 +000087 if (message.level == FATAL || print_as_messages_come_in_) {
88 logging::internal::PrintMessage(output_file_, message);
Brian Silvermanb3616972013-03-05 19:58:10 -080089 }
90
91 messages_.push_back(message);
92 }
93
94 ::std::vector<LogMessage> messages_;
Philipp Schradere41ed9d2015-03-15 22:57:13 +000095 bool print_as_messages_come_in_ = false;
96 FILE *output_file_ = stdout;
Brian Silverman459d37a2015-03-29 18:00:30 -040097 ::aos::Mutex messages_mutex_;
Austin Schuh82c0c822019-05-27 19:55:20 -070098
99 // Thread local storage for mock time. This is thread local because if
100 // someone spawns a thread and goes to town in parallel with a simulated event
101 // loop, we want to just print the actual monotonic clock out.
Brian Silvermanb47f5552020-10-01 15:08:14 -0700102 static AOS_THREAD_LOCAL bool mock_time_;
103 static AOS_THREAD_LOCAL ::aos::monotonic_clock::time_point monotonic_now_;
Brian Silvermanb3616972013-03-05 19:58:10 -0800104};
105
Brian Silvermanb47f5552020-10-01 15:08:14 -0700106AOS_THREAD_LOCAL bool TestLogImplementation::mock_time_ = false;
107AOS_THREAD_LOCAL ::aos::monotonic_clock::time_point
Austin Schuh82c0c822019-05-27 19:55:20 -0700108 TestLogImplementation::monotonic_now_ = ::aos::monotonic_clock::min_time;
109
Brian Silvermanb3616972013-03-05 19:58:10 -0800110class MyTestEventListener : public ::testing::EmptyTestEventListener {
Austin Schuh82c0c822019-05-27 19:55:20 -0700111 virtual void OnTestStart(const ::testing::TestInfo & /*test_info*/) {
Brian Silvermanb3616972013-03-05 19:58:10 -0800112 TestLogImplementation::GetInstance()->ClearMessages();
113 }
114 virtual void OnTestEnd(const ::testing::TestInfo &test_info) {
115 if (test_info.result()->Failed()) {
Philipp Schradere41ed9d2015-03-15 22:57:13 +0000116 printf("Test %s failed. Use '--print-logs' to see all log messages.\n",
Brian Silvermanb3616972013-03-05 19:58:10 -0800117 test_info.name());
Brian Silvermanb3616972013-03-05 19:58:10 -0800118 }
119 }
Brian Silvermanb91a37d2013-03-09 17:54:30 -0800120
Austin Schuha0c41ba2020-09-10 22:59:14 -0700121 virtual void OnTestPartResult(const ::testing::TestPartResult &result) {
Brian Silvermanb91a37d2013-03-09 17:54:30 -0800122 if (result.failed()) {
123 const char *failure_type = "unknown";
124 switch (result.type()) {
125 case ::testing::TestPartResult::Type::kNonFatalFailure:
126 failure_type = "EXPECT";
127 break;
128 case ::testing::TestPartResult::Type::kFatalFailure:
129 failure_type = "ASSERT";
130 break;
131 case ::testing::TestPartResult::Type::kSuccess:
132 break;
133 }
Austin Schuha0c41ba2020-09-10 22:59:14 -0700134 log_do(ERROR, "%s: %d: gtest %s failure\n%s\n", result.file_name(),
135 result.line_number(), failure_type, result.message());
Brian Silvermanb91a37d2013-03-09 17:54:30 -0800136 }
137 }
Brian Silvermanb3616972013-03-05 19:58:10 -0800138};
139
140void *DoEnableTestLogging() {
141 logging::Init();
Tyler Chatow4b471e12020-01-05 20:19:36 -0800142 logging::SetImplementation(TestLogImplementation::GetInstance());
Brian Silvermanb3616972013-03-05 19:58:10 -0800143
144 ::testing::UnitTest::GetInstance()->listeners().Append(
145 new MyTestEventListener());
146
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -0500147 return nullptr;
Brian Silvermanb3616972013-03-05 19:58:10 -0800148}
149
John Parkb5e47302020-01-08 19:58:18 -0800150static absl::once_flag enable_test_logging_once;
Brian Silvermanb3616972013-03-05 19:58:10 -0800151
152} // namespace
brians343bc112013-02-10 01:53:46 +0000153
Brian Silvermanb3616972013-03-05 19:58:10 -0800154void EnableTestLogging() {
John Parkb5e47302020-01-08 19:58:18 -0800155 absl::call_once(enable_test_logging_once, DoEnableTestLogging);
Brian Silvermanb3616972013-03-05 19:58:10 -0800156}
157
Austin Schuha0c41ba2020-09-10 22:59:14 -0700158void SetLogFileName(const char *filename) {
Philipp Schradere41ed9d2015-03-15 22:57:13 +0000159 TestLogImplementation::GetInstance()->SetOutputFile(filename);
160}
161
162void ForcePrintLogsDuringTests() {
163 TestLogImplementation::GetInstance()->PrintMessagesAsTheyComeIn();
164}
165
Austin Schuh82c0c822019-05-27 19:55:20 -0700166void MockTime(::aos::monotonic_clock::time_point monotonic_now) {
167 TestLogImplementation::GetInstance()->MockTime(monotonic_now);
168}
Austin Schuha0c41ba2020-09-10 22:59:14 -0700169void UnMockTime() { TestLogImplementation::GetInstance()->UnMockTime(); }
Austin Schuh82c0c822019-05-27 19:55:20 -0700170
brians343bc112013-02-10 01:53:46 +0000171} // namespace testing
brians343bc112013-02-10 01:53:46 +0000172} // namespace aos