blob: 9b9253ef395c46d746678fdb9c85283b6bfffbc9 [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 <memory>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/run_loop.h"
#include "base/test/gtest_util.h"
#include "base/unguessable_token.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/paint_preview/browser/compositor_utils.h"
#include "components/paint_preview/browser/paint_preview_base_service_test_factory.h"
#include "components/paint_preview/browser/paint_preview_compositor_client_impl.h"
#include "components/paint_preview/browser/paint_preview_compositor_service_impl.h"
#include "components/paint_preview/browser/warm_compositor.h"
#include "components/paint_preview/public/paint_preview_compositor_client.h"
#include "components/paint_preview/public/paint_preview_compositor_service.h"
#include "components/services/paint_preview_compositor/public/mojom/paint_preview_compositor.mojom.h"
#include "content/public/browser/service_process_host.h"
#include "content/public/test/browser_test.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace paint_preview {
namespace {
// These functions cast the public API for the CompositorService and
// CompositorClient to the *Impl versions. This exposes some internal test-only
// methods to validate internal state.
std::unique_ptr<PaintPreviewCompositorServiceImpl> ToCompositorServiceImpl(
std::unique_ptr<PaintPreviewCompositorService, base::OnTaskRunnerDeleter>
service) {
return std::unique_ptr<PaintPreviewCompositorServiceImpl>(
static_cast<PaintPreviewCompositorServiceImpl*>(service.release()));
}
std::unique_ptr<PaintPreviewCompositorClientImpl> ToCompositorClientImpl(
std::unique_ptr<PaintPreviewCompositorClient, base::OnTaskRunnerDeleter>
client) {
return std::unique_ptr<PaintPreviewCompositorClientImpl>(
static_cast<PaintPreviewCompositorClientImpl*>(client.release()));
}
bool IsBoundAndConnected(PaintPreviewCompositorClientImpl* compositor) {
base::RunLoop loop;
bool out;
compositor->IsBoundAndConnected(base::BindOnce(
[](base::OnceClosure quit, bool* out, bool success) {
*out = success;
std::move(quit).Run();
},
loop.QuitClosure(), base::Unretained(&out)));
loop.Run();
return out;
}
} // namespace
class PaintPreviewCompositorBrowserTest : public InProcessBrowserTest {
public:
PaintPreviewCompositorBrowserTest() = default;
~PaintPreviewCompositorBrowserTest() override = default;
PaintPreviewCompositorBrowserTest(const PaintPreviewCompositorBrowserTest&) =
delete;
PaintPreviewCompositorBrowserTest& operator=(
const PaintPreviewCompositorBrowserTest&) = delete;
protected:
void CreateServiceInstance() {
key_ = std::make_unique<SimpleFactoryKey>(
browser()->profile()->GetPath(),
browser()->profile()->IsOffTheRecord());
PaintPreviewBaseServiceTestFactory::GetInstance()->SetTestingFactory(
key_.get(),
base::BindRepeating(&PaintPreviewBaseServiceTestFactory::Build));
}
PaintPreviewBaseService* GetBaseService() {
return PaintPreviewBaseServiceTestFactory::GetForKey(key_.get());
}
private:
std::unique_ptr<SimpleFactoryKey> key_;
};
// Test that a "true" initialization works and doesn't crash.
IN_PROC_BROWSER_TEST_F(PaintPreviewCompositorBrowserTest,
TestInitializationSuccess) {
base::RunLoop loop;
mojo::Remote<mojom::PaintPreviewCompositorCollection> compositor_collection =
CreateCompositorCollection();
EXPECT_TRUE(compositor_collection.is_bound());
EXPECT_TRUE(compositor_collection.is_connected());
// If the compositor_collection hasn't crashed during initialization due to
// lacking font support then this call should succeed.
compositor_collection->ListCompositors(base::BindOnce(
[](base::OnceClosure quit,
const std::vector<base::UnguessableToken>& ids) {
EXPECT_EQ(ids.size(), 0U);
std::move(quit).Run();
},
loop.QuitClosure()));
loop.Run();
compositor_collection.reset();
}
IN_PROC_BROWSER_TEST_F(PaintPreviewCompositorBrowserTest, CompositorCreate) {
CreateServiceInstance();
auto compositor_service =
ToCompositorServiceImpl(StartCompositorService(base::DoNothing()));
base::RunLoop loop;
auto compositor = ToCompositorClientImpl(
compositor_service->CreateCompositor(loop.QuitClosure()));
loop.Run();
EXPECT_TRUE(compositor_service->HasActiveClients());
EXPECT_TRUE(base::Contains(compositor_service->ActiveClientsForTesting(),
compositor->Token()));
EXPECT_TRUE(IsBoundAndConnected(compositor.get()));
compositor.reset();
EXPECT_FALSE(compositor_service->HasActiveClients());
}
IN_PROC_BROWSER_TEST_F(PaintPreviewCompositorBrowserTest,
MultipleCompositorCreate) {
CreateServiceInstance();
auto compositor_service =
ToCompositorServiceImpl(StartCompositorService(base::DoNothing()));
EXPECT_EQ(0U, compositor_service->ActiveClientsForTesting().size());
EXPECT_FALSE(compositor_service->HasActiveClients());
base::RunLoop loop_0;
auto compositor_0 = ToCompositorClientImpl(
compositor_service->CreateCompositor(loop_0.QuitClosure()));
loop_0.Run();
EXPECT_TRUE(compositor_service->HasActiveClients());
EXPECT_EQ(1U, compositor_service->ActiveClientsForTesting().size());
EXPECT_TRUE(base::Contains(compositor_service->ActiveClientsForTesting(),
compositor_0->Token()));
EXPECT_TRUE(IsBoundAndConnected(compositor_0.get()));
base::RunLoop loop_1;
auto compositor_1 = ToCompositorClientImpl(
compositor_service->CreateCompositor(loop_1.QuitClosure()));
loop_1.Run();
EXPECT_TRUE(compositor_service->HasActiveClients());
EXPECT_EQ(2U, compositor_service->ActiveClientsForTesting().size());
EXPECT_TRUE(base::Contains(compositor_service->ActiveClientsForTesting(),
compositor_1->Token()));
EXPECT_TRUE(IsBoundAndConnected(compositor_1.get()));
EXPECT_NE(compositor_0->Token(), compositor_1->Token());
compositor_0.reset();
EXPECT_TRUE(compositor_service->HasActiveClients());
EXPECT_EQ(1U, compositor_service->ActiveClientsForTesting().size());
EXPECT_TRUE(base::Contains(compositor_service->ActiveClientsForTesting(),
compositor_1->Token()));
compositor_1.reset();
EXPECT_FALSE(compositor_service->HasActiveClients());
}
IN_PROC_BROWSER_TEST_F(PaintPreviewCompositorBrowserTest,
KillWithActiveCompositors) {
CreateServiceInstance();
// NOTE: the disconnect handler for the service as a whole only triggers if
// the service is killed unexpectedly. Here the |compositor_service| object
// is deleted (performing a graceful shutdown) so the handler won't run.
auto compositor_service =
ToCompositorServiceImpl(StartCompositorService(base::DoNothing()));
base::RunLoop loop;
auto compositor = ToCompositorClientImpl(
compositor_service->CreateCompositor(loop.QuitClosure()));
loop.Run();
EXPECT_TRUE(compositor_service->HasActiveClients());
EXPECT_TRUE(base::Contains(compositor_service->ActiveClientsForTesting(),
compositor->Token()));
EXPECT_TRUE(IsBoundAndConnected(compositor.get()));
base::RunLoop disconnect_loop;
compositor->SetDisconnectHandler(disconnect_loop.QuitClosure());
// Kill before releasing active compositors.
compositor_service.reset();
disconnect_loop.Run();
EXPECT_FALSE(IsBoundAndConnected(compositor.get()));
}
IN_PROC_BROWSER_TEST_F(PaintPreviewCompositorBrowserTest, PreWarmCompositor) {
// Start with warm compositor.
WarmCompositor* warm_compositor = WarmCompositor::GetInstance();
warm_compositor->WarmupCompositor();
auto compositor_service = ToCompositorServiceImpl(
warm_compositor->GetOrStartCompositorService(base::DoNothing()));
EXPECT_FALSE(warm_compositor->StopCompositor());
EXPECT_NE(compositor_service, nullptr);
compositor_service.reset();
EXPECT_EQ(compositor_service, nullptr);
// Start and stop.
warm_compositor->WarmupCompositor();
EXPECT_TRUE(warm_compositor->StopCompositor());
// Verify it is still possible to start if the compositor was prematurely
// stopped.
compositor_service = ToCompositorServiceImpl(
warm_compositor->GetOrStartCompositorService(base::DoNothing()));
EXPECT_NE(compositor_service, nullptr);
compositor_service.reset();
EXPECT_EQ(compositor_service, nullptr);
}
} // namespace paint_preview