blob: 1fbe89486194660e23ee5460e47c0e9d64b53eff [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 Hunga2a1ac32022-03-18 16:12:11 -070039 thread.scheduleTask("Basic", [&taskRan] { taskRan = true; }, 100ms);
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080040 std::this_thread::sleep_for(100ms - kJitter);
41 ASSERT_FALSE(taskRan);
42 std::this_thread::sleep_for(2 * kJitter);
Andy Hungcb90d202022-05-23 18:19:42 -070043 ASSERT_TRUE(taskRan); // timed-out called.
44 ASSERT_EQ(1ul, countChars(thread.timeoutToString(), REQUEST_START));
45 // nothing cancelled
46 ASSERT_EQ(0ul, countChars(thread.retiredToString(), REQUEST_START));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080047}
48
49TEST(TimerThread, Cancel) {
50 std::atomic<bool> taskRan = false;
51 TimerThread thread;
Andy Hunga2a1ac32022-03-18 16:12:11 -070052 TimerThread::Handle handle =
53 thread.scheduleTask("Cancel", [&taskRan] { taskRan = true; }, 100ms);
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080054 std::this_thread::sleep_for(100ms - kJitter);
55 ASSERT_FALSE(taskRan);
Andy Hunga2a1ac32022-03-18 16:12:11 -070056 ASSERT_TRUE(thread.cancelTask(handle));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080057 std::this_thread::sleep_for(2 * kJitter);
Andy Hungcb90d202022-05-23 18:19:42 -070058 ASSERT_FALSE(taskRan); // timed-out did not call.
59 ASSERT_EQ(0ul, countChars(thread.timeoutToString(), REQUEST_START));
60 // task cancelled.
61 ASSERT_EQ(1ul, countChars(thread.retiredToString(), REQUEST_START));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080062}
63
64TEST(TimerThread, CancelAfterRun) {
65 std::atomic<bool> taskRan = false;
66 TimerThread thread;
Andy Hunga2a1ac32022-03-18 16:12:11 -070067 TimerThread::Handle handle =
68 thread.scheduleTask("CancelAfterRun", [&taskRan] { taskRan = true; }, 100ms);
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080069 std::this_thread::sleep_for(100ms + kJitter);
Andy Hungcb90d202022-05-23 18:19:42 -070070 ASSERT_TRUE(taskRan); // timed-out called.
Andy Hunga2a1ac32022-03-18 16:12:11 -070071 ASSERT_FALSE(thread.cancelTask(handle));
Andy Hungcb90d202022-05-23 18:19:42 -070072 ASSERT_EQ(1ul, countChars(thread.timeoutToString(), REQUEST_START));
73 // nothing actually cancelled
74 ASSERT_EQ(0ul, countChars(thread.retiredToString(), REQUEST_START));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080075}
76
77TEST(TimerThread, MultipleTasks) {
Andy Hunga2a1ac32022-03-18 16:12:11 -070078 std::array<std::atomic<bool>, 6> taskRan{};
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080079 TimerThread thread;
80
81 auto startTime = std::chrono::steady_clock::now();
82
Andy Hunga2a1ac32022-03-18 16:12:11 -070083 thread.scheduleTask("0", [&taskRan] { taskRan[0] = true; }, 300ms);
84 thread.scheduleTask("1", [&taskRan] { taskRan[1] = true; }, 100ms);
85 thread.scheduleTask("2", [&taskRan] { taskRan[2] = true; }, 200ms);
86 thread.scheduleTask("3", [&taskRan] { taskRan[3] = true; }, 400ms);
87 auto handle4 = thread.scheduleTask("4", [&taskRan] { taskRan[4] = true; }, 200ms);
88 thread.scheduleTask("5", [&taskRan] { taskRan[5] = true; }, 200ms);
89
90 // 6 tasks pending
Andy Hungcb90d202022-05-23 18:19:42 -070091 ASSERT_EQ(6ul, countChars(thread.pendingToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -070092 // 0 tasks completed
Andy Hungcb90d202022-05-23 18:19:42 -070093 ASSERT_EQ(0ul, countChars(thread.retiredToString(), REQUEST_START));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080094
95 // Task 1 should trigger around 100ms.
96 std::this_thread::sleep_until(startTime + 100ms - kJitter);
97 ASSERT_FALSE(taskRan[0]);
98 ASSERT_FALSE(taskRan[1]);
99 ASSERT_FALSE(taskRan[2]);
100 ASSERT_FALSE(taskRan[3]);
101 ASSERT_FALSE(taskRan[4]);
102 ASSERT_FALSE(taskRan[5]);
103
104 std::this_thread::sleep_until(startTime + 100ms + kJitter);
105 ASSERT_FALSE(taskRan[0]);
106 ASSERT_TRUE(taskRan[1]);
107 ASSERT_FALSE(taskRan[2]);
108 ASSERT_FALSE(taskRan[3]);
109 ASSERT_FALSE(taskRan[4]);
110 ASSERT_FALSE(taskRan[5]);
111
112 // Cancel task 4 before it gets a chance to run.
113 thread.cancelTask(handle4);
114
115 // Tasks 2 and 5 should trigger around 200ms.
116 std::this_thread::sleep_until(startTime + 200ms - kJitter);
117 ASSERT_FALSE(taskRan[0]);
118 ASSERT_TRUE(taskRan[1]);
119 ASSERT_FALSE(taskRan[2]);
120 ASSERT_FALSE(taskRan[3]);
121 ASSERT_FALSE(taskRan[4]);
122 ASSERT_FALSE(taskRan[5]);
123
124 std::this_thread::sleep_until(startTime + 200ms + kJitter);
125 ASSERT_FALSE(taskRan[0]);
126 ASSERT_TRUE(taskRan[1]);
127 ASSERT_TRUE(taskRan[2]);
128 ASSERT_FALSE(taskRan[3]);
129 ASSERT_FALSE(taskRan[4]);
130 ASSERT_TRUE(taskRan[5]);
131
132 // Task 0 should trigger around 300ms.
133 std::this_thread::sleep_until(startTime + 300ms - kJitter);
134 ASSERT_FALSE(taskRan[0]);
135 ASSERT_TRUE(taskRan[1]);
136 ASSERT_TRUE(taskRan[2]);
137 ASSERT_FALSE(taskRan[3]);
138 ASSERT_FALSE(taskRan[4]);
139 ASSERT_TRUE(taskRan[5]);
140
141 std::this_thread::sleep_until(startTime + 300ms + kJitter);
142 ASSERT_TRUE(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
Andy Hunga2a1ac32022-03-18 16:12:11 -0700149 // 1 task pending
Andy Hungcb90d202022-05-23 18:19:42 -0700150 ASSERT_EQ(1ul, countChars(thread.pendingToString(), REQUEST_START));
151 // 4 tasks called on timeout, and 1 cancelled
152 ASSERT_EQ(4ul, countChars(thread.timeoutToString(), REQUEST_START));
153 ASSERT_EQ(1ul, countChars(thread.retiredToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700154
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800155 // Task 3 should trigger around 400ms.
156 std::this_thread::sleep_until(startTime + 400ms - kJitter);
157 ASSERT_TRUE(taskRan[0]);
158 ASSERT_TRUE(taskRan[1]);
159 ASSERT_TRUE(taskRan[2]);
160 ASSERT_FALSE(taskRan[3]);
161 ASSERT_FALSE(taskRan[4]);
162 ASSERT_TRUE(taskRan[5]);
163
Andy Hungcb90d202022-05-23 18:19:42 -0700164 // 4 tasks called on timeout and 1 cancelled
165 ASSERT_EQ(4ul, countChars(thread.timeoutToString(), REQUEST_START));
166 ASSERT_EQ(1ul, countChars(thread.retiredToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700167
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800168 std::this_thread::sleep_until(startTime + 400ms + kJitter);
169 ASSERT_TRUE(taskRan[0]);
170 ASSERT_TRUE(taskRan[1]);
171 ASSERT_TRUE(taskRan[2]);
172 ASSERT_TRUE(taskRan[3]);
173 ASSERT_FALSE(taskRan[4]);
174 ASSERT_TRUE(taskRan[5]);
Andy Hunga2a1ac32022-03-18 16:12:11 -0700175
176 // 0 tasks pending
Andy Hungcb90d202022-05-23 18:19:42 -0700177 ASSERT_EQ(0ul, countChars(thread.pendingToString(), REQUEST_START));
178 // 5 tasks called on timeout and 1 cancelled
179 ASSERT_EQ(5ul, countChars(thread.timeoutToString(), REQUEST_START));
180 ASSERT_EQ(1ul, countChars(thread.retiredToString(), REQUEST_START));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800181}
182
Andy Hunga2a1ac32022-03-18 16:12:11 -0700183TEST(TimerThread, TrackedTasks) {
184 TimerThread thread;
185
186 auto handle0 = thread.trackTask("0");
187 auto handle1 = thread.trackTask("1");
188 auto handle2 = thread.trackTask("2");
189
190 // 3 tasks pending
Andy Hungcb90d202022-05-23 18:19:42 -0700191 ASSERT_EQ(3ul, countChars(thread.pendingToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700192 // 0 tasks retired
Andy Hungcb90d202022-05-23 18:19:42 -0700193 ASSERT_EQ(0ul, countChars(thread.retiredToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700194
195 ASSERT_TRUE(thread.cancelTask(handle0));
196 ASSERT_TRUE(thread.cancelTask(handle1));
197
198 // 1 task pending
Andy Hungcb90d202022-05-23 18:19:42 -0700199 ASSERT_EQ(1ul, countChars(thread.pendingToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700200 // 2 tasks retired
Andy Hungcb90d202022-05-23 18:19:42 -0700201 ASSERT_EQ(2ul, countChars(thread.retiredToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700202
203 // handle1 is stale, cancel returns false.
204 ASSERT_FALSE(thread.cancelTask(handle1));
205
206 // 1 task pending
Andy Hungcb90d202022-05-23 18:19:42 -0700207 ASSERT_EQ(1ul, countChars(thread.pendingToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700208 // 2 tasks retired
Andy Hungcb90d202022-05-23 18:19:42 -0700209 ASSERT_EQ(2ul, countChars(thread.retiredToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700210
211 // Add another tracked task.
212 auto handle3 = thread.trackTask("3");
213
214 // 2 tasks pending
Andy Hungcb90d202022-05-23 18:19:42 -0700215 ASSERT_EQ(2ul, countChars(thread.pendingToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700216 // 2 tasks retired
Andy Hungcb90d202022-05-23 18:19:42 -0700217 ASSERT_EQ(2ul, countChars(thread.retiredToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700218
219 ASSERT_TRUE(thread.cancelTask(handle2));
220
221 // 1 tasks pending
Andy Hungcb90d202022-05-23 18:19:42 -0700222 ASSERT_EQ(1ul, countChars(thread.pendingToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700223 // 3 tasks retired
Andy Hungcb90d202022-05-23 18:19:42 -0700224 ASSERT_EQ(3ul, countChars(thread.retiredToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700225
226 ASSERT_TRUE(thread.cancelTask(handle3));
227
228 // 0 tasks pending
Andy Hungcb90d202022-05-23 18:19:42 -0700229 ASSERT_EQ(0ul, countChars(thread.pendingToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700230 // 4 tasks retired
Andy Hungcb90d202022-05-23 18:19:42 -0700231 ASSERT_EQ(4ul, countChars(thread.retiredToString(), REQUEST_START));
Andy Hunga2a1ac32022-03-18 16:12:11 -0700232}
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800233
234} // namespace