1 /*
2 * Copyright (c) 2023 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 "priority_queue.h"
17 #include <chrono>
18 #include <functional>
19 #include <gtest/gtest.h>
20 #include <memory>
21 #include <mutex>
22 #include <queue>
23 #include <set>
24 #include <shared_mutex>
25 #include <string>
26 #include <thread>
27
28 namespace OHOS::Test {
29 using namespace testing::ext;
30 using namespace OHOS;
31 using TaskId = uint64_t;
32 using Task = std::function<void()>;
33 using Duration = std::chrono::steady_clock::duration;
34 using Time = std::chrono::steady_clock::time_point;
35 static constexpr Duration INVALID_INTERVAL = std::chrono::milliseconds(0);
36 static constexpr uint64_t UNLIMITED_TIMES = std::numeric_limits<uint64_t>::max();
37 static constexpr TaskId INVALID_TASK_ID = static_cast<uint64_t>(0);
38 static constexpr uint32_t SHORT_INTERVAL = 100; // ms
39 class PriorityQueueTest : public testing::Test {
40 public:
41 struct TestTask {
__anon1573afca0102OHOS::Test::PriorityQueueTest::TestTask42 std::function<void()> exec = []() {};
43 Duration interval = INVALID_INTERVAL;
44 uint64_t times = UNLIMITED_TIMES;
45 TaskId taskId = INVALID_TASK_ID;
46 TestTask() = default;
47
ValidOHOS::Test::PriorityQueueTest::TestTask48 bool Valid() const
49 {
50 return taskId != INVALID_TASK_ID;
51 }
52 };
53 static void SetUpTestCase(void);
54 static void TearDownTestCase(void);
55 void SetUp();
56 void TearDown();
57
58 protected:
59 static PriorityQueue<PriorityQueueTest::TestTask, Time, TaskId> priorityqueue_;
60 static PriorityQueue<PriorityQueueTest::TestTask, Time, TaskId>::PQMatrix pqMatrix;
61 };
62 using TestTask = PriorityQueueTest::TestTask;
63 PriorityQueue<TestTask, Time, TaskId> PriorityQueueTest::priorityqueue_ =
64 PriorityQueue<TestTask, Time, TaskId>(TestTask());
65 PriorityQueue<TestTask, Time, TaskId>::PQMatrix PriorityQueueTest::pqMatrix =
66 PriorityQueue<TestTask, Time, TaskId>::PQMatrix(TestTask(), INVALID_TASK_ID);
67
SetUpTestCase(void)68 void PriorityQueueTest::SetUpTestCase(void) { }
69
TearDownTestCase(void)70 void PriorityQueueTest::TearDownTestCase(void) { }
71
SetUp(void)72 void PriorityQueueTest::SetUp(void) { }
73
TearDown(void)74 void PriorityQueueTest::TearDown(void)
75 {
76 priorityqueue_.Clean();
77 }
78
79 /**
80 * @tc.name: PQMatrix_001
81 * @tc.desc: test the PQMatrix(_Tsk task, _Tid id) function.
82 * @tc.type: FUNC
83 * @tc.require:
84 * @tc.author: suoqilong
85 */
86 HWTEST_F(PriorityQueueTest, PQMatrix_001, TestSize.Level1)
87 {
88 TestTask testTask;
89 auto id = testTask.taskId;
90 EXPECT_EQ(pqMatrix.id_, id);
91 }
92
93 /**
94 * @tc.name: PushPopSize_001
95 * @tc.desc: Invalid test task.
96 * @tc.type: FUNC
97 * @tc.require:
98 * @tc.author: suoqilong
99 */
100 HWTEST_F(PriorityQueueTest, PushPopSize_001, TestSize.Level1)
101 {
102 TestTask testTask;
103 auto id = testTask.taskId;
104 auto timely = std::chrono::seconds(0);
105 auto ret = priorityqueue_.Push(testTask, id, std::chrono::steady_clock::now() + timely);
106 EXPECT_EQ(ret, false);
107 auto retSize = priorityqueue_.Size();
108 EXPECT_EQ(retSize, 0u);
109 auto retPop = priorityqueue_.Pop();
110 EXPECT_EQ(retPop.taskId, INVALID_TASK_ID);
111 retSize = priorityqueue_.Size();
112 EXPECT_EQ(retSize, 0u);
113 }
114
115 /**
116 * @tc.name: PushPopSize_002
117 * @tc.desc: Testing a single task.
118 * @tc.type: FUNC
119 * @tc.require:
120 * @tc.author: suoqilong
121 */
122 HWTEST_F(PriorityQueueTest, PushPopSize_002, TestSize.Level1)
123 {
124 TestTask testTask;
125 auto id = ++(testTask.taskId);
126 auto timely = std::chrono::seconds(0);
127 auto ret = priorityqueue_.Push(testTask, id, std::chrono::steady_clock::now() + timely);
128 EXPECT_EQ(ret, true);
129 auto retSize = priorityqueue_.Size();
130 EXPECT_EQ(retSize, 1u);
131 auto retPop = priorityqueue_.Pop();
132 EXPECT_EQ(retPop.taskId, id);
133 retSize = priorityqueue_.Size();
134 EXPECT_EQ(retSize, 0u);
135 }
136
137 /**
138 * @tc.name: PushPopSize_003
139 * @tc.desc: Testing multiple tasks.
140 * @tc.type: FUNC
141 * @tc.require:
142 * @tc.author: suoqilong
143 */
144 HWTEST_F(PriorityQueueTest, PushPopSize_003, TestSize.Level1)
145 {
146 TestTask testTask;
147 for (int i = 0; i < 10; ++i) {
148 auto timely = std::chrono::seconds(0);
149 auto id = ++(testTask.taskId);
150 auto ret = priorityqueue_.Push(testTask, id, std::chrono::steady_clock::now() + timely);
151 EXPECT_EQ(ret, true);
152 }
153 auto retSize = priorityqueue_.Size();
154 EXPECT_EQ(retSize, 10u);
155 auto retPop = priorityqueue_.Pop();
156 EXPECT_EQ(retPop.taskId, 1);
157 retSize = priorityqueue_.Size();
158 EXPECT_EQ(retSize, 9u);
159 }
160
161 /**
162 * @tc.name: PushPopSize_004
163 * @tc.desc: Test the delay task.
164 * @tc.type: FUNC
165 * @tc.require:
166 * @tc.author: suoqilong
167 */
168 HWTEST_F(PriorityQueueTest, PushPopSize_004, TestSize.Level1)
169 {
170 TestTask testTask;
171 testTask.times = 1;
172 for (int i = 0; i < 5; ++i) {
173 auto delay = std::chrono::milliseconds(SHORT_INTERVAL);
174 auto id = ++(testTask.taskId);
175 auto ret = priorityqueue_.Push(testTask, id, std::chrono::steady_clock::now() + delay);
176 EXPECT_EQ(ret, true);
177 }
178 for (int i = 0; i < 5; ++i) {
179 auto timely = std::chrono::seconds(0);
180 auto id = ++(testTask.taskId);
181 auto ret = priorityqueue_.Push(testTask, id, std::chrono::steady_clock::now() + timely);
182 EXPECT_EQ(ret, true);
183 }
184 auto retSize = priorityqueue_.Size();
185 EXPECT_EQ(retSize, 10u);
186 for (int i = 0; i < 5; ++i) {
187 auto retPop = priorityqueue_.Pop();
188 EXPECT_EQ(retPop.taskId, i + 6);
189 }
190 for (int i = 0; i < 5; ++i) {
191 auto retPop = priorityqueue_.Pop();
192 EXPECT_EQ(retPop.taskId, i + 1);
193 }
194 retSize = priorityqueue_.Size();
195 EXPECT_EQ(retSize, 0u);
196 }
197
198 /**
199 * @tc.name: PushPopSize_005
200 * @tc.desc: Test the delay task.
201 * @tc.type: FUNC
202 * @tc.require:
203 * @tc.author: suoqilong
204 */
205 HWTEST_F(PriorityQueueTest, PushPopSize_005, TestSize.Level1)
206 {
207 TestTask testTask;
208 testTask.times = 1;
209 auto delay = std::chrono::milliseconds(SHORT_INTERVAL);
210 auto id = ++(testTask.taskId);
211 auto ret = priorityqueue_.Push(testTask, id, std::chrono::steady_clock::now() + delay);
212 EXPECT_EQ(ret, true);
213 auto retSize = priorityqueue_.Size();
214 EXPECT_EQ(retSize, 1u);
215 auto delayA = std::chrono::steady_clock::now();
216 auto retPop = priorityqueue_.Pop();
217 EXPECT_EQ(retPop.taskId, id);
218 auto delayB = std::chrono::steady_clock::now();
219 auto diff = std::chrono::duration_cast<std::chrono::milliseconds>(delayB - delayA).count();
220 auto delayms = std::chrono::duration_cast<std::chrono::milliseconds>(delay).count();
221 EXPECT_LT(diff, delayms * 1.5);
222 retSize = priorityqueue_.Size();
223 EXPECT_EQ(retSize, 0u);
224 }
225
226 /**
227 * @tc.name: Find_001
228 * @tc.desc: Invalid test task.
229 * @tc.type: FUNC
230 * @tc.require:
231 * @tc.author: suoqilong
232 */
233 HWTEST_F(PriorityQueueTest, Find_001, TestSize.Level1)
234 {
235 TestTask testTask;
236 auto id = testTask.taskId;
237 auto timely = std::chrono::seconds(0);
238 auto ret = priorityqueue_.Push(testTask, id, std::chrono::steady_clock::now() + timely);
239 EXPECT_EQ(ret, false);
240 auto retFind = priorityqueue_.Find(id);
241 EXPECT_EQ(retFind.taskId, INVALID_TASK_ID);
242 }
243
244 /**
245 * @tc.name: Find_002
246 * @tc.desc: test the priority_queue _Tsk Find(_Tid id) function.
247 * @tc.type: FUNC
248 * @tc.require:
249 * @tc.author: suoqilong
250 */
251 HWTEST_F(PriorityQueueTest, Find_002, TestSize.Level1)
252 {
253 TestTask testTask;
254 for (int i = 0; i < 10; ++i) {
255 auto timely = std::chrono::seconds(0);
256 auto id = ++(testTask.taskId);
257 auto ret = priorityqueue_.Push(testTask, id, std::chrono::steady_clock::now() + timely);
258 EXPECT_EQ(ret, true);
259 }
260 auto retSize = priorityqueue_.Size();
261 EXPECT_EQ(retSize, 10u);
262 auto retFind = priorityqueue_.Find(5);
263 EXPECT_EQ(retFind.taskId, 5);
264 retFind = priorityqueue_.Find(20);
265 EXPECT_EQ(retFind.taskId, INVALID_TASK_ID);
266 }
267
268 /**
269 * @tc.name: Update_001
270 * @tc.desc: Invalid test task.
271 * @tc.type: FUNC
272 * @tc.require:
273 * @tc.author: suoqilong
274 */
275 HWTEST_F(PriorityQueueTest, Update_001, TestSize.Level1)
276 {
__anon1573afca0202(TestTask &) 277 auto updater = [](TestTask &) {
278 return std::pair { false, Time() };
279 };
280 auto delay = std::chrono::milliseconds(SHORT_INTERVAL);
281 TestTask testTask;
282 testTask.times = 3;
283 auto id = testTask.taskId;
284 auto ret = priorityqueue_.Push(testTask, id, std::chrono::steady_clock::now() + delay);
285 EXPECT_EQ(ret, false);
286 auto retUpdate = priorityqueue_.Update(id, updater);
287 EXPECT_EQ(retUpdate, false);
288 }
289
290 /**
291 * @tc.name: Update_002
292 * @tc.desc: Test normal tasks.
293 * @tc.type: FUNC
294 * @tc.require:
295 * @tc.author: suoqilong
296 */
297 HWTEST_F(PriorityQueueTest, Update_002, TestSize.Level1)
298 {
__anon1573afca0302(TestTask &) 299 auto updater = [](TestTask &) {
300 return std::pair { false, Time() };
301 };
302 auto delay = std::chrono::milliseconds(SHORT_INTERVAL);
303 TestTask testTask;
304 testTask.times = 3;
305 auto id = ++(testTask.taskId);
306 auto ret = priorityqueue_.Push(testTask, id, std::chrono::steady_clock::now() + delay);
307 EXPECT_EQ(ret, true);
308 auto retUpdate = priorityqueue_.Update(id, updater);
309 EXPECT_EQ(retUpdate, true);
310 }
311
312 /**
313 * @tc.name: Update_003
314 * @tc.desc: Test the running tasks.
315 * @tc.type: FUNC
316 * @tc.require:
317 * @tc.author: suoqilong
318 */
319 HWTEST_F(PriorityQueueTest, Update_003, TestSize.Level1)
320 {
__anon1573afca0402(TestTask &) 321 auto updater = [](TestTask &) {
322 return std::pair { false, Time() };
323 };
324 auto delay = std::chrono::milliseconds(SHORT_INTERVAL);
325 TestTask testTask;
326 testTask.times = 3;
327 auto id = ++(testTask.taskId);
328 auto ret = priorityqueue_.Push(testTask, id, std::chrono::steady_clock::now() + delay);
329 EXPECT_EQ(ret, true);
330 auto retPop = priorityqueue_.Pop();
331 auto retUpdate = priorityqueue_.Update(retPop.taskId, updater);
332 EXPECT_EQ(retUpdate, false);
333 }
334
335 /**
336 * @tc.name: Update_004
337 * @tc.desc: Test the running tasks.
338 * @tc.type: FUNC
339 * @tc.require:
340 * @tc.author: suoqilong
341 */
342 HWTEST_F(PriorityQueueTest, Update_004, TestSize.Level1)
343 {
__anon1573afca0502(TestTask &) 344 auto updater = [](TestTask &) {
345 return std::pair { true, Time() };
346 };
347 auto delay = std::chrono::milliseconds(SHORT_INTERVAL);
348 TestTask testTask;
349 testTask.times = 3;
350 auto id = ++(testTask.taskId);
351 auto ret = priorityqueue_.Push(testTask, id, std::chrono::steady_clock::now() + delay);
352 EXPECT_EQ(ret, true);
353 auto retPop = priorityqueue_.Pop();
354 auto retUpdate = priorityqueue_.Update(retPop.taskId, updater);
355 EXPECT_EQ(retUpdate, true);
356 }
357
358 /**
359 * @tc.name: Update_005
360 * @tc.desc: Test the running and finish tasks.
361 * @tc.type: FUNC
362 * @tc.require:
363 * @tc.author: suoqilong
364 */
365 HWTEST_F(PriorityQueueTest, Update_005, TestSize.Level1)
366 {
__anon1573afca0602(TestTask &) 367 auto updater = [](TestTask &) {
368 return std::pair { false, Time() };
369 };
370 auto delay = std::chrono::milliseconds(SHORT_INTERVAL);
371 TestTask testTask;
372 testTask.times = 3;
373 auto id = ++(testTask.taskId);
374 auto ret = priorityqueue_.Push(testTask, id, std::chrono::steady_clock::now() + delay);
375 EXPECT_EQ(ret, true);
376 auto retPop = priorityqueue_.Pop();
377 priorityqueue_.Finish(id);
378 auto retUpdate = priorityqueue_.Update(retPop.taskId, updater);
379 EXPECT_EQ(retUpdate, false);
380 }
381
382 /**
383 * @tc.name: Update_006
384 * @tc.desc: Test the running and finish tasks.
385 * @tc.type: FUNC
386 * @tc.require:
387 * @tc.author: suoqilong
388 */
389 HWTEST_F(PriorityQueueTest, Update_006, TestSize.Level1)
390 {
__anon1573afca0702(TestTask &) 391 auto updater = [](TestTask &) {
392 return std::pair { true, Time() };
393 };
394 auto delay = std::chrono::milliseconds(SHORT_INTERVAL);
395 TestTask testTask;
396 testTask.times = 3;
397 auto id = ++(testTask.taskId);
398 auto ret = priorityqueue_.Push(testTask, id, std::chrono::steady_clock::now() + delay);
399 EXPECT_EQ(ret, true);
400 auto retPop = priorityqueue_.Pop();
401 priorityqueue_.Finish(id);
402 auto retUpdate = priorityqueue_.Update(retPop.taskId, updater);
403 EXPECT_EQ(retUpdate, false);
404 }
405
406 /**
407 * @tc.name: Remove_001
408 * @tc.desc: Invalid test task.
409 * @tc.type: FUNC
410 * @tc.require:
411 * @tc.author: suoqilong
412 */
413 HWTEST_F(PriorityQueueTest, Remove_001, TestSize.Level1)
414 {
415 TestTask testTask;
416 auto id = testTask.taskId;
417 auto delay = std::chrono::milliseconds(SHORT_INTERVAL);
418 auto ret = priorityqueue_.Push(testTask, id, std::chrono::steady_clock::now() + delay);
419 EXPECT_EQ(ret, false);
420 auto retRemove = priorityqueue_.Remove(id, false);
421 EXPECT_EQ(retRemove, false);
422 auto retSize = priorityqueue_.Size();
423 EXPECT_EQ(retSize, 0u);
424 }
425
426 /**
427 * @tc.name: Remove_002
428 * @tc.desc: Single and don't wait test task.
429 * @tc.type: FUNC
430 * @tc.require:
431 * @tc.author: suoqilong
432 */
433 HWTEST_F(PriorityQueueTest, Remove_002, TestSize.Level1)
434 {
435 TestTask testTask;
436 auto id = ++(testTask.taskId);
437 auto delay = std::chrono::milliseconds(SHORT_INTERVAL);
438 auto ret = priorityqueue_.Push(testTask, id, std::chrono::steady_clock::now() + delay);
439 EXPECT_EQ(ret, true);
440 auto retSize = priorityqueue_.Size();
441 EXPECT_EQ(retSize, 1u);
442 auto retRemove = priorityqueue_.Remove(id, false);
443 EXPECT_EQ(retRemove, true);
444 retSize = priorityqueue_.Size();
445 EXPECT_EQ(retSize, 0u);
446 }
447
448 /**
449 * @tc.name: Remove_003
450 * @tc.desc: Single and wait test task.
451 * @tc.type: FUNC
452 * @tc.require:
453 * @tc.author: suoqilong
454 */
455 HWTEST_F(PriorityQueueTest, Remove_003, TestSize.Level1)
456 {
457 TestTask testTask;
458 auto id = ++(testTask.taskId);
459 auto delay = std::chrono::milliseconds(SHORT_INTERVAL);
460 auto ret = priorityqueue_.Push(testTask, id, std::chrono::steady_clock::now() + delay);
461 EXPECT_EQ(ret, true);
462 auto retSize = priorityqueue_.Size();
463 EXPECT_EQ(retSize, 1u);
464 priorityqueue_.Finish(id);
465 auto retRemove = priorityqueue_.Remove(id, true);
466 EXPECT_EQ(retRemove, true);
467 retSize = priorityqueue_.Size();
468 EXPECT_EQ(retSize, 0u);
469 }
470
471 /**
472 * @tc.name: Clean_001
473 * @tc.desc: Testing a single task.
474 * @tc.type: FUNC
475 * @tc.require:
476 * @tc.author: suoqilong
477 */
478 HWTEST_F(PriorityQueueTest, Clean_001, TestSize.Level1)
479 {
480 TestTask testTask;
481 auto timely = std::chrono::seconds(0);
482 auto id = ++(testTask.taskId);
483 auto ret = priorityqueue_.Push(testTask, id, std::chrono::steady_clock::now() + timely);
484 EXPECT_EQ(ret, true);
485 auto retSize = priorityqueue_.Size();
486 EXPECT_EQ(retSize, 1u);
487 priorityqueue_.Clean();
488 retSize = priorityqueue_.Size();
489 EXPECT_EQ(retSize, 0u);
490 }
491
492 /**
493 * @tc.name: Clean_002
494 * @tc.desc: Testing multiple tasks.
495 * @tc.type: FUNC
496 * @tc.require:
497 * @tc.author: suoqilong
498 */
499 HWTEST_F(PriorityQueueTest, Clean_002, TestSize.Level1)
500 {
501 TestTask testTask;
502 for (int i = 0; i < 10; ++i) {
503 auto timely = std::chrono::seconds(0);
504 auto id = ++(testTask.taskId);
505 auto ret = priorityqueue_.Push(testTask, id, std::chrono::steady_clock::now() + timely);
506 EXPECT_EQ(ret, true);
507 }
508 auto retSize = priorityqueue_.Size();
509 EXPECT_EQ(retSize, 10u);
510 priorityqueue_.Clean();
511 retSize = priorityqueue_.Size();
512 EXPECT_EQ(retSize, 0u);
513 }
514
515 /**
516 * @tc.name: Finish_001
517 * @tc.desc: test the priority_queue void Finish(_Tid id) function.
518 * @tc.type: FUNC
519 * @tc.require:
520 * @tc.author: suoqilong
521 */
522 HWTEST_F(PriorityQueueTest, Finish_001, TestSize.Level1)
523 {
524 TestTask testTask;
525 auto id = ++(testTask.taskId);
526 auto delay = std::chrono::milliseconds(SHORT_INTERVAL);
527 auto ret = priorityqueue_.Push(testTask, id, std::chrono::steady_clock::now() + delay);
528 EXPECT_EQ(ret, true);
529 auto retSize = priorityqueue_.Size();
530 EXPECT_EQ(retSize, 1u);
531 priorityqueue_.Finish(id); // Marking Finish
532 auto retRemove = priorityqueue_.Remove(id, true);
533 EXPECT_EQ(retRemove, true);
534 retSize = priorityqueue_.Size();
535 EXPECT_EQ(retSize, 0u);
536 }
537 } // namespace OHOS::Test
538