blob: 55a5275ff75c359b18f6f371622165c9b989a15d [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/mediasession/media_session.h"
#include "base/test/simple_test_tick_clock.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_media_position_state.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
namespace blink {
using testing::_;
namespace {
class MockMediaSessionService : public mojom::blink::MediaSessionService {
public:
MockMediaSessionService() = default;
HeapMojoRemote<mojom::blink::MediaSessionService> CreateRemoteAndBind(
ContextLifecycleNotifier* notifier,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
HeapMojoRemote<mojom::blink::MediaSessionService> remote(notifier);
remote.Bind(receiver_.BindNewPipeAndPassRemote(), task_runner);
return remote;
}
void SetClient(
mojo::PendingRemote<mojom::blink::MediaSessionClient> client) override {}
void SetPlaybackState(
mojom::blink::MediaSessionPlaybackState state) override {}
MOCK_METHOD1(SetPositionState,
void(media_session::mojom::blink::MediaPositionPtr));
void SetMetadata(mojom::blink::SpecMediaMetadataPtr metadata) override {}
void SetMicrophoneState(
media_session::mojom::MicrophoneState microphone_state) override {}
void SetCameraState(media_session::mojom::CameraState camera_state) override {
}
void EnableAction(
media_session::mojom::blink::MediaSessionAction action) override {}
void DisableAction(
media_session::mojom::blink::MediaSessionAction action) override {}
private:
mojo::Receiver<mojom::blink::MediaSessionService> receiver_{this};
};
} // namespace
class MediaSessionTest : public PageTestBase {
public:
MediaSessionTest() = default;
MediaSessionTest(const MediaSessionTest&) = delete;
MediaSessionTest& operator=(const MediaSessionTest&) = delete;
void SetUp() override {
PageTestBase::SetUp();
mock_service_ = std::make_unique<MockMediaSessionService>();
media_session_ =
MediaSession::mediaSession(*GetFrame().DomWindow()->navigator());
media_session_->service_ = mock_service_->CreateRemoteAndBind(
GetFrame().DomWindow(),
GetFrame().DomWindow()->GetTaskRunner(TaskType::kMiscPlatformAPI));
media_session_->clock_ = &test_clock_;
}
void SetPositionState(double duration,
double position,
double playback_rate) {
auto* position_state = MediaPositionState::Create();
position_state->setDuration(duration);
position_state->setPosition(position);
position_state->setPlaybackRate(playback_rate);
NonThrowableExceptionState exception_state;
media_session_->setPositionState(position_state, exception_state);
}
void SetPositionStateThrowsException(double duration,
double position,
double playback_rate) {
auto* position_state = MediaPositionState::Create();
position_state->setDuration(duration);
position_state->setPosition(position);
position_state->setPlaybackRate(playback_rate);
DummyExceptionStateForTesting exception_state;
media_session_->setPositionState(position_state, exception_state);
EXPECT_TRUE(exception_state.HadException());
EXPECT_EQ(ESErrorType::kTypeError, exception_state.CodeAs<ESErrorType>());
}
void ClearPositionState() {
NonThrowableExceptionState exception_state;
media_session_->setPositionState(MediaPositionState::Create(),
exception_state);
}
void SetPlaybackState(const String& state) {
media_session_->setPlaybackState(state);
}
MockMediaSessionService& service() { return *mock_service_.get(); }
base::SimpleTestTickClock& clock() { return test_clock_; }
private:
base::SimpleTestTickClock test_clock_;
std::unique_ptr<MockMediaSessionService> mock_service_;
Persistent<MediaSession> media_session_;
};
TEST_F(MediaSessionTest, PlaybackPositionState_None) {
base::RunLoop loop;
EXPECT_CALL(service(), SetPositionState(_))
.WillOnce(testing::Invoke([&](auto position_state) {
EXPECT_EQ(base::Seconds(10), position_state->duration);
EXPECT_EQ(base::Seconds(5), position_state->position);
EXPECT_EQ(1.0, position_state->playback_rate);
EXPECT_EQ(clock().NowTicks(), position_state->last_updated_time);
loop.Quit();
}));
SetPlaybackState("none");
SetPositionState(10, 5, 1.0);
loop.Run();
}
TEST_F(MediaSessionTest, PlaybackPositionState_Paused) {
base::RunLoop loop;
EXPECT_CALL(service(), SetPositionState(_))
.WillOnce(testing::Invoke([&](auto position_state) {
EXPECT_EQ(base::Seconds(10), position_state->duration);
EXPECT_EQ(base::Seconds(5), position_state->position);
EXPECT_EQ(0.0, position_state->playback_rate);
EXPECT_EQ(clock().NowTicks(), position_state->last_updated_time);
loop.Quit();
}));
SetPlaybackState("paused");
SetPositionState(10, 5, 1.0);
loop.Run();
}
TEST_F(MediaSessionTest, PlaybackPositionState_Playing) {
base::RunLoop loop;
EXPECT_CALL(service(), SetPositionState(_))
.WillOnce(testing::Invoke([&](auto position_state) {
EXPECT_EQ(base::Seconds(10), position_state->duration);
EXPECT_EQ(base::Seconds(5), position_state->position);
EXPECT_EQ(1.0, position_state->playback_rate);
EXPECT_EQ(clock().NowTicks(), position_state->last_updated_time);
loop.Quit();
}));
SetPlaybackState("playing");
SetPositionState(10, 5, 1.0);
loop.Run();
}
TEST_F(MediaSessionTest, PlaybackPositionState_InfiniteDuration) {
base::RunLoop loop;
EXPECT_CALL(service(), SetPositionState(_))
.WillOnce(testing::Invoke([&](auto position_state) {
EXPECT_EQ(base::TimeDelta::Max(), position_state->duration);
EXPECT_EQ(base::Seconds(5), position_state->position);
EXPECT_EQ(1.0, position_state->playback_rate);
EXPECT_EQ(clock().NowTicks(), position_state->last_updated_time);
loop.Quit();
}));
SetPlaybackState("none");
SetPositionState(std::numeric_limits<double>::infinity(), 5, 1.0);
loop.Run();
}
TEST_F(MediaSessionTest, PlaybackPositionState_NaNDuration) {
SetPlaybackState("none");
SetPositionStateThrowsException(std::nan("10"), 5, 1.0);
}
TEST_F(MediaSessionTest, PlaybackPositionState_Paused_Clear) {
{
base::RunLoop loop;
EXPECT_CALL(service(), SetPositionState(_))
.WillOnce(testing::Invoke([&](auto position_state) {
EXPECT_EQ(base::Seconds(10), position_state->duration);
EXPECT_EQ(base::Seconds(5), position_state->position);
EXPECT_EQ(0.0, position_state->playback_rate);
EXPECT_EQ(clock().NowTicks(), position_state->last_updated_time);
loop.Quit();
}));
SetPlaybackState("paused");
SetPositionState(10, 5, 1.0);
loop.Run();
}
{
base::RunLoop loop;
EXPECT_CALL(service(), SetPositionState(_))
.WillOnce(testing::Invoke([&](auto position_state) {
EXPECT_FALSE(position_state);
loop.Quit();
}));
ClearPositionState();
loop.Run();
}
}
TEST_F(MediaSessionTest, PositionPlaybackState_None) {
base::RunLoop loop;
EXPECT_CALL(service(), SetPositionState(_))
.WillOnce(testing::Invoke([&](auto position_state) {
EXPECT_EQ(base::Seconds(10), position_state->duration);
EXPECT_EQ(base::Seconds(5), position_state->position);
EXPECT_EQ(1.0, position_state->playback_rate);
EXPECT_EQ(clock().NowTicks(), position_state->last_updated_time);
loop.Quit();
}));
SetPositionState(10, 5, 1.0);
SetPlaybackState("none");
loop.Run();
}
TEST_F(MediaSessionTest, PositionPlaybackState_Paused_None) {
{
base::RunLoop loop;
EXPECT_CALL(service(), SetPositionState(_))
.WillOnce(testing::Invoke([&](auto position_state) {
EXPECT_EQ(base::Minutes(10), position_state->duration);
EXPECT_EQ(base::Minutes(1), position_state->position);
EXPECT_EQ(1.0, position_state->playback_rate);
EXPECT_EQ(clock().NowTicks(), position_state->last_updated_time);
loop.Quit();
}));
SetPositionState(600, 60, 1.0);
loop.Run();
}
clock().Advance(base::Minutes(1));
{
base::RunLoop loop;
EXPECT_CALL(service(), SetPositionState(_))
.WillOnce(testing::Invoke([&](auto position_state) {
EXPECT_EQ(base::Minutes(10), position_state->duration);
EXPECT_EQ(base::Minutes(2), position_state->position);
EXPECT_EQ(0.0, position_state->playback_rate);
EXPECT_EQ(clock().NowTicks(), position_state->last_updated_time);
loop.Quit();
}));
SetPlaybackState("paused");
loop.Run();
}
clock().Advance(base::Minutes(1));
{
base::RunLoop loop;
EXPECT_CALL(service(), SetPositionState(_))
.WillOnce(testing::Invoke([&](auto position_state) {
EXPECT_EQ(base::Minutes(10), position_state->duration);
EXPECT_EQ(base::Minutes(2), position_state->position);
EXPECT_EQ(1.0, position_state->playback_rate);
EXPECT_EQ(clock().NowTicks(), position_state->last_updated_time);
loop.Quit();
}));
SetPlaybackState("none");
loop.Run();
}
}
TEST_F(MediaSessionTest, PositionPlaybackState_Paused_Playing) {
{
base::RunLoop loop;
EXPECT_CALL(service(), SetPositionState(_))
.WillOnce(testing::Invoke([&](auto position_state) {
EXPECT_EQ(base::Minutes(10), position_state->duration);
EXPECT_EQ(base::Minutes(1), position_state->position);
EXPECT_EQ(1.0, position_state->playback_rate);
EXPECT_EQ(clock().NowTicks(), position_state->last_updated_time);
loop.Quit();
}));
SetPositionState(600, 60, 1.0);
loop.Run();
}
clock().Advance(base::Minutes(1));
{
base::RunLoop loop;
EXPECT_CALL(service(), SetPositionState(_))
.WillOnce(testing::Invoke([&](auto position_state) {
EXPECT_EQ(base::Minutes(10), position_state->duration);
EXPECT_EQ(base::Minutes(2), position_state->position);
EXPECT_EQ(0.0, position_state->playback_rate);
EXPECT_EQ(clock().NowTicks(), position_state->last_updated_time);
loop.Quit();
}));
SetPlaybackState("paused");
loop.Run();
}
clock().Advance(base::Minutes(1));
{
base::RunLoop loop;
EXPECT_CALL(service(), SetPositionState(_))
.WillOnce(testing::Invoke([&](auto position_state) {
EXPECT_EQ(base::Minutes(10), position_state->duration);
EXPECT_EQ(base::Minutes(2), position_state->position);
EXPECT_EQ(1.0, position_state->playback_rate);
EXPECT_EQ(clock().NowTicks(), position_state->last_updated_time);
loop.Quit();
}));
SetPlaybackState("playing");
loop.Run();
}
}
TEST_F(MediaSessionTest, PositionPlaybackState_Playing) {
base::RunLoop loop;
EXPECT_CALL(service(), SetPositionState(_))
.WillOnce(testing::Invoke([&](auto position_state) {
EXPECT_EQ(base::Seconds(10), position_state->duration);
EXPECT_EQ(base::Seconds(5), position_state->position);
EXPECT_EQ(1.0, position_state->playback_rate);
EXPECT_EQ(clock().NowTicks(), position_state->last_updated_time);
loop.Quit();
}));
SetPositionState(10, 5, 1.0);
SetPlaybackState("playing");
loop.Run();
}
} // namespace blink