blob: 209a83faa9d0ecb25f34fcef48eeb910988d34eb [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/performance_manager/public/freezing/freezing.h"
#include "components/performance_manager/public/graph/page_node.h"
#include "components/performance_manager/public/performance_manager.h"
#include "components/performance_manager/test_support/performance_manager_test_harness.h"
#include "components/performance_manager/test_support/test_harness_helper.h"
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/web_contents_tester.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace performance_manager {
namespace freezing {
namespace {
constexpr char kCanFreeze[] = "Can freeze";
constexpr char kCannotFreeze[] = "Cannot freeze";
// Get the aggregated freezing vote associated with |contents|.
absl::optional<FreezingVote> GetFreezingVote(content::WebContents* contents) {
base::RunLoop run_loop;
absl::optional<FreezingVote> ret;
auto quit_closure = run_loop.QuitClosure();
PerformanceManager::CallOnGraph(
FROM_HERE,
base::BindOnce(
[](base::WeakPtr<PageNode> page_node, base::OnceClosure quit_closure,
absl::optional<FreezingVote>* expected_vote) {
EXPECT_TRUE(page_node);
auto vote = page_node->GetFreezingVote();
*expected_vote = vote;
std::move(quit_closure).Run();
},
PerformanceManager::GetPrimaryPageNodeForWebContents(contents),
std::move(quit_closure), &ret));
run_loop.Run();
return ret;
}
// Get the number of freezing votes associated with |contents|.
size_t GetVoteCount(content::WebContents* contents) {
base::RunLoop run_loop;
size_t ret = 0;
auto quit_closure = run_loop.QuitClosure();
PerformanceManager::CallOnGraph(
FROM_HERE,
base::BindOnce(
[](base::WeakPtr<PageNode> page_node, base::OnceClosure quit_closure,
size_t* vote_count) {
EXPECT_TRUE(page_node);
*vote_count =
FreezingVoteCountForPageOnPMForTesting(page_node.get());
std::move(quit_closure).Run();
},
PerformanceManager::GetPrimaryPageNodeForWebContents(contents),
std::move(quit_closure), &ret));
run_loop.Run();
return ret;
}
// Get the total number of freezing votes.
size_t GetTotalVoteCount() {
base::RunLoop run_loop;
size_t ret = 0;
auto quit_closure = run_loop.QuitClosure();
PerformanceManager::CallOnGraph(
FROM_HERE,
base::BindOnce(
[](base::OnceClosure quit_closure, size_t* vote_count, Graph* graph) {
*vote_count = TotalFreezingVoteCountOnPMForTesting(graph);
std::move(quit_closure).Run();
},
std::move(quit_closure), &ret));
run_loop.Run();
return ret;
}
} // namespace
class FreezingTest : public PerformanceManagerTestHarness {
public:
FreezingTest() = default;
~FreezingTest() override = default;
FreezingTest(const FreezingTest& other) = delete;
FreezingTest& operator=(const FreezingTest&) = delete;
void SetUp() override {
GetGraphFeatures().EnableFreezingVoteDecorator();
PerformanceManagerTestHarness::SetUp();
SetContents(CreateTestWebContents());
}
};
TEST_F(FreezingTest, FreezingToken) {
{
// Emit a positive freezing vote, this should make the page node freezable.
auto token = EmitFreezingVoteForWebContents(
web_contents(), FreezingVoteValue::kCanFreeze, kCanFreeze);
EXPECT_EQ(1U, GetVoteCount(web_contents()));
EXPECT_EQ(1U, GetTotalVoteCount());
EXPECT_EQ(GetFreezingVote(web_contents()),
FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
}
// Once the freezing vote token is destroyed the vote should be invalidated.
EXPECT_EQ(GetFreezingVote(web_contents()), absl::nullopt);
EXPECT_EQ(0U, GetVoteCount(web_contents()));
EXPECT_EQ(0U, GetTotalVoteCount());
// Same test but for a negative freezing vote.
{
auto token = EmitFreezingVoteForWebContents(
web_contents(), FreezingVoteValue::kCannotFreeze, kCannotFreeze);
EXPECT_EQ(1U, GetVoteCount(web_contents()));
EXPECT_EQ(1U, GetTotalVoteCount());
EXPECT_EQ(GetFreezingVote(web_contents()),
FreezingVote(FreezingVoteValue::kCannotFreeze, kCannotFreeze));
}
EXPECT_EQ(GetFreezingVote(web_contents()), absl::nullopt);
EXPECT_EQ(0U, GetTotalVoteCount());
// Emit multiple positive token for the same page.
{
auto token1 = EmitFreezingVoteForWebContents(
web_contents(), FreezingVoteValue::kCanFreeze, kCanFreeze);
EXPECT_EQ(1U, GetVoteCount(web_contents()));
EXPECT_EQ(1U, GetTotalVoteCount());
auto token2 = EmitFreezingVoteForWebContents(
web_contents(), FreezingVoteValue::kCanFreeze, kCanFreeze);
EXPECT_EQ(2U, GetVoteCount(web_contents()));
EXPECT_EQ(2U, GetTotalVoteCount());
auto token3 = EmitFreezingVoteForWebContents(
web_contents(), FreezingVoteValue::kCanFreeze, kCanFreeze);
EXPECT_EQ(GetFreezingVote(web_contents()),
FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
EXPECT_EQ(3U, GetVoteCount(web_contents()));
EXPECT_EQ(3U, GetTotalVoteCount());
token3.reset();
EXPECT_EQ(2U, GetVoteCount(web_contents()));
EXPECT_EQ(2U, GetTotalVoteCount());
EXPECT_EQ(GetFreezingVote(web_contents()),
FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
token2.reset();
EXPECT_EQ(1U, GetVoteCount(web_contents()));
EXPECT_EQ(1U, GetTotalVoteCount());
EXPECT_EQ(GetFreezingVote(web_contents()),
FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
token1.reset();
EXPECT_EQ(0U, GetVoteCount(web_contents()));
EXPECT_EQ(0U, GetTotalVoteCount());
EXPECT_EQ(GetFreezingVote(web_contents()), absl::nullopt);
}
}
TEST_F(FreezingTest, WebContentsDestroyedBeforeToken) {
// Emit a positive freezing vote, this should make the page node freezable.
auto token = EmitFreezingVoteForWebContents(
web_contents(), FreezingVoteValue::kCanFreeze, kCanFreeze);
EXPECT_EQ(GetFreezingVote(web_contents()),
FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
DeleteContents();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(0U, GetTotalVoteCount());
token.reset();
EXPECT_EQ(0U, GetTotalVoteCount());
}
TEST_F(FreezingTest, FreezingTokenMultiplePages) {
auto contents2 = CreateTestWebContents();
auto contents3 = CreateTestWebContents();
auto contents1_token1 = EmitFreezingVoteForWebContents(
web_contents(), FreezingVoteValue::kCanFreeze, kCanFreeze);
EXPECT_EQ(GetFreezingVote(web_contents()),
FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
EXPECT_EQ(GetFreezingVote(contents2.get()), absl::nullopt);
EXPECT_EQ(GetFreezingVote(contents3.get()), absl::nullopt);
EXPECT_EQ(1U, GetVoteCount(web_contents()));
EXPECT_EQ(0U, GetVoteCount(contents2.get()));
EXPECT_EQ(0U, GetVoteCount(contents3.get()));
EXPECT_EQ(1U, GetTotalVoteCount());
auto contents1_token2 = EmitFreezingVoteForWebContents(
web_contents(), FreezingVoteValue::kCanFreeze, kCanFreeze);
EXPECT_EQ(GetFreezingVote(web_contents()),
FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
EXPECT_EQ(GetFreezingVote(contents2.get()), absl::nullopt);
EXPECT_EQ(GetFreezingVote(contents3.get()), absl::nullopt);
EXPECT_EQ(2U, GetVoteCount(web_contents()));
EXPECT_EQ(0U, GetVoteCount(contents2.get()));
EXPECT_EQ(0U, GetVoteCount(contents3.get()));
EXPECT_EQ(2U, GetTotalVoteCount());
auto contents2_token = EmitFreezingVoteForWebContents(
contents2.get(), FreezingVoteValue::kCanFreeze, kCanFreeze);
EXPECT_EQ(GetFreezingVote(web_contents()),
FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
EXPECT_EQ(GetFreezingVote(contents2.get()),
FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
EXPECT_EQ(GetFreezingVote(contents3.get()), absl::nullopt);
EXPECT_EQ(2U, GetVoteCount(web_contents()));
EXPECT_EQ(1U, GetVoteCount(contents2.get()));
EXPECT_EQ(0U, GetVoteCount(contents3.get()));
EXPECT_EQ(3U, GetTotalVoteCount());
auto contents3_token = EmitFreezingVoteForWebContents(
contents3.get(), FreezingVoteValue::kCanFreeze, kCanFreeze);
EXPECT_EQ(GetFreezingVote(web_contents()),
FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
EXPECT_EQ(GetFreezingVote(contents2.get()),
FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
EXPECT_EQ(GetFreezingVote(contents3.get()),
FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
EXPECT_EQ(2U, GetVoteCount(web_contents()));
EXPECT_EQ(1U, GetVoteCount(contents2.get()));
EXPECT_EQ(1U, GetVoteCount(contents3.get()));
EXPECT_EQ(4U, GetTotalVoteCount());
contents1_token1.reset();
EXPECT_EQ(GetFreezingVote(web_contents()),
FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
EXPECT_EQ(GetFreezingVote(contents2.get()),
FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
EXPECT_EQ(GetFreezingVote(contents3.get()),
FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
EXPECT_EQ(1U, GetVoteCount(web_contents()));
EXPECT_EQ(1U, GetVoteCount(contents2.get()));
EXPECT_EQ(1U, GetVoteCount(contents3.get()));
EXPECT_EQ(3U, GetTotalVoteCount());
contents1_token2.reset();
EXPECT_EQ(GetFreezingVote(web_contents()), absl::nullopt);
EXPECT_EQ(GetFreezingVote(contents2.get()),
FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
EXPECT_EQ(GetFreezingVote(contents3.get()),
FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
EXPECT_EQ(0U, GetVoteCount(web_contents()));
EXPECT_EQ(1U, GetVoteCount(contents2.get()));
EXPECT_EQ(1U, GetVoteCount(contents3.get()));
EXPECT_EQ(2U, GetTotalVoteCount());
contents2_token.reset();
EXPECT_EQ(GetFreezingVote(web_contents()), absl::nullopt);
EXPECT_EQ(GetFreezingVote(contents2.get()), absl::nullopt);
EXPECT_EQ(GetFreezingVote(contents3.get()),
FreezingVote(FreezingVoteValue::kCanFreeze, kCanFreeze));
EXPECT_EQ(0U, GetVoteCount(web_contents()));
EXPECT_EQ(0U, GetVoteCount(contents2.get()));
EXPECT_EQ(1U, GetVoteCount(contents3.get()));
EXPECT_EQ(1U, GetTotalVoteCount());
contents3_token.reset();
EXPECT_EQ(GetFreezingVote(web_contents()), absl::nullopt);
EXPECT_EQ(GetFreezingVote(contents2.get()), absl::nullopt);
EXPECT_EQ(GetFreezingVote(contents3.get()), absl::nullopt);
EXPECT_EQ(0U, GetVoteCount(web_contents()));
EXPECT_EQ(0U, GetVoteCount(contents2.get()));
EXPECT_EQ(0U, GetVoteCount(contents3.get()));
EXPECT_EQ(0U, GetTotalVoteCount());
}
} // namespace freezing
} // namespace performance_manager