blob: 838363652cc32d482360f5fdaa8ac06ff1d2043d [file] [log] [blame]
// Copyright 2019 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 "content/browser/media/media_experiment_manager.h"
#include "base/bind_helpers.h"
#include "base/memory/ptr_util.h"
#include "base/time/time.h"
#include "base/version.h"
#include "media/base/media_controller.h"
#include "media/base/mock_filters.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
using ScopedPlayerState = MediaExperimentManager::ScopedPlayerState;
class MockExperimentClient : public MediaExperimentManager::Client {
public:
MOCK_METHOD1(OnExperimentStarted, void(const MediaPlayerId& player));
MOCK_METHOD1(OnExperimentStopped, void(const MediaPlayerId& player));
};
class MediaExperimentManagerTest : public testing::Test {
public:
MediaExperimentManagerTest()
: manager_(std::make_unique<MediaExperimentManager>()),
player_id_1_(nullptr, 1),
player_id_2_(nullptr, 2) {}
protected:
std::unique_ptr<MediaExperimentManager> manager_;
// Unique player IDs. Note that we can't CreateMediaPlayerIdForTesting()
// since it doesn't return unique IDs.
MediaPlayerId player_id_1_;
MediaPlayerId player_id_2_;
};
TEST_F(MediaExperimentManagerTest, CreateAndDestroyPlayer) {
MockExperimentClient client;
EXPECT_EQ(manager_->GetPlayerCountForTesting(), 0u);
manager_->PlayerCreated(player_id_1_, &client);
EXPECT_EQ(manager_->GetPlayerCountForTesting(), 1u);
manager_->PlayerCreated(player_id_2_, &client);
EXPECT_EQ(manager_->GetPlayerCountForTesting(), 2u);
manager_->PlayerDestroyed(player_id_1_);
EXPECT_EQ(manager_->GetPlayerCountForTesting(), 1u);
manager_->PlayerDestroyed(player_id_2_);
EXPECT_EQ(manager_->GetPlayerCountForTesting(), 0u);
}
TEST_F(MediaExperimentManagerTest, CreatePlayerAndDestroyClient) {
// Create two players from one client, and make sure that destroying the
// client destroys both players.
MockExperimentClient client;
manager_->PlayerCreated(player_id_1_, &client);
manager_->PlayerCreated(player_id_2_, &client);
EXPECT_EQ(manager_->GetPlayerCountForTesting(), 2u);
manager_->ClientDestroyed(&client);
EXPECT_EQ(manager_->GetPlayerCountForTesting(), 0u);
}
TEST_F(MediaExperimentManagerTest, CreateTwoClientsAndDestroyOneClient) {
// Create one player each in two clients, and verify that destroying one
// client destroys only one player.
MockExperimentClient client_1;
MockExperimentClient client_2;
manager_->PlayerCreated(player_id_1_, &client_1);
manager_->PlayerCreated(player_id_2_, &client_2);
EXPECT_EQ(manager_->GetPlayerCountForTesting(), 2u);
manager_->ClientDestroyed(&client_1);
EXPECT_EQ(manager_->GetPlayerCountForTesting(), 1u);
}
TEST_F(MediaExperimentManagerTest, ScopedPlayerStateModifiesState) {
MockExperimentClient client_1;
MockExperimentClient client_2;
manager_->PlayerCreated(player_id_1_, &client_1);
manager_->PlayerCreated(player_id_2_, &client_2);
// Set the player state differently for each player. We set two things so
// that each player has a non-default value.
{
ScopedPlayerState state = manager_->GetPlayerState(player_id_1_);
state->is_fullscreen = true;
state->is_pip = false;
}
{
ScopedPlayerState state = manager_->GetPlayerState(player_id_2_);
state->is_fullscreen = false;
state->is_pip = true;
}
// Make sure that the player state matches what we set for it.
{
ScopedPlayerState state = manager_->GetPlayerState(player_id_1_);
EXPECT_TRUE(state->is_fullscreen);
EXPECT_FALSE(state->is_pip);
}
{
ScopedPlayerState state = manager_->GetPlayerState(player_id_2_);
EXPECT_FALSE(state->is_fullscreen);
EXPECT_TRUE(state->is_pip);
}
}
TEST_F(MediaExperimentManagerTest, ScopedPlayerStateCallsCallback) {
bool cb_called = false;
base::OnceClosure cb = base::BindOnce([](bool* flag) { *flag = true; },
base::Unretained(&cb_called));
MediaExperimentManager::PlayerState state;
state.is_fullscreen = false;
// Normally, these would not by dynamically allocated. However, this makes
// it much easier to control when they're destroyed. This is also why we
// reference the underying state as (*scoped_1)-> ; we want tp use the
// overloaded -> operator on ScopedPlayerState, not unique_ptr.
std::unique_ptr<ScopedPlayerState> scoped_1 =
std::make_unique<ScopedPlayerState>(std::move(cb), &state);
(*scoped_1)->is_fullscreen = true;
EXPECT_TRUE(state.is_fullscreen);
EXPECT_FALSE(cb_called);
// Moving |scoped_1| and deleting it should not call the callback.
std::unique_ptr<ScopedPlayerState> scoped_2 =
std::make_unique<ScopedPlayerState>(std::move(*scoped_1));
scoped_1.reset();
EXPECT_FALSE(cb_called);
// |scoped_2| should now modify |state|.
(*scoped_2)->is_fullscreen = false;
EXPECT_FALSE(state.is_fullscreen);
// Deleting |scoped_2| should call the callback.
scoped_2.reset();
EXPECT_TRUE(cb_called);
}
} // namespace content