blob: db6246c508875d1127d5fc00a0e00e09b8167832 [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"
John Park33858a32018-09-28 23:05:48 -070010#include "aos/logging/implementations.h"
11#include "aos/mutex/mutex.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.
Austin Schuha0c41ba2020-09-10 22:59:14 -070041 static std::shared_ptr<TestLogImplementation> GetInstance() {
42 static std::shared_ptr<TestLogImplementation> instance =
43 std::make_unique<TestLogImplementation>();
John Parkb5e47302020-01-08 19:58:18 -080044 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
Austin Schuha0c41ba2020-09-10 22:59:14 -070075 // Don't call these from outside this class.
Philipp Schradere41ed9d2015-03-15 22:57:13 +000076 ~TestLogImplementation() {
77 if (output_file_ != stdout) {
78 fclose(output_file_);
79 }
80 }
Brian Silvermanb3616972013-03-05 19:58:10 -080081
Austin Schuha0c41ba2020-09-10 22:59:14 -070082 private:
Brian Silvermanbe858a12014-04-30 17:37:28 -070083 virtual void HandleMessage(const LogMessage &message) override {
Brian Silverman459d37a2015-03-29 18:00:30 -040084 ::aos::MutexLocker locker(&messages_mutex_);
Philipp Schradere41ed9d2015-03-15 22:57:13 +000085 if (message.level == FATAL || print_as_messages_come_in_) {
86 logging::internal::PrintMessage(output_file_, message);
Brian Silvermanb3616972013-03-05 19:58:10 -080087 }
88
89 messages_.push_back(message);
90 }
91
92 ::std::vector<LogMessage> messages_;
Philipp Schradere41ed9d2015-03-15 22:57:13 +000093 bool print_as_messages_come_in_ = false;
94 FILE *output_file_ = stdout;
Brian Silverman459d37a2015-03-29 18:00:30 -040095 ::aos::Mutex messages_mutex_;
Austin Schuh82c0c822019-05-27 19:55:20 -070096
97 // Thread local storage for mock time. This is thread local because if
98 // someone spawns a thread and goes to town in parallel with a simulated event
99 // loop, we want to just print the actual monotonic clock out.
100 static thread_local bool mock_time_;
101 static thread_local ::aos::monotonic_clock::time_point monotonic_now_;
Brian Silvermanb3616972013-03-05 19:58:10 -0800102};
103
Austin Schuh82c0c822019-05-27 19:55:20 -0700104thread_local bool TestLogImplementation::mock_time_ = false;
105thread_local ::aos::monotonic_clock::time_point
106 TestLogImplementation::monotonic_now_ = ::aos::monotonic_clock::min_time;
107
Brian Silvermanb3616972013-03-05 19:58:10 -0800108class MyTestEventListener : public ::testing::EmptyTestEventListener {
Austin Schuh82c0c822019-05-27 19:55:20 -0700109 virtual void OnTestStart(const ::testing::TestInfo & /*test_info*/) {
Brian Silvermanb3616972013-03-05 19:58:10 -0800110 TestLogImplementation::GetInstance()->ClearMessages();
111 }
112 virtual void OnTestEnd(const ::testing::TestInfo &test_info) {
113 if (test_info.result()->Failed()) {
Philipp Schradere41ed9d2015-03-15 22:57:13 +0000114 printf("Test %s failed. Use '--print-logs' to see all log messages.\n",
Brian Silvermanb3616972013-03-05 19:58:10 -0800115 test_info.name());
Brian Silvermanb3616972013-03-05 19:58:10 -0800116 }
117 }
Brian Silvermanb91a37d2013-03-09 17:54:30 -0800118
Austin Schuha0c41ba2020-09-10 22:59:14 -0700119 virtual void OnTestPartResult(const ::testing::TestPartResult &result) {
Brian Silvermanb91a37d2013-03-09 17:54:30 -0800120 if (result.failed()) {
121 const char *failure_type = "unknown";
122 switch (result.type()) {
123 case ::testing::TestPartResult::Type::kNonFatalFailure:
124 failure_type = "EXPECT";
125 break;
126 case ::testing::TestPartResult::Type::kFatalFailure:
127 failure_type = "ASSERT";
128 break;
129 case ::testing::TestPartResult::Type::kSuccess:
130 break;
131 }
Austin Schuha0c41ba2020-09-10 22:59:14 -0700132 log_do(ERROR, "%s: %d: gtest %s failure\n%s\n", result.file_name(),
133 result.line_number(), failure_type, result.message());
Brian Silvermanb91a37d2013-03-09 17:54:30 -0800134 }
135 }
Brian Silvermanb3616972013-03-05 19:58:10 -0800136};
137
138void *DoEnableTestLogging() {
139 logging::Init();
Tyler Chatow4b471e12020-01-05 20:19:36 -0800140 logging::SetImplementation(TestLogImplementation::GetInstance());
Brian Silvermanb3616972013-03-05 19:58:10 -0800141
142 ::testing::UnitTest::GetInstance()->listeners().Append(
143 new MyTestEventListener());
144
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -0500145 return nullptr;
Brian Silvermanb3616972013-03-05 19:58:10 -0800146}
147
John Parkb5e47302020-01-08 19:58:18 -0800148static absl::once_flag enable_test_logging_once;
Brian Silvermanb3616972013-03-05 19:58:10 -0800149
150} // namespace
brians343bc112013-02-10 01:53:46 +0000151
Brian Silvermanb3616972013-03-05 19:58:10 -0800152void EnableTestLogging() {
John Parkb5e47302020-01-08 19:58:18 -0800153 absl::call_once(enable_test_logging_once, DoEnableTestLogging);
Brian Silvermanb3616972013-03-05 19:58:10 -0800154}
155
Austin Schuha0c41ba2020-09-10 22:59:14 -0700156void SetLogFileName(const char *filename) {
Philipp Schradere41ed9d2015-03-15 22:57:13 +0000157 TestLogImplementation::GetInstance()->SetOutputFile(filename);
158}
159
160void ForcePrintLogsDuringTests() {
161 TestLogImplementation::GetInstance()->PrintMessagesAsTheyComeIn();
162}
163
Austin Schuh82c0c822019-05-27 19:55:20 -0700164void MockTime(::aos::monotonic_clock::time_point monotonic_now) {
165 TestLogImplementation::GetInstance()->MockTime(monotonic_now);
166}
Austin Schuha0c41ba2020-09-10 22:59:14 -0700167void UnMockTime() { TestLogImplementation::GetInstance()->UnMockTime(); }
Austin Schuh82c0c822019-05-27 19:55:20 -0700168
brians343bc112013-02-10 01:53:46 +0000169} // namespace testing
brians343bc112013-02-10 01:53:46 +0000170} // namespace aos