OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "core/dom/Document.h" | |
6 #include "core/html/AutoplayExperimentHelper.h" | |
7 #include "platform/UserGestureIndicator.h" | |
8 #include "testing/gmock/include/gmock/gmock.h" | |
9 #include "testing/gtest/include/gtest/gtest.h" | |
10 | |
11 namespace blink { | |
12 | |
13 using namespace testing; | |
14 using RecordMetricsBehavior = AutoplayExperimentHelper::Client::RecordMetricsBeh avior; | |
15 | |
16 class MockAutoplayClient : public AutoplayExperimentHelper::Client { | |
17 public: | |
18 enum ElementType { VIDEO, | |
19 AUDIO }; | |
philipj_slow
2016/01/12 15:12:18
Enum on a single line or each entry on a separate
liberato (no reviews please)
2016/01/29 08:25:24
Done.
| |
20 | |
21 MockAutoplayClient(const char* mode = "enabled-forvideo", ElementType type = VIDEO) | |
philipj_slow
2016/01/12 15:12:18
The default value of at least mode doesn't make th
liberato (no reviews please)
2016/01/29 08:25:24
Done.
| |
22 : m_mode(mode) | |
23 , m_duration(100) | |
24 { | |
25 // Set up default behaviors that the helper is allowed to use or cache | |
26 // during construction. | |
27 | |
28 EXPECT_CALL(*this, autoplayExperimentMode()) | |
29 .WillRepeatedly(Return(m_mode)); | |
30 | |
31 // Use m_isVideo to answer these. | |
32 EXPECT_CALL(*this, isHTMLVideoElement()) | |
33 .WillRepeatedly(Return(type == VIDEO)); | |
34 EXPECT_CALL(*this, isHTMLAudioElement()) | |
35 .WillRepeatedly(Return(type != VIDEO)); | |
philipj_slow
2016/01/12 15:12:18
type == AUDIO?
liberato (no reviews please)
2016/01/29 08:25:24
Done.
| |
36 | |
37 // Now set up some useful defaults. | |
38 // Remember that this are only evaluated once. | |
39 EXPECT_CALL(*this, duration()) | |
philipj_slow
2016/01/12 15:12:18
Reading http://stackoverflow.com/questions/1393347
liberato (no reviews please)
2016/01/29 08:25:24
Done, plus NiceMock to supress the warnings.
philipj_slow
2016/02/02 08:08:15
It worked, yay!
| |
40 .WillRepeatedly(Return(m_duration)); | |
41 EXPECT_CALL(*this, currentTime()) | |
42 .WillRepeatedly(Return(0)); | |
43 | |
44 // Default to "not optimized for mobile" page. | |
45 EXPECT_CALL(*this, isLegacyViewportType()) | |
46 .WillRepeatedly(Return(false)); | |
47 | |
48 // Other handy defaults. | |
49 EXPECT_CALL(*this, paused()) | |
50 .WillRepeatedly(Return(true)); | |
51 EXPECT_CALL(*this, pageVisibilityState()) | |
52 .WillRepeatedly(Return(PageVisibilityStateVisible)); | |
53 EXPECT_CALL(*this, absoluteBoundingBoxRect()) | |
54 .WillRepeatedly(Return( | |
55 IntRect(10, 10, 100, 100))); | |
56 | |
57 // Normally, the autoplay experiment should not modify lots of other | |
58 // state unless we explicitly expect it. | |
59 EXPECT_CALL(*this, setMuted(_)) | |
60 .Times(0); | |
61 EXPECT_CALL(*this, removeUserGestureRequirement()) | |
62 .Times(0); | |
63 EXPECT_CALL(*this, setRequestPositionUpdates(true)) | |
64 .Times(0); | |
65 EXPECT_CALL(*this, recordAutoplayMetric(_)) | |
66 .Times(0); | |
67 } | |
68 | |
69 virtual ~MockAutoplayClient() {} | |
70 | |
71 MOCK_CONST_METHOD0(currentTime, double()); | |
72 MOCK_CONST_METHOD0(duration, double()); | |
73 MOCK_CONST_METHOD0(paused, bool()); | |
74 MOCK_CONST_METHOD0(muted, bool()); | |
75 MOCK_METHOD1(setMuted, void(bool)); | |
76 MOCK_METHOD0(playInternal, void()); | |
77 MOCK_CONST_METHOD0(isUserGestureRequiredForPlay, bool()); | |
78 MOCK_METHOD0(removeUserGestureRequirement, void()); | |
79 MOCK_METHOD1(recordAutoplayMetric, void(AutoplayMetrics)); | |
80 MOCK_METHOD1(shouldAutoplay, bool(RecordMetricsBehavior)); | |
81 MOCK_CONST_METHOD0(isHTMLVideoElement, bool()); | |
82 MOCK_CONST_METHOD0(isHTMLAudioElement, bool()); | |
83 MOCK_METHOD0(isLegacyViewportType, bool()); | |
84 MOCK_CONST_METHOD0(pageVisibilityState, PageVisibilityState()); | |
85 MOCK_CONST_METHOD0(autoplayExperimentMode, String()); | |
86 MOCK_METHOD1(setRequestPositionUpdates, void(bool)); | |
87 MOCK_CONST_METHOD0(absoluteBoundingBoxRect, IntRect()); | |
88 | |
89 const char* m_mode; | |
90 // const since changes to it won't affect the mocked value. | |
91 const double m_duration; | |
92 }; | |
93 | |
94 class AutoplayExperimentTest : public ::testing::Test { | |
95 public: | |
96 AutoplayExperimentTest() | |
97 : client(nullptr) | |
98 , helper(nullptr) | |
99 { | |
100 } | |
101 ~AutoplayExperimentTest() | |
102 { | |
103 if (helper) | |
104 delete helper; | |
philipj_slow
2016/01/12 15:12:18
Looks like you really want an auto pointer, so Own
liberato (no reviews please)
2016/01/29 08:25:25
Done.
| |
105 | |
106 if (client) | |
107 delete client; | |
108 } | |
109 | |
110 bool isEligible() | |
111 { | |
112 return helper->isEligible(); | |
113 } | |
114 | |
115 void setInterface(MockAutoplayClient* client) | |
116 { | |
117 this->client = client; | |
118 | |
119 // Set some defaults. | |
120 setUserGestureRequiredForPlay(true); | |
121 setShouldAutoplay(true); | |
122 setIsMuted(false); | |
123 | |
124 helper = new AutoplayExperimentHelper(*client); | |
125 } | |
126 | |
127 MockAutoplayClient* client; | |
philipj_slow
2016/01/12 15:12:18
https://www.chromium.org/blink/coding-style#TOC-Na
liberato (no reviews please)
2016/01/29 08:25:24
don't know why i did that. thanks.
| |
128 AutoplayExperimentHelper* helper; | |
129 | |
130 // Mirror updatePlayState to transition to play. | |
131 void startPlayback() | |
132 { | |
133 EXPECT_CALL(*client, paused()) | |
134 .WillRepeatedly(Return(false)); | |
135 EXPECT_CALL(*client, recordAutoplayMetric(AnyPlaybackStarted)) | |
136 .Times(1); | |
137 helper->playbackStarted(); | |
138 } | |
139 | |
140 void startPlaybackWithoutUserGesture() | |
141 { | |
142 EXPECT_FALSE(UserGestureIndicator::processingUserGesture()); | |
143 startPlayback(); | |
144 } | |
145 | |
146 void startPlaybackWithUserGesture() | |
147 { | |
148 UserGestureIndicator indicator(DefinitelyProcessingUserGesture); | |
149 EXPECT_TRUE(UserGestureIndicator::processingUserGesture()); | |
150 startPlayback(); | |
151 } | |
152 | |
153 void setCurrentTimeToEnd() | |
154 { | |
155 EXPECT_CALL(*client, currentTime()) | |
philipj_slow
2016/01/12 15:12:18
Is this how unit tests are normally written? I'm u
liberato (no reviews please)
2016/01/29 08:25:24
moved to ON_CALL, and make a NiceMock out of it to
| |
156 .WillRepeatedly(Return(client->m_duration)); | |
157 } | |
158 | |
159 void setUserGestureRequiredForPlay(bool required) | |
160 { | |
161 EXPECT_CALL(*client, isUserGestureRequiredForPlay()) | |
162 .WillRepeatedly(Return(required)); | |
163 } | |
164 | |
165 void setShouldAutoplay(bool should) | |
166 { | |
167 EXPECT_CALL(*client, shouldAutoplay(_)) | |
168 .WillRepeatedly(Return(should)); | |
169 } | |
170 | |
171 void setIsMuted(bool isMuted) | |
172 { | |
173 EXPECT_CALL(*client, muted()) | |
174 .WillRepeatedly(Return(isMuted)); | |
175 } | |
176 | |
177 void pausePlaybackExpectingBailout(bool expectingAutoplay) | |
178 { | |
179 EXPECT_CALL(*client, recordAutoplayMetric(AnyPlaybackPaused)) | |
180 .Times(1); | |
181 EXPECT_CALL(*client, recordAutoplayMetric(AnyPlaybackBailout)) | |
182 .Times(1); | |
183 if (expectingAutoplay) { | |
184 EXPECT_CALL(*client, recordAutoplayMetric(AutoplayPaused)) | |
185 .Times(1); | |
186 EXPECT_CALL(*client, recordAutoplayMetric(AutoplayBailout)) | |
187 .Times(1); | |
188 } | |
189 helper->pauseMethodCalled(); | |
190 } | |
191 | |
192 void pausePlaybackNotExpectingBailout(bool expectingAutoplay) | |
philipj_slow
2016/01/12 15:12:18
Doesn't this have to EXPECT_CALL *something* to fa
liberato (no reviews please)
2016/01/29 08:25:24
added Times(0) for both bailout cases.
| |
193 { | |
194 EXPECT_CALL(*client, recordAutoplayMetric(AnyPlaybackPaused)) | |
195 .Times(1); | |
196 if (expectingAutoplay) | |
197 EXPECT_CALL(*client, recordAutoplayMetric(AutoplayPaused)).Times(1); | |
198 setCurrentTimeToEnd(); | |
199 helper->pauseMethodCalled(); | |
200 } | |
201 | |
202 void endPlayback(bool expectingAutoplay) | |
203 { | |
204 EXPECT_CALL(*client, recordAutoplayMetric(AnyPlaybackComplete)) | |
205 .Times(1); | |
206 if (expectingAutoplay) | |
207 EXPECT_CALL(*client, recordAutoplayMetric(AutoplayComplete)).Times(1 ); | |
208 helper->playbackEnded(); | |
209 } | |
210 | |
211 void moveIntoViewport() | |
212 { | |
213 helper->positionChanged(IntRect(0, 0, 200, 200)); | |
214 helper->triggerAutoplayViewportCheckForTesting(); | |
215 } | |
216 }; | |
217 | |
218 TEST_F(AutoplayExperimentTest, IsNotEligibleWithEmptyMode) | |
219 { | |
220 setInterface(new MockAutoplayClient("")); | |
221 EXPECT_FALSE(isEligible()); | |
222 } | |
223 | |
224 TEST_F(AutoplayExperimentTest, IsVideoEligibleForVideoMode) | |
225 { | |
226 // Video should be eligible in "forvideo" mode. | |
227 setInterface(new MockAutoplayClient()); | |
228 EXPECT_TRUE(isEligible()); | |
229 } | |
230 | |
231 TEST_F(AutoplayExperimentTest, IsAudioNotEligibleForVideoMode) | |
232 { | |
233 // Audio should not be eligible for video mode. | |
234 setInterface(new MockAutoplayClient("enabled-forvideo", MockAutoplayClient:: AUDIO)); | |
235 EXPECT_FALSE(isEligible()); | |
236 } | |
237 | |
238 TEST_F(AutoplayExperimentTest, IsEligibleRequiresUserGesture) | |
239 { | |
240 setInterface(new MockAutoplayClient()); | |
241 // If a user gesture is not required, then we're not eligible. | |
242 EXPECT_CALL(*client, isUserGestureRequiredForPlay()) | |
243 .WillRepeatedly(Return(false)); | |
244 EXPECT_FALSE(isEligible()); | |
245 } | |
246 | |
247 TEST_F(AutoplayExperimentTest, IsEligibleRequiresShouldAutoplay) | |
248 { | |
249 setInterface(new MockAutoplayClient()); | |
250 // If we shouldn't autoplay, then we're not eligible. | |
251 EXPECT_CALL(*client, shouldAutoplay(_)) | |
252 .WillRepeatedly(Return(false)); | |
253 EXPECT_FALSE(isEligible()); | |
254 } | |
255 | |
256 TEST_F(AutoplayExperimentTest, IsAudioEligibleForAudioMode) | |
257 { | |
258 setInterface(new MockAutoplayClient("enabled-foraudio", MockAutoplayClient:: AUDIO)); | |
259 EXPECT_TRUE(isEligible()); | |
260 } | |
261 | |
262 TEST_F(AutoplayExperimentTest, EligibleIfOptimizedForMobile) | |
263 { | |
264 setInterface(new MockAutoplayClient("enabled-forvideo-ifmobile")); | |
265 // Should not be eligible with our default of "not mobile". | |
266 EXPECT_FALSE(isEligible()); | |
267 | |
268 EXPECT_CALL(*client, isLegacyViewportType()) | |
269 .WillRepeatedly(Return(true)); | |
270 EXPECT_TRUE(isEligible()); | |
271 } | |
272 | |
273 TEST_F(AutoplayExperimentTest, EligibleIfMuted) | |
274 { | |
275 setInterface(new MockAutoplayClient("enabled-forvideo-ifmuted")); | |
276 // Should not be eligible with our default of "not muted". | |
277 EXPECT_FALSE(isEligible()); | |
278 | |
279 EXPECT_CALL(*client, muted()) | |
280 .WillRepeatedly(Return(true)); | |
281 EXPECT_TRUE(isEligible()); | |
282 } | |
283 | |
284 TEST_F(AutoplayExperimentTest, BecameReadyAutoplayThenBailout) | |
285 { | |
286 setInterface(new MockAutoplayClient()); | |
287 | |
288 EXPECT_CALL(*client, removeUserGestureRequirement()) | |
289 .Times(1); | |
290 EXPECT_CALL(*client, recordAutoplayMetric(AutoplayMediaFound)) | |
291 .Times(1); | |
292 helper->becameReadyToPlay(); | |
293 | |
294 EXPECT_CALL(*client, recordAutoplayMetric(GesturelessPlaybackStartedByAutopl ayFlagImmediately)) | |
295 .Times(1); | |
296 startPlaybackWithoutUserGesture(); | |
297 | |
298 pausePlaybackExpectingBailout(true); | |
299 } | |
300 | |
301 TEST_F(AutoplayExperimentTest, BecameReadyAutoplayThenPause) | |
302 { | |
303 setInterface(new MockAutoplayClient()); | |
304 | |
305 EXPECT_CALL(*client, removeUserGestureRequirement()) | |
306 .Times(1); | |
307 EXPECT_CALL(*client, recordAutoplayMetric(AutoplayMediaFound)) | |
308 .Times(1); | |
309 helper->becameReadyToPlay(); | |
310 | |
311 EXPECT_CALL(*client, recordAutoplayMetric(GesturelessPlaybackStartedByAutopl ayFlagImmediately)) | |
312 .Times(1); | |
313 startPlaybackWithoutUserGesture(); | |
314 | |
315 pausePlaybackNotExpectingBailout(true); | |
316 } | |
317 | |
318 TEST_F(AutoplayExperimentTest, BecameReadyAutoplayThenComplete) | |
319 { | |
320 setInterface(new MockAutoplayClient()); | |
321 | |
322 EXPECT_CALL(*client, removeUserGestureRequirement()) | |
323 .Times(1); | |
324 EXPECT_CALL(*client, recordAutoplayMetric(AutoplayMediaFound)) | |
325 .Times(1); | |
326 helper->becameReadyToPlay(); | |
327 | |
328 EXPECT_CALL(*client, recordAutoplayMetric(GesturelessPlaybackStartedByAutopl ayFlagImmediately)) | |
329 .Times(1); | |
330 startPlaybackWithoutUserGesture(); | |
331 | |
332 // Now stop at the end. | |
333 endPlayback(true); | |
334 } | |
335 | |
336 TEST_F(AutoplayExperimentTest, NoUserGestureNeededShouldNotOverride) | |
337 { | |
338 // Make sure that we don't override the user gesture if it isn't needed. | |
339 setInterface(new MockAutoplayClient()); | |
340 setUserGestureRequiredForPlay(false); | |
341 | |
342 // It is still autoplay media, though. | |
343 EXPECT_CALL(*client, recordAutoplayMetric(AutoplayMediaFound)) | |
344 .Times(1); | |
345 helper->becameReadyToPlay(); | |
346 | |
347 EXPECT_CALL(*client, recordAutoplayMetric(GesturelessPlaybackUnknownReason)) | |
348 .Times(1); | |
349 startPlaybackWithoutUserGesture(); | |
350 } | |
351 | |
352 TEST_F(AutoplayExperimentTest, NoAutoplayMetricsIfNoAutoplay) | |
353 { | |
354 // If playback is started while processing a user gesture, then nothing | |
355 // should be overridden or logged about autoplay. | |
356 setInterface(new MockAutoplayClient()); | |
357 setUserGestureRequiredForPlay(false); | |
358 setShouldAutoplay(false); | |
359 startPlaybackWithUserGesture(); | |
360 | |
361 // Expect bailout, but not from autoplay. | |
362 pausePlaybackExpectingBailout(false); | |
363 } | |
364 | |
365 TEST_F(AutoplayExperimentTest, PlayMethodThenBailout) | |
366 { | |
367 setInterface(new MockAutoplayClient()); | |
368 setShouldAutoplay(false); // No autoplay attribute. | |
369 | |
370 EXPECT_CALL(*client, removeUserGestureRequirement()) | |
371 .Times(1); | |
372 EXPECT_CALL(*client, recordAutoplayMetric(AutoplayMediaFound)) | |
373 .Times(1); | |
374 helper->playMethodCalled(); | |
375 | |
376 EXPECT_CALL(*client, recordAutoplayMetric(GesturelessPlaybackStartedByPlayMe thodImmediately)) | |
377 .Times(1); | |
378 startPlaybackWithoutUserGesture(); | |
379 | |
380 pausePlaybackExpectingBailout(true); | |
381 } | |
382 | |
383 TEST_F(AutoplayExperimentTest, DeferAutoplayUntilMuted) | |
384 { | |
385 setInterface(new MockAutoplayClient("enabled-forvideo-ifmuted")); | |
386 | |
387 // Should not override the gesture requirement yet. | |
388 EXPECT_CALL(*client, recordAutoplayMetric(AutoplayMediaFound)) | |
389 .Times(1); | |
390 helper->becameReadyToPlay(); | |
391 | |
392 // When we toggle the muted attribute, it should start. | |
393 EXPECT_CALL(*client, removeUserGestureRequirement()) | |
394 .Times(1); | |
395 EXPECT_CALL(*client, playInternal()) | |
396 .Times(1); | |
397 setIsMuted(true); | |
398 helper->mutedChanged(); | |
399 | |
400 // When playback starts (in response to playInternal()), it should also | |
401 // record why. 'After scroll' isn't the best name, but this isn't a common case. | |
402 EXPECT_CALL(*client, recordAutoplayMetric(GesturelessPlaybackStartedByAutopl ayFlagAfterScroll)) | |
403 .Times(1); | |
404 startPlaybackWithoutUserGesture(); | |
405 } | |
406 | |
407 TEST_F(AutoplayExperimentTest, DeferPlaybackUntilInViewport) | |
408 { | |
409 setInterface(new MockAutoplayClient("enabled-forvideo-ifviewport")); | |
410 | |
411 // Should not override the gesture requirement yet. | |
412 EXPECT_CALL(*client, recordAutoplayMetric(AutoplayMediaFound)) | |
413 .Times(1); | |
414 EXPECT_CALL(*client, setRequestPositionUpdates(true)) | |
415 .Times(1); | |
416 helper->becameReadyToPlay(); | |
417 | |
418 EXPECT_CALL(*client, removeUserGestureRequirement()) | |
419 .Times(1); | |
420 EXPECT_CALL(*client, playInternal()) | |
421 .Times(1); | |
422 EXPECT_CALL(*client, setRequestPositionUpdates(false)) | |
423 .Times(1); | |
424 moveIntoViewport(); | |
425 } | |
426 } | |
OLD | NEW |