blob: 93cd64c549870e5928555dd9483cf236fbb46170 [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);
43 ASSERT_TRUE(taskRan);
Andy Hunga2a1ac32022-03-18 16:12:11 -070044 ASSERT_EQ(1, countChars(thread.retiredToString(), REQUEST_START));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080045}
46
47TEST(TimerThread, Cancel) {
48 std::atomic<bool> taskRan = false;
49 TimerThread thread;
Andy Hunga2a1ac32022-03-18 16:12:11 -070050 TimerThread::Handle handle =
51 thread.scheduleTask("Cancel", [&taskRan] { taskRan = true; }, 100ms);
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080052 std::this_thread::sleep_for(100ms - kJitter);
53 ASSERT_FALSE(taskRan);
Andy Hunga2a1ac32022-03-18 16:12:11 -070054 ASSERT_TRUE(thread.cancelTask(handle));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080055 std::this_thread::sleep_for(2 * kJitter);
56 ASSERT_FALSE(taskRan);
Andy Hunga2a1ac32022-03-18 16:12:11 -070057 ASSERT_EQ(1, countChars(thread.retiredToString(), REQUEST_START));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080058}
59
60TEST(TimerThread, CancelAfterRun) {
61 std::atomic<bool> taskRan = false;
62 TimerThread thread;
Andy Hunga2a1ac32022-03-18 16:12:11 -070063 TimerThread::Handle handle =
64 thread.scheduleTask("CancelAfterRun", [&taskRan] { taskRan = true; }, 100ms);
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080065 std::this_thread::sleep_for(100ms + kJitter);
66 ASSERT_TRUE(taskRan);
Andy Hunga2a1ac32022-03-18 16:12:11 -070067 ASSERT_FALSE(thread.cancelTask(handle));
68 ASSERT_EQ(1, countChars(thread.retiredToString(), REQUEST_START));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080069}
70
71TEST(TimerThread, MultipleTasks) {
Andy Hunga2a1ac32022-03-18 16:12:11 -070072 std::array<std::atomic<bool>, 6> taskRan{};
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080073 TimerThread thread;
74
75 auto startTime = std::chrono::steady_clock::now();
76
Andy Hunga2a1ac32022-03-18 16:12:11 -070077 thread.scheduleTask("0", [&taskRan] { taskRan[0] = true; }, 300ms);
78 thread.scheduleTask("1", [&taskRan] { taskRan[1] = true; }, 100ms);
79 thread.scheduleTask("2", [&taskRan] { taskRan[2] = true; }, 200ms);
80 thread.scheduleTask("3", [&taskRan] { taskRan[3] = true; }, 400ms);
81 auto handle4 = thread.scheduleTask("4", [&taskRan] { taskRan[4] = true; }, 200ms);
82 thread.scheduleTask("5", [&taskRan] { taskRan[5] = true; }, 200ms);
83
84 // 6 tasks pending
85 ASSERT_EQ(6, countChars(thread.pendingToString(), REQUEST_START));
86 // 0 tasks completed
87 ASSERT_EQ(0, countChars(thread.retiredToString(), REQUEST_START));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -080088
89 // Task 1 should trigger around 100ms.
90 std::this_thread::sleep_until(startTime + 100ms - kJitter);
91 ASSERT_FALSE(taskRan[0]);
92 ASSERT_FALSE(taskRan[1]);
93 ASSERT_FALSE(taskRan[2]);
94 ASSERT_FALSE(taskRan[3]);
95 ASSERT_FALSE(taskRan[4]);
96 ASSERT_FALSE(taskRan[5]);
97
98 std::this_thread::sleep_until(startTime + 100ms + kJitter);
99 ASSERT_FALSE(taskRan[0]);
100 ASSERT_TRUE(taskRan[1]);
101 ASSERT_FALSE(taskRan[2]);
102 ASSERT_FALSE(taskRan[3]);
103 ASSERT_FALSE(taskRan[4]);
104 ASSERT_FALSE(taskRan[5]);
105
106 // Cancel task 4 before it gets a chance to run.
107 thread.cancelTask(handle4);
108
109 // Tasks 2 and 5 should trigger around 200ms.
110 std::this_thread::sleep_until(startTime + 200ms - kJitter);
111 ASSERT_FALSE(taskRan[0]);
112 ASSERT_TRUE(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 + 200ms + kJitter);
119 ASSERT_FALSE(taskRan[0]);
120 ASSERT_TRUE(taskRan[1]);
121 ASSERT_TRUE(taskRan[2]);
122 ASSERT_FALSE(taskRan[3]);
123 ASSERT_FALSE(taskRan[4]);
124 ASSERT_TRUE(taskRan[5]);
125
126 // Task 0 should trigger around 300ms.
127 std::this_thread::sleep_until(startTime + 300ms - kJitter);
128 ASSERT_FALSE(taskRan[0]);
129 ASSERT_TRUE(taskRan[1]);
130 ASSERT_TRUE(taskRan[2]);
131 ASSERT_FALSE(taskRan[3]);
132 ASSERT_FALSE(taskRan[4]);
133 ASSERT_TRUE(taskRan[5]);
134
135 std::this_thread::sleep_until(startTime + 300ms + kJitter);
136 ASSERT_TRUE(taskRan[0]);
137 ASSERT_TRUE(taskRan[1]);
138 ASSERT_TRUE(taskRan[2]);
139 ASSERT_FALSE(taskRan[3]);
140 ASSERT_FALSE(taskRan[4]);
141 ASSERT_TRUE(taskRan[5]);
142
Andy Hunga2a1ac32022-03-18 16:12:11 -0700143 // 1 task pending
144 ASSERT_EQ(1, countChars(thread.pendingToString(), REQUEST_START));
145 // 4 tasks ran and 1 cancelled
146 ASSERT_EQ(4 + 1, countChars(thread.retiredToString(), REQUEST_START));
147
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800148 // Task 3 should trigger around 400ms.
149 std::this_thread::sleep_until(startTime + 400ms - 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 // 4 tasks ran and 1 cancelled
158 ASSERT_EQ(4 + 1, countChars(thread.retiredToString(), REQUEST_START));
159
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800160 std::this_thread::sleep_until(startTime + 400ms + kJitter);
161 ASSERT_TRUE(taskRan[0]);
162 ASSERT_TRUE(taskRan[1]);
163 ASSERT_TRUE(taskRan[2]);
164 ASSERT_TRUE(taskRan[3]);
165 ASSERT_FALSE(taskRan[4]);
166 ASSERT_TRUE(taskRan[5]);
Andy Hunga2a1ac32022-03-18 16:12:11 -0700167
168 // 0 tasks pending
169 ASSERT_EQ(0, countChars(thread.pendingToString(), REQUEST_START));
170 // 5 tasks ran and 1 cancelled
171 ASSERT_EQ(5 + 1, countChars(thread.retiredToString(), REQUEST_START));
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800172}
173
Andy Hunga2a1ac32022-03-18 16:12:11 -0700174TEST(TimerThread, TrackedTasks) {
175 TimerThread thread;
176
177 auto handle0 = thread.trackTask("0");
178 auto handle1 = thread.trackTask("1");
179 auto handle2 = thread.trackTask("2");
180
181 // 3 tasks pending
182 ASSERT_EQ(3, countChars(thread.pendingToString(), REQUEST_START));
183 // 0 tasks retired
184 ASSERT_EQ(0, countChars(thread.retiredToString(), REQUEST_START));
185
186 ASSERT_TRUE(thread.cancelTask(handle0));
187 ASSERT_TRUE(thread.cancelTask(handle1));
188
189 // 1 task pending
190 ASSERT_EQ(1, countChars(thread.pendingToString(), REQUEST_START));
191 // 2 tasks retired
192 ASSERT_EQ(2, countChars(thread.retiredToString(), REQUEST_START));
193
194 // handle1 is stale, cancel returns false.
195 ASSERT_FALSE(thread.cancelTask(handle1));
196
197 // 1 task pending
198 ASSERT_EQ(1, countChars(thread.pendingToString(), REQUEST_START));
199 // 2 tasks retired
200 ASSERT_EQ(2, countChars(thread.retiredToString(), REQUEST_START));
201
202 // Add another tracked task.
203 auto handle3 = thread.trackTask("3");
204
205 // 2 tasks pending
206 ASSERT_EQ(2, countChars(thread.pendingToString(), REQUEST_START));
207 // 2 tasks retired
208 ASSERT_EQ(2, countChars(thread.retiredToString(), REQUEST_START));
209
210 ASSERT_TRUE(thread.cancelTask(handle2));
211
212 // 1 tasks pending
213 ASSERT_EQ(1, countChars(thread.pendingToString(), REQUEST_START));
214 // 3 tasks retired
215 ASSERT_EQ(3, countChars(thread.retiredToString(), REQUEST_START));
216
217 ASSERT_TRUE(thread.cancelTask(handle3));
218
219 // 0 tasks pending
220 ASSERT_EQ(0, countChars(thread.pendingToString(), REQUEST_START));
221 // 4 tasks retired
222 ASSERT_EQ(4, countChars(thread.retiredToString(), REQUEST_START));
223}
Ytai Ben-Tsvi1ea62c92021-11-10 14:38:27 -0800224
225} // namespace