1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <broadcastradio-utils/WorkerThread.h>
18 #include <gtest/gtest.h>
19 
20 namespace {
21 
22 using namespace std::chrono_literals;
23 
24 using android::WorkerThread;
25 
26 using std::atomic;
27 using std::chrono::time_point;
28 using std::chrono::steady_clock;
29 using std::is_sorted;
30 using std::lock_guard;
31 using std::mutex;
32 using std::this_thread::sleep_for;
33 using std::vector;
34 
35 #define ASSERT_EQ_WITH_TOLERANCE(val1, val2, tolerance) \
36     ASSERT_LE((val1) - (tolerance), (val2));            \
37     ASSERT_GE((val1) + (tolerance), (val2));
38 
TEST(WorkerThreadTest,oneTask)39 TEST(WorkerThreadTest, oneTask) {
40     atomic<bool> executed(false);
41     atomic<time_point<steady_clock>> stop;
42     WorkerThread thread;
43 
44     auto start = steady_clock::now();
45     thread.schedule(
46         [&]() {
47             stop = steady_clock::now();
48             executed = true;
49         },
50         100ms);
51 
52     sleep_for(150ms);
53 
54     ASSERT_TRUE(executed);
55     auto delta = stop.load() - start;
56     ASSERT_EQ_WITH_TOLERANCE(delta, 100ms, 50ms);
57 }
58 
TEST(WorkerThreadTest,cancelSecond)59 TEST(WorkerThreadTest, cancelSecond) {
60     atomic<bool> executed1(false);
61     atomic<bool> executed2(false);
62     WorkerThread thread;
63 
64     thread.schedule([&]() { executed2 = true; }, 100ms);
65     thread.schedule([&]() { executed1 = true; }, 25ms);
66 
67     sleep_for(50ms);
68     thread.cancelAll();
69     sleep_for(100ms);
70 
71     ASSERT_TRUE(executed1);
72     ASSERT_FALSE(executed2);
73 }
74 
TEST(WorkerThreadTest,executeInOrder)75 TEST(WorkerThreadTest, executeInOrder) {
76     mutex mut;
77     vector<int> order;
78     WorkerThread thread;
79 
80     thread.schedule(
81         [&]() {
82             lock_guard<mutex> lk(mut);
83             order.push_back(0);
84         },
85         50ms);
86 
87     thread.schedule(
88         [&]() {
89             lock_guard<mutex> lk(mut);
90             order.push_back(4);
91         },
92         400ms);
93 
94     thread.schedule(
95         [&]() {
96             lock_guard<mutex> lk(mut);
97             order.push_back(1);
98         },
99         100ms);
100 
101     thread.schedule(
102         [&]() {
103             lock_guard<mutex> lk(mut);
104             order.push_back(3);
105         },
106         300ms);
107 
108     thread.schedule(
109         [&]() {
110             lock_guard<mutex> lk(mut);
111             order.push_back(2);
112         },
113         200ms);
114 
115     sleep_for(500ms);
116 
117     ASSERT_EQ(5u, order.size());
118     ASSERT_TRUE(is_sorted(order.begin(), order.end()));
119 }
120 
TEST(WorkerThreadTest,dontExecuteAfterDestruction)121 TEST(WorkerThreadTest, dontExecuteAfterDestruction) {
122     atomic<bool> executed1(false);
123     atomic<bool> executed2(false);
124     {
125         WorkerThread thread;
126 
127         thread.schedule([&]() { executed2 = true; }, 100ms);
128         thread.schedule([&]() { executed1 = true; }, 25ms);
129 
130         sleep_for(50ms);
131     }
132     sleep_for(100ms);
133 
134     ASSERT_TRUE(executed1);
135     ASSERT_FALSE(executed2);
136 }
137 
138 }  // anonymous namespace
139