Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(470)

Unified Diff: third_party/WebKit/Source/core/html/AutoplayExperimentTest.cpp

Issue 1470153004: Autoplay experiment metric fixes and additions. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: ...because tests. Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/html/AutoplayExperimentTest.cpp
diff --git a/third_party/WebKit/Source/core/html/AutoplayExperimentTest.cpp b/third_party/WebKit/Source/core/html/AutoplayExperimentTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5614a0fb54c04ed7ee30ce4a14b71c2564e378e2
--- /dev/null
+++ b/third_party/WebKit/Source/core/html/AutoplayExperimentTest.cpp
@@ -0,0 +1,436 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/dom/Document.h"
+#include "core/html/AutoplayExperimentHelper.h"
+#include "platform/UserGestureIndicator.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// msvc refuses to compile if we use all of ::testing, due to a conflict with
+// WTF::NotNull. So, we just use what we need.
+using ::testing::Return;
+using ::testing::NiceMock;
+using ::testing::_;
+
+namespace blink {
+
+class MockAutoplayClient : public AutoplayExperimentHelper::Client {
+public:
+ enum ElementType { Video, Audio };
+
+ MockAutoplayClient(const char* mode, ElementType type)
+ : m_mode(mode)
+ , m_duration(100)
+ {
+ // Set up default behaviors that the helper is allowed to use or cache
+ // during construction.
+
+ ON_CALL(*this, autoplayExperimentMode())
+ .WillByDefault(Return(m_mode));
+
+ // Use m_isVideo to answer these.
+ ON_CALL(*this, isHTMLVideoElement())
+ .WillByDefault(Return(type == Video));
+ ON_CALL(*this, isHTMLAudioElement())
+ .WillByDefault(Return(type == Audio));
+
+ // Now set up some useful defaults.
+ // Remember that this are only evaluated once.
+ ON_CALL(*this, duration())
+ .WillByDefault(Return(m_duration));
+ ON_CALL(*this, currentTime())
+ .WillByDefault(Return(0));
+
+ // Default to "not optimized for mobile" page.
+ ON_CALL(*this, isLegacyViewportType())
+ .WillByDefault(Return(false));
+
+ // Other handy defaults.
+ ON_CALL(*this, ended())
+ .WillByDefault(Return(false));
+ ON_CALL(*this, pageVisibilityState())
+ .WillByDefault(Return(PageVisibilityStateVisible));
+ ON_CALL(*this, absoluteBoundingBoxRect())
+ .WillByDefault(Return(
+ IntRect(10, 10, 100, 100)));
+
+ // Normally, the autoplay experiment should not modify lots of other
+ // state unless we explicitly expect it.
+ EXPECT_CALL(*this, setMuted(_))
+ .Times(0);
+ EXPECT_CALL(*this, removeUserGestureRequirement())
+ .Times(0);
+ EXPECT_CALL(*this, setRequestPositionUpdates(true))
+ .Times(0);
+ EXPECT_CALL(*this, recordAutoplayMetric(_))
+ .Times(0);
+ }
+
+ virtual ~MockAutoplayClient() {}
+
+ MOCK_CONST_METHOD0(currentTime, double());
+ MOCK_CONST_METHOD0(duration, double());
+ MOCK_CONST_METHOD0(ended, bool());
+ MOCK_CONST_METHOD0(muted, bool());
+ MOCK_METHOD1(setMuted, void(bool));
+ MOCK_METHOD0(playInternal, void());
+ MOCK_CONST_METHOD0(isUserGestureRequiredForPlay, bool());
+ MOCK_METHOD0(removeUserGestureRequirement, void());
+ MOCK_METHOD1(recordAutoplayMetric, void(AutoplayMetrics));
+ MOCK_METHOD0(shouldAutoplay, bool());
+ MOCK_CONST_METHOD0(isHTMLVideoElement, bool());
+ MOCK_CONST_METHOD0(isHTMLAudioElement, bool());
+ MOCK_METHOD0(isLegacyViewportType, bool());
+ MOCK_CONST_METHOD0(pageVisibilityState, PageVisibilityState());
+ MOCK_CONST_METHOD0(autoplayExperimentMode, String());
+ MOCK_METHOD1(setRequestPositionUpdates, void(bool));
+ MOCK_CONST_METHOD0(absoluteBoundingBoxRect, IntRect());
+
+ const char* m_mode;
+ // const since changes to it won't affect the mocked value.
+ const double m_duration;
+};
+
+class AutoplayExperimentTest : public ::testing::Test {
+public:
+ AutoplayExperimentTest() {}
+
+ ~AutoplayExperimentTest() {}
+
+ bool isEligible()
+ {
+ return m_helper->isEligible();
+ }
+
+ void setInterface(PassOwnPtrWillBeRawPtr<MockAutoplayClient> client)
+ {
+ m_client = client;
+
+ // Set some defaults.
+ setUserGestureRequiredForPlay(true);
+ setShouldAutoplay(true);
+ setIsMuted(false);
+
+ m_helper = AutoplayExperimentHelper::create(m_client.get());
+ }
+
+#if ENABLE(OILPAN)
+ void TearDown()
+ {
+ // Be sure that the mock is destructed before the test, so that any
+ // missing expectations are noticed. Otherwise, the test will pass
+ // and then missing expectations will show up in the log, without
+ // causing a test failure.
+ m_helper.clear();
+ m_client.clear();
+ Heap::collectAllGarbage();
+ }
+#endif
+
+ OwnPtrWillBePersistent<MockAutoplayClient> m_client;
+ OwnPtrWillBePersistent<AutoplayExperimentHelper> m_helper;
+
+ // Mirror updatePlayState to transition to play.
+ void startPlayback()
+ {
+ EXPECT_CALL(*m_client, recordAutoplayMetric(AnyPlaybackStarted))
+ .Times(1);
+ m_helper->playbackStarted();
+ }
+
+ void startPlaybackWithoutUserGesture()
+ {
+ EXPECT_FALSE(UserGestureIndicator::processingUserGesture());
+ startPlayback();
+ }
+
+ void startPlaybackWithUserGesture()
+ {
+ UserGestureIndicator indicator(DefinitelyProcessingUserGesture);
+ EXPECT_TRUE(UserGestureIndicator::processingUserGesture());
+ startPlayback();
+ }
+
+ void setUserGestureRequiredForPlay(bool required)
+ {
+ ON_CALL(*m_client, isUserGestureRequiredForPlay())
+ .WillByDefault(Return(required));
+ }
+
+ void setShouldAutoplay(bool should)
+ {
+ ON_CALL(*m_client, shouldAutoplay())
+ .WillByDefault(Return(should));
+ }
+
+ void setIsMuted(bool isMuted)
+ {
+ ON_CALL(*m_client, muted())
+ .WillByDefault(Return(isMuted));
+ }
+
+ void pausePlaybackExpectingBailout(bool expectingAutoplay)
+ {
+ EXPECT_CALL(*m_client, recordAutoplayMetric(AnyPlaybackPaused))
+ .Times(1);
+ EXPECT_CALL(*m_client, recordAutoplayMetric(AnyPlaybackBailout))
+ .Times(1);
+ if (expectingAutoplay) {
+ EXPECT_CALL(*m_client, recordAutoplayMetric(AutoplayPaused))
+ .Times(1);
+ EXPECT_CALL(*m_client, recordAutoplayMetric(AutoplayBailout))
+ .Times(1);
+ }
+ m_helper->pauseMethodCalled();
+ m_helper->playbackStopped();
+ }
+
+ void pausePlaybackNotExpectingBailout(bool expectingAutoplay)
+ {
+ EXPECT_CALL(*m_client, recordAutoplayMetric(AnyPlaybackPaused))
+ .Times(1);
+ if (expectingAutoplay)
+ EXPECT_CALL(*m_client, recordAutoplayMetric(AutoplayPaused)).Times(1);
+ EXPECT_CALL(*m_client, recordAutoplayMetric(AnyPlaybackBailout)).Times(0);
+ EXPECT_CALL(*m_client, recordAutoplayMetric(AutoplayBailout)).Times(0);
+
+ // Move past the bailout point, but not to the end. That way, we don't
+ // have to set ended().
+ ON_CALL(*m_client, currentTime())
+ .WillByDefault(Return(m_client->m_duration-1));
+
+ m_helper->pauseMethodCalled();
+ m_helper->playbackStopped();
+ }
+
+ void endPlayback(bool expectingAutoplay)
+ {
+ EXPECT_CALL(*m_client, recordAutoplayMetric(AnyPlaybackComplete))
+ .Times(1);
+ if (expectingAutoplay)
+ EXPECT_CALL(*m_client, recordAutoplayMetric(AutoplayComplete)).Times(1);
+ ON_CALL(*m_client, currentTime())
+ .WillByDefault(Return(m_client->m_duration));
+ ON_CALL(*m_client, ended())
+ .WillByDefault(Return(true));
+ m_helper->playbackStopped();
+ }
+
+ void moveIntoViewport()
+ {
+ m_helper->positionChanged(IntRect(0, 0, 200, 200));
+ m_helper->triggerAutoplayViewportCheckForTesting();
+ }
+};
+
+TEST_F(AutoplayExperimentTest, IsNotEligibleWithEmptyMode)
+{
+ setInterface(adoptPtrWillBeNoop(new NiceMock<MockAutoplayClient>("", MockAutoplayClient::Video)));
+ EXPECT_FALSE(isEligible());
+}
+
+TEST_F(AutoplayExperimentTest, IsVideoEligibleForVideoMode)
+{
+ // Video should be eligible in "forvideo" mode.
+ setInterface(adoptPtrWillBeNoop(new NiceMock<MockAutoplayClient>("enabled-forvideo", MockAutoplayClient::Video)));
+ EXPECT_TRUE(isEligible());
+}
+
+TEST_F(AutoplayExperimentTest, IsAudioNotEligibleForVideoMode)
+{
+ // Audio should not be eligible for video mode.
+ setInterface(adoptPtrWillBeNoop(new NiceMock<MockAutoplayClient>("enabled-forvideo", MockAutoplayClient::Audio)));
+ EXPECT_FALSE(isEligible());
+}
+
+TEST_F(AutoplayExperimentTest, IsEligibleRequiresUserGesture)
+{
+ setInterface(adoptPtrWillBeNoop(new NiceMock<MockAutoplayClient>("enabled-forvideo", MockAutoplayClient::Video)));
+ // If a user gesture is not required, then we're not eligible.
+ ON_CALL(*m_client, isUserGestureRequiredForPlay())
+ .WillByDefault(Return(false));
+ EXPECT_FALSE(isEligible());
+}
+
+TEST_F(AutoplayExperimentTest, IsEligibleRequiresShouldAutoplay)
+{
+ setInterface(adoptPtrWillBeNoop(new NiceMock<MockAutoplayClient>("enabled-forvideo", MockAutoplayClient::Video)));
+ // If we shouldn't autoplay, then we're not eligible.
+ ON_CALL(*m_client, shouldAutoplay())
+ .WillByDefault(Return(false));
+ EXPECT_FALSE(isEligible());
+}
+
+TEST_F(AutoplayExperimentTest, IsAudioEligibleForAudioMode)
+{
+ setInterface(adoptPtrWillBeNoop(new NiceMock<MockAutoplayClient>("enabled-foraudio", MockAutoplayClient::Audio)));
+ EXPECT_TRUE(isEligible());
+}
+
+TEST_F(AutoplayExperimentTest, EligibleIfOptimizedForMobile)
+{
+ setInterface(adoptPtrWillBeNoop(new NiceMock<MockAutoplayClient>("enabled-forvideo-ifmobile", MockAutoplayClient::Video)));
+ // Should not be eligible with our default of "not mobile".
+ EXPECT_FALSE(isEligible());
+
+ ON_CALL(*m_client, isLegacyViewportType())
+ .WillByDefault(Return(true));
+ EXPECT_TRUE(isEligible());
+}
+
+TEST_F(AutoplayExperimentTest, EligibleIfMuted)
+{
+ setInterface(adoptPtrWillBeNoop(new NiceMock<MockAutoplayClient>("enabled-forvideo-ifmuted", MockAutoplayClient::Video)));
+ // Should not be eligible with our default of "not muted".
+ EXPECT_FALSE(isEligible());
+
+ ON_CALL(*m_client, muted())
+ .WillByDefault(Return(true));
+ EXPECT_TRUE(isEligible());
+}
+
+TEST_F(AutoplayExperimentTest, BecameReadyAutoplayThenBailout)
+{
+ setInterface(adoptPtrWillBeNoop(new NiceMock<MockAutoplayClient>("enabled-forvideo", MockAutoplayClient::Video)));
+
+ EXPECT_CALL(*m_client, removeUserGestureRequirement())
+ .Times(1);
+ EXPECT_CALL(*m_client, recordAutoplayMetric(AutoplayMediaFound))
+ .Times(1);
+ m_helper->becameReadyToPlay();
+
+ EXPECT_CALL(*m_client, recordAutoplayMetric(GesturelessPlaybackStartedByAutoplayFlagImmediately))
+ .Times(1);
+ startPlaybackWithoutUserGesture();
+
+ pausePlaybackExpectingBailout(true);
+}
+
+TEST_F(AutoplayExperimentTest, BecameReadyAutoplayThenPause)
+{
+ setInterface(adoptPtrWillBeNoop(new NiceMock<MockAutoplayClient>("enabled-forvideo", MockAutoplayClient::Video)));
+
+ EXPECT_CALL(*m_client, removeUserGestureRequirement())
+ .Times(1);
+ EXPECT_CALL(*m_client, recordAutoplayMetric(AutoplayMediaFound))
+ .Times(1);
+ m_helper->becameReadyToPlay();
+
+ EXPECT_CALL(*m_client, recordAutoplayMetric(GesturelessPlaybackStartedByAutoplayFlagImmediately))
+ .Times(1);
+ startPlaybackWithoutUserGesture();
+
+ pausePlaybackNotExpectingBailout(true);
+}
+
+TEST_F(AutoplayExperimentTest, BecameReadyAutoplayThenComplete)
+{
+ setInterface(adoptPtrWillBeNoop(new NiceMock<MockAutoplayClient>("enabled-forvideo", MockAutoplayClient::Video)));
+
+ EXPECT_CALL(*m_client, removeUserGestureRequirement())
+ .Times(1);
+ EXPECT_CALL(*m_client, recordAutoplayMetric(AutoplayMediaFound))
+ .Times(1);
+ m_helper->becameReadyToPlay();
+
+ EXPECT_CALL(*m_client, recordAutoplayMetric(GesturelessPlaybackStartedByAutoplayFlagImmediately))
+ .Times(1);
+ startPlaybackWithoutUserGesture();
+
+ // Now stop at the end.
+ endPlayback(true);
+}
+
+TEST_F(AutoplayExperimentTest, NoUserGestureNeededShouldNotOverride)
+{
+ // Make sure that we don't override the user gesture if it isn't needed.
+ setInterface(adoptPtrWillBeNoop(new NiceMock<MockAutoplayClient>("enabled-forvideo", MockAutoplayClient::Video)));
+ setUserGestureRequiredForPlay(false);
+
+ // It is still autoplay media, though.
+ EXPECT_CALL(*m_client, recordAutoplayMetric(AutoplayMediaFound))
+ .Times(1);
+ m_helper->becameReadyToPlay();
+
+ EXPECT_CALL(*m_client, recordAutoplayMetric(GesturelessPlaybackNotOverridden))
+ .Times(1);
+ startPlaybackWithoutUserGesture();
+}
+
+TEST_F(AutoplayExperimentTest, NoAutoplayMetricsIfNoAutoplay)
+{
+ // If playback is started while processing a user gesture, then nothing
+ // should be overridden or logged about autoplay.
+ setInterface(adoptPtrWillBeNoop(new NiceMock<MockAutoplayClient>("enabled-forvideo", MockAutoplayClient::Video)));
+ setUserGestureRequiredForPlay(false);
+ setShouldAutoplay(false);
+ startPlaybackWithUserGesture();
+
+ // Expect bailout, but not from autoplay.
+ pausePlaybackExpectingBailout(false);
+}
+
+TEST_F(AutoplayExperimentTest, PlayMethodThenBailout)
+{
+ setInterface(adoptPtrWillBeNoop(new NiceMock<MockAutoplayClient>("enabled-forvideo", MockAutoplayClient::Video)));
+ setShouldAutoplay(false); // No autoplay attribute.
+
+ EXPECT_CALL(*m_client, removeUserGestureRequirement())
+ .Times(1);
+ EXPECT_CALL(*m_client, recordAutoplayMetric(AutoplayMediaFound))
+ .Times(1);
+ m_helper->playMethodCalled();
+
+ EXPECT_CALL(*m_client, recordAutoplayMetric(GesturelessPlaybackStartedByPlayMethodImmediately))
+ .Times(1);
+ startPlaybackWithoutUserGesture();
+
+ pausePlaybackExpectingBailout(true);
+}
+
+TEST_F(AutoplayExperimentTest, DeferAutoplayUntilMuted)
+{
+ setInterface(adoptPtrWillBeNoop(new NiceMock<MockAutoplayClient>("enabled-forvideo-ifmuted", MockAutoplayClient::Video)));
+
+ // Should not override the gesture requirement yet.
+ EXPECT_CALL(*m_client, recordAutoplayMetric(AutoplayMediaFound))
+ .Times(1);
+ m_helper->becameReadyToPlay();
+
+ // When we toggle the muted attribute, it should start.
+ EXPECT_CALL(*m_client, removeUserGestureRequirement())
+ .Times(1);
+ EXPECT_CALL(*m_client, playInternal())
+ .Times(1);
+ setIsMuted(true);
+ m_helper->mutedChanged();
+
+ // When playback starts (in response to playInternal()), it should also
+ // record why. 'After scroll' isn't the best name, but this isn't a common case.
+ EXPECT_CALL(*m_client, recordAutoplayMetric(GesturelessPlaybackStartedByAutoplayFlagAfterScroll))
+ .Times(1);
+ startPlaybackWithoutUserGesture();
+}
+
+TEST_F(AutoplayExperimentTest, DeferPlaybackUntilInViewport)
+{
+ setInterface(adoptPtrWillBeNoop(new NiceMock<MockAutoplayClient>("enabled-forvideo-ifviewport", MockAutoplayClient::Video)));
+
+ // Should not override the gesture requirement yet.
+ EXPECT_CALL(*m_client, recordAutoplayMetric(AutoplayMediaFound))
+ .Times(1);
+ EXPECT_CALL(*m_client, setRequestPositionUpdates(true))
+ .Times(1);
+ m_helper->becameReadyToPlay();
+
+ EXPECT_CALL(*m_client, removeUserGestureRequirement())
+ .Times(1);
+ EXPECT_CALL(*m_client, playInternal())
+ .Times(1);
+ EXPECT_CALL(*m_client, setRequestPositionUpdates(false))
+ .Times(1);
+ moveIntoViewport();
+}
+}

Powered by Google App Engine
This is Rietveld 408576698