1 /*
2 * Copyright (c) 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 <hilog_adapter.h>
17 #include <stdlib.h>
18 #include "functionalext.h"
19 #include "test.h"
20 #include <stdio.h>
21 #include <stdbool.h>
22 #include <time.h>
23 #include <errno.h>
24 #include <pthread.h>
25 #include <sys/un.h>
26 #include <bits/alltypes.h>
27 #include <sys/socket.h>
28 #include <linux/socket.h>
29 #include <fcntl.h>
30 #include <dirent.h>
31 #include <securec.h>
32 #include <libc.h>
33
34 #define MUSL_LOG_TYPE LOG_CORE
35 #define MUSL_LOG_DOMAIN 0xD003F00
36 #define MUSL_LOG_TAG "MUSL"
37 #define LOG_ERROR (6)
38 #define CLOSE_FD_COUNT (1024)
39
40 #define ENABLE_LOG "param set musl.log.enable true"
41 #define LOG_LEVEL_ERROR "param set musl.log.level ERROR"
42
43 #define MUSL_LOGE(...) ((void)HiLogAdapterPrint(MUSL_LOG_TYPE, LOG_ERROR, MUSL_LOG_DOMAIN, MUSL_LOG_TAG, __VA_ARGS__))
44
45 #define PRINT_STRING_A "HilogAdapterPrinttest_a"
46 #define PRINT_STRING_B "HilogAdapterPrinttest_b"
47 #define PRINT_STRING_C "HilogAdapterPrinttest_c"
48
49 #define ZERO (0)
50 #define TWO (2)
51 #define THREE (3)
52 #define NEGATIVE_ONE (-1)
53 #define INVALID_SOCKET (-1)
54 #define THREAD_COUNT (10)
55 #define STR_LENGTH (20)
56 char str[THREAD_COUNT][STR_LENGTH];
57
GenerateRandomString(char * randomString,int index)58 void GenerateRandomString(char* randomString, int index)
59 {
60 #define RANDOM_STRING_LENGTH (16)
61 #define RANDOM_STRING_END (18)
62 #define RANDOM_STRING_START (2)
63 // 将索引转换为字符串并拼接到随机字符串前面
64 (void)sprintf_s(randomString, STR_LENGTH, "%02d", index);
65
66 char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
67 int r = 0;
68 int num = 0;
69 int fd = open("/dev/random", O_RDONLY);
70 if (fd == NEGATIVE_ONE) {
71 strcpy_s(randomString + RANDOM_STRING_START, RANDOM_STRING_LENGTH, "MUSLHILOGFIXED");
72 } else {
73 for (int i = RANDOM_STRING_START; i < RANDOM_STRING_LENGTH; i++) {
74 read(fd, &r, sizeof(int));
75 // 非安全场景,使用种子确保随机字符串每次运行都不一样
76 randomString[i] = charset[r % (sizeof(charset) - 1)];
77 }
78 }
79 close(fd);
80 randomString[RANDOM_STRING_END] = '\0'; // 添加字符串结尾符
81 }
82
83 // 检查是否有相应的日志生成,如果有当前日志,则返回true,如果没有则返回false
CheckHiLogPrint(char * needToMatch)84 bool CheckHiLogPrint(char *needToMatch)
85 {
86 #define COMMAND_SIZE (50)
87 #define READ_SIZE (49)
88 #define BUFFER_SIZE (1024)
89 #define FAIL_CLOSE (-1)
90 bool flag = false;
91 // 1. 通过system函数读取当前hilog日志信息
92 char command[] = "/bin/hilog -x | grep ";
93 char finalCommand[COMMAND_SIZE];
94 int res = snprintf_s(finalCommand, COMMAND_SIZE, READ_SIZE, "%s%s", command, needToMatch);
95 if (res == NEGATIVE_ONE) {
96 printf("CheckHiLogPrint command generate snprintf_s failed\n");
97 return false;
98 }
99 finalCommand[READ_SIZE] = '\0';
100 char buffer[BUFFER_SIZE];
101 FILE* pipe;
102 pipe = popen(finalCommand, "r");
103 if (pipe == NULL) {
104 printf("CheckHiLogPrint: Failed to run command\n");
105 return false;
106 }
107
108 // 读取命令输出并打印
109 while (fgets(buffer, BUFFER_SIZE, pipe) != NULL) {
110 printf("%s", buffer);
111 flag = true;
112 }
113
114 // 关闭管道并获取返回值
115 int returnValue = pclose(pipe);
116 if (returnValue == FAIL_CLOSE) {
117 printf("CheckHiLogPrint pclose failed returnValue=-1 errno=%d\n", errno);
118 }
119 return flag;
120 }
121
122 // 子线程打印日志执行的函数
FunctionPrintLog(void * arg)123 void* FunctionPrintLog(void* arg)
124 {
125 int index = (int)arg;
126 int ret = HiLogAdapterPrint(MUSL_LOG_TYPE, LOG_ERROR, MUSL_LOG_DOMAIN, MUSL_LOG_TAG,
127 "FunctionPrintLog %{public}s", str[index]);
128 return NULL;
129 }
130 /**
131 * @tc.name : HiLogAdapterPrint_0010
132 * @tc.desc : Test HiLogAdapterPrint after musl_log_reset
133 * @tc.level : Level 2
134 */
HiLogAdapterPrint_0010(void)135 static void HiLogAdapterPrint_0010(void)
136 {
137 musl_log_reset();
138 int ret = HiLogAdapterPrint(MUSL_LOG_TYPE, LOG_ERROR, MUSL_LOG_DOMAIN, MUSL_LOG_TAG, PRINT_STRING_A);
139 EXPECT_NE("HiLogAdapterPrint_0010", ret, 0);
140 // 同时也要查看hilog
141 EXPECT_EQ("HiLogAdapterPrint_0010", CheckHiLogPrint(PRINT_STRING_A), true);
142 ret = HiLogAdapterPrint(MUSL_LOG_TYPE, LOG_INFO, MUSL_LOG_DOMAIN, MUSL_LOG_TAG, PRINT_STRING_B);
143 EXPECT_EQ("HiLogAdapterPrint_0010", ret, -1);
144 }
145
146 /**
147 * @tc.name : HilogAdapterPrint_0020
148 * @tc.desc : Test single thread HilogAdapterPrint after hilog fd close
149 * @tc.level : Level 2
150 */
HilogAdapterPrint_0020(void)151 static void HilogAdapterPrint_0020(void)
152 {
153 musl_log_reset();
154 // We need to refresh the hilog socket to close previous socket
155 RefreshHiLogSocketFd();
156 // 前置条件:校验g_socketFd无效
157 EXPECT_EQ("HilogAdapterPrint_0020 CheckHilogInvalid", CheckHilogValid(), ZERO);
158 int ret = HiLogAdapterPrint(MUSL_LOG_TYPE, LOG_ERROR, MUSL_LOG_DOMAIN, MUSL_LOG_TAG, PRINT_STRING_C);
159 // 检查g_socketFd有效
160 EXPECT_NE("HilogAdapterPrint_0020 CheckHilogValid", CheckHilogValid(), ZERO);
161 // 检查write正常
162 EXPECT_GT("HiLogAdapterPrint_0020", ret, 0);
163 bool result = CheckHiLogPrint(PRINT_STRING_C);
164 // 检查有日志生成
165 EXPECT_EQ("HilogAdapterPrint_0020_CheckHiLogPrint", result, true);
166 }
167
168 /**
169 * @tc.name : HilogAdapterPrint_0030
170 * @tc.desc : dls3阶段初始化异常时,线程自己初始化成功,
171 * 单线程:预期是能够替换g_socketFd,并能够正常打印日志
172 * 多线程:预期是能够替换g_socketFd,并能够正常打印日志,且fd未发生泄漏
173 * @tc.level : Level 2
174 */
HilogAdapterPrint_0030(void)175 static void HilogAdapterPrint_0030(void)
176 {
177 musl_log_reset();
178 // 关闭socketFd
179 RefreshHiLogSocketFd();
180 // 前置条件:校验g_socketFd无效
181 EXPECT_EQ("HilogAdapterPrint_0030 CheckHilogInvalid", CheckHilogValid(), ZERO);
182 pthread_t threads[THREAD_COUNT];
183 int threadCreateResult = -1;
184 printf("libc.can_do_threads=%d\n", libc.can_do_threads);
185 // 创建线程并发打印,每个线程打印的日志都不能丢
186 for (int i = ZERO; i < THREAD_COUNT; i++) {
187 // 生成一个随机字符串,然后将下标通过值传递给子线程,让子线程拿到全局的数据
188 GenerateRandomString(str[i], i);
189 if (libc.can_do_threads) {
190 threadCreateResult = pthread_create(&threads[i], NULL, FunctionPrintLog, (void *)i);
191 }
192 if (threadCreateResult != 0) {
193 fprintf(stderr, "Failed to create thread %d errno=%d\n", i, errno);
194 FunctionPrintLog((void *)i);
195 }
196 }
197
198 // 检查g_socketFd有效
199 EXPECT_NE("HilogAdapterPrint_0030 CheckHilogValid", CheckHilogValid(), ZERO);
200 // 等待线程执行完毕
201 for (int i = ZERO; i < THREAD_COUNT; i++) {
202 if (libc.can_do_threads && pthread_join(threads[i], NULL) != 0) {
203 fprintf(stderr, "Failed to join thread %d\n", i);
204 }
205 // 在这里判断当前日志是否打印成功
206 bool result = CheckHiLogPrint(str[i]);
207 EXPECT_EQ("HilogAdapterPrint_0030_CheckHiLogPrint", result, true);
208 }
209 }
210
main(void)211 int main(void)
212 {
213 // 解除限制
214 system("/bin/hilog -Q pidoff");
215 system("/bin/hilog -Q domainoff");
216
217 system(ENABLE_LOG);
218 system(LOG_LEVEL_ERROR);
219 HiLogAdapterPrint_0010();
220 HilogAdapterPrint_0020();
221 HilogAdapterPrint_0030();
222
223 // 恢复限制
224 system("/bin/hilog -Q pidon");
225 system("/bin/hilog -Q domainon");
226 return t_status;
227 }
228