• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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