1 // Copyright 2016 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 "third_party/blink/renderer/core/html/media/html_media_element.h"
6
7 #include "base/test/gtest_util.h"
8 #include "testing/gmock/include/gmock/gmock.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "third_party/blink/public/mojom/autoplay/autoplay.mojom-blink.h"
11 #include "third_party/blink/public/platform/web_media_player.h"
12 #include "third_party/blink/public/platform/web_media_player_source.h"
13 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
14 #include "third_party/blink/renderer/core/frame/settings.h"
15 #include "third_party/blink/renderer/core/html/media/html_audio_element.h"
16 #include "third_party/blink/renderer/core/html/media/html_video_element.h"
17 #include "third_party/blink/renderer/core/html/media/media_error.h"
18 #include "third_party/blink/renderer/core/html/time_ranges.h"
19 #include "third_party/blink/renderer/core/html/track/audio_track_list.h"
20 #include "third_party/blink/renderer/core/html/track/video_track_list.h"
21 #include "third_party/blink/renderer/core/loader/empty_clients.h"
22 #include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
23 #include "third_party/blink/renderer/platform/heap/heap.h"
24 #include "third_party/blink/renderer/platform/network/network_state_notifier.h"
25 #include "third_party/blink/renderer/platform/testing/empty_web_media_player.h"
26 #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
27 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
28 #include "third_party/blink/renderer/platform/wtf/vector.h"
29
30 using ::testing::_;
31 using ::testing::AnyNumber;
32 using ::testing::NanSensitiveDoubleEq;
33 using ::testing::Return;
34
35 namespace blink {
36
37 namespace {
38
39 class MockWebMediaPlayer : public EmptyWebMediaPlayer {
40 public:
41 MOCK_CONST_METHOD0(HasAudio, bool());
42 MOCK_CONST_METHOD0(HasVideo, bool());
43 MOCK_CONST_METHOD0(Duration, double());
44 MOCK_CONST_METHOD0(CurrentTime, double());
45 MOCK_CONST_METHOD0(IsEnded, bool());
46 MOCK_CONST_METHOD0(GetNetworkState, NetworkState());
47 MOCK_CONST_METHOD0(WouldTaintOrigin, bool());
48 MOCK_METHOD1(SetLatencyHint, void(double));
49 MOCK_METHOD1(EnabledAudioTracksChanged, void(const WebVector<TrackId>&));
50 MOCK_METHOD1(SelectedVideoTrackChanged, void(TrackId*));
51 MOCK_METHOD3(
52 Load,
53 WebMediaPlayer::LoadTiming(LoadType load_type,
54 const blink::WebMediaPlayerSource& source,
55 CorsMode cors_mode));
56 MOCK_CONST_METHOD0(DidLazyLoad, bool());
57
58 MOCK_METHOD0(GetSrcAfterRedirects, GURL());
59 };
60
61 class WebMediaStubLocalFrameClient : public EmptyLocalFrameClient {
62 public:
WebMediaStubLocalFrameClient(std::unique_ptr<WebMediaPlayer> player)63 explicit WebMediaStubLocalFrameClient(std::unique_ptr<WebMediaPlayer> player)
64 : player_(std::move(player)) {}
65
CreateWebMediaPlayer(HTMLMediaElement &,const WebMediaPlayerSource &,WebMediaPlayerClient * client)66 std::unique_ptr<WebMediaPlayer> CreateWebMediaPlayer(
67 HTMLMediaElement&,
68 const WebMediaPlayerSource&,
69 WebMediaPlayerClient* client) override {
70 DCHECK(player_) << " Empty injected player - already used?";
71 return std::move(player_);
72 }
73
74 private:
75 std::unique_ptr<WebMediaPlayer> player_;
76 };
77
78 enum class MediaTestParam { kAudio, kVideo };
79
80 } // namespace
81
82 class HTMLMediaElementTest : public testing::TestWithParam<MediaTestParam> {
83 protected:
SetUp()84 void SetUp() override {
85 // Sniff the media player pointer to facilitate mocking.
86 auto mock_media_player = std::make_unique<MockWebMediaPlayer>();
87 media_player_ = mock_media_player.get();
88
89 // Most tests do not care about this call, nor its return value. Those that
90 // do will clear this expectation and set custom expectations/returns.
91 EXPECT_CALL(*mock_media_player, HasAudio()).WillRepeatedly(Return(true));
92 EXPECT_CALL(*mock_media_player, HasVideo()).WillRepeatedly(Return(true));
93 EXPECT_CALL(*mock_media_player, Duration()).WillRepeatedly(Return(1.0));
94 EXPECT_CALL(*mock_media_player, CurrentTime()).WillRepeatedly(Return(0));
95 EXPECT_CALL(*mock_media_player, Load(_, _, _))
96 .Times(AnyNumber())
97 .WillRepeatedly(Return(WebMediaPlayer::LoadTiming::kImmediate));
98 EXPECT_CALL(*mock_media_player, DidLazyLoad).WillRepeatedly(Return(false));
99 EXPECT_CALL(*mock_media_player, WouldTaintOrigin)
100 .WillRepeatedly(Return(true));
101 EXPECT_CALL(*mock_media_player, GetNetworkState)
102 .WillRepeatedly(Return(WebMediaPlayer::kNetworkStateIdle));
103 EXPECT_CALL(*mock_media_player, SetLatencyHint(_)).Times(AnyNumber());
104
105 dummy_page_holder_ = std::make_unique<DummyPageHolder>(
106 IntSize(), nullptr,
107 MakeGarbageCollected<WebMediaStubLocalFrameClient>(
108 std::move(mock_media_player)));
109
110 if (GetParam() == MediaTestParam::kAudio) {
111 media_ = MakeGarbageCollected<HTMLAudioElement>(
112 dummy_page_holder_->GetDocument());
113 } else {
114 media_ = MakeGarbageCollected<HTMLVideoElement>(
115 dummy_page_holder_->GetDocument());
116 }
117 }
118
Media() const119 HTMLMediaElement* Media() const { return media_.Get(); }
SetCurrentSrc(const AtomicString & src)120 void SetCurrentSrc(const AtomicString& src) {
121 KURL url(src);
122 Media()->current_src_ = url;
123 }
124
MockMediaPlayer()125 MockWebMediaPlayer* MockMediaPlayer() { return media_player_; }
126
WasAutoplayInitiated()127 bool WasAutoplayInitiated() { return Media()->WasAutoplayInitiated(); }
128
CouldPlayIfEnoughData()129 bool CouldPlayIfEnoughData() { return Media()->CouldPlayIfEnoughData(); }
130
ShouldDelayLoadEvent()131 bool ShouldDelayLoadEvent() { return Media()->should_delay_load_event_; }
132
SetReadyState(HTMLMediaElement::ReadyState state)133 void SetReadyState(HTMLMediaElement::ReadyState state) {
134 Media()->SetReadyState(state);
135 }
136
SetNetworkState(WebMediaPlayer::NetworkState state)137 void SetNetworkState(WebMediaPlayer::NetworkState state) {
138 Media()->SetNetworkState(state);
139 }
140
MediaShouldBeOpaque() const141 bool MediaShouldBeOpaque() const { return Media()->MediaShouldBeOpaque(); }
142
SetError(MediaError * err)143 void SetError(MediaError* err) { Media()->MediaEngineError(err); }
144
SimulateHighMediaEngagement()145 void SimulateHighMediaEngagement() {
146 Media()->GetDocument().GetPage()->AddAutoplayFlags(
147 mojom::blink::kAutoplayFlagHighMediaEngagement);
148 }
149
HasLazyLoadObserver() const150 bool HasLazyLoadObserver() const {
151 return !!Media()->lazy_load_intersection_observer_;
152 }
153
GetExecutionContext() const154 ExecutionContext* GetExecutionContext() const {
155 return dummy_page_holder_->GetFrame().DomWindow();
156 }
157
158 private:
159 std::unique_ptr<DummyPageHolder> dummy_page_holder_;
160 Persistent<HTMLMediaElement> media_;
161
162 // Owned by WebMediaStubLocalFrameClient.
163 MockWebMediaPlayer* media_player_;
164 };
165
166 INSTANTIATE_TEST_SUITE_P(Audio,
167 HTMLMediaElementTest,
168 testing::Values(MediaTestParam::kAudio));
169 INSTANTIATE_TEST_SUITE_P(Video,
170 HTMLMediaElementTest,
171 testing::Values(MediaTestParam::kVideo));
172
TEST_P(HTMLMediaElementTest,effectiveMediaVolume)173 TEST_P(HTMLMediaElementTest, effectiveMediaVolume) {
174 struct TestData {
175 double volume;
176 bool muted;
177 double effective_volume;
178 } test_data[] = {
179 {0.0, false, 0.0}, {0.5, false, 0.5}, {1.0, false, 1.0},
180 {0.0, true, 0.0}, {0.5, true, 0.0}, {1.0, true, 0.0},
181 };
182
183 for (const auto& data : test_data) {
184 Media()->setVolume(data.volume);
185 Media()->setMuted(data.muted);
186 EXPECT_EQ(data.effective_volume, Media()->EffectiveMediaVolume());
187 }
188 }
189
190 enum class TestURLScheme {
191 kHttp,
192 kHttps,
193 kFtp,
194 kFile,
195 kData,
196 kBlob,
197 };
198
SrcSchemeToURL(TestURLScheme scheme)199 AtomicString SrcSchemeToURL(TestURLScheme scheme) {
200 switch (scheme) {
201 case TestURLScheme::kHttp:
202 return "http://example.com/foo.mp4";
203 case TestURLScheme::kHttps:
204 return "https://example.com/foo.mp4";
205 case TestURLScheme::kFtp:
206 return "ftp://example.com/foo.mp4";
207 case TestURLScheme::kFile:
208 return "file:///foo/bar.mp4";
209 case TestURLScheme::kData:
210 return "data:video/mp4;base64,XXXXXXX";
211 case TestURLScheme::kBlob:
212 return "blob:http://example.com/00000000-0000-0000-0000-000000000000";
213 default:
214 NOTREACHED();
215 }
216 return g_empty_atom;
217 }
218
TEST_P(HTMLMediaElementTest,preloadType)219 TEST_P(HTMLMediaElementTest, preloadType) {
220 struct TestData {
221 bool data_saver_enabled;
222 bool is_cellular;
223 TestURLScheme src_scheme;
224 AtomicString preload_to_set;
225 AtomicString preload_expected;
226 } test_data[] = {
227 // Tests for conditions in which preload type should be overriden to
228 // "none".
229 {false, false, TestURLScheme::kHttp, "auto", "auto"},
230 {true, false, TestURLScheme::kHttps, "auto", "auto"},
231 {true, false, TestURLScheme::kFtp, "metadata", "metadata"},
232 {false, false, TestURLScheme::kHttps, "auto", "auto"},
233 {false, false, TestURLScheme::kFile, "auto", "auto"},
234 {false, false, TestURLScheme::kData, "metadata", "metadata"},
235 {false, false, TestURLScheme::kBlob, "auto", "auto"},
236 {false, false, TestURLScheme::kFile, "none", "none"},
237 // Tests for conditions in which preload type should be overriden to
238 // "metadata".
239 {false, true, TestURLScheme::kHttp, "auto", "metadata"},
240 {false, true, TestURLScheme::kHttp, "scheme", "metadata"},
241 {false, true, TestURLScheme::kHttp, "none", "none"},
242 // Tests that the preload is overriden to "metadata".
243 {false, false, TestURLScheme::kHttp, "foo", "metadata"},
244 };
245
246 int index = 0;
247 for (const auto& data : test_data) {
248 GetNetworkStateNotifier().SetSaveDataEnabledOverride(
249 data.data_saver_enabled);
250 if (data.is_cellular) {
251 GetNetworkStateNotifier().SetNetworkConnectionInfoOverride(
252 true, WebConnectionType::kWebConnectionTypeCellular3G,
253 WebEffectiveConnectionType::kTypeUnknown, 1.0, 2.0);
254 } else {
255 GetNetworkStateNotifier().ClearOverride();
256 }
257 SetCurrentSrc(SrcSchemeToURL(data.src_scheme));
258 Media()->setPreload(data.preload_to_set);
259
260 EXPECT_EQ(data.preload_expected, Media()->preload())
261 << "preload type differs at index" << index;
262 ++index;
263 }
264 }
265
TEST_P(HTMLMediaElementTest,CouldPlayIfEnoughDataRespondsToPlay)266 TEST_P(HTMLMediaElementTest, CouldPlayIfEnoughDataRespondsToPlay) {
267 EXPECT_FALSE(CouldPlayIfEnoughData());
268 Media()->Play();
269 EXPECT_TRUE(CouldPlayIfEnoughData());
270 }
271
TEST_P(HTMLMediaElementTest,CouldPlayIfEnoughDataRespondsToEnded)272 TEST_P(HTMLMediaElementTest, CouldPlayIfEnoughDataRespondsToEnded) {
273 Media()->SetSrc(SrcSchemeToURL(TestURLScheme::kHttp));
274 Media()->Play();
275
276 test::RunPendingTasks();
277
278 MockWebMediaPlayer* mock_wmpi =
279 reinterpret_cast<MockWebMediaPlayer*>(Media()->GetWebMediaPlayer());
280 ASSERT_NE(mock_wmpi, nullptr);
281 EXPECT_CALL(*mock_wmpi, IsEnded()).WillRepeatedly(Return(false));
282 EXPECT_TRUE(CouldPlayIfEnoughData());
283
284 // Playback can only end once the ready state is above kHaveMetadata.
285 SetReadyState(HTMLMediaElement::kHaveFutureData);
286 EXPECT_FALSE(Media()->paused());
287 EXPECT_FALSE(Media()->ended());
288 EXPECT_TRUE(CouldPlayIfEnoughData());
289
290 // Now advance current time to duration and verify ended state.
291 testing::Mock::VerifyAndClearExpectations(mock_wmpi);
292 EXPECT_CALL(*mock_wmpi, CurrentTime())
293 .WillRepeatedly(Return(Media()->duration()));
294 EXPECT_CALL(*mock_wmpi, IsEnded()).WillRepeatedly(Return(true));
295 EXPECT_FALSE(CouldPlayIfEnoughData());
296 EXPECT_TRUE(Media()->ended());
297 }
298
TEST_P(HTMLMediaElementTest,CouldPlayIfEnoughDataRespondsToError)299 TEST_P(HTMLMediaElementTest, CouldPlayIfEnoughDataRespondsToError) {
300 Media()->SetSrc(SrcSchemeToURL(TestURLScheme::kHttp));
301 Media()->Play();
302
303 test::RunPendingTasks();
304
305 MockWebMediaPlayer* mock_wmpi =
306 reinterpret_cast<MockWebMediaPlayer*>(Media()->GetWebMediaPlayer());
307 EXPECT_NE(mock_wmpi, nullptr);
308 EXPECT_TRUE(CouldPlayIfEnoughData());
309
310 SetReadyState(HTMLMediaElement::kHaveMetadata);
311 EXPECT_FALSE(Media()->paused());
312 EXPECT_FALSE(Media()->ended());
313 EXPECT_TRUE(CouldPlayIfEnoughData());
314
315 SetError(MakeGarbageCollected<MediaError>(MediaError::kMediaErrDecode, ""));
316 EXPECT_FALSE(CouldPlayIfEnoughData());
317 }
318
TEST_P(HTMLMediaElementTest,SetLatencyHint)319 TEST_P(HTMLMediaElementTest, SetLatencyHint) {
320 const double kNan = std::numeric_limits<double>::quiet_NaN();
321
322 // Initial value.
323 Media()->SetSrc(SrcSchemeToURL(TestURLScheme::kHttp));
324 EXPECT_CALL(*MockMediaPlayer(), SetLatencyHint(NanSensitiveDoubleEq(kNan)));
325
326 test::RunPendingTasks();
327 testing::Mock::VerifyAndClearExpectations(MockMediaPlayer());
328
329 // Valid value.
330 EXPECT_CALL(*MockMediaPlayer(), SetLatencyHint(NanSensitiveDoubleEq(1.0)));
331 Media()->setLatencyHint(1.0);
332
333 test::RunPendingTasks();
334 testing::Mock::VerifyAndClearExpectations(MockMediaPlayer());
335
336 // Invalid value.
337 EXPECT_CALL(*MockMediaPlayer(), SetLatencyHint(NanSensitiveDoubleEq(kNan)));
338 Media()->setLatencyHint(-1.0);
339 }
340
TEST_P(HTMLMediaElementTest,CouldPlayIfEnoughDataInfiniteStreamNeverEnds)341 TEST_P(HTMLMediaElementTest, CouldPlayIfEnoughDataInfiniteStreamNeverEnds) {
342 Media()->SetSrc(SrcSchemeToURL(TestURLScheme::kHttp));
343 Media()->Play();
344
345 test::RunPendingTasks();
346
347 EXPECT_CALL(*MockMediaPlayer(), Duration())
348 .WillRepeatedly(Return(std::numeric_limits<double>::infinity()));
349 EXPECT_CALL(*MockMediaPlayer(), CurrentTime())
350 .WillRepeatedly(Return(std::numeric_limits<double>::infinity()));
351
352 SetReadyState(HTMLMediaElement::kHaveMetadata);
353 EXPECT_FALSE(Media()->paused());
354 EXPECT_FALSE(Media()->ended());
355 EXPECT_TRUE(CouldPlayIfEnoughData());
356 }
357
TEST_P(HTMLMediaElementTest,AutoplayInitiated_DocumentActivation_Low_Gesture)358 TEST_P(HTMLMediaElementTest, AutoplayInitiated_DocumentActivation_Low_Gesture) {
359 // Setup is the following:
360 // - Policy: DocumentUserActivation (aka. unified autoplay)
361 // - MEI: low;
362 // - Frame received user gesture.
363 ScopedMediaEngagementBypassAutoplayPoliciesForTest scoped_feature(true);
364 Media()->GetDocument().GetSettings()->SetAutoplayPolicy(
365 AutoplayPolicy::Type::kDocumentUserActivationRequired);
366 LocalFrame::NotifyUserActivation(Media()->GetDocument().GetFrame());
367
368 Media()->Play();
369
370 EXPECT_FALSE(WasAutoplayInitiated());
371 }
372
TEST_P(HTMLMediaElementTest,AutoplayInitiated_DocumentActivation_High_Gesture)373 TEST_P(HTMLMediaElementTest,
374 AutoplayInitiated_DocumentActivation_High_Gesture) {
375 // Setup is the following:
376 // - Policy: DocumentUserActivation (aka. unified autoplay)
377 // - MEI: high;
378 // - Frame received user gesture.
379 ScopedMediaEngagementBypassAutoplayPoliciesForTest scoped_feature(true);
380 Media()->GetDocument().GetSettings()->SetAutoplayPolicy(
381 AutoplayPolicy::Type::kDocumentUserActivationRequired);
382 SimulateHighMediaEngagement();
383 LocalFrame::NotifyUserActivation(Media()->GetDocument().GetFrame());
384
385 Media()->Play();
386
387 EXPECT_FALSE(WasAutoplayInitiated());
388 }
389
TEST_P(HTMLMediaElementTest,AutoplayInitiated_DocumentActivation_High_NoGesture)390 TEST_P(HTMLMediaElementTest,
391 AutoplayInitiated_DocumentActivation_High_NoGesture) {
392 // Setup is the following:
393 // - Policy: DocumentUserActivation (aka. unified autoplay)
394 // - MEI: high;
395 // - Frame did not receive user gesture.
396 ScopedMediaEngagementBypassAutoplayPoliciesForTest scoped_feature(true);
397 Media()->GetDocument().GetSettings()->SetAutoplayPolicy(
398 AutoplayPolicy::Type::kDocumentUserActivationRequired);
399 SimulateHighMediaEngagement();
400
401 Media()->Play();
402
403 EXPECT_TRUE(WasAutoplayInitiated());
404 }
405
TEST_P(HTMLMediaElementTest,AutoplayInitiated_GestureRequired_Gesture)406 TEST_P(HTMLMediaElementTest, AutoplayInitiated_GestureRequired_Gesture) {
407 // Setup is the following:
408 // - Policy: user gesture is required.
409 // - Frame received a user gesture.
410 // - MEI doesn't matter as it's not used by the policy.
411 Media()->GetDocument().GetSettings()->SetAutoplayPolicy(
412 AutoplayPolicy::Type::kUserGestureRequired);
413 LocalFrame::NotifyUserActivation(Media()->GetDocument().GetFrame());
414
415 Media()->Play();
416
417 EXPECT_FALSE(WasAutoplayInitiated());
418 }
419
TEST_P(HTMLMediaElementTest,AutoplayInitiated_NoGestureRequired_Gesture)420 TEST_P(HTMLMediaElementTest, AutoplayInitiated_NoGestureRequired_Gesture) {
421 // Setup is the following:
422 // - Policy: no user gesture is required.
423 // - Frame received a user gesture.
424 // - MEI doesn't matter as it's not used by the policy.
425 Media()->GetDocument().GetSettings()->SetAutoplayPolicy(
426 AutoplayPolicy::Type::kNoUserGestureRequired);
427 LocalFrame::NotifyUserActivation(Media()->GetDocument().GetFrame());
428
429 Media()->Play();
430
431 EXPECT_FALSE(WasAutoplayInitiated());
432 }
433
TEST_P(HTMLMediaElementTest,AutoplayInitiated_NoGestureRequired_NoGesture)434 TEST_P(HTMLMediaElementTest, AutoplayInitiated_NoGestureRequired_NoGesture) {
435 // Setup is the following:
436 // - Policy: no user gesture is required.
437 // - Frame did not receive a user gesture.
438 // - MEI doesn't matter as it's not used by the policy.
439 Media()->GetDocument().GetSettings()->SetAutoplayPolicy(
440 AutoplayPolicy::Type::kNoUserGestureRequired);
441
442 Media()->Play();
443
444 EXPECT_TRUE(WasAutoplayInitiated());
445 }
446
TEST_P(HTMLMediaElementTest,DeferredMediaPlayerLoadDoesNotDelayWindowLoadEvent)447 TEST_P(HTMLMediaElementTest,
448 DeferredMediaPlayerLoadDoesNotDelayWindowLoadEvent) {
449 // Source isn't really important, we just need something to let load algorithm
450 // run up to the point of calling WebMediaPlayer::Load().
451 Media()->SetSrc(SrcSchemeToURL(TestURLScheme::kHttp));
452
453 // WebMediaPlayer will signal that it will defer loading to some later time.
454 testing::Mock::VerifyAndClearExpectations(MockMediaPlayer());
455 EXPECT_CALL(*MockMediaPlayer(), Load(_, _, _))
456 .WillOnce(Return(WebMediaPlayer::LoadTiming::kDeferred));
457
458 // Window's 'load' event starts out "delayed".
459 EXPECT_TRUE(ShouldDelayLoadEvent());
460 Media()->load();
461 test::RunPendingTasks();
462
463 // No longer delayed because WMP loading is deferred.
464 EXPECT_FALSE(ShouldDelayLoadEvent());
465 }
466
TEST_P(HTMLMediaElementTest,ImmediateMediaPlayerLoadDoesDelayWindowLoadEvent)467 TEST_P(HTMLMediaElementTest, ImmediateMediaPlayerLoadDoesDelayWindowLoadEvent) {
468 // Source isn't really important, we just need something to let load algorithm
469 // run up to the point of calling WebMediaPlayer::Load().
470 Media()->SetSrc(SrcSchemeToURL(TestURLScheme::kHttp));
471
472 // WebMediaPlayer will signal that it will do the load immediately.
473 EXPECT_CALL(*MockMediaPlayer(), Load(_, _, _))
474 .WillOnce(Return(WebMediaPlayer::LoadTiming::kImmediate));
475
476 // Window's 'load' event starts out "delayed".
477 EXPECT_TRUE(ShouldDelayLoadEvent());
478 Media()->load();
479 test::RunPendingTasks();
480
481 // Still delayed because WMP loading is not deferred.
482 EXPECT_TRUE(ShouldDelayLoadEvent());
483 }
484
TEST_P(HTMLMediaElementTest,DefaultTracksAreEnabled)485 TEST_P(HTMLMediaElementTest, DefaultTracksAreEnabled) {
486 // Default tracks should start enabled, not be created then enabled.
487 EXPECT_CALL(*MockMediaPlayer(), EnabledAudioTracksChanged(_)).Times(0);
488 EXPECT_CALL(*MockMediaPlayer(), SelectedVideoTrackChanged(_)).Times(0);
489
490 Media()->SetSrc(SrcSchemeToURL(TestURLScheme::kHttp));
491 test::RunPendingTasks();
492 SetReadyState(HTMLMediaElement::kHaveFutureData);
493
494 ASSERT_EQ(1u, Media()->audioTracks().length());
495 ASSERT_EQ(1u, Media()->videoTracks().length());
496 EXPECT_TRUE(Media()->audioTracks().AnonymousIndexedGetter(0)->enabled());
497 EXPECT_TRUE(Media()->videoTracks().AnonymousIndexedGetter(0)->selected());
498 }
499
500 // Ensure a visibility observer is created for lazy loading.
TEST_P(HTMLMediaElementTest,VisibilityObserverCreatedForLazyLoad)501 TEST_P(HTMLMediaElementTest, VisibilityObserverCreatedForLazyLoad) {
502 Media()->SetSrc(SrcSchemeToURL(TestURLScheme::kHttp));
503 test::RunPendingTasks();
504
505 EXPECT_CALL(*MockMediaPlayer(), DidLazyLoad()).WillRepeatedly(Return(true));
506
507 SetReadyState(HTMLMediaElement::kHaveFutureData);
508 EXPECT_EQ(HasLazyLoadObserver(), GetParam() == MediaTestParam::kVideo);
509 }
510
TEST_P(HTMLMediaElementTest,DomInteractive)511 TEST_P(HTMLMediaElementTest, DomInteractive) {
512 EXPECT_FALSE(Media()->GetDocument().GetTiming().DomInteractive().is_null());
513 }
514
TEST_P(HTMLMediaElementTest,ContextPaused)515 TEST_P(HTMLMediaElementTest, ContextPaused) {
516 Media()->SetSrc(SrcSchemeToURL(TestURLScheme::kHttp));
517 Media()->Play();
518
519 test::RunPendingTasks();
520 SetReadyState(HTMLMediaElement::kHaveFutureData);
521
522 EXPECT_FALSE(Media()->paused());
523 GetExecutionContext()->SetLifecycleState(
524 mojom::FrameLifecycleState::kFrozenAutoResumeMedia);
525 EXPECT_TRUE(Media()->paused());
526 GetExecutionContext()->SetLifecycleState(
527 mojom::FrameLifecycleState::kRunning);
528 EXPECT_FALSE(Media()->paused());
529 GetExecutionContext()->SetLifecycleState(mojom::FrameLifecycleState::kFrozen);
530 EXPECT_TRUE(Media()->paused());
531 GetExecutionContext()->SetLifecycleState(
532 mojom::FrameLifecycleState::kRunning);
533 EXPECT_TRUE(Media()->paused());
534 }
535
TEST_P(HTMLMediaElementTest,GcMarkingNoAllocWebTimeRanges)536 TEST_P(HTMLMediaElementTest, GcMarkingNoAllocWebTimeRanges) {
537 auto* thread_state = ThreadState::Current();
538 ThreadState::NoAllocationScope no_allocation_scope(thread_state);
539 EXPECT_FALSE(thread_state->IsAllocationAllowed());
540 // Use of TimeRanges is not allowed during GC marking (crbug.com/970150)
541 EXPECT_DCHECK_DEATH(MakeGarbageCollected<TimeRanges>(0, 0));
542 // Instead of using TimeRanges, WebTimeRanges can be used without GC
543 Vector<WebTimeRanges> ranges;
544 ranges.emplace_back();
545 ranges[0].emplace_back(0, 0);
546 }
547
548 // Reproduce crbug.com/970150
TEST_P(HTMLMediaElementTest,GcMarkingNoAllocHasActivity)549 TEST_P(HTMLMediaElementTest, GcMarkingNoAllocHasActivity) {
550 Media()->SetSrc(SrcSchemeToURL(TestURLScheme::kHttp));
551 Media()->Play();
552
553 test::RunPendingTasks();
554 SetReadyState(HTMLMediaElement::kHaveFutureData);
555 SetError(MakeGarbageCollected<MediaError>(MediaError::kMediaErrDecode, ""));
556
557 EXPECT_FALSE(Media()->paused());
558
559 auto* thread_state = ThreadState::Current();
560 ThreadState::NoAllocationScope no_allocation_scope(thread_state);
561 EXPECT_FALSE(thread_state->IsAllocationAllowed());
562 Media()->HasPendingActivity();
563 }
564
TEST_P(HTMLMediaElementTest,CapturesRedirectedSrc)565 TEST_P(HTMLMediaElementTest, CapturesRedirectedSrc) {
566 // Verify that the element captures the redirected URL.
567 Media()->SetSrc(SrcSchemeToURL(TestURLScheme::kHttp));
568 Media()->Play();
569 test::RunPendingTasks();
570
571 // Should start at the original.
572 EXPECT_EQ(Media()->downloadURL(), Media()->currentSrc());
573
574 GURL redirected_url("https://redirected.com");
575 EXPECT_CALL(*MockMediaPlayer(), GetSrcAfterRedirects())
576 .WillRepeatedly(Return(redirected_url));
577 SetReadyState(HTMLMediaElement::kHaveFutureData);
578
579 EXPECT_EQ(Media()->downloadURL(), redirected_url);
580 }
581
TEST_P(HTMLMediaElementTest,EmptyRedirectedSrcUsesOriginal)582 TEST_P(HTMLMediaElementTest, EmptyRedirectedSrcUsesOriginal) {
583 // If the player returns an empty URL for the redirected src, then the element
584 // should continue using currentSrc().
585 Media()->SetSrc(SrcSchemeToURL(TestURLScheme::kHttp));
586 Media()->Play();
587 test::RunPendingTasks();
588 EXPECT_EQ(Media()->downloadURL(), Media()->currentSrc());
589 SetReadyState(HTMLMediaElement::kHaveFutureData);
590 EXPECT_EQ(Media()->downloadURL(), Media()->currentSrc());
591 }
592
TEST_P(HTMLMediaElementTest,NoPendingActivityEvenIfBeforeMetadata)593 TEST_P(HTMLMediaElementTest, NoPendingActivityEvenIfBeforeMetadata) {
594 Media()->SetSrc(SrcSchemeToURL(TestURLScheme::kHttp));
595 test::RunPendingTasks();
596
597 MockWebMediaPlayer* mock_wmpi =
598 reinterpret_cast<MockWebMediaPlayer*>(Media()->GetWebMediaPlayer());
599 EXPECT_CALL(*mock_wmpi, WouldTaintOrigin()).WillRepeatedly(Return(true));
600 EXPECT_NE(mock_wmpi, nullptr);
601
602 EXPECT_TRUE(MediaShouldBeOpaque());
603 EXPECT_TRUE(Media()->HasPendingActivity());
604 SetNetworkState(WebMediaPlayer::kNetworkStateIdle);
605 EXPECT_FALSE(Media()->HasPendingActivity());
606 EXPECT_TRUE(MediaShouldBeOpaque());
607 }
608
609 } // namespace blink
610