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 std::lock_guard<std::mutex> lock(g_mutex);
110 ++g_times;
111 }
112
TestFuncSubOneTime(int & i)113 void TestFuncSubOneTime(int& i)
114 {
115 std::lock_guard<std::mutex> lock(g_mutex);
116 --g_times;
117 }
118
119 // simple task, total task num less than the MaxTaskNum
120 HWTEST_F(UtilsThreadPoolTest, test_05, TestSize.Level0)
121 {
122 ThreadPool pool;
123 pool.Start(5);
124 EXPECT_EQ(pool.GetName(), "");
125 EXPECT_EQ((int)pool.GetThreadsNum(), 5);
126 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
127
128 for (int i = 0; i < 3; ++i)
129 {
130 auto task = std::bind(TestFuncAddOneTime, i);
131 pool.AddTask(task);
132 }
133
134 for (int i = 0; i < 2; ++i)
135 {
136 auto task = std::bind(TestFuncSubOneTime, i);
137 pool.AddTask(task);
138 }
139
140 sleep(1);
141 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
142 // add 5 tasks, add 3 times and sub 2 times
143 EXPECT_EQ(g_times, 1);
144 pool.Stop();
145 }
146
147 // simaple task, total task num exceed the MaxTaskNum and the threads num
148 HWTEST_F(UtilsThreadPoolTest, test_06, TestSize.Level0)
149 {
150 ThreadPool pool;
151 pool.Start(5);
152 EXPECT_EQ(pool.GetName(), "");
153 EXPECT_EQ((int)pool.GetThreadsNum(), 5);
154 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
155
156 pool.SetMaxTaskNum(10);
157
158 for (int i = 0; i < 8; ++i)
159 {
160 auto task = std::bind(TestFuncAddOneTime, i);
161 pool.AddTask(task);
162 }
163
164 for (int i = 0; i < 7; ++i)
165 {
166 auto task = std::bind(TestFuncSubOneTime, i);
167 pool.AddTask(task);
168 }
169
170 sleep(1);
171 // 1 second should be enough to complete these tasks. if not, this case would be fail
172 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
173 // add 5 task, add 3 times and sub 2 times
174 EXPECT_EQ(g_times, 1);
175 pool.Stop();
176 }
177
TestFuncAddWait(int & i)178 void TestFuncAddWait(int& i)
179 {
180 std::unique_lock<std::mutex> lk(g_mutex);
181 ++g_times;
182 printf("after func:%s0%d called, :%d\n", __func__, i, g_times);
183 g_cv.wait(lk, [] {return g_ready;});
184 printf("func:%s0%d received ready signal!\n", __func__, i);
185 }
186
TestFuncSubWait(int & i)187 void TestFuncSubWait(int& i)
188 {
189 std::unique_lock<std::mutex> lk(g_mutex);
190 --g_times;
191 printf("after func:%s0%d called, :%d\n", __func__, i, g_times);
192 g_cv.wait(lk, [] {return g_ready;});
193 printf("func:%s0%d received ready signal!\n", __func__, i);
194 }
195
196 // complex task, wait for notify by the main thread
197 // total task num less than the threads num and the MaxTaskNum
198 HWTEST_F(UtilsThreadPoolTest, test_07, TestSize.Level0)
199 {
200 ThreadPool pool;
201 pool.Start(5);
202 EXPECT_EQ(pool.GetName(), "");
203 EXPECT_EQ((int)pool.GetThreadsNum(), 5);
204 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
205
206 for (int i = 0; i < 3; ++i)
207 {
208 auto task = std::bind(TestFuncAddWait, i);
209 pool.AddTask(task);
210 }
211
212 for (int i = 0; i < 2; ++i)
213 {
214 auto task = std::bind(TestFuncSubWait, i);
215 pool.AddTask(task);
216 }
217
218 std::this_thread::sleep_for(std::chrono::seconds(1)); // release cpu proactively, let the task threads go into wait
219 {
220 std::lock_guard<std::mutex> lk(g_mutex);
221 g_ready = true;
222 }
223
224 g_cv.notify_all();
225
226 // these tasks are endless Loop, 5 threads process 5 tasks, zero task remains in the task queue
227 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
228 // add 5 task, add 3 times and sub 2 times
229 EXPECT_EQ(g_times, 1);
230 pool.Stop();
231 }
232
233 HWTEST_F(UtilsThreadPoolTest, test_08, TestSize.Level0)
234 {
235 ThreadPool pool;
236 pool.Start(5);
237 EXPECT_EQ(pool.GetName(), "");
238 EXPECT_EQ((int)pool.GetThreadsNum(), 5);
239 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
240
241 pool.SetMaxTaskNum(10);
242
243 // ADD 15 tasks
244 for (int i = 0; i < 8; ++i)
245 {
246 auto task = std::bind(TestFuncAddWait, i);
247 pool.AddTask(task);
248 }
249
250 for (int i = 0; i < 7; ++i)
251 {
252 auto task = std::bind(TestFuncSubWait, i);
253 pool.AddTask(task);
254 }
255
256 sleep(1);
257 // at this time, the first 5 tasks execute and wait for notify, the rest 10 tasks stay in the task queue.
258 EXPECT_EQ((int)pool.GetCurTaskNum(), 10);
259 // FIFO,
260 EXPECT_EQ(g_times, 5);
261
262 // notify_all
263 {
264 std::lock_guard<std::mutex> lk(g_mutex);
265 g_ready = true;
266 }
267 g_cv.notify_all();
268
269 // after noity, task thread wake up, and g_ready is true, new tasks didn't need to wait
270 sleep(1);
271 // these tasks are endless Loop, and total num of task exceed the MaxTaskNum
272 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
273 EXPECT_EQ(g_times, 1);
274 pool.Stop();
275 }
276
TestFuncGetName(const std::string & poolName)277 void TestFuncGetName(const std::string& poolName)
278 {
279 char name[16];
280 prctl(PR_GET_NAME, name);
281 std::string nameStr(name);
282 size_t found = nameStr.find(poolName);
283 EXPECT_EQ(found, 0);
284 }
285
286 /*
287 * Test_09 is used to verify the name set to ThreadPool will be set as the real name of threads in pool.
288 */
289 HWTEST_F(UtilsThreadPoolTest, test_09, TestSize.Level0)
290 {
291 std::string poolName("test_09_pool");
292 ThreadPool pool(poolName);
293 pool.Start(5);
294 EXPECT_EQ(pool.GetName(), poolName);
295 EXPECT_EQ((int)pool.GetThreadsNum(), 5);
296 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
297
298 for (int i = 0; i < 5; ++i)
299 {
300 auto task = std::bind(TestFuncGetName, poolName);
301 pool.AddTask(task);
302 }
303
304 sleep(1);
305 // these tasks are endless Loop, 5 threads process 5 tasks, zero task remains in the task queue
306 EXPECT_EQ((int)pool.GetCurTaskNum(), 0);
307 pool.Stop();
308 }
309 } // namespace
310 } // namespace OHOS
311