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 <ctime>
19#include <iostream>
20#include <sstream>
21#include <string>
22
23#include <unistd.h>
24
25#include <gtest/gtest.h>
26
27#include "hilog/log.h"
28#include "parameters.h"
29
30#undef LOG_DOMAIN
31#define LOG_DOMAIN 0xD002D00
32
33#undef LOG_TAG
34#define LOG_TAG "HILOGTEST_C"
35
36using namespace testing::ext;
37
38namespace OHOS {
39namespace HiviewDFX {
40namespace HiLogTest {
41const HiLogLabel APP_LABEL = { LOG_APP, 0x002a, "HILOGTEST_CPP" };
42const HiLogLabel LABEL = { LOG_CORE, 0xD002D00, "HILOGTEST_CPP" };
43const HiLogLabel ILLEGAL_DOMAIN_LABEL = { LOG_CORE, 0xD00EEEE, "HILOGTEST_CPP" };
44static constexpr unsigned int SOME_LOGS = 10;
45static constexpr unsigned int MORE_LOGS = 100;
46static constexpr unsigned int OVER_LOGS = 1000;
47
48enum LogInterfaceType {
49    DEBUG_METHOD = 0,
50    INFO_METHOD = 1,
51    WARN_METHOD = 2,
52    ERROR_METHOD = 3,
53    FATAL_METHOD = 4,
54    METHODS_NUMBER = 5,
55};
56
57using LogMethodFunc = std::function<void(const std::string &msg)>;
58
59static const std::array<LogMethodFunc, METHODS_NUMBER> LOG_C_METHODS = {
60    [] (const std::string &msg) {
61        HILOG_DEBUG(LOG_CORE, "%{public}s", msg.c_str());
62    },
63    [] (const std::string &msg) {
64        HILOG_INFO(LOG_CORE, "%{public}s", msg.c_str());
65    },
66    [] (const std::string &msg) {
67        HILOG_WARN(LOG_CORE, "%{public}s", msg.c_str());
68    },
69    [] (const std::string &msg) {
70        HILOG_ERROR(LOG_CORE, "%{public}s", msg.c_str());
71    },
72    [] (const std::string &msg) {
73        HILOG_FATAL(LOG_CORE, "%{public}s", msg.c_str());
74    },
75};
76
77static const std::array<LogMethodFunc, METHODS_NUMBER> LOG_CPP_METHODS = {
78    [] (const std::string &msg) {
79        HiLog::Debug(LABEL, "%{public}s", msg.c_str());
80    },
81    [] (const std::string &msg) {
82        HiLog::Info(LABEL, "%{public}s", msg.c_str());
83    },
84    [] (const std::string &msg) {
85        HiLog::Warn(LABEL, "%{public}s", msg.c_str());
86    },
87    [] (const std::string &msg) {
88        HiLog::Error(LABEL, "%{public}s", msg.c_str());
89    },
90    [] (const std::string &msg) {
91        HiLog::Fatal(LABEL, "%{public}s", msg.c_str());
92    },
93};
94
95static std::string PopenToString(const std::string &command)
96{
97    std::string str;
98    constexpr int bufferSize = 1024;
99    FILE *fp = popen(command.c_str(), "re");
100    if (fp != nullptr) {
101        char buf[bufferSize] = {0};
102        size_t n = fread(buf, 1, sizeof(buf), fp);
103        while (n > 0) {
104            str.append(buf, n);
105            n = fread(buf, 1, sizeof(buf), fp);
106        }
107        pclose(fp);
108    }
109    std::cout << "PopenToString res: " << str << std::endl;
110    return str;
111}
112
113class HiLogNDKTest : public testing::Test {
114public:
115    static void SetUpTestCase();
116    static void TearDownTestCase() {}
117    void SetUp();
118    void TearDown() {}
119};
120
121void HiLogNDKTest::SetUpTestCase()
122{
123    (void)PopenToString("hilog -Q pidoff");
124    (void)PopenToString("hilog -Q domainoff");
125}
126
127void HiLogNDKTest::SetUp()
128{
129    (void)PopenToString("hilog -r");
130}
131
132static std::string RandomStringGenerator()
133{
134    std::string str;
135    int logLen = 16;
136    char index;
137    for (int i = 0; i < logLen; ++i) {
138        index = rand() % ('z' - 'a') + 'a';
139        str.append(1, index);
140    }
141    return str;
142}
143
144static void HiLogWriteTest(LogInterfaceType methodType, unsigned int count,
145    const std::array<LogMethodFunc, METHODS_NUMBER> &logMethods)
146{
147    std::string logMsg(RandomStringGenerator());
148    for (unsigned int i = 0; i < count; ++i) {
149        logMethods.at(methodType)(logMsg + std::to_string(i));
150    }
151    usleep(1000); /* 1000: sleep 1 ms */
152    std::string logMsgs = PopenToString("/system/bin/hilog -x");
153    unsigned int realCount = 0;
154    std::stringstream ss(logMsgs);
155    std::string str;
156    while (!ss.eof()) {
157        getline(ss, str);
158        if (str.find(logMsg) != std::string::npos) {
159            ++realCount;
160        }
161    }
162    unsigned int allowedLeastLogCount = count - count * 1 / 10; /* 1 / 10: loss rate less than 10% */
163    if (methodType == DEBUG_METHOD) {
164        allowedLeastLogCount = 0; /* 0: debug log is allowed to be closed */
165    }
166    EXPECT_GE(realCount, allowedLeastLogCount);
167}
168
169static void FlowCtlTest(const HiLogLabel &label, const std::string keyWord)
170{
171    const std::string str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
172    for (unsigned int i = 0; i < OVER_LOGS; ++i) {
173        HiLog::Info(label, "%{public}s:%{public}d", str.c_str(), i);
174    }
175    sleep(1); /* 1: sleep 1 s */
176    HiLog::Info(label, "%{public}s", str.c_str());
177    std::string logMsgs = PopenToString("hilog -x -T LOGLIMIT");
178    EXPECT_TRUE(logMsgs.find(keyWord) != std::string::npos);
179}
180
181/**
182 * @tc.name: Dfx_HiLogNDKTest_PrintDebugLog_001
183 * @tc.desc: Call HILOG_DEBUG to print logs.
184 * @tc.type: FUNC
185 */
186HWTEST_F(HiLogNDKTest, PrintDebugLog_001, TestSize.Level1)
187{
188    /**
189     * @tc.steps: step1. Call HILOG_DEBUG to print logs and call hilog to read it
190     * @tc.expected: step1. Logs can be printed only if hilog.debug is enabled.
191     */
192    HiLogWriteTest(DEBUG_METHOD, SOME_LOGS, LOG_C_METHODS);
193}
194
195/**
196 * @tc.name: Dfx_HiLogNDKTest_PrintInfoLog_001
197 * @tc.desc: Call HILOG_INFO to print logs.
198 * @tc.type: FUNC
199 */
200HWTEST_F(HiLogNDKTest, PrintInfoLog_001, TestSize.Level1)
201{
202    /**
203     * @tc.steps: step1. Call HILOG_INFO to print logs and call hilog to read it
204     * @tc.expected: step1. Logs printed without loss.
205     */
206    HiLogWriteTest(INFO_METHOD, SOME_LOGS, LOG_C_METHODS);
207}
208
209/**
210 * @tc.name: Dfx_HiLogNDKTest_PrintWarnLog_001
211 * @tc.desc: Call HILOG_WARN to print logs.
212 * @tc.type: FUNC
213 */
214HWTEST_F(HiLogNDKTest, PrintWarnLog_001, TestSize.Level1)
215{
216    /**
217     * @tc.steps: step1. Call HILOG_WARN to print logs and call hilog to read it
218     * @tc.expected: step1. Logs printed without loss.
219     */
220    HiLogWriteTest(WARN_METHOD, SOME_LOGS, LOG_C_METHODS);
221}
222
223/**
224 * @tc.name: Dfx_HiLogNDKTest_PrintErrorLog_001
225 * @tc.desc: Call HILOG_ERROR to print logs.
226 * @tc.type: FUNC
227 */
228HWTEST_F(HiLogNDKTest, PrintErrorLog_001, TestSize.Level1)
229{
230    /**
231     * @tc.steps: step1. Call HILOG_ERROR to print logs and call hilog to read it
232     * @tc.expected: step1. Logs printed without loss.
233     */
234    HiLogWriteTest(ERROR_METHOD, SOME_LOGS, LOG_C_METHODS);
235}
236
237/**
238 * @tc.name: Dfx_HiLogNDKTest_PrintFatalLog_001
239 * @tc.desc: Call HILOG_FATAL to print logs.
240 * @tc.type: FUNC
241 */
242HWTEST_F(HiLogNDKTest, PrintFatalLog_001, TestSize.Level1)
243{
244    /**
245     * @tc.steps: step1. Call HILOG_FATAL to print logs and call hilog to read it
246     * @tc.expected: step1. Logs printed without loss.
247     */
248    HiLogWriteTest(FATAL_METHOD, SOME_LOGS, LOG_C_METHODS);
249}
250
251/**
252 * @tc.name: Dfx_HiLogNDKTest_LogLossCheck_001
253 * @tc.desc: HiLog log loss rate must less than 10%.
254 * @tc.type: FUNC
255 */
256HWTEST_F(HiLogNDKTest, LogLossCheck_001, TestSize.Level1)
257{
258    /**
259     * @tc.steps: step1. Call HILOG_INFO to print logs and call hilog to read it
260     * @tc.expected: step1. Calculate log loss rate and it should less than 10%
261     */
262    HiLogWriteTest(INFO_METHOD, MORE_LOGS, LOG_C_METHODS);
263}
264
265/**
266 * @tc.name: Dfx_HiLogNDKTest_PrintDebugLog_002
267 * @tc.desc: Call HiLog::Debug to print logs.
268 * @tc.type: FUNC
269 */
270HWTEST_F(HiLogNDKTest, PrintDebugLog_002, TestSize.Level1)
271{
272    /**
273     * @tc.steps: step1. Call HiLog::Debug to print logs and call hilog to read it
274     * @tc.expected: step1. Logs can be printed only if hilog.debug is enabled.
275     */
276    HiLogWriteTest(DEBUG_METHOD, SOME_LOGS, LOG_CPP_METHODS);
277}
278
279/**
280 * @tc.name: Dfx_HiLogNDKTest_PrintInfoLog_002
281 * @tc.desc: Call HiLog::Info to print logs.
282 * @tc.type: FUNC
283 */
284HWTEST_F(HiLogNDKTest, PrintInfoLog_002, TestSize.Level1)
285{
286    /**
287     * @tc.steps: step1. Call HiLog::Info to print logs and call hilog to read it
288     * @tc.expected: step1. Logs printed without loss.
289     */
290    HiLogWriteTest(INFO_METHOD, SOME_LOGS, LOG_CPP_METHODS);
291}
292
293/**
294 * @tc.name: Dfx_HiLogNDKTest_PrintWarnLog_002
295 * @tc.desc: Call HiLog::Warn print logs.
296 * @tc.type: FUNC
297 */
298HWTEST_F(HiLogNDKTest, PrintWarnLog_002, TestSize.Level1)
299{
300    /**
301     * @tc.steps: step1. Call HiLog::Warn to print logs and call hilog to read it
302     * @tc.expected: step1. Logs printed without loss.
303     */
304    HiLogWriteTest(WARN_METHOD, SOME_LOGS, LOG_CPP_METHODS);
305}
306
307/**
308 * @tc.name: Dfx_HiLogNDKTest_PrintErrorLog_002
309 * @tc.desc: Call HiLog::Error to print logs.
310 * @tc.type: FUNC
311 */
312HWTEST_F(HiLogNDKTest, PrintErrorLog_002, TestSize.Level1)
313{
314    /**
315     * @tc.steps: step1. Call HiLog::Error to print logs and call hilog to read it
316     * @tc.expected: step1. Logs printed without loss.
317     */
318    HiLogWriteTest(ERROR_METHOD, SOME_LOGS, LOG_CPP_METHODS);
319}
320
321/**
322 * @tc.name: Dfx_HiLogNDKTest_PrintFatalLog_002
323 * @tc.desc: Call HiLog::Fatal to print logs.
324 * @tc.type: FUNC
325 */
326HWTEST_F(HiLogNDKTest, PrintFatalLog_002, TestSize.Level1)
327{
328    /**
329     * @tc.steps: step1. Call HiLog::Fatal to print logs and call hilog to read it
330     * @tc.expected: step1. Logs printed without loss.
331     */
332    HiLogWriteTest(FATAL_METHOD, SOME_LOGS, LOG_CPP_METHODS);
333}
334
335/**
336 * @tc.name: Dfx_HiLogNDKTest_LogLossCheck_002
337 * @tc.desc: HiLog log loss rate must less than 10%
338 * @tc.type: FUNC
339 */
340HWTEST_F(HiLogNDKTest, LogLossCheck_002, TestSize.Level1)
341{
342    /**
343     * @tc.steps: step1. Call HiLog::Info to print logs and call hilog to read it
344     * @tc.expected: step1. Calculate log loss rate and it should less than 10%
345     */
346    HiLogWriteTest(INFO_METHOD, MORE_LOGS, LOG_CPP_METHODS);
347}
348
349/**
350 * @tc.name: Dfx_HiLogNDKTest_IsLoggable_001
351 * @tc.desc: Check whether is loggable for each log level
352 * @tc.type: FUNC
353 */
354HWTEST_F(HiLogNDKTest, IsLoggable_001, TestSize.Level1)
355{
356    /**
357     * @tc.steps: step1. Call HiLogIsLoggable to check whether is loggable for each log level.
358     * @tc.expected: step1. LOG_DEBUG and lower level should return false in release version, and others return true.
359     */
360    if (OHOS::system::GetParameter("hilog.loggable.global", "D") == "D") {
361        EXPECT_TRUE(HiLogIsLoggable(0xD002D00, LOG_TAG, LOG_DEBUG));
362    } else {
363        EXPECT_FALSE(HiLogIsLoggable(0xD002D00, LOG_TAG, LOG_DEBUG));
364    }
365    EXPECT_TRUE(HiLogIsLoggable(0xD002D00, LOG_TAG, LOG_INFO));
366    EXPECT_TRUE(HiLogIsLoggable(0xD002D00, LOG_TAG, LOG_WARN));
367    EXPECT_TRUE(HiLogIsLoggable(0xD002D00, LOG_TAG, LOG_ERROR));
368    EXPECT_TRUE(HiLogIsLoggable(0xD002D00, LOG_TAG, LOG_FATAL));
369    EXPECT_TRUE(HiLogIsLoggable(0xD002D00, "abc", LOG_WARN));
370}
371
372/**
373 * @tc.name: Dfx_HiLogNDKTest_DomainCheck_001
374 * @tc.desc: test illegal domainID
375 * @tc.type: FUNC
376 * @tc.require:issueI5NU4L
377 */
378HWTEST_F(HiLogNDKTest, DomainCheck_001, TestSize.Level1)
379{
380    (void)PopenToString("param set hilog.debug.on false");
381    (void)PopenToString("param set persist.sys.hilog.debug.on false");
382    std::string logMsg(RandomStringGenerator());
383    for (unsigned int i = 0; i < SOME_LOGS; ++i) {
384        HiLog::Info(ILLEGAL_DOMAIN_LABEL, "%{public}s", logMsg.c_str());
385    }
386    usleep(1000); /* 1000: sleep 1 ms */
387    std::string logMsgs = PopenToString("/system/bin/hilog -x");
388    unsigned int realCount = 0;
389    std::stringstream ss(logMsgs);
390    std::string str;
391    while (!ss.eof()) {
392        getline(ss, str);
393        if (str.find(logMsg) != std::string::npos) {
394            ++realCount;
395        }
396    }
397    EXPECT_EQ(realCount, 0);
398}
399
400/**
401 * @tc.name: Dfx_HiLogNDKTest_hilogSocketTest
402 * @tc.desc: Query hilog socket rights
403 * @tc.type: FUNC
404 * @tc.require:issueI5NU7F
405 */
406HWTEST_F(HiLogNDKTest, hilogSocketTest, TestSize.Level1)
407{
408    std::string str;
409    std::string hilogControlRights = "srw-rw----";
410    std::string logMsgs = PopenToString("ls -al //dev/unix/socket/hilogControl");
411    std::stringstream ss(logMsgs);
412    getline(ss, str);
413    EXPECT_TRUE(str.find(hilogControlRights) != std::string::npos);
414}
415
416/**
417 * @tc.name: Dfx_HiLogNDKTest_pidFlowCtrlTest
418 * @tc.desc: hilog pidFlowCtrlTest
419 * @tc.type: FUNC
420 */
421HWTEST_F(HiLogNDKTest, pidFlowCtrlTest, TestSize.Level1)
422{
423    (void)PopenToString("hilog -Q pidon");
424    const std::string pidCtrlLog = "DROPPED";
425    FlowCtlTest(APP_LABEL, pidCtrlLog);
426    (void)PopenToString("hilog -Q pidoff");
427}
428
429/**
430 * @tc.name: Dfx_HiLogNDKTest_domainFlowCtrlTest
431 * @tc.desc: hilog domainFlowCtrlTest
432 * @tc.type: FUNC
433 */
434HWTEST_F(HiLogNDKTest, domainFlowCtrlTest, TestSize.Level1)
435{
436    (void)PopenToString("hilog -Q domainon");
437    const std::string domainCtrlLog = "dropped";
438    FlowCtlTest(LABEL, domainCtrlLog);
439    (void)PopenToString("hilog -Q domainoff");
440}
441} // namespace HiLogTest
442} // namespace HiviewDFX
443} // namespace OHOS
444