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