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