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 <gtest/gtest.h>
16#include "thread_ex.h"
17#include <iostream>
18#include <cstdio>
19#include <sys/prctl.h>
20using namespace testing::ext;
21using namespace std;
22
23namespace OHOS {
24namespace {
25static int times = 0;
26using ThreadRunFunc = bool (*)(int& data);
27
28class UtilsThreadTest : public testing::Test {
29public:
30    static void SetUpTestCase(void);
31    static void TearDownTestCase(void);
32    void SetUp();
33    void TearDown();
34};
35
36void UtilsThreadTest::SetUpTestCase(void)
37{
38    // input testsuit setup step
39}
40
41void UtilsThreadTest::TearDownTestCase(void)
42{
43    // input testsuit teardown step
44}
45
46void UtilsThreadTest::SetUp(void)
47{
48    // recover times
49    times = 0;
50}
51
52void UtilsThreadTest::TearDown(void)
53{
54    // recover times
55    times = 0;
56}
57
58bool TestRun01(int& data)
59{
60    ++data;
61    return false;
62}
63
64bool TestRun02(int& data)
65{
66    ++data;
67    return true;
68}
69
70bool TestRun03(int& data)
71{
72    static const int TRY_TIMES = 10;
73    if (times <= TRY_TIMES) {
74        ++data;
75        return true;
76    }
77
78    return false;
79}
80
81constexpr int DEFAULT_PRIO = 0;
82const std::string& DEFAULT_THREAD_NAME = "default";
83
84class TestThread : public OHOS::Thread {
85public:
86    TestThread(const int data, const bool readyToWork, ThreadRunFunc runFunc)
87        : data_(data), priority_(DEFAULT_PRIO), name_(DEFAULT_THREAD_NAME), readyToWork_(readyToWork), runFunc_(runFunc)
88        {};
89
90    TestThread() = delete;
91    ~TestThread() {}
92
93    bool ReadyToWork() override;
94
95    int data_;
96    int priority_;
97    std::string name_;
98protected:
99    bool Run() override;
100
101private:
102    bool readyToWork_;
103    ThreadRunFunc runFunc_;
104};
105
106bool TestThread::ReadyToWork()
107{
108    return readyToWork_;
109}
110
111bool TestThread::Run()
112{
113    priority_ = getpriority(PRIO_PROCESS, 0);
114    char threadName[MAX_THREAD_NAME_LEN + 1] = {0};
115    prctl(PR_GET_NAME, threadName, 0, 0);
116    name_ = threadName;
117
118    if (runFunc_ != nullptr) {
119        return (*runFunc_)(data_);
120    }
121
122    return false;
123}
124
125/*
126 * @tc.name: testThread001
127 * @tc.desc: ThreadTest
128 */
129HWTEST_F(UtilsThreadTest, testThread001, TestSize.Level0)
130{
131    times = 0;
132    std::unique_ptr<TestThread> test = std::make_unique<TestThread>(0, false, TestRun01);
133    ThreadStatus status = test->Start("test_thread_01", THREAD_PROI_LOW, 1024);
134    EXPECT_EQ(status == ThreadStatus::OK, true);
135
136    pthread_t thread = test->GetThread();
137
138    // pthread_equal return non-zero if equal
139    EXPECT_EQ(pthread_equal(thread, -1) != 0, (test->IsRunning() ? false : true));
140
141    // ReadyToWork return false, RUN will not be called!
142    EXPECT_EQ(test->priority_, DEFAULT_PRIO);
143    EXPECT_EQ(test->name_, DEFAULT_THREAD_NAME);
144
145    // get stacksize of threa, may be different because of system memory align
146    EXPECT_EQ(test->data_, 0);
147    EXPECT_EQ(times, 0);
148    test->NotifyExitSync();
149    sleep(1);
150    EXPECT_EQ(pthread_equal(test->GetThread(), -1) != 0, (test->IsRunning() ? false : true));
151}
152
153/*
154 * @tc.name: testThread002
155 * @tc.desc: ThreadTest
156 */
157HWTEST_F(UtilsThreadTest, testThread002, TestSize.Level0)
158{
159    times = 0;
160    std::unique_ptr<TestThread> test = std::make_unique<TestThread>(0, true, TestRun01);
161    ThreadStatus status = test->Start("test_thread_02", THREAD_PROI_LOW, 1024);
162
163    EXPECT_EQ(status == ThreadStatus::OK, true);
164
165    sleep(1); // let the new thread has chance to run
166
167    // pthread_equal return non-zero if equal, RUN return false,may exit already
168    EXPECT_EQ(pthread_equal(test->GetThread(), -1) != 0, (test->IsRunning() ? false : true));
169
170    // ReadyToWork return true, RUN will be called!
171    EXPECT_EQ(test->priority_, THREAD_PROI_LOW);
172    EXPECT_EQ(test->name_, "test_thread_02");
173
174    EXPECT_EQ(test->data_, 1);
175    EXPECT_EQ(times, 0);
176    test->NotifyExitSync();
177    sleep(1);
178    EXPECT_EQ(pthread_equal(test->GetThread(), -1) != 0, (test->IsRunning() ? false : true));
179}
180
181/*
182 * @tc.name: testThread003
183 * @tc.desc: ThreadTest
184 */
185HWTEST_F(UtilsThreadTest, testThread003, TestSize.Level0)
186{
187    times = 0;
188    std::unique_ptr<TestThread> test = std::make_unique<TestThread>(0, false, TestRun02);
189    ThreadStatus status = test->Start("test_thread_03", THREAD_PROI_LOW, 1024);
190    EXPECT_EQ(status == ThreadStatus::OK, true);
191
192    pthread_t thread = test->GetThread();
193
194    // pthread_equal return non-zero if equal
195    EXPECT_EQ(pthread_equal(thread , -1) != 0, (test->IsRunning() ? false : true));
196
197    // ReadyToWork return false, RUN will not be called!
198    EXPECT_EQ(test->priority_, DEFAULT_PRIO);
199    EXPECT_EQ(test->name_, DEFAULT_THREAD_NAME);
200
201    EXPECT_EQ(test->data_, 0);
202    EXPECT_EQ(times, 0);
203    test->NotifyExitSync();
204    sleep(1);
205    EXPECT_EQ(pthread_equal(test->GetThread(), -1) != 0, (test->IsRunning() ? false : true));
206}
207
208/*
209 * @tc.name: testThread004
210 * @tc.desc: ThreadTest
211 */
212HWTEST_F(UtilsThreadTest, testThread004, TestSize.Level0)
213{
214    times = 0;
215    std::unique_ptr<TestThread> test = std::make_unique<TestThread>(0, true, TestRun02);
216    ThreadStatus status = test->Start("test_thread_04", THREAD_PROI_LOW, 1024);
217
218    EXPECT_EQ(status == ThreadStatus::OK, true);
219
220    sleep(1); // let the new thread has chance to run
221
222    // pthread_equal return non-zero if equal, RUN return false,may exit already
223    EXPECT_EQ(pthread_equal(test->GetThread(), -1) != 0, (test->IsRunning() ? false : true));
224
225    // ReadyToWork return true, RUN will be called!
226    EXPECT_EQ(test->priority_, THREAD_PROI_LOW);
227    EXPECT_EQ(test->name_, "test_thread_04");
228
229    EXPECT_GT(test->data_, 1);
230    EXPECT_EQ(times, 0);
231    test->NotifyExitSync();
232    sleep(1);
233    EXPECT_EQ(pthread_equal(test->GetThread(), -1) != 0, (test->IsRunning() ? false : true));
234}
235
236/*
237 * @tc.name: testThread005
238 * @tc.desc: ThreadTest
239 */
240HWTEST_F(UtilsThreadTest, testThread005, TestSize.Level0)
241{
242    times = 0;
243    std::unique_ptr<TestThread> test = std::make_unique<TestThread>(0, false, TestRun03);
244    ThreadStatus status = test->Start("test_thread_05", THREAD_PROI_LOW, 1024);
245    EXPECT_EQ(status == ThreadStatus::OK, true);
246
247    pthread_t thread = test->GetThread();
248
249    // pthread_equal return non-zero if equal
250    EXPECT_EQ(pthread_equal(thread , -1) != 0, (test->IsRunning() ? false : true));
251
252    // ReadyToWork return false, RUN will not be called!
253    EXPECT_EQ(test->priority_, DEFAULT_PRIO);
254    EXPECT_EQ(test->name_, DEFAULT_THREAD_NAME);
255
256    EXPECT_EQ(test->data_, 0);
257    EXPECT_EQ(times, 0);
258    test->NotifyExitSync();
259    sleep(1);
260    EXPECT_EQ(pthread_equal(test->GetThread(), -1) != 0, (test->IsRunning() ? false : true));
261}
262
263/*
264 * @tc.name: testThread006
265 * @tc.desc: ThreadTest
266 */
267HWTEST_F(UtilsThreadTest, testThread006, TestSize.Level0)
268{
269    times = 0;
270    std::unique_ptr<TestThread> test = std::make_unique<TestThread>(0, true, TestRun03);
271    ThreadStatus status = test->Start("test_thread_06", THREAD_PROI_LOW, 1024);
272
273    EXPECT_EQ(status == ThreadStatus::OK, true);
274
275    sleep(1); // let the new thread has chance to run
276
277    // pthread_equal return non-zero if equal, RUN return false,may exit already
278    EXPECT_EQ(pthread_equal(test->GetThread(), -1) != 0, (test->IsRunning() ? false : true));
279
280    // ReadyToWork return true, RUN will be called!
281    EXPECT_EQ(test->priority_, THREAD_PROI_LOW);
282    EXPECT_EQ(test->name_, "test_thread_06");
283
284    EXPECT_GT(test->data_, 10);
285    EXPECT_EQ(times, 0);
286
287    times = 100;
288    EXPECT_GT(test->data_, 10);
289
290    sleep(1); // let the new thread has chance to run
291
292    // times > 10, TestRun03 return false, thread exit
293    EXPECT_EQ(pthread_equal(test->GetThread(), -1) != 0, (test->IsRunning() ? false : true));
294}
295
296/*
297 * @tc.name: testThread007
298 * @tc.desc: ThreadTest
299 */
300HWTEST_F(UtilsThreadTest, testThread007, TestSize.Level0)
301{
302    times = 0;
303    std::unique_ptr<TestThread> test = std::make_unique<TestThread>(0, true, TestRun03);
304    ThreadStatus status = test->Start("", THREAD_PROI_LOW, 0);
305
306    EXPECT_EQ(status == ThreadStatus::OK, true);
307    if (test->IsRunning()) {
308        status = test->Start("", THREAD_PROI_NORMAL, 1024);
309        EXPECT_EQ(status == ThreadStatus::INVALID_OPERATION, true);
310
311        test->NotifyExitSync();
312        EXPECT_EQ(pthread_equal(test->GetThread(), -1) != 0, (test->IsRunning() ? false : true));
313    }
314
315    sleep(1); // let the new thread has chance to run
316
317    EXPECT_EQ(pthread_equal(test->GetThread(), -1) != 0, (test->IsRunning() ? false : true));
318}
319
320/*
321 * @tc.name: testThread008
322 * @tc.desc: ThreadTest
323 */
324HWTEST_F(UtilsThreadTest, testThread008, TestSize.Level0)
325{
326    times = 0;
327    std::unique_ptr<TestThread> test = std::make_unique<TestThread>(0, true, TestRun03);
328
329    bool res = test->Thread::ReadyToWork();
330    EXPECT_EQ(res, true);
331
332    ThreadStatus status = test->Start("", THREAD_PROI_NORMAL, 1024);
333    EXPECT_EQ(status == ThreadStatus::OK, true);
334
335    sleep(1);
336    test->NotifyExitAsync();
337
338    sleep(1); // let the new thread has chance to run
339    EXPECT_EQ(pthread_equal(test->GetThread(), -1) != 0, (test->IsRunning() ? false : true));
340}
341
342class TestThread2 : public OHOS::Thread {
343public:
344    TestThread2(const int data, ThreadRunFunc runFunc)
345        : data_(data), priority_(DEFAULT_PRIO), name_(DEFAULT_THREAD_NAME), runFunc_(runFunc)
346        {};
347
348    TestThread2() = delete;
349    ~TestThread2() {}
350
351    int data_;
352    int priority_;
353    std::string name_;
354protected:
355    bool Run() override;
356
357private:
358    ThreadRunFunc runFunc_;
359};
360
361bool TestThread2::Run()
362{
363    priority_ = getpriority(PRIO_PROCESS, 0);
364    char threadName[MAX_THREAD_NAME_LEN + 1] = {0};
365    prctl(PR_GET_NAME, threadName, 0, 0);
366    name_ = threadName;
367
368    if (runFunc_ != nullptr) {
369        return (*runFunc_)(data_);
370    }
371
372    return false;
373}
374
375/*
376 * @tc.name: testThread009
377 * @tc.desc: ThreadTest
378 */
379HWTEST_F(UtilsThreadTest, testThread009, TestSize.Level0)
380{
381    times = 0;
382    std::unique_ptr<TestThread2> test = std::make_unique<TestThread2>(0, TestRun03);
383
384    bool res = test->ReadyToWork();
385    EXPECT_EQ(res, true);
386
387    ThreadStatus status = test->Start("", THREAD_PROI_NORMAL, 1024);
388    EXPECT_EQ(status == ThreadStatus::OK, true);
389
390    sleep(1);
391    test->NotifyExitAsync();
392
393    sleep(1); // let the new thread has chance to run
394    EXPECT_EQ(pthread_equal(test->GetThread(), -1) != 0, (test->IsRunning() ? false : true));
395}
396
397}  // namespace
398}  // namespace OHOS