1 /*
2 * Copyright (c) 2021-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 <chrono>
17 #include <cstdio>
18 #include <sys/prctl.h>
19 #include <gtest/gtest.h>
20 #include "thread_pool.h"
21
22 using namespace testing::ext;
23
24 namespace OHOS {
25 namespace {
26 class UtilsThreadPoolTest : public testing::Test
27 {
28 public :
29 static void SetUpTestCase(void);
30 static void TearDownTestCase(void);
31 void SetUp();
32 void TearDown();
33 };
34
35 int g_times = 0;
36 bool g_ready = false;
37 std::mutex g_mutex;
38 std::condition_variable g_cv;
39
SetUpTestCase(void)40 void UtilsThreadPoolTest::SetUpTestCase(void)
41 {
42 // step 2: input testsuit setup step
43 }
44
TearDownTestCase(void)45 void UtilsThreadPoolTest::TearDownTestCase(void)
46 {
47 // step 2: input testsuit teardown step
48 }
49
SetUp(void)50 void UtilsThreadPoolTest::SetUp(void)
51 {
52 // recover
53 g_times = 0;
54 g_ready = false;
55 }
56
TearDown(void)57 void UtilsThreadPoolTest::TearDown(void)
58 {
59 // recover
60 g_times = 0;
61 g_ready = false;
62
63 }
64
65 HWTEST_F(UtilsThreadPoolTest, test_01, TestSize.Level0)
66 {
67 ThreadPool pool;
68 EXPECT_EQ(pool.GetName(), "");
69 EXPECT_EQ((int)pool.GetMaxTaskNum(), 0);
70 EXPECT_EQ((int)pool.GetThreadsNum(), 0);
71 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
72 }
73
74 HWTEST_F(UtilsThreadPoolTest, test_02, TestSize.Level0)
75 {
76 ThreadPool pool("test_02_pool");
77 EXPECT_EQ(pool.GetName(), "test_02_pool");
78 EXPECT_EQ((int)pool.GetMaxTaskNum(), 0);
79 EXPECT_EQ((int)pool.GetThreadsNum(), 0);
80 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
81 }
82
83 HWTEST_F(UtilsThreadPoolTest, test_03, TestSize.Level0)
84 {
85 ThreadPool pool("test_02_pool");
86 pool.SetMaxTaskNum(10);
87 EXPECT_EQ(pool.GetName(), "test_02_pool");
88 EXPECT_EQ((int)pool.GetMaxTaskNum(), 10);
89 EXPECT_EQ((int)pool.GetThreadsNum(), 0);
90 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
91 }
92
93 HWTEST_F(UtilsThreadPoolTest, test_04, TestSize.Level0)
94 {
95 ThreadPool pool;
96 pool.Start(4);
97 EXPECT_EQ(pool.GetName(), "");
98 EXPECT_EQ((int)pool.GetMaxTaskNum(), 0);
99 EXPECT_EQ((int)pool.GetThreadsNum(), 4);
100 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
101
102 // add no task, g_times has no change
103 EXPECT_EQ(g_times, 0);
104 pool.Stop();
105 }
106
TestFuncAddOneTime(int & i)107 void TestFuncAddOneTime(int& i)
108 {
109 ++g_times;
110 }
111
TestFuncSubOneTime(int & i)112 void TestFuncSubOneTime(int& i)
113 {
114 --g_times;
115 }
116
117 // simple task, total task num less than the MaxTaskNum
118 HWTEST_F(UtilsThreadPoolTest, test_05, TestSize.Level0)
119 {
120 ThreadPool pool;
121 pool.Start(5);
122 EXPECT_EQ(pool.GetName(), "");
123 EXPECT_EQ((int)pool.GetThreadsNum(), 5);
124 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
125
126 for (int i = 0; i < 3; ++i)
127 {
128 auto task = std::bind(TestFuncAddOneTime, i);
129 pool.AddTask(task);
130 }
131
132 for (int i = 0; i < 2; ++i)
133 {
134 auto task = std::bind(TestFuncSubOneTime, i);
135 pool.AddTask(task);
136 }
137
138 sleep(1);
139 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
140 // add 5 tasks, add 3 times and sub 2 times
141 EXPECT_EQ(g_times, 1);
142 pool.Stop();
143 }
144
145 // simaple task, total task num exceed the MaxTaskNum and the threads num
146 HWTEST_F(UtilsThreadPoolTest, test_06, TestSize.Level0)
147 {
148 ThreadPool pool;
149 pool.Start(5);
150 EXPECT_EQ(pool.GetName(), "");
151 EXPECT_EQ((int)pool.GetThreadsNum(), 5);
152 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
153
154 pool.SetMaxTaskNum(10);
155
156 for (int i = 0; i < 8; ++i)
157 {
158 auto task = std::bind(TestFuncAddOneTime, i);
159 pool.AddTask(task);
160 }
161
162 for (int i = 0; i < 7; ++i)
163 {
164 auto task = std::bind(TestFuncSubOneTime, i);
165 pool.AddTask(task);
166 }
167
168 sleep(1);
169 // 1 second should be enough to complete these tasks. if not, this case would be fail
170 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
171 // add 5 task, add 3 times and sub 2 times
172 EXPECT_EQ(g_times, 1);
173 pool.Stop();
174 }
175
TestFuncAddWait(int & i)176 void TestFuncAddWait(int& i)
177 {
178 ++g_times;
179 printf("after func:%s0%d called, :%d\n", __func__, i, g_times);
180 std::unique_lock<std::mutex> lk(g_mutex);
181 g_cv.wait(lk, [] {return g_ready;});
182 printf("func:%s0%d received ready signal!\n", __func__, i);
183 }
184
TestFuncSubWait(int & i)185 void TestFuncSubWait(int& i)
186 {
187 --g_times;
188 printf("after func:%s0%d called, :%d\n", __func__, i, g_times);
189 std::unique_lock<std::mutex> lk(g_mutex);
190 g_cv.wait(lk, [] {return g_ready;});
191 printf("func:%s0%d received ready signal!\n", __func__, i);
192 }
193
194 // complex task, wait for notify by the main thread
195 // total task num less than the threads num and the MaxTaskNum
196 HWTEST_F(UtilsThreadPoolTest, test_07, TestSize.Level0)
197 {
198 ThreadPool pool;
199 pool.Start(5);
200 EXPECT_EQ(pool.GetName(), "");
201 EXPECT_EQ((int)pool.GetThreadsNum(), 5);
202 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
203
204 for (int i = 0; i < 3; ++i)
205 {
206 auto task = std::bind(TestFuncAddWait, i);
207 pool.AddTask(task);
208 }
209
210 for (int i = 0; i < 2; ++i)
211 {
212 auto task = std::bind(TestFuncSubWait, i);
213 pool.AddTask(task);
214 }
215
216 std::this_thread::sleep_for(std::chrono::seconds(1)); // release cpu proactively, let the task threads go into wait
217 {
218 std::lock_guard<std::mutex> lk(g_mutex);
219 g_ready = true;
220 }
221
222 g_cv.notify_all();
223
224 // these tasks are endless Loop, 5 threads process 5 tasks, zero task remains in the task queue
225 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
226 // add 5 task, add 3 times and sub 2 times
227 EXPECT_EQ(g_times, 1);
228 pool.Stop();
229 }
230
231 HWTEST_F(UtilsThreadPoolTest, test_08, TestSize.Level0)
232 {
233 ThreadPool pool;
234 pool.Start(5);
235 EXPECT_EQ(pool.GetName(), "");
236 EXPECT_EQ((int)pool.GetThreadsNum(), 5);
237 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
238
239 pool.SetMaxTaskNum(10);
240
241 // ADD 15 tasks
242 for (int i = 0; i < 8; ++i)
243 {
244 auto task = std::bind(TestFuncAddWait, i);
245 pool.AddTask(task);
246 }
247
248 for (int i = 0; i < 7; ++i)
249 {
250 auto task = std::bind(TestFuncSubWait, i);
251 pool.AddTask(task);
252 }
253
254 sleep(1);
255 // at this time, the first 5 tasks execute and wait for notify, the rest 10 tasks stay in the task queue.
256 EXPECT_EQ((int)pool.GetCurTaskNum(), 10);
257 // FIFO,
258 EXPECT_EQ(g_times, 5);
259
260 // notify_all
261 {
262 std::lock_guard<std::mutex> lk(g_mutex);
263 g_ready = true;
264 }
265 g_cv.notify_all();
266
267 // after noity, task thread wake up, and g_ready is true, new tasks didn't need to wait
268 sleep(1);
269 // these tasks are endless Loop, and total num of task exceed the MaxTaskNum
270 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
271 EXPECT_EQ(g_times, 1);
272 pool.Stop();
273 }
274
TestFuncGetName(const std::string & poolName)275 void TestFuncGetName(const std::string& poolName)
276 {
277 char name[16];
278 prctl(PR_GET_NAME, name);
279 std::string nameStr(name);
280 size_t found = nameStr.find(poolName);
281 EXPECT_EQ(found, 0);
282 }
283
284 /*
285 * Test_09 is used to verify the name set to ThreadPool will be set as the real name of threads in pool.
286 */
287 HWTEST_F(UtilsThreadPoolTest, test_09, TestSize.Level0)
288 {
289 std::string poolName("test_09_pool");
290 ThreadPool pool(poolName);
291 pool.Start(5);
292 EXPECT_EQ(pool.GetName(), poolName);
293 EXPECT_EQ((int)pool.GetThreadsNum(), 5);
294 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
295
296 for (int i = 0; i < 5; ++i)
297 {
298 auto task = std::bind(TestFuncGetName, poolName);
299 pool.AddTask(task);
300 }
301
302 sleep(1);
303 // these tasks are endless Loop, 5 threads process 5 tasks, zero task remains in the task queue
304 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
305 pool.Stop();
306 }
307 } // namespace
308 } // namespace OHOS
309