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