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