blob: bc600817633c5a21ed6a9f18dd36f25fdc9ef42f [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"
Sabina Davis2ed5ea22017-09-26 22:27:42 -070011#include "aos/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() {
42 static Once<TestLogImplementation> once(CreateInstance);
43 return once.Get();
44 }
45
46 // Clears out all of the messages already recorded.
47 void ClearMessages() {
Brian Silverman459d37a2015-03-29 18:00:30 -040048 ::aos::MutexLocker locker(&messages_mutex_);
Brian Silvermanb3616972013-03-05 19:58:10 -080049 messages_.clear();
50 }
51
52 // Prints out all of the messages (like when a test fails).
53 void PrintAllMessages() {
Brian Silverman459d37a2015-03-29 18:00:30 -040054 ::aos::MutexLocker locker(&messages_mutex_);
Brian Silvermanb3616972013-03-05 19:58:10 -080055 for (auto it = messages_.begin(); it != messages_.end(); ++it) {
56 logging::internal::PrintMessage(stdout, *it);
57 }
58 }
59
Philipp Schradere41ed9d2015-03-15 22:57:13 +000060 void SetOutputFile(const char *filename) {
61 if (strcmp("-", filename) != 0) {
62 FILE *newfile = fopen(filename, "w");
63
64 if (newfile) {
65 output_file_ = newfile;
66 }
67 }
68 }
69
Austin Schuh1bf8a212019-05-26 22:13:14 -070070 bool fill_type_cache() override { return false; }
71
Philipp Schradere41ed9d2015-03-15 22:57:13 +000072 void PrintMessagesAsTheyComeIn() { print_as_messages_come_in_ = true; }
73
Brian Silvermanb3616972013-03-05 19:58:10 -080074 private:
75 TestLogImplementation() {}
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
82 static TestLogImplementation *CreateInstance() {
83 return new TestLogImplementation();
84 }
85
Brian Silvermanbe858a12014-04-30 17:37:28 -070086 virtual void HandleMessage(const LogMessage &message) override {
Brian Silverman459d37a2015-03-29 18:00:30 -040087 ::aos::MutexLocker locker(&messages_mutex_);
Philipp Schradere41ed9d2015-03-15 22:57:13 +000088 if (message.level == FATAL || print_as_messages_come_in_) {
89 logging::internal::PrintMessage(output_file_, message);
Brian Silvermanb3616972013-03-05 19:58:10 -080090 }
91
92 messages_.push_back(message);
93 }
94
95 ::std::vector<LogMessage> messages_;
Philipp Schradere41ed9d2015-03-15 22:57:13 +000096 bool print_as_messages_come_in_ = false;
97 FILE *output_file_ = stdout;
Brian Silverman459d37a2015-03-29 18:00:30 -040098 ::aos::Mutex messages_mutex_;
Austin Schuh82c0c822019-05-27 19:55:20 -070099
100 // Thread local storage for mock time. This is thread local because if
101 // someone spawns a thread and goes to town in parallel with a simulated event
102 // loop, we want to just print the actual monotonic clock out.
103 static thread_local bool mock_time_;
104 static thread_local ::aos::monotonic_clock::time_point monotonic_now_;
Brian Silvermanb3616972013-03-05 19:58:10 -0800105};
106
Austin Schuh82c0c822019-05-27 19:55:20 -0700107thread_local bool TestLogImplementation::mock_time_ = false;
108thread_local ::aos::monotonic_clock::time_point
109 TestLogImplementation::monotonic_now_ = ::aos::monotonic_clock::min_time;
110
Brian Silvermanb3616972013-03-05 19:58:10 -0800111class MyTestEventListener : public ::testing::EmptyTestEventListener {
Austin Schuh82c0c822019-05-27 19:55:20 -0700112 virtual void OnTestStart(const ::testing::TestInfo & /*test_info*/) {
Brian Silvermanb3616972013-03-05 19:58:10 -0800113 TestLogImplementation::GetInstance()->ClearMessages();
114 }
115 virtual void OnTestEnd(const ::testing::TestInfo &test_info) {
116 if (test_info.result()->Failed()) {
Philipp Schradere41ed9d2015-03-15 22:57:13 +0000117 printf("Test %s failed. Use '--print-logs' to see all log messages.\n",
Brian Silvermanb3616972013-03-05 19:58:10 -0800118 test_info.name());
Brian Silvermanb3616972013-03-05 19:58:10 -0800119 }
120 }
Brian Silvermanb91a37d2013-03-09 17:54:30 -0800121
122 virtual void OnTestPartResult( const ::testing::TestPartResult &result) {
123 if (result.failed()) {
124 const char *failure_type = "unknown";
125 switch (result.type()) {
126 case ::testing::TestPartResult::Type::kNonFatalFailure:
127 failure_type = "EXPECT";
128 break;
129 case ::testing::TestPartResult::Type::kFatalFailure:
130 failure_type = "ASSERT";
131 break;
132 case ::testing::TestPartResult::Type::kSuccess:
133 break;
134 }
135 log_do(ERROR, "%s: %d: gtest %s failure\n%s\n",
136 result.file_name(),
137 result.line_number(),
138 failure_type,
139 result.message());
140 }
141 }
Brian Silvermanb3616972013-03-05 19:58:10 -0800142};
143
144void *DoEnableTestLogging() {
145 logging::Init();
146 logging::AddImplementation(TestLogImplementation::GetInstance());
147
148 ::testing::UnitTest::GetInstance()->listeners().Append(
149 new MyTestEventListener());
150
Brian Silvermanf5f8d8e2015-12-06 18:39:12 -0500151 return nullptr;
Brian Silvermanb3616972013-03-05 19:58:10 -0800152}
153
154Once<void> enable_test_logging_once(DoEnableTestLogging);
155
156} // namespace
brians343bc112013-02-10 01:53:46 +0000157
Brian Silvermanb3616972013-03-05 19:58:10 -0800158void EnableTestLogging() {
159 enable_test_logging_once.Get();
160}
161
Philipp Schradere41ed9d2015-03-15 22:57:13 +0000162void SetLogFileName(const char* filename) {
163 TestLogImplementation::GetInstance()->SetOutputFile(filename);
164}
165
166void ForcePrintLogsDuringTests() {
167 TestLogImplementation::GetInstance()->PrintMessagesAsTheyComeIn();
168}
169
Austin Schuh82c0c822019-05-27 19:55:20 -0700170void MockTime(::aos::monotonic_clock::time_point monotonic_now) {
171 TestLogImplementation::GetInstance()->MockTime(monotonic_now);
172}
173void UnMockTime() {
174 TestLogImplementation::GetInstance()->UnMockTime();
175}
176
brians343bc112013-02-10 01:53:46 +0000177} // namespace testing
brians343bc112013-02-10 01:53:46 +0000178} // namespace aos