blob: 1847112cb254b405ff1177e8bec2d1ab77bf70c0 [file] [log] [blame]
// Copyright 2021 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/compute_pressure/compute_pressure_manager.h"
#include <memory>
#include <utility>
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "content/browser/compute_pressure/compute_pressure_test_support.h"
#include "content/public/browser/global_routing_id.h"
#include "content/test/test_render_frame_host.h"
#include "content/test/test_web_contents.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/test_support/fake_message_dispatch_context.h"
#include "mojo/public/cpp/test_support/test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/mojom/compute_pressure/compute_pressure.mojom.h"
namespace content {
class ComputePressureManagerTest : public RenderViewHostImplTestHarness {
public:
void SetUp() override {
RenderViewHostImplTestHarness::SetUp();
NavigateAndCommit(kTestUrl);
SetManager(ComputePressureManager::CreateForTesting(
std::make_unique<FakeCpuProbe>(), base::Milliseconds(1),
base::Milliseconds(1)));
}
void TearDown() override {
// Get the CpuProbe freed.
manager_.reset();
task_environment()->RunUntilIdle();
RenderViewHostImplTestHarness::TearDown();
}
void SetManager(std::unique_ptr<ComputePressureManager> new_manager) {
manager_ = std::move(new_manager);
int process_id = main_rfh()->GetProcess()->GetID();
int routing_id = main_rfh()->GetRoutingID();
main_frame_id_ = GlobalRenderFrameHostId(process_id, routing_id);
main_host_.reset();
manager_->BindReceiver(kTestOrigin, main_frame_id_,
main_host_.BindNewPipeAndPassReceiver());
main_host_sync_ =
std::make_unique<ComputePressureHostSync>(main_host_.get());
}
protected:
const GURL kTestUrl{"https://example.com/compute_pressure.html"};
const url::Origin kTestOrigin =
url::Origin::Create(GURL("https://example.com"));
const url::Origin kInsecureOrigin =
url::Origin::Create(GURL("http://example.com"));
const url::Origin kThirdPartyOrigin =
url::Origin::Create(GURL("https://other.com"));
// Quantization scheme used in most tests.
const blink::mojom::ComputePressureQuantization kQuantization = {
{0.2, 0.5, 0.8},
{0.5}};
base::test::ScopedFeatureList scoped_feature_list_;
GlobalRenderFrameHostId main_frame_id_;
// This member is a std::unique_ptr instead of a plain ComputePressureManager
// so it can be replaced inside tests.
std::unique_ptr<ComputePressureManager> manager_;
mojo::Remote<blink::mojom::ComputePressureHost> main_host_;
std::unique_ptr<ComputePressureHostSync> main_host_sync_;
};
// Disabled on Fuchsia arm64 debug builds: https://crbug.com/1250654
#if defined(OS_FUCHSIA) && defined(_DEBUG) && defined(ARCH_CPU_ARM64)
#define MAYBE_OneObserver DISABLED_OneObserver
#elif defined(OS_LINUX) && defined(USE_OZONE) // https://crbug.com/1226086
#define MAYBE_OneObserver DISABLED_OneObserver
#else
#define MAYBE_OneObserver OneObserver
#endif
TEST_F(ComputePressureManagerTest, MAYBE_OneObserver) {
FakeComputePressureObserver observer;
ASSERT_EQ(main_host_sync_->AddObserver(kQuantization,
observer.BindNewPipeAndPassRemote()),
blink::mojom::ComputePressureStatus::kOk);
observer.WaitForUpdate();
EXPECT_THAT(observer.updates(), testing::SizeIs(testing::Ge(1u)));
EXPECT_THAT(
observer.updates(),
testing::Contains(blink::mojom::ComputePressureState(0.35, 0.75)));
}
// Disabled on Fuchsia arm64 debug builds: https://crbug.com/1250654
#if defined(OS_FUCHSIA) && defined(_DEBUG) && defined(ARCH_CPU_ARM64)
#define MAYBE_ThreeObservers DISABLED_ThreeObservers
#elif defined(OS_LINUX) && defined(USE_OZONE) // https://crbug.com/1226086
#define MAYBE_ThreeObservers DISABLED_ThreeObservers
#else
#define MAYBE_ThreeObservers ThreeObservers
#endif
TEST_F(ComputePressureManagerTest, MAYBE_ThreeObservers) {
FakeComputePressureObserver observer1;
ASSERT_EQ(main_host_sync_->AddObserver(kQuantization,
observer1.BindNewPipeAndPassRemote()),
blink::mojom::ComputePressureStatus::kOk);
FakeComputePressureObserver observer2;
ASSERT_EQ(main_host_sync_->AddObserver(kQuantization,
observer2.BindNewPipeAndPassRemote()),
blink::mojom::ComputePressureStatus::kOk);
FakeComputePressureObserver observer3;
ASSERT_EQ(main_host_sync_->AddObserver(kQuantization,
observer3.BindNewPipeAndPassRemote()),
blink::mojom::ComputePressureStatus::kOk);
FakeComputePressureObserver::WaitForUpdates(
{&observer1, &observer2, &observer3});
EXPECT_THAT(observer1.updates(), testing::SizeIs(testing::Ge(1u)));
EXPECT_THAT(
observer1.updates(),
testing::Contains(blink::mojom::ComputePressureState(0.35, 0.75)));
EXPECT_THAT(observer2.updates(), testing::SizeIs(testing::Ge(1u)));
EXPECT_THAT(
observer2.updates(),
testing::Contains(blink::mojom::ComputePressureState(0.35, 0.75)));
EXPECT_THAT(observer3.updates(), testing::SizeIs(testing::Ge(1u)));
EXPECT_THAT(
observer3.updates(),
testing::Contains(blink::mojom::ComputePressureState(0.35, 0.75)));
}
TEST_F(ComputePressureManagerTest, AddObserver_ThirdPartyFrame) {
mojo::Remote<blink::mojom::ComputePressureHost> third_party_host;
manager_->BindReceiver(kThirdPartyOrigin, main_frame_id_,
third_party_host.BindNewPipeAndPassReceiver());
auto third_party_host_sync =
std::make_unique<ComputePressureHostSync>(third_party_host.get());
FakeComputePressureObserver third_party_observer;
EXPECT_EQ(third_party_host_sync->AddObserver(
kQuantization, third_party_observer.BindNewPipeAndPassRemote()),
blink::mojom::ComputePressureStatus::kSecurityError);
FakeComputePressureObserver first_party_observer;
EXPECT_EQ(main_host_sync_->AddObserver(
kQuantization, first_party_observer.BindNewPipeAndPassRemote()),
blink::mojom::ComputePressureStatus::kOk);
}
TEST_F(ComputePressureManagerTest, AddObserver_NoVisibility) {
test_rvh()->SimulateWasHidden();
FakeComputePressureObserver observer;
EXPECT_EQ(main_host_sync_->AddObserver(kQuantization,
observer.BindNewPipeAndPassRemote()),
blink::mojom::ComputePressureStatus::kOk);
}
TEST_F(ComputePressureManagerTest, AddObserver_InvalidFrame) {
GlobalRenderFrameHostId invalid_routing_id(
main_rfh()->GetProcess()->GetID() + 1, main_rfh()->GetRoutingID() + 1);
mojo::Remote<blink::mojom::ComputePressureHost> invalid_host;
manager_->BindReceiver(kTestOrigin, invalid_routing_id,
invalid_host.BindNewPipeAndPassReceiver());
auto invalid_host_sync =
std::make_unique<ComputePressureHostSync>(invalid_host.get());
FakeComputePressureObserver invalid_observer;
EXPECT_EQ(invalid_host_sync->AddObserver(
kQuantization, invalid_observer.BindNewPipeAndPassRemote()),
blink::mojom::ComputePressureStatus::kSecurityError);
FakeComputePressureObserver valid_observer;
EXPECT_EQ(main_host_sync_->AddObserver(
kQuantization, valid_observer.BindNewPipeAndPassRemote()),
blink::mojom::ComputePressureStatus::kOk);
}
TEST_F(ComputePressureManagerTest, AddObserver_InvalidQuantization) {
FakeComputePressureObserver invalid_observer;
blink::mojom::ComputePressureQuantization invalid_quantization(
std::vector<double>{-1.0}, std::vector<double>{0.5});
{
mojo::test::BadMessageObserver bad_message_observer;
EXPECT_EQ(
main_host_sync_->AddObserver(
invalid_quantization, invalid_observer.BindNewPipeAndPassRemote()),
blink::mojom::ComputePressureStatus::kSecurityError);
EXPECT_EQ("Invalid quantization", bad_message_observer.WaitForBadMessage());
}
FakeComputePressureObserver valid_observer;
EXPECT_EQ(main_host_sync_->AddObserver(
kQuantization, valid_observer.BindNewPipeAndPassRemote()),
blink::mojom::ComputePressureStatus::kOk);
}
TEST_F(ComputePressureManagerTest, AddObserver_InsecureOrigin) {
{
mojo::FakeMessageDispatchContext fake_dispatch_context;
mojo::test::BadMessageObserver bad_message_observer;
mojo::Remote<blink::mojom::ComputePressureHost> insecure_host;
manager_->BindReceiver(kInsecureOrigin, main_frame_id_,
insecure_host.BindNewPipeAndPassReceiver());
EXPECT_EQ("Compute Pressure access from an insecure origin",
bad_message_observer.WaitForBadMessage());
}
FakeComputePressureObserver valid_observer;
EXPECT_EQ(main_host_sync_->AddObserver(
kQuantization, valid_observer.BindNewPipeAndPassRemote()),
blink::mojom::ComputePressureStatus::kOk);
}
TEST_F(ComputePressureManagerTest, AddObserver_NoProbe) {
SetManager(ComputePressureManager::CreateForTesting(
/*cpu_probe=*/nullptr, base::Milliseconds(1), base::Milliseconds(1)));
FakeComputePressureObserver observer;
EXPECT_EQ(main_host_sync_->AddObserver(kQuantization,
observer.BindNewPipeAndPassRemote()),
blink::mojom::ComputePressureStatus::kNotSupported);
}
TEST_F(ComputePressureManagerTest, AddObserver_NoFeature) {
scoped_feature_list_.Reset();
scoped_feature_list_.InitAndDisableFeature(blink::features::kComputePressure);
mojo::FakeMessageDispatchContext fake_dispatch_context;
mojo::test::BadMessageObserver bad_message_observer;
mojo::Remote<blink::mojom::ComputePressureHost> insecure_host;
manager_->BindReceiver(kInsecureOrigin, main_frame_id_,
insecure_host.BindNewPipeAndPassReceiver());
EXPECT_EQ("Compute Pressure not enabled",
bad_message_observer.WaitForBadMessage());
}
} // namespace content