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