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>
20 using namespace testing::ext;
21 using namespace std;
22 
23 namespace OHOS {
24 namespace {
25 static int times = 0;
26 using ThreadRunFunc = bool (*)(int& data);
27 
28 class UtilsThreadTest : public testing::Test {
29 public:
30     static void SetUpTestCase(void);
31     static void TearDownTestCase(void);
32     void SetUp();
33     void TearDown();
34 };
35 
SetUpTestCase(void)36 void UtilsThreadTest::SetUpTestCase(void)
37 {
38     // input testsuit setup step
39 }
40 
TearDownTestCase(void)41 void UtilsThreadTest::TearDownTestCase(void)
42 {
43     // input testsuit teardown step
44 }
45 
SetUp(void)46 void UtilsThreadTest::SetUp(void)
47 {
48     // recover times
49     times = 0;
50 }
51 
TearDown(void)52 void UtilsThreadTest::TearDown(void)
53 {
54     // recover times
55     times = 0;
56 }
57 
TestRun01(int & data)58 bool TestRun01(int& data)
59 {
60     ++data;
61     return false;
62 }
63 
TestRun02(int & data)64 bool TestRun02(int& data)
65 {
66     ++data;
67     return true;
68 }
69 
TestRun03(int & data)70 bool 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 
81 constexpr int DEFAULT_PRIO = 0;
82 const std::string& DEFAULT_THREAD_NAME = "default";
83 
84 class TestThread : public OHOS::Thread {
85 public:
TestThread(const int data,const bool readyToWork,ThreadRunFunc runFunc)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;
~TestThread()91     ~TestThread() {}
92 
93     bool ReadyToWork() override;
94 
95     int data_;
96     int priority_;
97     std::string name_;
98 protected:
99     bool Run() override;
100 
101 private:
102     bool readyToWork_;
103     ThreadRunFunc runFunc_;
104 };
105 
ReadyToWork()106 bool TestThread::ReadyToWork()
107 {
108     return readyToWork_;
109 }
110 
Run()111 bool 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  */
129 HWTEST_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  */
157 HWTEST_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  */
185 HWTEST_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  */
212 HWTEST_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  */
240 HWTEST_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  */
267 HWTEST_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  */
300 HWTEST_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  */
324 HWTEST_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 
342 class TestThread2 : public OHOS::Thread {
343 public:
TestThread2(const int data,ThreadRunFunc runFunc)344     TestThread2(const int data, ThreadRunFunc runFunc)
345         : data_(data), priority_(DEFAULT_PRIO), name_(DEFAULT_THREAD_NAME), runFunc_(runFunc)
346         {};
347 
348     TestThread2() = delete;
~TestThread2()349     ~TestThread2() {}
350 
351     int data_;
352     int priority_;
353     std::string name_;
354 protected:
355     bool Run() override;
356 
357 private:
358     ThreadRunFunc runFunc_;
359 };
360 
Run()361 bool 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  */
379 HWTEST_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