1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "os/thread.h"
17 #include "utils/logger.h"
18 #include "utils/string_helpers.h"
19
20 #include <cstdio>
21
22 #include <fstream>
23 #include <regex>
24 #include <streambuf>
25
26 #include <gtest/gtest.h>
27
28 namespace panda::test {
29
TEST(Logger,Initialization)30 TEST(Logger, Initialization)
31 {
32 EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
33
34 testing::FLAGS_gtest_death_test_style = "fast";
35 testing::internal::CaptureStderr();
36
37 LOG(DEBUG, COMMON) << "1";
38 LOG(INFO, COMMON) << "2";
39 LOG(ERROR, COMMON) << "3";
40
41 std::string err = testing::internal::GetCapturedStderr();
42 EXPECT_EQ(err, "");
43
44 EXPECT_DEATH_IF_SUPPORTED(LOG(FATAL, COMMON) << "4", "");
45
46 Logger::InitializeStdLogging(Logger::Level::DEBUG, panda::LoggerComponentMaskAll);
47 EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
48
49 testing::internal::CaptureStderr();
50
51 LOG(DEBUG, COMMON) << "a";
52 LOG(INFO, COMMON) << "b";
53 LOG(ERROR, COMMON) << "c";
54
55 err = testing::internal::GetCapturedStderr();
56 uint32_t tid = os::thread::GetCurrentThreadId();
57 std::string res = helpers::string::Format(
58 #ifndef NDEBUG
59 "[TID %06x] D/common: a\n"
60 #endif
61 "[TID %06x] I/common: b\n"
62 "[TID %06x] E/common: c\n",
63 tid, tid, tid);
64 EXPECT_EQ(err, res);
65
66 EXPECT_DEATH_IF_SUPPORTED(LOG(FATAL, COMMON) << "d", "\\[TID [0-9a-f]{6}\\] F/common: d");
67
68 Logger::Destroy();
69 EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
70
71 testing::internal::CaptureStderr();
72
73 LOG(DEBUG, COMMON) << "1";
74 LOG(INFO, COMMON) << "2";
75 LOG(ERROR, COMMON) << "3";
76
77 err = testing::internal::GetCapturedStderr();
78 EXPECT_EQ(err, "");
79
80 EXPECT_DEATH_IF_SUPPORTED(LOG(FATAL, COMMON) << "4", "");
81 }
82
TEST(Logger,FilterInfo)83 TEST(Logger, FilterInfo)
84 {
85 Logger::InitializeStdLogging(Logger::Level::INFO, panda::LoggerComponentMaskAll);
86 EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
87
88 testing::internal::CaptureStderr();
89
90 LOG(DEBUG, COMMON) << "a";
91 LOG(INFO, COMMON) << "b";
92 LOG(ERROR, COMMON) << "c";
93
94 std::string err = testing::internal::GetCapturedStderr();
95 uint32_t tid = os::thread::GetCurrentThreadId();
96 std::string res = helpers::string::Format(
97 "[TID %06x] I/common: b\n"
98 "[TID %06x] E/common: c\n",
99 tid, tid);
100 EXPECT_EQ(err, res);
101
102 Logger::Destroy();
103 EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
104 }
105
TEST(Logger,FilterError)106 TEST(Logger, FilterError)
107 {
108 Logger::InitializeStdLogging(Logger::Level::ERROR, panda::LoggerComponentMaskAll);
109 EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
110
111 testing::internal::CaptureStderr();
112
113 LOG(DEBUG, COMMON) << "a";
114 LOG(INFO, COMMON) << "b";
115 LOG(ERROR, COMMON) << "c";
116
117 std::string err = testing::internal::GetCapturedStderr();
118 uint32_t tid = os::thread::GetCurrentThreadId();
119 std::string res = helpers::string::Format("[TID %06x] E/common: c\n", tid);
120 EXPECT_EQ(err, res);
121
122 Logger::Destroy();
123 EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
124 }
125
TEST(Logger,FilterFatal)126 TEST(Logger, FilterFatal)
127 {
128 Logger::InitializeStdLogging(Logger::Level::FATAL, panda::LoggerComponentMaskAll);
129 EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
130
131 testing::internal::CaptureStderr();
132
133 LOG(DEBUG, COMMON) << "a";
134 LOG(INFO, COMMON) << "b";
135 LOG(ERROR, COMMON) << "c";
136
137 std::string err = testing::internal::GetCapturedStderr();
138 uint32_t tid = os::thread::GetCurrentThreadId();
139 EXPECT_EQ(err, "");
140
141 Logger::Destroy();
142 EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
143 }
144
TEST(Logger,ComponentFilter)145 TEST(Logger, ComponentFilter)
146 {
147 panda::Logger::ComponentMask component_mask;
148 component_mask.set(Logger::Component::CLASS_LINKER);
149 component_mask.set(Logger::Component::GC);
150
151 Logger::InitializeStdLogging(Logger::Level::INFO, component_mask);
152 EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
153 EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::CLASS_LINKER));
154 EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::GC));
155
156 testing::internal::CaptureStderr();
157
158 LOG(INFO, COMMON) << "a";
159 LOG(INFO, CLASS_LINKER) << "b";
160 LOG(INFO, RUNTIME) << "c";
161 LOG(INFO, GC) << "d";
162
163 std::string err = testing::internal::GetCapturedStderr();
164 uint32_t tid = os::thread::GetCurrentThreadId();
165 std::string res = helpers::string::Format(
166 "[TID %06x] I/classlinker: b\n"
167 "[TID %06x] I/gc: d\n",
168 tid, tid);
169 EXPECT_EQ(err, res);
170
171 Logger::Destroy();
172 EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
173 }
174
TEST(Logger,FileLogging)175 TEST(Logger, FileLogging)
176 {
177 uint32_t tid = os::thread::GetCurrentThreadId();
178 std::string log_filename = helpers::string::Format("/tmp/gtest_panda_logger_file_%06x", tid);
179
180 Logger::InitializeFileLogging(log_filename, Logger::Level::INFO,
181 panda::Logger::ComponentMask().set(Logger::Component::COMMON));
182 EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
183 EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::COMMON));
184
185 LOG(DEBUG, COMMON) << "a";
186 LOG(INFO, COMMON) << "b";
187 LOG(ERROR, CLASS_LINKER) << "c";
188 LOG(ERROR, COMMON) << "d";
189
190 #if GTEST_HAS_DEATH_TEST
191 testing::FLAGS_gtest_death_test_style = "fast";
192
193 EXPECT_DEATH(LOG(FATAL, COMMON) << "e", "");
194
195 std::string res = helpers::string::Format(
196 "\\[TID %06x\\] I/common: b\n"
197 "\\[TID %06x\\] E/common: d\n"
198 "\\[TID [0-9a-f]{6}\\] F/common: e\n",
199 tid, tid);
200 std::regex e(res);
201 {
202 std::ifstream log_file_stream(log_filename);
203 std::string log_file_content((std::istreambuf_iterator<char>(log_file_stream)),
204 std::istreambuf_iterator<char>());
205 EXPECT_TRUE(std::regex_match(log_file_content, e));
206 }
207 #endif // GTEST_HAS_DEATH_TEST
208
209 EXPECT_EQ(std::remove(log_filename.c_str()), 0);
210
211 Logger::Destroy();
212 EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
213 }
214
TEST(Logger,Multiline)215 TEST(Logger, Multiline)
216 {
217 Logger::InitializeStdLogging(Logger::Level::INFO, panda::Logger::ComponentMask().set(Logger::Component::COMMON));
218 EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
219 EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::COMMON));
220
221 testing::internal::CaptureStderr();
222
223 LOG(INFO, COMMON) << "a\nb\nc\n\nd\n";
224
225 std::string err = testing::internal::GetCapturedStderr();
226 uint32_t tid = os::thread::GetCurrentThreadId();
227 std::string res = helpers::string::Format(
228 "[TID %06x] I/common: a\n"
229 "[TID %06x] I/common: b\n"
230 "[TID %06x] I/common: c\n"
231 "[TID %06x] I/common: \n"
232 "[TID %06x] I/common: d\n"
233 "[TID %06x] I/common: \n",
234 tid, tid, tid, tid, tid, tid);
235 EXPECT_EQ(err, res);
236
237 Logger::Destroy();
238 EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
239 }
240
TEST(Logger,PLog)241 TEST(Logger, PLog)
242 {
243 Logger::InitializeStdLogging(Logger::Level::INFO, panda::LoggerComponentMaskAll);
244 EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
245
246 testing::internal::CaptureStderr();
247
248 int errnum = errno;
249
250 errno = EEXIST;
251 PLOG(ERROR, COMMON) << "a";
252 errno = EACCES;
253 PLOG(INFO, CLASS_LINKER) << "b";
254 errno = errnum;
255
256 std::string err = testing::internal::GetCapturedStderr();
257 uint32_t tid = os::thread::GetCurrentThreadId();
258 std::string res = helpers::string::Format(
259 "[TID %06x] E/common: a: File exists\n"
260 "[TID %06x] I/classlinker: b: Permission denied\n",
261 tid, tid, tid, tid);
262 EXPECT_EQ(err, res);
263
264 Logger::Destroy();
265 EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
266 }
267
TEST(Logger,LogIf)268 TEST(Logger, LogIf)
269 {
270 Logger::InitializeStdLogging(Logger::Level::INFO, panda::LoggerComponentMaskAll);
271 EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
272
273 testing::internal::CaptureStderr();
274
275 LOG_IF(true, INFO, COMMON) << "a";
276 LOG_IF(false, INFO, COMMON) << "b";
277
278 std::string err = testing::internal::GetCapturedStderr();
279 uint32_t tid = os::thread::GetCurrentThreadId();
280 std::string res = helpers::string::Format("[TID %06x] I/common: a\n", tid);
281 EXPECT_EQ(err, res);
282
283 Logger::Destroy();
284 EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
285 }
286
TEST(Logger,LogOnce)287 TEST(Logger, LogOnce)
288 {
289 Logger::InitializeStdLogging(Logger::Level::INFO, panda::LoggerComponentMaskAll);
290 EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
291
292 testing::internal::CaptureStderr();
293
294 LOG_ONCE(INFO, COMMON) << "a";
295 for (int i = 0; i < 10; ++i) {
296 LOG_ONCE(INFO, COMMON) << "b";
297 }
298 LOG_ONCE(INFO, COMMON) << "c";
299
300 std::string err = testing::internal::GetCapturedStderr();
301 uint32_t tid = os::thread::GetCurrentThreadId();
302 std::string res = helpers::string::Format(
303 "[TID %06x] I/common: a\n"
304 "[TID %06x] I/common: b\n"
305 "[TID %06x] I/common: c\n",
306 tid, tid, tid);
307 EXPECT_EQ(err, res);
308
309 Logger::Destroy();
310 EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
311 }
312
TEST(Logger,LogDfx)313 TEST(Logger, LogDfx)
314 {
315 Logger::InitializeStdLogging(Logger::Level::ERROR, panda::LoggerComponentMaskAll);
316 EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
317
318 DfxController::Initialize();
319 EXPECT_TRUE(DfxController::IsInitialized());
320 EXPECT_EQ(DfxController::GetOptionValue(DfxOptionHandler::DFXLOG), 0);
321
322 testing::internal::CaptureStderr();
323
324 LOG_DFX(COMMON) << "a";
325 LOG_DFX(COMMON) << "b";
326 LOG_DFX(COMMON) << "c";
327
328 std::string err = testing::internal::GetCapturedStderr();
329 EXPECT_EQ(err, "");
330
331 DfxController::ResetOptionValueFromString("dfx-log:1");
332 EXPECT_EQ(DfxController::GetOptionValue(DfxOptionHandler::DFXLOG), 1);
333
334 testing::internal::CaptureStderr();
335
336 LOG_DFX(COMMON) << "a";
337 LOG_DFX(COMMON) << "b";
338 LOG_DFX(COMMON) << "c";
339
340 err = testing::internal::GetCapturedStderr();
341 uint32_t tid = os::thread::GetCurrentThreadId();
342 std::string res = helpers::string::Format(
343 "[TID %06x] E/dfx: common log:a\n"
344 "[TID %06x] E/dfx: common log:b\n"
345 "[TID %06x] E/dfx: common log:c\n",
346 tid, tid, tid);
347 EXPECT_EQ(err, res);
348
349 Logger::Destroy();
350 EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
351
352 DfxController::Destroy();
353 EXPECT_FALSE(DfxController::IsInitialized());
354 }
355
356 } // namespace panda::test
357