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 <info/fatal_message.h>
17
18#include <errno.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <test.h>
23#include <pthread.h>
24#include <unistd.h>
25#include <sys/wait.h>
26
27#define EXPECT_TRUE(c)                \
28    do                                \
29    {                                 \
30        if (!(c))                     \
31            t_error("[%s] failed\n"); \
32    } while (0)
33
34#define FORK(fpid)                    \
35    do                                \
36    {                                 \
37        if (fpid < 0) {               \
38            t_error("error in fork!");\
39        }                             \
40    } while (0)
41
42typedef void (*TEST_FUN)(void);
43static const int WAIT_TIME = 1;
44
45/**
46 * @tc.name      : get_fatal_message
47 * @tc.desc      : Test the function of get_fatal_message.
48 * @tc.level     : Level 0
49 */
50static void fatal_message_0010(void)
51{
52    fatal_msg_t *fatal_message = get_fatal_message();
53    EXPECT_TRUE(fatal_message == NULL);
54}
55
56/**
57 * @tc.name      : set_fatal_message
58 * @tc.desc      : Test the function of set_fatal_message.
59 * @tc.level     : Level 0
60 */
61static void fatal_message_0020(void)
62{
63    const char msg[1024] = {"abcdefghijklmnopqrstuvwxyz1234567890"};
64    fatal_msg_t *fatal_message = NULL;
65
66    int childRet = 0;
67    int pidParent = 0;
68    int pidChild = 0;
69
70    pid_t fpid;
71    fpid = fork();
72    FORK(fpid);
73    if (fpid == 0) {
74        pidChild = getpid();
75        set_fatal_message(msg);
76        fatal_message = get_fatal_message();
77        EXPECT_TRUE(strcmp(fatal_message->msg, msg) == 0);
78        exit(0);
79    }
80    waitpid(fpid, &childRet, 0);
81    EXPECT_TRUE(childRet == 0);
82}
83
84/**
85 * @tc.name      : set_fatal_message
86 * @tc.desc      : Test the multiple processes of set_fatal_message.
87 * @tc.level     : Level 0
88 */
89static void fatal_message_0030(void)
90{
91    fatal_msg_t *fatal_message = NULL;
92
93    const char msgChild[1024] = {"msgChild"};
94    const char msgParent[1024] = {"msgParent"};
95
96    int childRet = 0;
97    int pidChild = 0;
98    int pidParent = 0;
99    int pidCParent = 0;
100    int pidCChild = 0;
101
102    pid_t fpid;
103
104    // start process
105    fpid = fork();
106    FORK(fpid);
107    if (fpid == 0) {
108        pidChild = getpid();
109    } else {
110        pidParent = getpid();
111        pid_t fpidChild;
112
113        // start process again
114        fpidChild = fork();
115        if (fpidChild < 0) {
116            t_printf("error in fork!");
117        } else if (fpidChild == 0) {
118            pidCChild = getpid();
119            set_fatal_message(msgParent);
120            fatal_message = get_fatal_message();
121            EXPECT_TRUE(strcmp(fatal_message->msg, msgParent) == 0);
122            exit(0);
123        } else {
124            pidCParent = getpid();
125            set_fatal_message(msgChild);
126            fatal_message = get_fatal_message();
127            EXPECT_TRUE(strcmp(fatal_message->msg, msgChild) == 0);
128            waitpid(fpidChild, &childRet, 0);
129            EXPECT_TRUE(childRet == 0);
130        }
131    }
132}
133
134/**
135 * @tc.name      : set_fatal_message
136 * @tc.desc      : Test the multiple processes of set_fatal_message,
137*                  One of the threads crashed.
138 * @tc.level     : Level 0
139 */
140static void fatal_message_0040(void)
141{
142    fatal_msg_t *fatal_message = NULL;
143
144    const char msgChild[1024] = {"msgChild004"};
145    const char msgParent[1024] = {"msgParent004"};
146
147    int childRet = 0;
148    int pidChild = 0;
149    int pidParent = 0;
150    int pidCParent = 0;
151    int pidCChild = 0;
152
153    pid_t fpid;
154
155    // start process
156    fpid = fork();
157    FORK(fpid);
158    if (fpid == 0) {
159        pidChild = getpid();
160    } else {
161        pidParent = getpid();
162        pid_t fpidChild;
163
164        // start process again
165        fpidChild = fork();
166        if (fpidChild < 0) {
167            t_printf("error in fork!");
168        } else if (fpidChild == 0) {
169            pidCChild = getpid();
170            char *str = NULL;
171            str[0] = 0;
172            // Process crash. Unable to continue calling the set_fatal_message interface
173        } else {
174            pidCParent = getpid();
175            set_fatal_message(msgParent);
176            fatal_message = get_fatal_message();
177            EXPECT_TRUE(strcmp(fatal_message->msg, msgParent) == 0);
178            waitpid(fpidChild, &childRet, 0);
179            EXPECT_TRUE(childRet != 0);
180        }
181    }
182}
183
184void *ThreadFun1(void *arg)
185{
186    if (arg == NULL) {
187        t_printf("ThreadFun1 arg is NULL");
188    }
189    fatal_msg_t *fatal_message = get_fatal_message();
190    EXPECT_TRUE(strcmp(fatal_message->msg, (char *)arg) == 0);
191    pthread_exit("ThreadFun1 Exit");
192}
193
194void *ThreadFun2(void *arg)
195{
196    if (arg == NULL) {
197        t_printf("ThreadFun2 arg is NULL");
198    }
199    fatal_msg_t *fatal_message = get_fatal_message();
200    EXPECT_TRUE(strcmp(fatal_message->msg, (char *)arg) == 0);
201    pthread_exit("ThreadFun2 Exit");
202}
203
204/**
205 * @tc.name      : set_fatal_message
206 * @tc.desc      : Test the multithreading of set_fatal_message.
207 * @tc.level     : Level 0
208 */
209static void fatal_message_0050(void)
210{
211    const char msgThread[1024] = {"msgThread"};
212    int res;
213    pthread_t fatalMessageThread1, fatalMessageThread2;
214
215    set_fatal_message(msgThread);
216    res = pthread_create(&fatalMessageThread1, NULL, ThreadFun1, (void *)msgThread);
217    if (res != 0) {
218        t_printf("pthread_create1 error.");
219    }
220    sleep(WAIT_TIME);
221
222    res = pthread_create(&fatalMessageThread2, NULL, ThreadFun2, (void *)msgThread);
223    if (res != 0) {
224        t_printf("pthread_create2 error.");
225    }
226    pthread_join(fatalMessageThread1, NULL);
227    pthread_join(fatalMessageThread2, NULL);
228}
229
230/**
231 * @tc.name      : set_fatal_message
232 * @tc.desc      : Test the function of null message.
233 * @tc.level     : Level 0
234 */
235static void fatal_message_0060(void)
236{
237    const char* msg = NULL;
238    fatal_msg_t *fatal_message = NULL;
239
240    int pidChild = 0;
241
242    pid_t fpid;
243    fpid = fork();
244    FORK(fpid);
245    if (fpid == 0) {
246        pidChild = getpid();
247        set_fatal_message(msg);
248        fatal_message = get_fatal_message();
249        EXPECT_TRUE(fatal_message == NULL);
250        exit(pidChild);
251    }
252}
253
254/**
255 * @tc.name      : set_fatal_message
256 * @tc.desc      : Test the function of multi call set_fatal_message.
257 * @tc.level     : Level 0
258 */
259static void fatal_message_0070(void)
260{
261    const char msg[1024] = {"abcdefghijklmnopqrstuvwxyz1234567890"};
262    const char msg1[1024] = {"abcdefghijklmnopqr"};
263    fatal_msg_t *fatal_message = NULL;
264
265    int pidParent = 0;
266    int pidChild = 0;
267
268    pid_t fpid;
269    fpid = fork();
270    if (fpid < 0) {
271        t_printf("error in fork!");
272    } else if (fpid == 0) {
273        pidChild = getpid();
274        set_fatal_message(msg);
275        fatal_message = get_fatal_message();
276        EXPECT_TRUE(strcmp(fatal_message->msg, msg) == 0);
277
278        set_fatal_message(msg1);
279        fatal_message = get_fatal_message();
280        EXPECT_TRUE(strcmp(fatal_message->msg, msg) == 0);
281
282        exit(pidChild);
283    }
284}
285
286
287TEST_FUN G_Fun_Array[] = {
288    fatal_message_0010,
289    fatal_message_0020,
290    fatal_message_0030,
291    fatal_message_0040,
292    fatal_message_0050,
293    fatal_message_0060,
294    fatal_message_0070
295};
296
297int main(void)
298{
299    int childPid, childRet;
300    int num = sizeof(G_Fun_Array) / sizeof(TEST_FUN);
301    for (int pos = 0; pos < num; ++pos) {
302        // Run each function in a new process to
303        // keep the initial state of fatal_message.
304        if ((childPid = fork()) == 0) {
305            G_Fun_Array[pos]();
306            exit(0);
307        }
308        waitpid(childPid, &childRet, 0);
309        EXPECT_TRUE(childRet == 0);
310    }
311
312    return t_status;
313}
314