1/**
2 * Copyright (c) 2021-2022 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/file.h"
17#include "os/thread.h"
18#include "utils/logger.h"
19#include "utils/string_helpers.h"
20
21#include <cstdio>
22
23#include <fstream>
24#include <regex>
25#include <streambuf>
26
27#include <gtest/gtest.h>
28
29namespace panda::test {
30
31class LoggerTest : public testing::Test {
32public:
33    static void SetUpTestSuite()
34    {
35#ifndef HOST_UT
36        system("mount -o rw,remount /");
37#endif
38    }
39};
40
41HWTEST_F(LoggerTest, Initialization, testing::ext::TestSize.Level0)
42{
43    EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
44
45    testing::FLAGS_gtest_death_test_style = "fast";
46    testing::internal::CaptureStderr();
47
48    LOG(DEBUG, COMMON) << "1";
49    LOG(INFO, COMMON) << "2";
50    LOG(ERROR, COMMON) << "3";
51
52    std::string err = testing::internal::GetCapturedStderr();
53    EXPECT_EQ(err, "");
54
55    EXPECT_DEATH_IF_SUPPORTED(LOG(FATAL, COMMON) << "4", "");
56
57    Logger::InitializeStdLogging(Logger::Level::DEBUG, panda::LoggerComponentMaskAll);
58    EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
59
60    testing::internal::CaptureStderr();
61
62    LOG(DEBUG, COMMON) << "a";
63    LOG(INFO, COMMON) << "b";
64    LOG(ERROR, COMMON) << "c";
65
66    err = testing::internal::GetCapturedStderr();
67    uint32_t tid = os::thread::GetCurrentThreadId();
68    std::string res = helpers::string::Format(
69#ifndef NDEBUG
70        "[TID %06x] D/common: a\n"
71#endif
72        "[TID %06x] I/common: b\n"
73        "[TID %06x] E/common: c\n",
74        tid, tid, tid);
75    EXPECT_EQ(err, res);
76
77    EXPECT_DEATH_IF_SUPPORTED(LOG(FATAL, COMMON) << "d", "\\[TID [0-9a-f]{6}\\] F/common: d");
78
79    Logger::Destroy();
80    EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
81
82    testing::internal::CaptureStderr();
83
84    LOG(DEBUG, COMMON) << "1";
85    LOG(INFO, COMMON) << "2";
86    LOG(ERROR, COMMON) << "3";
87
88    err = testing::internal::GetCapturedStderr();
89    EXPECT_EQ(err, "");
90
91    EXPECT_DEATH_IF_SUPPORTED(LOG(FATAL, COMMON) << "4", "");
92}
93
94HWTEST_F(LoggerTest, LoggingExceptionsFatal, testing::ext::TestSize.Level0)
95{
96    testing::FLAGS_gtest_death_test_style = "fast";
97
98    panda::Logger::ComponentMask component_mask;
99    component_mask.set(Logger::Component::COMPILER);
100
101    Logger::InitializeStdLogging(Logger::Level::FATAL, component_mask);
102    EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::COMPILER));
103    EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ASSEMBLER));
104    EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::DISASSEMBLER));
105    EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::ERROR, Logger::Component::COMPILER));
106    EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::ERROR, Logger::Component::ASSEMBLER));
107    EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::ERROR, Logger::Component::DISASSEMBLER));
108
109    EXPECT_DEATH_IF_SUPPORTED(LOG(FATAL, COMPILER) << "d1", "\\[TID [0-9a-f]{6}\\] F/compiler: d1");
110    EXPECT_DEATH_IF_SUPPORTED(LOG(FATAL, ASSEMBLER) << "d2", "\\[TID [0-9a-f]{6}\\] F/assembler: d2");
111    EXPECT_DEATH_IF_SUPPORTED(LOG(FATAL, DISASSEMBLER) << "d3", "\\[TID [0-9a-f]{6}\\] F/disassembler: d3");
112
113    testing::internal::CaptureStderr();
114
115    LOG(ERROR, COMPILER) << "c";
116    LOG(ERROR, ASSEMBLER) << "a";
117    LOG(ERROR, DISASSEMBLER) << "d";
118
119    std::string err = testing::internal::GetCapturedStderr();
120    EXPECT_EQ(err, "");
121
122    Logger::Destroy();
123}
124
125HWTEST_F(LoggerTest, LoggingExceptionsError, testing::ext::TestSize.Level0)
126{
127    testing::FLAGS_gtest_death_test_style = "fast";
128
129    panda::Logger::ComponentMask component_mask;
130    component_mask.set(Logger::Component::COMPILER);
131
132    Logger::InitializeStdLogging(Logger::Level::ERROR, component_mask);
133    EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::COMPILER));
134    EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ASSEMBLER));
135    EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::DISASSEMBLER));
136    EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::ERROR, Logger::Component::COMPILER));
137    EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::ERROR, Logger::Component::ASSEMBLER));
138    EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::ERROR, Logger::Component::DISASSEMBLER));
139
140    EXPECT_DEATH_IF_SUPPORTED(LOG(FATAL, COMPILER) << "d1", "\\[TID [0-9a-f]{6}\\] F/compiler: d1");
141    EXPECT_DEATH_IF_SUPPORTED(LOG(FATAL, ASSEMBLER) << "d2", "\\[TID [0-9a-f]{6}\\] F/assembler: d2");
142    EXPECT_DEATH_IF_SUPPORTED(LOG(FATAL, DISASSEMBLER) << "d3", "\\[TID [0-9a-f]{6}\\] F/disassembler: d3");
143
144    testing::internal::CaptureStderr();
145
146    LOG(ERROR, COMPILER) << "c";
147    LOG(ERROR, ASSEMBLER) << "a";
148    LOG(ERROR, DISASSEMBLER) << "d";
149
150    std::string err = testing::internal::GetCapturedStderr();
151    uint32_t tid = os::thread::GetCurrentThreadId();
152    std::string res = helpers::string::Format("[TID %06x] E/compiler: c\n", tid);
153    EXPECT_EQ(err, res);
154
155    Logger::Destroy();
156}
157
158HWTEST_F(LoggerTest, FilterInfo, testing::ext::TestSize.Level0)
159{
160    Logger::InitializeStdLogging(Logger::Level::INFO, panda::LoggerComponentMaskAll);
161    EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
162
163    testing::internal::CaptureStderr();
164
165    LOG(DEBUG, COMMON) << "a";
166    LOG(INFO, COMMON) << "b";
167    LOG(ERROR, COMMON) << "c";
168
169    std::string err = testing::internal::GetCapturedStderr();
170    uint32_t tid = os::thread::GetCurrentThreadId();
171    std::string res = helpers::string::Format(
172        "[TID %06x] I/common: b\n"
173        "[TID %06x] E/common: c\n",
174        tid, tid);
175    EXPECT_EQ(err, res);
176
177    Logger::Destroy();
178    EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
179}
180
181HWTEST_F(LoggerTest, FilterError, testing::ext::TestSize.Level0)
182{
183    Logger::InitializeStdLogging(Logger::Level::ERROR, panda::LoggerComponentMaskAll);
184    EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
185
186    testing::internal::CaptureStderr();
187
188    LOG(DEBUG, COMMON) << "a";
189    LOG(INFO, COMMON) << "b";
190    LOG(ERROR, COMMON) << "c";
191
192    std::string err = testing::internal::GetCapturedStderr();
193    uint32_t tid = os::thread::GetCurrentThreadId();
194    std::string res = helpers::string::Format("[TID %06x] E/common: c\n", tid);
195    EXPECT_EQ(err, res);
196
197    Logger::Destroy();
198    EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
199}
200
201HWTEST_F(LoggerTest, FilterFatal, testing::ext::TestSize.Level0)
202{
203    Logger::InitializeStdLogging(Logger::Level::FATAL, panda::LoggerComponentMaskAll);
204    EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
205
206    testing::internal::CaptureStderr();
207
208    LOG(DEBUG, COMMON) << "a";
209    LOG(INFO, COMMON) << "b";
210    LOG(ERROR, COMMON) << "c";
211
212    std::string err = testing::internal::GetCapturedStderr();
213    EXPECT_EQ(err, "");
214
215    Logger::Destroy();
216    EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
217}
218
219HWTEST_F(LoggerTest, ComponentFilter, testing::ext::TestSize.Level0)
220{
221    panda::Logger::ComponentMask component_mask;
222    component_mask.set(Logger::Component::COMPILER);
223    component_mask.set(Logger::Component::GC);
224
225    Logger::InitializeStdLogging(Logger::Level::INFO, component_mask);
226    EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::WARNING, Logger::Component::ALLOC));
227    EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::COMPILER));
228    EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::GC));
229
230    testing::internal::CaptureStderr();
231
232    LOG(INFO, COMMON) << "a";
233    LOG(INFO, COMPILER) << "b";
234    LOG(INFO, RUNTIME) << "c";
235    LOG(INFO, GC) << "d";
236
237    std::string err = testing::internal::GetCapturedStderr();
238    uint32_t tid = os::thread::GetCurrentThreadId();
239    std::string res = helpers::string::Format(
240        "[TID %06x] I/compiler: b\n"
241        "[TID %06x] I/gc: d\n",
242        tid, tid);
243    EXPECT_EQ(err, res);
244
245    Logger::Destroy();
246    EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
247}
248
249HWTEST_F(LoggerTest, FileLogging, testing::ext::TestSize.Level0)
250{
251    uint32_t tid = os::thread::GetCurrentThreadId();
252    std::string log_filename = helpers::string::Format("/tmp/gtest_panda_logger_file_%06x", tid);
253
254    auto file = os::file::Open(log_filename, os::file::Mode::READWRITECREATE);
255    ASSERT_TRUE(file.IsValid());
256
257    Logger::InitializeFileLogging(log_filename, Logger::Level::INFO,
258                                  panda::Logger::ComponentMask().set(Logger::Component::COMMON));
259    EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
260    EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::COMMON));
261
262    LOG(DEBUG, COMMON) << "a";
263    LOG(INFO, COMMON) << "b";
264    LOG(ERROR, COMPILER) << "c";
265    LOG(ERROR, COMMON) << "d";
266
267#if GTEST_HAS_DEATH_TEST
268    testing::FLAGS_gtest_death_test_style = "fast";
269
270    EXPECT_DEATH(LOG(FATAL, COMMON) << "e", "");
271
272    std::string res = helpers::string::Format(
273        "\\[TID %06x\\] I/common: b\n"
274        "\\[TID %06x\\] E/common: d\n"
275        "\\[TID [0-9a-f]{6}\\] F/common: e\n",
276        tid, tid);
277    std::regex e(res);
278    {
279        std::ifstream log_file_stream(log_filename);
280        std::string log_file_content((std::istreambuf_iterator<char>(log_file_stream)),
281                                     std::istreambuf_iterator<char>());
282        EXPECT_TRUE(std::regex_match(log_file_content, e));
283    }
284#endif  // GTEST_HAS_DEATH_TEST
285
286    EXPECT_EQ(std::remove(log_filename.c_str()), 0);
287
288    Logger::Destroy();
289    EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
290}
291
292HWTEST_F(LoggerTest, Multiline, testing::ext::TestSize.Level0)
293{
294    Logger::InitializeStdLogging(Logger::Level::INFO, panda::Logger::ComponentMask().set(Logger::Component::COMMON));
295    EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
296    EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::COMMON));
297
298    testing::internal::CaptureStderr();
299
300    LOG(INFO, COMMON) << "a\nb\nc\n\nd\n";
301
302    std::string err = testing::internal::GetCapturedStderr();
303    uint32_t tid = os::thread::GetCurrentThreadId();
304    std::string res = helpers::string::Format(
305        "[TID %06x] I/common: a\n"
306        "[TID %06x] I/common: b\n"
307        "[TID %06x] I/common: c\n"
308        "[TID %06x] I/common: \n"
309        "[TID %06x] I/common: d\n"
310        "[TID %06x] I/common: \n",
311        tid, tid, tid, tid, tid, tid);
312    EXPECT_EQ(err, res);
313
314    Logger::Destroy();
315    EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
316}
317
318HWTEST_F(LoggerTest, LogIf, testing::ext::TestSize.Level0)
319{
320    Logger::InitializeStdLogging(Logger::Level::INFO, panda::LoggerComponentMaskAll);
321    EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
322
323    testing::internal::CaptureStderr();
324
325    LOG_IF(true, INFO, COMMON) << "a";
326    LOG_IF(false, INFO, COMMON) << "b";
327
328    std::string err = testing::internal::GetCapturedStderr();
329    uint32_t tid = os::thread::GetCurrentThreadId();
330    std::string res = helpers::string::Format("[TID %06x] I/common: a\n", tid);
331    EXPECT_EQ(err, res);
332
333    Logger::Destroy();
334    EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
335}
336
337HWTEST_F(LoggerTest, LogOnce, testing::ext::TestSize.Level0)
338{
339    Logger::InitializeStdLogging(Logger::Level::INFO, panda::LoggerComponentMaskAll);
340    EXPECT_TRUE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
341
342    testing::internal::CaptureStderr();
343
344    LOG_ONCE(INFO, COMMON) << "a";
345    for (int i = 0; i < 10; ++i) {
346        LOG_ONCE(INFO, COMMON) << "b";
347    }
348    LOG_ONCE(INFO, COMMON) << "c";
349
350    std::string err = testing::internal::GetCapturedStderr();
351    uint32_t tid = os::thread::GetCurrentThreadId();
352    std::string res = helpers::string::Format(
353        "[TID %06x] I/common: a\n"
354        "[TID %06x] I/common: b\n"
355        "[TID %06x] I/common: c\n",
356        tid, tid, tid);
357    EXPECT_EQ(err, res);
358
359    Logger::Destroy();
360    EXPECT_FALSE(Logger::IsLoggingOn(Logger::Level::FATAL, Logger::Component::ALLOC));
361}
362
363}  // namespace panda::test
364