blob: deb743a77903444ab816441270b496a76d378cda [file] [log] [blame]
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -08001/*
2 * Copyright (C) 2021 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 <chrono>
18#include <thread>
19#include <gtest/gtest.h>
20#include <mediautils/TimerThread.h>
21
22using namespace std::chrono_literals;
Andy Hunga2a1ac32022-03-18 16:12:11 -070023using namespace android::mediautils;
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080024
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080025namespace {
26
27constexpr auto kJitter = 10ms;
28
Andy Hunga2a1ac32022-03-18 16:12:11 -070029// Each task written by *ToString() will start with a left brace.
30constexpr char REQUEST_START = '{';
31
32inline size_t countChars(std::string_view s, char c) {
33 return std::count(s.begin(), s.end(), c);
34}
35
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080036TEST(TimerThread, Basic) {
37 std::atomic<bool> taskRan = false;
38 TimerThread thread;
Andy Hungdf1ed5c2022-06-13 19:49:43 -070039 TimerThread::Handle handle =
40 thread.scheduleTask("Basic", [&taskRan](TimerThread::Handle handle __unused) {
41 taskRan = true; }, 100ms);
42 ASSERT_TRUE(TimerThread::isTimeoutHandle(handle));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080043 std::this_thread::sleep_for(100ms - kJitter);
44 ASSERT_FALSE(taskRan);
45 std::this_thread::sleep_for(2 * kJitter);
46 ASSERT_TRUE(taskRan);
Andy Hunga2a1ac32022-03-18 16:12:11 -070047 ASSERT_EQ(1, countChars(thread.retiredToString(), REQUEST_START));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080048}
49
50TEST(TimerThread, Cancel) {
51 std::atomic<bool> taskRan = false;
52 TimerThread thread;
Andy Hunga2a1ac32022-03-18 16:12:11 -070053 TimerThread::Handle handle =
Andy Hungdf1ed5c2022-06-13 19:49:43 -070054 thread.scheduleTask("Cancel", [&taskRan](TimerThread::Handle handle __unused) {
55 taskRan = true; }, 100ms);
56 ASSERT_TRUE(TimerThread::isTimeoutHandle(handle));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080057 std::this_thread::sleep_for(100ms - kJitter);
58 ASSERT_FALSE(taskRan);
Andy Hunga2a1ac32022-03-18 16:12:11 -070059 ASSERT_TRUE(thread.cancelTask(handle));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080060 std::this_thread::sleep_for(2 * kJitter);
61 ASSERT_FALSE(taskRan);
Andy Hunga2a1ac32022-03-18 16:12:11 -070062 ASSERT_EQ(1, countChars(thread.retiredToString(), REQUEST_START));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080063}
64
65TEST(TimerThread, CancelAfterRun) {
66 std::atomic<bool> taskRan = false;
67 TimerThread thread;
Andy Hunga2a1ac32022-03-18 16:12:11 -070068 TimerThread::Handle handle =
Andy Hungdf1ed5c2022-06-13 19:49:43 -070069 thread.scheduleTask("CancelAfterRun",
70 [&taskRan](TimerThread::Handle handle __unused) {
71 taskRan = true; }, 100ms);
72 ASSERT_TRUE(TimerThread::isTimeoutHandle(handle));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080073 std::this_thread::sleep_for(100ms + kJitter);
74 ASSERT_TRUE(taskRan);
Andy Hunga2a1ac32022-03-18 16:12:11 -070075 ASSERT_FALSE(thread.cancelTask(handle));
76 ASSERT_EQ(1, countChars(thread.retiredToString(), REQUEST_START));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080077}
78
79TEST(TimerThread, MultipleTasks) {
Andy Hunga2a1ac32022-03-18 16:12:11 -070080 std::array<std::atomic<bool>, 6> taskRan{};
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080081 TimerThread thread;
82
83 auto startTime = std::chrono::steady_clock::now();
84
Andy Hungdf1ed5c2022-06-13 19:49:43 -070085 thread.scheduleTask("0", [&taskRan](TimerThread::Handle handle __unused) {
86 taskRan[0] = true; }, 300ms);
87 thread.scheduleTask("1", [&taskRan](TimerThread::Handle handle __unused) {
88 taskRan[1] = true; }, 100ms);
89 thread.scheduleTask("2", [&taskRan](TimerThread::Handle handle __unused) {
90 taskRan[2] = true; }, 200ms);
91 thread.scheduleTask("3", [&taskRan](TimerThread::Handle handle __unused) {
92 taskRan[3] = true; }, 400ms);
93 auto handle4 = thread.scheduleTask("4", [&taskRan](TimerThread::Handle handle __unused) {
94 taskRan[4] = true; }, 200ms);
95 thread.scheduleTask("5", [&taskRan](TimerThread::Handle handle __unused) {
96 taskRan[5] = true; }, 200ms);
Andy Hunga2a1ac32022-03-18 16:12:11 -070097
98 // 6 tasks pending
99 ASSERT_EQ(6, countChars(thread.pendingToString(), REQUEST_START));
100 // 0 tasks completed
101 ASSERT_EQ(0, countChars(thread.retiredToString(), REQUEST_START));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800102
103 // Task 1 should trigger around 100ms.
104 std::this_thread::sleep_until(startTime + 100ms - kJitter);
105 ASSERT_FALSE(taskRan[0]);
106 ASSERT_FALSE(taskRan[1]);
107 ASSERT_FALSE(taskRan[2]);
108 ASSERT_FALSE(taskRan[3]);
109 ASSERT_FALSE(taskRan[4]);
110 ASSERT_FALSE(taskRan[5]);
111
112 std::this_thread::sleep_until(startTime + 100ms + kJitter);
113 ASSERT_FALSE(taskRan[0]);
114 ASSERT_TRUE(taskRan[1]);
115 ASSERT_FALSE(taskRan[2]);
116 ASSERT_FALSE(taskRan[3]);
117 ASSERT_FALSE(taskRan[4]);
118 ASSERT_FALSE(taskRan[5]);
119
120 // Cancel task 4 before it gets a chance to run.
121 thread.cancelTask(handle4);
122
123 // Tasks 2 and 5 should trigger around 200ms.
124 std::this_thread::sleep_until(startTime + 200ms - kJitter);
125 ASSERT_FALSE(taskRan[0]);
126 ASSERT_TRUE(taskRan[1]);
127 ASSERT_FALSE(taskRan[2]);
128 ASSERT_FALSE(taskRan[3]);
129 ASSERT_FALSE(taskRan[4]);
130 ASSERT_FALSE(taskRan[5]);
131
132 std::this_thread::sleep_until(startTime + 200ms + kJitter);
133 ASSERT_FALSE(taskRan[0]);
134 ASSERT_TRUE(taskRan[1]);
135 ASSERT_TRUE(taskRan[2]);
136 ASSERT_FALSE(taskRan[3]);
137 ASSERT_FALSE(taskRan[4]);
138 ASSERT_TRUE(taskRan[5]);
139
140 // Task 0 should trigger around 300ms.
141 std::this_thread::sleep_until(startTime + 300ms - kJitter);
142 ASSERT_FALSE(taskRan[0]);
143 ASSERT_TRUE(taskRan[1]);
144 ASSERT_TRUE(taskRan[2]);
145 ASSERT_FALSE(taskRan[3]);
146 ASSERT_FALSE(taskRan[4]);
147 ASSERT_TRUE(taskRan[5]);
148
149 std::this_thread::sleep_until(startTime + 300ms + kJitter);
150 ASSERT_TRUE(taskRan[0]);
151 ASSERT_TRUE(taskRan[1]);
152 ASSERT_TRUE(taskRan[2]);
153 ASSERT_FALSE(taskRan[3]);
154 ASSERT_FALSE(taskRan[4]);
155 ASSERT_TRUE(taskRan[5]);
156
Andy Hunga2a1ac32022-03-18 16:12:11 -0700157 // 1 task pending
158 ASSERT_EQ(1, countChars(thread.pendingToString(), REQUEST_START));
159 // 4 tasks ran and 1 cancelled
160 ASSERT_EQ(4 + 1, countChars(thread.retiredToString(), REQUEST_START));
161
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800162 // Task 3 should trigger around 400ms.
163 std::this_thread::sleep_until(startTime + 400ms - kJitter);
164 ASSERT_TRUE(taskRan[0]);
165 ASSERT_TRUE(taskRan[1]);
166 ASSERT_TRUE(taskRan[2]);
167 ASSERT_FALSE(taskRan[3]);
168 ASSERT_FALSE(taskRan[4]);
169 ASSERT_TRUE(taskRan[5]);
170
Andy Hunga2a1ac32022-03-18 16:12:11 -0700171 // 4 tasks ran and 1 cancelled
172 ASSERT_EQ(4 + 1, countChars(thread.retiredToString(), REQUEST_START));
173
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800174 std::this_thread::sleep_until(startTime + 400ms + kJitter);
175 ASSERT_TRUE(taskRan[0]);
176 ASSERT_TRUE(taskRan[1]);
177 ASSERT_TRUE(taskRan[2]);
178 ASSERT_TRUE(taskRan[3]);
179 ASSERT_FALSE(taskRan[4]);
180 ASSERT_TRUE(taskRan[5]);
Andy Hunga2a1ac32022-03-18 16:12:11 -0700181
182 // 0 tasks pending
183 ASSERT_EQ(0, countChars(thread.pendingToString(), REQUEST_START));
184 // 5 tasks ran and 1 cancelled
185 ASSERT_EQ(5 + 1, countChars(thread.retiredToString(), REQUEST_START));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800186}
187
Andy Hunga2a1ac32022-03-18 16:12:11 -0700188TEST(TimerThread, TrackedTasks) {
189 TimerThread thread;
190
191 auto handle0 = thread.trackTask("0");
192 auto handle1 = thread.trackTask("1");
193 auto handle2 = thread.trackTask("2");
194
Andy Hungdf1ed5c2022-06-13 19:49:43 -0700195 ASSERT_TRUE(TimerThread::isNoTimeoutHandle(handle0));
196 ASSERT_TRUE(TimerThread::isNoTimeoutHandle(handle1));
197 ASSERT_TRUE(TimerThread::isNoTimeoutHandle(handle2));
198
Andy Hunga2a1ac32022-03-18 16:12:11 -0700199 // 3 tasks pending
200 ASSERT_EQ(3, countChars(thread.pendingToString(), REQUEST_START));
201 // 0 tasks retired
202 ASSERT_EQ(0, countChars(thread.retiredToString(), REQUEST_START));
203
204 ASSERT_TRUE(thread.cancelTask(handle0));
205 ASSERT_TRUE(thread.cancelTask(handle1));
206
207 // 1 task pending
208 ASSERT_EQ(1, countChars(thread.pendingToString(), REQUEST_START));
209 // 2 tasks retired
210 ASSERT_EQ(2, countChars(thread.retiredToString(), REQUEST_START));
211
212 // handle1 is stale, cancel returns false.
213 ASSERT_FALSE(thread.cancelTask(handle1));
214
215 // 1 task pending
216 ASSERT_EQ(1, countChars(thread.pendingToString(), REQUEST_START));
217 // 2 tasks retired
218 ASSERT_EQ(2, countChars(thread.retiredToString(), REQUEST_START));
219
220 // Add another tracked task.
221 auto handle3 = thread.trackTask("3");
Andy Hungdf1ed5c2022-06-13 19:49:43 -0700222 ASSERT_TRUE(TimerThread::isNoTimeoutHandle(handle3));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700223
224 // 2 tasks pending
225 ASSERT_EQ(2, countChars(thread.pendingToString(), REQUEST_START));
226 // 2 tasks retired
227 ASSERT_EQ(2, countChars(thread.retiredToString(), REQUEST_START));
228
229 ASSERT_TRUE(thread.cancelTask(handle2));
230
231 // 1 tasks pending
232 ASSERT_EQ(1, countChars(thread.pendingToString(), REQUEST_START));
233 // 3 tasks retired
234 ASSERT_EQ(3, countChars(thread.retiredToString(), REQUEST_START));
235
236 ASSERT_TRUE(thread.cancelTask(handle3));
237
238 // 0 tasks pending
239 ASSERT_EQ(0, countChars(thread.pendingToString(), REQUEST_START));
240 // 4 tasks retired
241 ASSERT_EQ(4, countChars(thread.retiredToString(), REQUEST_START));
242}
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800243
244} // namespace