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 <array>
17 #include <cstdlib>
18 #include <cstdio>
19 #include <ctime>
20 #include <dirent.h>
21 #include <iostream>
22 #include <securec.h>
23 #include <sstream>
24 #include <stdatomic.h>
25 #include <string>
26 #include <sys/socket.h>
27 #include <sys/stat.h>
28 #include <sys/un.h>
29 #include <thread>
30
31 #include <gtest/gtest.h>
32 #include <hilog_common.h>
33
34 #include "hilog_base/log_base.h"
35
36 #undef LOG_DOMAIN
37 #define LOG_DOMAIN 0xD002D00
38
39 #undef LOG_TAG
40 #define LOG_TAG "HILOGBASETEST"
41
42 using namespace testing::ext;
43
44 namespace OHOS {
45 namespace HiviewDFX {
46 namespace HiLogBaseTest {
47 static constexpr unsigned int SOME_LOGS = 10;
48 static constexpr unsigned int MORE_LOGS = 100;
49 static constexpr unsigned int SHORT_LOG = 16;
50 static constexpr unsigned int LONG_LOG = 1000;
51 static constexpr unsigned int VERY_LONG_LOG = 2048;
52 static constexpr unsigned int THREAD_COUNT = 10;
53 static std::string g_str[THREAD_COUNT];
54 #define TWO (2)
55 #define NEGATIVE_ONE (-1)
56
57 enum LogInterfaceType {
58 DEBUG_METHOD = 0,
59 INFO_METHOD = 1,
60 WARN_METHOD = 2,
61 ERROR_METHOD = 3,
62 FATAL_METHOD = 4,
63 METHODS_NUMBER = 5,
64 };
65
66 using LogMethodFunc = std::function<void(const std::string &msg)>;
67
68 static const std::array<std::string, METHODS_NUMBER> METHOD_NAMES = {
69 "Debug", "Info", "Warn", "Error", "Fatal"
70 };
71
72 static const std::array<LogMethodFunc, METHODS_NUMBER> LOG_C_METHODS = {
__anon8b8c17a90102() 73 [] (const std::string &msg) {
74 HILOG_BASE_DEBUG(LOG_CORE, "%{public}s", msg.c_str());
75 },
__anon8b8c17a90202() 76 [] (const std::string &msg) {
77 HILOG_BASE_INFO(LOG_CORE, "%{public}s", msg.c_str());
78 },
__anon8b8c17a90302() 79 [] (const std::string &msg) {
80 HILOG_BASE_WARN(LOG_CORE, "%{public}s", msg.c_str());
81 },
__anon8b8c17a90402() 82 [] (const std::string &msg) {
83 HILOG_BASE_ERROR(LOG_CORE, "%{public}s", msg.c_str());
84 },
__anon8b8c17a90502() 85 [] (const std::string &msg) {
86 HILOG_BASE_FATAL(LOG_CORE, "%{public}s", msg.c_str());
87 },
88 };
89
PopenToString(const std::string & command)90 static std::string PopenToString(const std::string &command)
91 {
92 std::string str;
93 constexpr int bufferSize = 1024;
94 FILE *fp = popen(command.c_str(), "re");
95 if (fp != nullptr) {
96 char buf[bufferSize] = {0};
97 size_t n = fread(buf, 1, sizeof(buf), fp);
98 while (n > 0) {
99 str.append(buf, n);
100 n = fread(buf, 1, sizeof(buf), fp);
101 }
102 pclose(fp);
103 }
104 return str;
105 }
106
107 // Function executed by the subthread to print logs
FunctionPrintLog(int index)108 void FunctionPrintLog(int index)
109 {
110 HiLogBasePrint(LOG_INIT, LOG_ERROR, 0xD002D00, LOG_TAG, "FunctionPrintLog %{public}s", g_str[index].c_str());
111 }
112
113 //Check whether corresponding logs are generated. If yes, true is returned. If no, false is returned.
CheckHiLogPrint(char * needToMatch)114 bool CheckHiLogPrint(char *needToMatch)
115 {
116 constexpr int COMMAND_SIZE = 50;
117 constexpr int BUFFER_SIZE = 1024;
118 constexpr int FAIL_CLOSE = -1;
119 bool ret = false;
120 // Use the system function to read the current hilog information.
121 char command[] = "/bin/hilog -x | grep ";
122 char finalCommand[COMMAND_SIZE];
123 int res = snprintf_s(finalCommand, COMMAND_SIZE, COMMAND_SIZE - 1, "%s%s", command, needToMatch);
124 if (res == NEGATIVE_ONE) {
125 printf("CheckHiLogPrint command generate snprintf_s failed\n");
126 return false;
127 }
128 finalCommand[COMMAND_SIZE - 1] = '\0';
129 char buffer[BUFFER_SIZE];
130 FILE* pipe = popen(finalCommand, "r");
131 if (pipe == nullptr) {
132 printf("CheckHiLogPrint: Failed to run command\n");
133 return false;
134 }
135
136 // Read command output and print
137 while (fgets(buffer, BUFFER_SIZE, pipe) != nullptr) {
138 printf("%s", buffer);
139 ret = true;
140 }
141
142 // Close the pipe and get the return value
143 int returnValue = pclose(pipe);
144 if (returnValue == FAIL_CLOSE) {
145 printf("CheckHiLogPrint pclose failed returnValue=-1 errno=%d\n", errno);
146 }
147 return ret;
148 }
149
150 class HiLogBaseNDKTest : public testing::Test {
151 public:
152 static void SetUpTestCase();
TearDownTestCase()153 static void TearDownTestCase() {}
154 void SetUp();
TearDown()155 void TearDown() {}
156 };
157
SetUpTestCase()158 void HiLogBaseNDKTest::SetUpTestCase()
159 {
160 (void)PopenToString("hilog -Q pidoff");
161 (void)PopenToString("hilog -Q domainoff");
162 }
163
SetUp()164 void HiLogBaseNDKTest::SetUp()
165 {
166 (void)PopenToString("hilog -r");
167 }
168
RandomStringGenerator(uint32_t logLen=16)169 static std::string RandomStringGenerator(uint32_t logLen = 16)
170 {
171 std::string str;
172 for (uint32_t i = 0; i < logLen; ++i) {
173 char newChar = rand() % ('z' - 'a') + 'a';
174 str.append(1, newChar);
175 }
176 return str;
177 }
178
HiLogWriteTest(LogMethodFunc loggingMethod,uint32_t logCount,uint32_t logLen,bool isDebug)179 static void HiLogWriteTest(LogMethodFunc loggingMethod, uint32_t logCount, uint32_t logLen, bool isDebug)
180 {
181 std::string logMsg(RandomStringGenerator(logLen));
182 for (uint32_t i = 0; i < logCount; ++i) {
183 loggingMethod(logMsg + std::to_string(i));
184 }
185 if (logMsg.length() > MAX_LOG_LEN-1) {
186 logMsg = logMsg.substr(0, MAX_LOG_LEN-1);
187 }
188 usleep(1000); /* 1000: sleep 1 ms */
189 std::string logMsgs = PopenToString("/system/bin/hilog -x");
190 uint32_t realCount = 0;
191 std::stringstream ss(logMsgs);
192 std::string str;
193 while (!ss.eof()) {
194 getline(ss, str);
195 if (str.find(logMsg) != std::string::npos) {
196 ++realCount;
197 }
198 }
199 uint32_t allowedLeastLogCount = logCount - logCount * 1 / 10; /* 1 / 10: loss rate less than 10% */
200 if (isDebug) {
201 allowedLeastLogCount = 0; /* 0: debug log is allowed to be closed */
202 }
203 EXPECT_GE(realCount, allowedLeastLogCount);
204 }
205
206 HWTEST_F(HiLogBaseNDKTest, SomeLogs, TestSize.Level1)
207 {
208 for(uint32_t i = 0; i < METHODS_NUMBER; ++i) {
209 std::cout << "Starting " << METHOD_NAMES[i] << " test\n";
210 HiLogWriteTest(LOG_C_METHODS[i], SOME_LOGS, SHORT_LOG, i == DEBUG_METHOD);
211 }
212 }
213
214 HWTEST_F(HiLogBaseNDKTest, MoreLogs, TestSize.Level1)
215 {
216 for(uint32_t i = 0; i < METHODS_NUMBER; ++i) {
217 std::cout << "Starting " << METHOD_NAMES[i] << " test\n";
218 HiLogWriteTest(LOG_C_METHODS[i], MORE_LOGS, SHORT_LOG, i == DEBUG_METHOD);
219 }
220 }
221
222 HWTEST_F(HiLogBaseNDKTest, LongLogs, TestSize.Level1)
223 {
224 for(uint32_t i = 0; i < METHODS_NUMBER; ++i) {
225 std::cout << "Starting " << METHOD_NAMES[i] << " test\n";
226 HiLogWriteTest(LOG_C_METHODS[i], 5, LONG_LOG, i == DEBUG_METHOD);
227 }
228 }
229
230 HWTEST_F(HiLogBaseNDKTest, VeryLongLogs, TestSize.Level1)
231 {
232 for(uint32_t i = 0; i < METHODS_NUMBER; ++i) {
233 std::cout << "Starting " << METHOD_NAMES[i] << " test\n";
234 HiLogWriteTest(LOG_C_METHODS[i], 5, VERY_LONG_LOG, i == DEBUG_METHOD);
235 }
236 }
237
238 HWTEST_F(HiLogBaseNDKTest, MemAllocTouch1, TestSize.Level1)
239 {
240 #undef TEXT_TO_CHECK
241 #define TEXT_TO_CHECK "Float potential mem alloc"
242 HILOG_BASE_ERROR(LOG_CORE, TEXT_TO_CHECK " %{public}515.2f", 123.3);
243 usleep(1000); /* 1000: sleep 1 ms */
244 std::string logMsgs = PopenToString("/system/bin/hilog -x");
245 uint32_t realCount = 0;
246 std::stringstream ss(logMsgs);
247 std::string str;
248 while (!ss.eof()) {
249 getline(ss, str);
250 if (str.find(TEXT_TO_CHECK) != std::string::npos) {
251 ++realCount;
252 }
253 }
254
255 EXPECT_EQ(realCount, 1);
256 }
257
258 HWTEST_F(HiLogBaseNDKTest, MemAllocTouch2, TestSize.Level1)
259 {
260 #undef TEXT_TO_CHECK
261 #define TEXT_TO_CHECK "Float potential mem alloc"
262 HILOG_BASE_ERROR(LOG_CORE, TEXT_TO_CHECK " %{public}000000005.00000002f", 123.3);
263 usleep(1000); /* 1000: sleep 1 ms */
264 std::string logMsgs = PopenToString("/system/bin/hilog -x");
265 uint32_t realCount = 0;
266 std::stringstream ss(logMsgs);
267 std::string str;
268 while (!ss.eof()) {
269 getline(ss, str);
270 if (str.find(TEXT_TO_CHECK) != std::string::npos) {
271 ++realCount;
272 }
273 }
274
275 EXPECT_EQ(realCount, 1);
276 }
277
278 HWTEST_F(HiLogBaseNDKTest, IsLoggable, TestSize.Level1)
279 {
280 EXPECT_TRUE(HiLogBaseIsLoggable(0xD002D00, LOG_TAG, LOG_DEBUG));
281 EXPECT_TRUE(HiLogBaseIsLoggable(0xD002D00, LOG_TAG, LOG_INFO));
282 EXPECT_TRUE(HiLogBaseIsLoggable(0xD002D00, LOG_TAG, LOG_WARN));
283 EXPECT_TRUE(HiLogBaseIsLoggable(0xD002D00, LOG_TAG, LOG_ERROR));
284 EXPECT_TRUE(HiLogBaseIsLoggable(0xD002D00, LOG_TAG, LOG_FATAL));
285 EXPECT_TRUE(HiLogBaseIsLoggable(0xD002D00, "abc", LOG_WARN));
286 EXPECT_FALSE(HiLogBaseIsLoggable(0xD002D00, "abc", LOG_LEVEL_MIN));
287 }
288
289 HWTEST_F(HiLogBaseNDKTest, HilogBasePrintCheck, TestSize.Level1)
290 {
291 std::thread threads[THREAD_COUNT];
292 // Create threads and print logs concurrently. Logs printed by each thread cannot be lost.
293 for (int i = 0; i < THREAD_COUNT; i++) {
294 // Generate a random string, and then pass the subscript to the child thread through the value,
295 // so that the child thread can obtain the global data.
296 g_str[i] = RandomStringGenerator();
297 threads[i] = std::thread(FunctionPrintLog, i);
298 }
299 // Wait for the thread execution to complete.
300 for (int i = 0; i < THREAD_COUNT; i++) {
301 threads[i].join();
302 bool result = CheckHiLogPrint(g_str[i].data());
303 EXPECT_EQ(result, true);
304 }
305 }
306 } // namespace HiLogTest
307 } // namespace HiviewDFX
308 } // namespace OHOS