blob: 8656f6389e1dff5276b0a5966b732194513a3498 [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 Hung2aa15102022-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);
Andy Hungcb90d202022-05-23 18:19:42 -070046 ASSERT_TRUE(taskRan); // timed-out called.
47 ASSERT_EQ(1ul, countChars(thread.timeoutToString(), REQUEST_START));
48 // nothing cancelled
49 ASSERT_EQ(0ul, countChars(thread.retiredToString(), REQUEST_START));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080050}
51
52TEST(TimerThread, Cancel) {
53 std::atomic<bool> taskRan = false;
54 TimerThread thread;
Andy Hunga2a1ac32022-03-18 16:12:11 -070055 TimerThread::Handle handle =
Andy Hung2aa15102022-06-13 19:49:43 -070056 thread.scheduleTask("Cancel", [&taskRan](TimerThread::Handle handle __unused) {
57 taskRan = true; }, 100ms);
58 ASSERT_TRUE(TimerThread::isTimeoutHandle(handle));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080059 std::this_thread::sleep_for(100ms - kJitter);
60 ASSERT_FALSE(taskRan);
Andy Hunga2a1ac32022-03-18 16:12:11 -070061 ASSERT_TRUE(thread.cancelTask(handle));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080062 std::this_thread::sleep_for(2 * kJitter);
Andy Hungcb90d202022-05-23 18:19:42 -070063 ASSERT_FALSE(taskRan); // timed-out did not call.
64 ASSERT_EQ(0ul, countChars(thread.timeoutToString(), REQUEST_START));
65 // task cancelled.
66 ASSERT_EQ(1ul, countChars(thread.retiredToString(), REQUEST_START));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080067}
68
69TEST(TimerThread, CancelAfterRun) {
70 std::atomic<bool> taskRan = false;
71 TimerThread thread;
Andy Hunga2a1ac32022-03-18 16:12:11 -070072 TimerThread::Handle handle =
Andy Hung2aa15102022-06-13 19:49:43 -070073 thread.scheduleTask("CancelAfterRun",
74 [&taskRan](TimerThread::Handle handle __unused) {
75 taskRan = true; }, 100ms);
76 ASSERT_TRUE(TimerThread::isTimeoutHandle(handle));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080077 std::this_thread::sleep_for(100ms + kJitter);
Andy Hungcb90d202022-05-23 18:19:42 -070078 ASSERT_TRUE(taskRan); // timed-out called.
Andy Hunga2a1ac32022-03-18 16:12:11 -070079 ASSERT_FALSE(thread.cancelTask(handle));
Andy Hungcb90d202022-05-23 18:19:42 -070080 ASSERT_EQ(1ul, countChars(thread.timeoutToString(), REQUEST_START));
81 // nothing actually cancelled
82 ASSERT_EQ(0ul, countChars(thread.retiredToString(), REQUEST_START));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080083}
84
85TEST(TimerThread, MultipleTasks) {
Andy Hunga2a1ac32022-03-18 16:12:11 -070086 std::array<std::atomic<bool>, 6> taskRan{};
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080087 TimerThread thread;
88
89 auto startTime = std::chrono::steady_clock::now();
90
Andy Hung2aa15102022-06-13 19:49:43 -070091 thread.scheduleTask("0", [&taskRan](TimerThread::Handle handle __unused) {
92 taskRan[0] = true; }, 300ms);
93 thread.scheduleTask("1", [&taskRan](TimerThread::Handle handle __unused) {
94 taskRan[1] = true; }, 100ms);
95 thread.scheduleTask("2", [&taskRan](TimerThread::Handle handle __unused) {
96 taskRan[2] = true; }, 200ms);
97 thread.scheduleTask("3", [&taskRan](TimerThread::Handle handle __unused) {
98 taskRan[3] = true; }, 400ms);
99 auto handle4 = thread.scheduleTask("4", [&taskRan](TimerThread::Handle handle __unused) {
100 taskRan[4] = true; }, 200ms);
101 thread.scheduleTask("5", [&taskRan](TimerThread::Handle handle __unused) {
102 taskRan[5] = true; }, 200ms);
Andy Hunga2a1ac32022-03-18 16:12:11 -0700103
104 // 6 tasks pending
Andy Hungcb90d202022-05-23 18:19:42 -0700105 ASSERT_EQ(6ul, countChars(thread.pendingToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700106 // 0 tasks completed
Andy Hungcb90d202022-05-23 18:19:42 -0700107 ASSERT_EQ(0ul, countChars(thread.retiredToString(), REQUEST_START));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800108
109 // Task 1 should trigger around 100ms.
110 std::this_thread::sleep_until(startTime + 100ms - kJitter);
111 ASSERT_FALSE(taskRan[0]);
112 ASSERT_FALSE(taskRan[1]);
113 ASSERT_FALSE(taskRan[2]);
114 ASSERT_FALSE(taskRan[3]);
115 ASSERT_FALSE(taskRan[4]);
116 ASSERT_FALSE(taskRan[5]);
117
118 std::this_thread::sleep_until(startTime + 100ms + kJitter);
119 ASSERT_FALSE(taskRan[0]);
120 ASSERT_TRUE(taskRan[1]);
121 ASSERT_FALSE(taskRan[2]);
122 ASSERT_FALSE(taskRan[3]);
123 ASSERT_FALSE(taskRan[4]);
124 ASSERT_FALSE(taskRan[5]);
125
126 // Cancel task 4 before it gets a chance to run.
127 thread.cancelTask(handle4);
128
129 // Tasks 2 and 5 should trigger around 200ms.
130 std::this_thread::sleep_until(startTime + 200ms - kJitter);
131 ASSERT_FALSE(taskRan[0]);
132 ASSERT_TRUE(taskRan[1]);
133 ASSERT_FALSE(taskRan[2]);
134 ASSERT_FALSE(taskRan[3]);
135 ASSERT_FALSE(taskRan[4]);
136 ASSERT_FALSE(taskRan[5]);
137
138 std::this_thread::sleep_until(startTime + 200ms + kJitter);
139 ASSERT_FALSE(taskRan[0]);
140 ASSERT_TRUE(taskRan[1]);
141 ASSERT_TRUE(taskRan[2]);
142 ASSERT_FALSE(taskRan[3]);
143 ASSERT_FALSE(taskRan[4]);
144 ASSERT_TRUE(taskRan[5]);
145
146 // Task 0 should trigger around 300ms.
147 std::this_thread::sleep_until(startTime + 300ms - kJitter);
148 ASSERT_FALSE(taskRan[0]);
149 ASSERT_TRUE(taskRan[1]);
150 ASSERT_TRUE(taskRan[2]);
151 ASSERT_FALSE(taskRan[3]);
152 ASSERT_FALSE(taskRan[4]);
153 ASSERT_TRUE(taskRan[5]);
154
155 std::this_thread::sleep_until(startTime + 300ms + kJitter);
156 ASSERT_TRUE(taskRan[0]);
157 ASSERT_TRUE(taskRan[1]);
158 ASSERT_TRUE(taskRan[2]);
159 ASSERT_FALSE(taskRan[3]);
160 ASSERT_FALSE(taskRan[4]);
161 ASSERT_TRUE(taskRan[5]);
162
Andy Hunga2a1ac32022-03-18 16:12:11 -0700163 // 1 task pending
Andy Hungcb90d202022-05-23 18:19:42 -0700164 ASSERT_EQ(1ul, countChars(thread.pendingToString(), REQUEST_START));
165 // 4 tasks called on timeout, and 1 cancelled
166 ASSERT_EQ(4ul, countChars(thread.timeoutToString(), REQUEST_START));
167 ASSERT_EQ(1ul, countChars(thread.retiredToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700168
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800169 // Task 3 should trigger around 400ms.
170 std::this_thread::sleep_until(startTime + 400ms - kJitter);
171 ASSERT_TRUE(taskRan[0]);
172 ASSERT_TRUE(taskRan[1]);
173 ASSERT_TRUE(taskRan[2]);
174 ASSERT_FALSE(taskRan[3]);
175 ASSERT_FALSE(taskRan[4]);
176 ASSERT_TRUE(taskRan[5]);
177
Andy Hungcb90d202022-05-23 18:19:42 -0700178 // 4 tasks called on timeout and 1 cancelled
179 ASSERT_EQ(4ul, countChars(thread.timeoutToString(), REQUEST_START));
180 ASSERT_EQ(1ul, countChars(thread.retiredToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700181
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800182 std::this_thread::sleep_until(startTime + 400ms + kJitter);
183 ASSERT_TRUE(taskRan[0]);
184 ASSERT_TRUE(taskRan[1]);
185 ASSERT_TRUE(taskRan[2]);
186 ASSERT_TRUE(taskRan[3]);
187 ASSERT_FALSE(taskRan[4]);
188 ASSERT_TRUE(taskRan[5]);
Andy Hunga2a1ac32022-03-18 16:12:11 -0700189
190 // 0 tasks pending
Andy Hungcb90d202022-05-23 18:19:42 -0700191 ASSERT_EQ(0ul, countChars(thread.pendingToString(), REQUEST_START));
192 // 5 tasks called on timeout and 1 cancelled
193 ASSERT_EQ(5ul, countChars(thread.timeoutToString(), REQUEST_START));
194 ASSERT_EQ(1ul, countChars(thread.retiredToString(), REQUEST_START));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800195}
196
Andy Hunga2a1ac32022-03-18 16:12:11 -0700197TEST(TimerThread, TrackedTasks) {
198 TimerThread thread;
199
200 auto handle0 = thread.trackTask("0");
201 auto handle1 = thread.trackTask("1");
202 auto handle2 = thread.trackTask("2");
203
Andy Hung2aa15102022-06-13 19:49:43 -0700204 ASSERT_TRUE(TimerThread::isNoTimeoutHandle(handle0));
205 ASSERT_TRUE(TimerThread::isNoTimeoutHandle(handle1));
206 ASSERT_TRUE(TimerThread::isNoTimeoutHandle(handle2));
207
Andy Hunga2a1ac32022-03-18 16:12:11 -0700208 // 3 tasks pending
Andy Hungcb90d202022-05-23 18:19:42 -0700209 ASSERT_EQ(3ul, countChars(thread.pendingToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700210 // 0 tasks retired
Andy Hungcb90d202022-05-23 18:19:42 -0700211 ASSERT_EQ(0ul, countChars(thread.retiredToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700212
213 ASSERT_TRUE(thread.cancelTask(handle0));
214 ASSERT_TRUE(thread.cancelTask(handle1));
215
216 // 1 task pending
Andy Hungcb90d202022-05-23 18:19:42 -0700217 ASSERT_EQ(1ul, countChars(thread.pendingToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700218 // 2 tasks retired
Andy Hungcb90d202022-05-23 18:19:42 -0700219 ASSERT_EQ(2ul, countChars(thread.retiredToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700220
221 // handle1 is stale, cancel returns false.
222 ASSERT_FALSE(thread.cancelTask(handle1));
223
224 // 1 task pending
Andy Hungcb90d202022-05-23 18:19:42 -0700225 ASSERT_EQ(1ul, countChars(thread.pendingToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700226 // 2 tasks retired
Andy Hungcb90d202022-05-23 18:19:42 -0700227 ASSERT_EQ(2ul, countChars(thread.retiredToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700228
229 // Add another tracked task.
230 auto handle3 = thread.trackTask("3");
Andy Hung2aa15102022-06-13 19:49:43 -0700231 ASSERT_TRUE(TimerThread::isNoTimeoutHandle(handle3));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700232
233 // 2 tasks pending
Andy Hungcb90d202022-05-23 18:19:42 -0700234 ASSERT_EQ(2ul, countChars(thread.pendingToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700235 // 2 tasks retired
Andy Hungcb90d202022-05-23 18:19:42 -0700236 ASSERT_EQ(2ul, countChars(thread.retiredToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700237
238 ASSERT_TRUE(thread.cancelTask(handle2));
239
240 // 1 tasks pending
Andy Hungcb90d202022-05-23 18:19:42 -0700241 ASSERT_EQ(1ul, countChars(thread.pendingToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700242 // 3 tasks retired
Andy Hungcb90d202022-05-23 18:19:42 -0700243 ASSERT_EQ(3ul, countChars(thread.retiredToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700244
245 ASSERT_TRUE(thread.cancelTask(handle3));
246
247 // 0 tasks pending
Andy Hungcb90d202022-05-23 18:19:42 -0700248 ASSERT_EQ(0ul, countChars(thread.pendingToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700249 // 4 tasks retired
Andy Hungcb90d202022-05-23 18:19:42 -0700250 ASSERT_EQ(4ul, countChars(thread.retiredToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700251}
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800252
253} // namespace