1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
media / base / android / media_service_throttler_unittest.cc [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/base/android/media_service_throttler.h"
#include "base/memory/raw_ptr.h"
#include "base/numerics/safe_conversions.h"
#include "base/test/simple_test_tick_clock.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "media/base/android/media_server_crash_listener.h"
#include "media/base/fake_single_thread_task_runner.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
// From base/media/android/media_service_throttler.cc
const int kMaxBurstClients = 10;
class MediaServiceThrottlerTest : public testing::Test {
public:
MediaServiceThrottlerTest() {
throttler_ = MediaServiceThrottler::GetInstance();
clock_.SetNowTicks(base::TimeTicks());
throttler_->SetTickClockForTesting(&clock_);
test_task_runner_ =
base::MakeRefCounted<FakeSingleThreadTaskRunner>(&clock_);
throttler_->ResetInternalStateForTesting();
throttler_->SetCrashListenerTaskRunnerForTesting(test_task_runner_);
base_delay_ = throttler_->GetBaseThrottlingRateForTesting();
}
MediaServiceThrottlerTest(const MediaServiceThrottlerTest&) = delete;
MediaServiceThrottlerTest& operator=(const MediaServiceThrottlerTest&) =
delete;
void SimulateCrashes(int number_of_crashes) {
for (int i = 0; i < number_of_crashes; ++i)
throttler_->OnMediaServerCrash(false);
}
// Simulates the scheduling of |number_of_clients| and returns the last
// scheduling delay.
base::TimeDelta SimulateClientCreations(int number_of_clients) {
for (int i = 0; i < number_of_clients - 1; ++i)
throttler_->GetDelayForClientCreation();
return throttler_->GetDelayForClientCreation();
}
base::TimeDelta GetCurrentDelayBetweenClients() {
// Schedule two clients and return the difference between their scheduling
// slots.
return -(throttler_->GetDelayForClientCreation() -
throttler_->GetDelayForClientCreation());
}
base::TimeTicks TestNow() { return clock_.NowTicks(); }
raw_ptr<MediaServiceThrottler> throttler_;
base::SimpleTestTickClock clock_;
base::TimeDelta base_delay_;
scoped_refptr<FakeSingleThreadTaskRunner> test_task_runner_;
// Necessary, or else base::SingleThreadTaskRunner::GetCurrentDefault() fails.
base::test::SingleThreadTaskEnvironment task_environment_;
};
// Canary test case.
TEST_F(MediaServiceThrottlerTest, BaseCase) {
EXPECT_EQ(base::TimeDelta(), throttler_->GetDelayForClientCreation());
}
// Makes sure we can "burst" schedule clients.
TEST_F(MediaServiceThrottlerTest, NoCrash_UnderBurstThreshold_ShouldNotDelay) {
int number_burst_client_scheduled = 0;
while (base::TimeDelta() == throttler_->GetDelayForClientCreation())
number_burst_client_scheduled++;
EXPECT_EQ(kMaxBurstClients, number_burst_client_scheduled);
}
// Makes sure that, when burst scheduling a client, we schedule it from
// last scheduled burst client (vs scheduling it |base_delay_| from now).
TEST_F(MediaServiceThrottlerTest, NoCrash_OverBurstThreshold_ShouldDelay) {
// Schedule clients until the next one would be over burst threshold.
SimulateClientCreations(kMaxBurstClients);
// Make sure the next client that is scheduled is scheduled in its normal time
// slot.
EXPECT_EQ(base_delay_ * (kMaxBurstClients + 1),
throttler_->GetDelayForClientCreation());
}
// Makes sure that clients are scheduled |base_delay| apart.
TEST_F(MediaServiceThrottlerTest,
NoCrash_OverBurstThreshold_ShouldDelayLinearly) {
// Schedule clients until the next one would be over burst threshold.
SimulateClientCreations(kMaxBurstClients);
// Delays between two clients should be |base_delay_| apart.
EXPECT_EQ(base_delay_, GetCurrentDelayBetweenClients());
// Delays should remain constant (GetCurrentDelayBetweenClients() is not
// idempotent and actually schedules new clients).
EXPECT_EQ(GetCurrentDelayBetweenClients(), GetCurrentDelayBetweenClients());
}
// Makes sure that for every |base_delay_| that has elapsed, we can burst
// schedule an extra client.
TEST_F(MediaServiceThrottlerTest,
NoCrash_BurstThreshold_ShouldBeSlidingWindow) {
// Schedule some clients below the burst threshold.
SimulateClientCreations(7);
clock_.Advance(base_delay_ * 5);
// Make sure the passage of allows for more clients to be scheduled, since
// 7 + 8 > kMaxBurstClients.
EXPECT_EQ(base::TimeDelta(), SimulateClientCreations(8));
}
// Makes sure that, if not enough time has elapsed, we do not burst schedule
// new clients.
TEST_F(MediaServiceThrottlerTest,
NoCrash_OverBurstThresholdWithTimeLapse_ShouldDelay) {
// Schedule some clients way above the burst threshold.
SimulateClientCreations(3 * kMaxBurstClients);
// Advance the time so there are still 2 * kMaxBurstClients pending clients.
clock_.Advance(base_delay_ * kMaxBurstClients);
// Make sure delay we do not burst schedule new clients.
EXPECT_NE(base::TimeDelta(), throttler_->GetDelayForClientCreation());
}
// Makes sure that after a certain amount of inactivity, the scheduling clock is
// reset.
TEST_F(MediaServiceThrottlerTest, NoCrash_LongInactivity_ShouldReset) {
// Schedule two minutes' worth of clients.
SimulateClientCreations(base::ClampFloor(base::Minutes(2) / base_delay_));
// Advance the time so the scheduler perceived a full minute of inactivity.
clock_.Advance(base::Seconds(61));
// Make sure new clients are burst scheduled.
EXPECT_EQ(base::TimeDelta(), throttler_->GetDelayForClientCreation());
}
// Makes sure that crashes increase the scheduling delay.
TEST_F(MediaServiceThrottlerTest, WithCrash_BaseCase_DelayShouldIncrease) {
// Schedule clients until the next one would be over burst threshold.
SimulateClientCreations(kMaxBurstClients);
base::TimeDelta no_crash_delay = GetCurrentDelayBetweenClients();
SimulateCrashes(1);
base::TimeDelta crash_delay = GetCurrentDelayBetweenClients();
EXPECT_NE(base_delay_, crash_delay);
EXPECT_GT(crash_delay, no_crash_delay);
}
// Makes sure that we tolerate 1 crash per minute.
TEST_F(MediaServiceThrottlerTest,
WithCrash_SingleCrash_DelayShouldNotIncrease) {
// Schedule clients until the next one would be over burst threshold.
SimulateClientCreations(kMaxBurstClients);
SimulateCrashes(1);
clock_.Advance(base::Milliseconds(1));
// Because we use the floor function when calculating crashes, a small time
// advance should nullify a single crash.
EXPECT_EQ(base_delay_, GetCurrentDelayBetweenClients());
}
// Makes sure that more than 1 crash per minute causes increased delays.
TEST_F(MediaServiceThrottlerTest, WithCrash_ManyCrashes_DelayShouldIncrease) {
// Schedule clients until the next one would be over burst threshold.
SimulateClientCreations(kMaxBurstClients);
SimulateCrashes(2);
clock_.Advance(base::Milliseconds(1));
// The delay after crashes should be greater than the base delay.
EXPECT_LT(base_delay_, GetCurrentDelayBetweenClients());
}
// Makes sure that an increase in server crashes leads to delay increases.
TEST_F(MediaServiceThrottlerTest,
WithCrash_ConsecutiveCrashes_DelayShouldIncreaseWithNumberOfCrashes) {
// Schedule clients until the next one would be over burst threshold.
SimulateClientCreations(kMaxBurstClients);
base::TimeDelta last_delay = base_delay_;
for (int i = 0; i < 5; ++i) {
SimulateCrashes(1);
base::TimeDelta current_delay = GetCurrentDelayBetweenClients();
EXPECT_LT(last_delay, current_delay);
last_delay = current_delay;
}
}
// Makes sure that crashes affect the number of burst clients we can schedule.
TEST_F(MediaServiceThrottlerTest, WithCrash_ShouldAllowFewerBurstClients) {
int number_burst_client_scheduled = 0;
SimulateCrashes(1);
while (base::TimeDelta() == throttler_->GetDelayForClientCreation())
number_burst_client_scheduled++;
EXPECT_GT(kMaxBurstClients, number_burst_client_scheduled);
}
// Makes sure delays are capped to a certain maximal value.
TEST_F(MediaServiceThrottlerTest, WithCrash_ManyCrashes_DelayShouldMaxOut) {
// Schedule clients until the next one would be over burst threshold.
SimulateClientCreations(kMaxBurstClients);
SimulateCrashes(10);
base::TimeDelta capped_delay = GetCurrentDelayBetweenClients();
SimulateCrashes(10);
EXPECT_EQ(capped_delay, GetCurrentDelayBetweenClients());
}
// Makes sure a minute without crashes resets the crash counter.
TEST_F(MediaServiceThrottlerTest, WithCrash_NoCrashesForAMinute_ShouldReset) {
SimulateCrashes(10);
// The effective server crash count should be reset because it has been over
// a minute since the last crash.
clock_.Advance(base::Seconds(61));
SimulateClientCreations(kMaxBurstClients);
EXPECT_EQ(base_delay_, GetCurrentDelayBetweenClients());
}
// Makes sure a steady crashes do not resets the crash counter.
TEST_F(MediaServiceThrottlerTest, WithCrash_ConstantCrashes_ShouldNotReset) {
SimulateCrashes(9);
// The effective server crash count should not be reset.
clock_.Advance(base::Seconds(59));
SimulateCrashes(1);
clock_.Advance(base::Seconds(2));
SimulateClientCreations(kMaxBurstClients);
EXPECT_LT(base_delay_, GetCurrentDelayBetweenClients());
}
// Makes sure the crash listener shuts down after a minute of not having
// received any client creation request.
TEST_F(MediaServiceThrottlerTest, CrashListener_NoRequests_ShouldShutDown) {
// Schedule many minutes worth of clients. This is to prove that the
// MediaServerCrashListener's clean up happens after lack of requests, as
// opposed to lack of actually scheduled clients.
SimulateClientCreations(base::ClampFloor(base::Minutes(3) / base_delay_));
// The MediaServerCrashListener should be alive, with 1s second to spare.
clock_.Advance(base::Seconds(59));
test_task_runner_->RunTasks();
EXPECT_TRUE(throttler_->IsCrashListenerAliveForTesting());
// Requesting a new client creation should reset the internal timer, and
// cancel the release request that was scheduled 59 seconds ago.
throttler_->GetDelayForClientCreation();
// The MediaServerCrashListener should be alive, with 58s second to spare.
clock_.Advance(base::Seconds(2));
test_task_runner_->RunTasks();
EXPECT_TRUE(throttler_->IsCrashListenerAliveForTesting());
// The MediaServerCrashListener should be dead.
clock_.Advance(base::Seconds(59));
test_task_runner_->RunTasks();
EXPECT_FALSE(throttler_->IsCrashListenerAliveForTesting());
}
// Makes sure the crash listener shuts down after a minute of not having
// received any client creation request, regardless of when crashes occur.
TEST_F(MediaServiceThrottlerTest,
CrashListener_NoRequestsWithCrashes_ShouldShutDown) {
// Schedule many minutes worth of clients. This is to prove that the
// MediaServerCrashListener's clean up happens after lack of requests, as
// opposed to lack of actually scheduled clients.
SimulateClientCreations(base::ClampFloor(base::Minutes(3) / base_delay_));
// The MediaServerCrashListener should be alive, with 1s second to spare.
clock_.Advance(base::Seconds(59));
test_task_runner_->RunTasks();
EXPECT_TRUE(throttler_->IsCrashListenerAliveForTesting());
// Crashes should not affect the MediaServerCrashListener's lifetime.
SimulateCrashes(1);
// The MediaServerCrashListener should be dead.
clock_.Advance(base::Seconds(2));
test_task_runner_->RunTasks();
EXPECT_FALSE(throttler_->IsCrashListenerAliveForTesting());
}
} // namespace media