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#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <stdlib.h>
19#include <limits.h>
20#include <sys/shm.h>
21#include <assert.h>
22#include <unistd.h>
23#include <gtest/gtest.h>
24#include "utils.h"
25#include "mt_utils.h"
26#include "log.h"
27#include "KernelConstants.h"
28
29using namespace testing::ext;
30
31class ProcessTest : public::testing::Test {
32};
33
34/**
35 * @tc.number   SUB_KERNEL_PROCESS_LINE_BIGEXIT_0100
36 * @tc.name     Basic test about _Exit
37 * @tc.desc     [C- SOFTWARE -0200]
38 */
39HWTEST_F(ProcessTest, testLineBigExit, Function | MediumTest | Level2)
40{
41    int exitCode;
42    pid_t pid;
43    int reInt[4] = {0, 1, 100, 255};
44
45    for (int i = 0; i < sizeof(reInt) / sizeof(int); i++) {
46        pid = fork();
47        ASSERT_TRUE(pid >= 0) << "> parent: fork errno = " << errno;
48        if (pid == 0) {
49            _Exit(reInt[i]);
50        }
51        Msleep(50);
52        exitCode = 0;
53        ASSERT_EQ(CheckProcStatus(pid, &exitCode, 0), 1);
54        ASSERT_EQ(exitCode, reInt[i]);
55    }
56}
57
58/**
59 * @tc.number   SUB_KERNEL_PROCESS_LINE_BIGEXIT_0200
60 * @tc.name     Test _Exit about IO flush
61 * @tc.desc     [C- SOFTWARE -0200]
62 */
63HWTEST_F(ProcessTest, testLineBigExitFlush, Function | MediumTest | Level3)
64{
65    const char* testFile = "TEST_FILE.txt";
66    char writeBuf[] = "this is a file";
67    char readBuf[20] = {0};
68    pid_t pid;
69
70    pid = fork();
71    ASSERT_TRUE(pid >= 0) << "> parent: fork errno = " << errno;
72    if (pid == 0) {
73
74        // write
75        FILE *fp = fopen(testFile, "w+");
76        if (fp == nullptr) {
77            LOG("> child fopen errno = %d", errno);
78            _Exit(1);
79        }
80        fwrite(writeBuf, sizeof(writeBuf), 1, fp);
81        _Exit(0);
82    }
83
84    WaitProcExitedOK(pid);
85
86    // read
87    FILE *fp = fopen(testFile, "r+");
88    ASSERT_NE(fp, nullptr) << "> fopen errno = " << errno;
89    EXPECT_EQ(fread(readBuf, sizeof(writeBuf), 1, fp), 0);
90    EXPECT_STRNE(writeBuf, readBuf) << "> writeBuf = " << writeBuf\
91                                    << "\n> readBuf = " << readBuf;
92    EXPECT_NE(fclose(fp), -1) << "> fclose errno =" <<errno;
93    remove(testFile);
94}
95
96int g_shmid0;
97
98void AtexitCallback0(void)
99{
100    LOG("> AtexitCallback0");
101    pid_t *shared = (int*)shmat(g_shmid0, nullptr, 0);
102    if (shared == (void *)-1) {
103        LOG("> AtexitCallback0 shmat errno = %d", errno);
104        _Exit(1);
105    }
106    *shared = getppid();
107    if ((shmdt(shared)) == -1) {
108        LOG("> AtexitCallback0 shmdt errno = %d", errno);
109        _Exit(1);
110    }
111    LOG("> 333");
112}
113
114/**
115 * @tc.number   SUB_KERNEL_PROCESS_LINE_BIGEXIT_0300
116 * @tc.name     Test _Exit about call functions registered with atexit
117 * @tc.desc     [C- SOFTWARE -0200]
118 */
119HWTEST_F(ProcessTest, testLineBigExitAtexit, Function | MediumTest | Level3)
120{
121    const int memSize = 1024;
122    g_shmid0 = shmget(IPC_PRIVATE, memSize, 0666 | IPC_CREAT);
123    ASSERT_NE(g_shmid0, -1) << "> parent: shmid errno = " << errno;
124    pid_t pid = fork();
125    ASSERT_TRUE(pid >= 0) << "> parent: fork errno = " << errno;
126    if (pid == 0) {
127        Msleep(20);
128        if (atexit(AtexitCallback0) != 0) {
129            _Exit(1);
130        }
131        LOG("> 222");
132        _Exit(0);
133    }
134    pid_t *shared = (int*)shmat(g_shmid0, nullptr, 0);
135    LOG("> 111");
136    WaitProcExitedOK(pid);
137    LOG("> 444");
138    ASSERT_NE(shared, (void*)-1) << "> shmat errno = " << errno;
139    EXPECT_NE(*shared, getpid());
140    ASSERT_NE(shmdt(shared), -1) << "> parent: shmdt errno = " << errno;
141    ASSERT_NE(shmctl(g_shmid0, IPC_RMID, nullptr), -1) << "> shmctl : IPC_RMID : errno = " << errno;
142}
143
144/**
145 * @tc.number   SUB_KERNEL_PROCESS_LINE_EXIT_0100
146 * @tc.name     Basic test about _exit
147 * @tc.desc     [C- SOFTWARE -0200]
148 */
149HWTEST_F(ProcessTest, testLineExit, Function | MediumTest | Level2)
150{
151    int exitCode;
152    pid_t pid;
153    int reInt[4] = {0, 1, 100, 255};
154
155    for (int i = 0; i < sizeof(reInt) / sizeof(int); i++) {
156        pid = fork();
157        ASSERT_TRUE(pid >= 0) << "> parent: fork errno = " << errno;
158        if (pid == 0) {
159            _exit(reInt[i]);
160        }
161        Msleep(50);
162        exitCode = 0;
163        ASSERT_EQ(CheckProcStatus(pid, &exitCode, 0), 1);
164        ASSERT_EQ(exitCode, reInt[i]);
165    }
166}
167
168/**
169 * @tc.number   SUB_KERNEL_PROCESS_LINE_EXIT_0200
170 * @tc.name     Test _exit about IO flush
171 * @tc.desc     [C- SOFTWARE -0200]
172 */
173HWTEST_F(ProcessTest, testLineExitFlush, Function | MediumTest | Level3)
174{
175    const char* testFile = "TEST_FILE.txt";
176    char writeBuf[] = "this is a file";
177    char readBuf[20] = {0};
178    pid_t pid;
179
180    pid = fork();
181    ASSERT_TRUE(pid >= 0) << "> parent: fork errno = " << errno;
182    if (pid == 0) {
183
184        // write
185        FILE *fp = fopen(testFile, "w+");
186        if (fp == nullptr) {
187            LOG("> child fopen errno = %d", errno);
188            _exit(1);
189        }
190        fwrite(writeBuf, sizeof(writeBuf), 1, fp);
191        _exit(0);
192    }
193
194    WaitProcExitedOK(pid);
195
196    // read
197    FILE *fp = fopen(testFile, "r+");
198    ASSERT_NE(fp, nullptr) << "> fopen errno = " << errno;
199    EXPECT_EQ(fread(readBuf, sizeof(writeBuf), 1, fp), 0);
200    EXPECT_STRNE(writeBuf, readBuf) << "> writeBuf = " << writeBuf\
201                                    << "\n> readBuf = " << readBuf;
202    EXPECT_NE(fclose(fp), -1) << "> fclose errno =" <<errno;
203    remove(testFile);
204}
205
206int g_shmid1;
207
208void AtexitCallback1(void)
209{
210    LOG("> AtexitCallback0");
211    pid_t *shared = (int*)shmat(g_shmid1, nullptr, 0);
212    if (shared == (void *)-1) {
213        LOG("> AtexitCallback0 shmat errno = %d", errno);
214        _exit(1);
215    }
216    *shared = getppid();
217    if ((shmdt(shared)) == -1) {
218        LOG("> AtexitCallback0 shmdt errno = %d", errno);
219        _exit(1);
220    }
221    LOG("> 333");
222}
223
224/**
225 * @tc.number   SUB_KERNEL_PROCESS_LINE_EXIT_0300
226 * @tc.name     Test _exit about call functions registered with atexit
227 * @tc.desc     [C- SOFTWARE -0200]
228 */
229HWTEST_F(ProcessTest, testLineExitAtexit, Function | MediumTest | Level3)
230{
231    const int memSize = 1024;
232    g_shmid1 = shmget(IPC_PRIVATE, memSize, 0666 | IPC_CREAT);
233    ASSERT_NE(g_shmid1, -1) << "> parent: shmid errno = " << errno;
234    pid_t pid = fork();
235    ASSERT_TRUE(pid >= 0) << "> parent: fork errno = " << errno;
236    if (pid == 0) {
237        Msleep(20);
238        if (atexit(AtexitCallback1) != 0) {
239            _exit(1);
240        }
241        LOG("> 222");
242        _exit(0);
243    }
244    pid_t *shared = (int*)shmat(g_shmid1, nullptr, 0);
245    LOG("> 111");
246    WaitProcExitedOK(pid);
247    LOG("> 444");
248    ASSERT_NE(shared, (void*)-1) << "> shmat errno = " << errno;
249    EXPECT_NE(*shared, getpid());
250    ASSERT_NE(shmdt(shared), -1) << "> parent: shmdt errno = " << errno;
251    ASSERT_NE(shmctl(g_shmid1, IPC_RMID, nullptr), -1) << "> shmctl : IPC_RMID : errno = " << errno;
252}
253
254/**
255 * @tc.number   SUB_KERNEL_PROCESS_EXIT_0100
256 * @tc.name     Basic test about exit
257 * @tc.desc     [C- SOFTWARE -0200]
258 */
259HWTEST_F(ProcessTest, testExit, Function | MediumTest | Level2)
260{
261    int exitCode;
262    pid_t pid;
263    int reInt[4] = {0, 1, 100, 255};
264
265    for (int i = 0; i < sizeof(reInt) / sizeof(int); i++) {
266        pid = fork();
267        ASSERT_TRUE(pid >= 0) << "> parent: fork errno = " << errno;
268        if (pid == 0) {
269            exit(reInt[i]);
270        }
271        Msleep(50);
272        exitCode = 0;
273        ASSERT_EQ(CheckProcStatus(pid, &exitCode, 0), 1);
274        ASSERT_EQ(exitCode, reInt[i]);
275    }
276}
277/**
278 * @tc.number   SUB_KERNEL_PROCESS_ASSERT_0100
279 * @tc.name     Basic test about assert true
280 * @tc.desc     [C- SOFTWARE -0200]
281 */
282HWTEST_F(ProcessTest, testAssertTrue, Function | MediumTest | Level3)
283{
284    pid_t pid = fork();
285    ASSERT_TRUE(pid >= 0) << "> parent: fork errno = " << errno;
286    if (pid == 0) {
287        assert(true);
288        exit(0);
289    }
290    Msleep(50);
291    WaitProcExitedOK(pid);
292}
293
294int FunctionAssertFalse(void)
295{
296    pid_t pid = fork();
297    if (pid < 0) {
298        LOG("> fork errno = %d", errno);
299        return 0;
300    } else if (pid == 0) {
301        assert(false);
302        LOG("> child not stop");
303        exit(0);
304    }
305    Msleep(50);
306    int exitCode = 0;
307    int reInt = CheckProcStatus(pid, &exitCode, 0);
308    if ((reInt == 2) && (exitCode == SIGABRT)) {
309        LOG("> Success");
310        return 1;
311    }
312    LOG("> Fail");
313    return 0;
314}
315
316/**
317 * @tc.number   SUB_KERNEL_PROCESS_ASSERT_0200
318 * @tc.name     Basic test about assert false
319 * @tc.desc     [C- SOFTWARE -0200]
320 */
321HWTEST_F(ProcessTest, testAssertFalse, Function | MediumTest | Level3)
322{
323    pid_t pid = fork();
324    ASSERT_TRUE(pid >= 0) << "> parent: fork errno = " << errno;
325    if (pid == 0) {
326        assert(false);
327        LOG("> child not stop");
328        exit(0);
329    }
330    Msleep(50);
331    int exitCode = 0;
332    ASSERT_EQ(CheckProcStatus(pid, &exitCode, 0), 2);
333    ASSERT_EQ(exitCode, SIGABRT);
334}
335
336int g_shmid;
337
338void AtexitCallback(void)
339{
340    LOG("> AtexitCallback");
341    pid_t *shared = (int*)shmat(g_shmid, nullptr, 0);
342    if (shared == (void *)-1) {
343        LOG("> AtexitCallback shmat errno = %d", errno);
344        exit(1);
345    }
346    *shared = getppid();
347    if ((shmdt(shared)) == -1) {
348        LOG("> AtexitCallback shmdt errno = %d", errno);
349        exit(1);
350    }
351}
352
353/**
354 * @tc.number   SUB_KERNEL_PROCESS_ATEXIT_0100
355 * @tc.name     Basic test about atexit
356 * @tc.desc     [C- SOFTWARE -0200]
357 */
358HWTEST_F(ProcessTest, testAtexit, Function | MediumTest | Level3)
359{
360    const int memSize = 1024;
361    g_shmid = shmget(IPC_PRIVATE, memSize, 0666 | IPC_CREAT);
362    ASSERT_NE(g_shmid, -1) << "> parent: shmid errno = " << errno;
363    pid_t pid = fork();
364    ASSERT_TRUE(pid >= 0) << "> parent: fork errno = " << errno;
365    if (pid == 0) {
366        Msleep(20);
367        if (atexit(AtexitCallback) != 0) {
368            LOG("> atexit errno = %d", errno);
369            exit(1);
370        }
371        exit(0);
372    }
373    pid_t *shared = (int*)shmat(g_shmid, nullptr, 0);
374
375    WaitProcExitedOK(pid);
376    ASSERT_NE(shared, (void*)-1) << "> shmat errno = " << errno;
377    EXPECT_EQ(*shared, getpid());
378    ASSERT_NE(shmdt(shared), -1) << "> parent: shmdt errno = " << errno;
379    ASSERT_NE(shmctl(g_shmid, IPC_RMID, nullptr), -1) << "> shmctl : IPC_RMID : errno = " << errno;
380}
381
382/**
383 * @tc.number     SUB_KERNEL_PROCESS_WAIT_0100
384 * @tc.name       test wait return
385 * @tc.desc       [C- SOFTWARE -0200]
386 */
387HWTEST_F(ProcessTest, testWaitReturn, Function | MediumTest | Level3)
388{
389    InitGlobalVariable();
390    pid_t pid = fork();
391    ASSERT_TRUE(pid >= 0) << "> fork errno = " << errno;
392    if (pid == 0) {
393        int myPid = (int)getpid();
394        LOG("> child pid = %d", myPid);
395        SetGlobalVariable(myPid);
396        exit(0);
397    }
398    Msleep(20);
399    int pidChild = (int)wait(nullptr);
400    LOG("> pidChild = %d", pidChild);
401    int expectPid = GetGlobalVariable();
402    EXPECT_EQ(pidChild, expectPid);
403    DeleteGlobalVariable();
404}
405
406
407/**
408 * @tc.number     SUB_KERNEL_PROCESS_WAIT_0200
409 * @tc.name       test wait parameter
410 * @tc.desc       [C- SOFTWARE -0200]
411 */
412HWTEST_F(ProcessTest, testWaitTest, Function | MediumTest | Level3)
413{
414    int childReturn = GetRandom(256) - 1;
415    LOG("> childReturn = %d", childReturn);
416
417    pid_t pid = fork();
418    ASSERT_TRUE(pid >= 0) << "> fork errno = " << errno;
419    if (pid == 0) {
420        exit(childReturn);
421    }
422    Msleep(20);
423    int status = 0;
424    int pidChild = (int)wait(&status);
425    EXPECT_NE(pidChild, -1);
426    EXPECT_TRUE(WIFEXITED(status));
427    EXPECT_EQ(WEXITSTATUS(status), childReturn);
428}
429
430/**
431 * @tc.number     SUB_KERNEL_PROCESS_WAIT_0300
432 * @tc.name       test wait killed by SIGABRT
433 * @tc.desc       [C- SOFTWARE -0200]
434 */
435HWTEST_F(ProcessTest, testWaitKilled, Function | MediumTest | Level3)
436{
437    pid_t pid = fork();
438    ASSERT_TRUE(pid >= 0) << "> fork errno = " << errno;
439    if (pid == 0) {
440        Msleep(40);
441        exit(0);
442    }
443    Msleep(20);
444    kill(pid, SIGABRT);
445    int status = 0;
446    int pidChild = (int)wait(&status);
447    EXPECT_NE(pidChild, -1);
448    EXPECT_TRUE(WIFSIGNALED(status));
449    EXPECT_EQ(WTERMSIG(status), SIGABRT);
450}
451
452/**
453 * @tc.number     SUB_KERNEL_PROCESS_WAITPID_0100
454 * @tc.name       waitpid basic test
455 * @tc.desc       [C- SOFTWARE -0200]
456 */
457HWTEST_F(ProcessTest, testWaitPidBasic, Function | MediumTest | Level3)
458{
459    int childReturn = GetRandom(128) - 1;
460    LOG("> childReturn = %d", childReturn);
461
462    pid_t pid = fork();
463    ASSERT_TRUE(pid >= 0) << "> fork errno = " << errno;
464    if (pid == 0) {
465        exit(childReturn);
466    }
467    Msleep(20);
468    int status = 0;
469    int pidChild = (int)waitpid(pid, &status, 0);
470    EXPECT_NE(pidChild, -1);
471    EXPECT_TRUE(WIFEXITED(status));
472    EXPECT_EQ(WEXITSTATUS(status), childReturn);
473}
474
475/**
476 * @tc.number     SUB_KERNEL_PROCESS_WAITPID_0200
477 * @tc.name       test waitpid with WNOHANG
478 * @tc.desc       [C- SOFTWARE -0200]
479 */
480HWTEST_F(ProcessTest, testWaitPidTest, Function | MediumTest | Level3)
481{
482    InitGlobalVariable();
483    SetGlobalVariable(1);
484    pid_t pid = fork();
485    ASSERT_TRUE(pid >= 0) << "> fork errno = " << errno;
486    if (pid == 0) {
487        Msleep(50);
488        SetGlobalVariable(2);
489        exit(0);
490    }
491    Msleep(20);
492    int status = 0;
493    int pidChild = (int)waitpid(pid, &status, WNOHANG);
494    int expectPid = GetGlobalVariable();
495    EXPECT_EQ(expectPid, 1);
496    EXPECT_EQ(pidChild, 0);
497    Msleep(50);
498    WaitProcExitedOK(pid);
499    DeleteGlobalVariable();
500}
501