blob: 208ac4000859dfdc87b83e39f275160c6259412f [file] [log] [blame]
// Copyright 2018 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 "services/ws/window_service.h"
#include <memory>
#include "base/bind.h"
#include "base/run_loop.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/test/test_connector_factory.h"
#include "services/ws/public/cpp/host/gpu_interface_provider.h"
#include "services/ws/public/mojom/constants.mojom.h"
#include "services/ws/public/mojom/window_tree.mojom.h"
#include "services/ws/test_wm.mojom.h"
#include "services/ws/window_manager_interface.h"
#include "services/ws/window_service_test_setup.h"
#include "services/ws/window_tree.h"
#include "services/ws/window_tree_test_helper.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace ws {
namespace {
// Used as callback from ScheduleEmbed().
void ScheduleEmbedCallback(base::UnguessableToken* result_token,
const base::UnguessableToken& actual_token) {
*result_token = actual_token;
}
} // namespace
TEST(WindowServiceTest, DeleteWithClients) {
// Use |test_setup| to configure aura and other state.
WindowServiceTestSetup test_setup;
// Create another WindowService.
TestWindowServiceDelegate test_window_service_delegate;
WindowService window_service(&test_window_service_delegate, nullptr,
test_setup.focus_controller());
service_manager::TestConnectorFactory factory;
window_service.BindServiceRequest(
factory.RegisterInstance(mojom::kServiceName));
// Connect to |window_service| and ask for a new WindowTree.
mojom::WindowTreeFactoryPtr window_tree_factory;
factory.GetDefaultConnector()->BindInterface(mojom::kServiceName,
&window_tree_factory);
mojom::WindowTreePtr window_tree;
mojom::WindowTreeClientPtr client;
mojom::WindowTreeClientRequest client_request = MakeRequest(&client);
window_tree_factory->CreateWindowTree(MakeRequest(&window_tree),
std::move(client));
// Use FlushForTesting() to ensure WindowService processes the request.
window_tree_factory.FlushForTesting();
// There should be at least one WindowTree.
EXPECT_FALSE(window_service.window_trees().empty());
// Destroying the |window_service| should remove all the WindowTrees and
// ensure a DCHECK isn't hit in ~WindowTree.
}
// Implementation of mojom::TestWm that sets a boolean when DoIt() is called.
class TestWm : public WindowManagerInterface, public test::mojom::TestWm {
public:
TestWm(mojo::ScopedInterfaceEndpointHandle handle, bool* do_it_called)
: binding_(this,
mojo::AssociatedInterfaceRequest<test::mojom::TestWm>(
std::move(handle))),
do_it_called_(do_it_called) {}
// test::mojom::TestWm:
void DoIt() override { *do_it_called_ = true; }
private:
mojo::AssociatedBinding<test::mojom::TestWm> binding_;
bool* do_it_called_;
DISALLOW_COPY_AND_ASSIGN(TestWm);
};
// Subclass os TestWindowServiceDelegate that creates TestWm.
class TestWindowServiceDelegateWithInterface
: public TestWindowServiceDelegate {
public:
TestWindowServiceDelegateWithInterface() = default;
~TestWindowServiceDelegateWithInterface() override = default;
bool do_it_called() const { return do_it_called_; }
// TestWindowServiceDelegate:
std::unique_ptr<WindowManagerInterface> CreateWindowManagerInterface(
WindowTree* window_tree,
const std::string& name,
mojo::ScopedInterfaceEndpointHandle handle) override {
if (name != test::mojom::TestWm::Name_)
return nullptr;
return std::make_unique<TestWm>(std::move(handle), &do_it_called_);
}
private:
bool do_it_called_ = false;
DISALLOW_COPY_AND_ASSIGN(TestWindowServiceDelegateWithInterface);
};
TEST(WindowServiceTest, GetWindowManagerInterface) {
// Use |test_setup| to configure aura and other state.
WindowServiceTestSetup test_setup;
// Create another WindowService.
TestWindowServiceDelegateWithInterface test_window_service_delegate;
WindowService window_service(&test_window_service_delegate, nullptr,
test_setup.focus_controller());
service_manager::TestConnectorFactory factory;
window_service.BindServiceRequest(
factory.RegisterInstance(mojom::kServiceName));
// Connect to |window_service| and ask for a new WindowTree.
mojom::WindowTreeFactoryPtr window_tree_factory;
factory.GetDefaultConnector()->BindInterface(mojom::kServiceName,
&window_tree_factory);
mojom::WindowTreePtr window_tree;
mojom::WindowTreeClientPtr client;
mojom::WindowTreeClientRequest client_request = MakeRequest(&client);
window_tree_factory->CreateWindowTree(MakeRequest(&window_tree),
std::move(client));
// Request the TestWm interface and call a function on it.
mojom::WindowManagerAssociatedPtr wm;
window_tree->BindWindowManagerInterface(test::mojom::TestWm::Name_,
MakeRequest(&wm));
test::mojom::TestWmAssociatedPtr test_wm(
mojo::AssociatedInterfacePtrInfo<test::mojom::TestWm>(
wm.PassInterface().PassHandle(), test::mojom::TestWm::Version_));
test_wm->DoIt();
test_wm.FlushForTesting();
EXPECT_TRUE(test_window_service_delegate.do_it_called());
}
// Test client ids assigned to window trees that connect to the window service.
TEST(WindowServiceTest, ClientIds) {
// Use |test_setup| to configure aura and other state.
WindowServiceTestSetup test_setup;
// Create another WindowService.
TestWindowServiceDelegate test_window_service_delegate;
WindowService window_service(&test_window_service_delegate, nullptr,
test_setup.focus_controller());
// The first window tree should have the initial client id.
auto tree = window_service.CreateWindowTree(nullptr);
EXPECT_EQ(kInitialClientId, WindowTreeTestHelper(tree.get()).client_id());
// The second window tree should have an incremented client id.
tree = window_service.CreateWindowTree(nullptr);
EXPECT_EQ(kInitialClientId + 1, WindowTreeTestHelper(tree.get()).client_id());
}
// Test client ids assigned to window trees in the decrementing mode.
TEST(WindowServiceTest, ClientIdsDecrement) {
// Use |test_setup| to configure aura and other state.
WindowServiceTestSetup test_setup;
// Create another WindowService that decrements window ids.
const bool decrement = true;
TestWindowServiceDelegate test_window_service_delegate;
WindowService window_service(&test_window_service_delegate, nullptr,
test_setup.focus_controller(), decrement);
// The first window tree should have the initial decrementing client id.
auto tree = window_service.CreateWindowTree(nullptr);
EXPECT_EQ(kInitialClientIdDecrement,
WindowTreeTestHelper(tree.get()).client_id());
// The second window tree should have a decremented client id.
tree = window_service.CreateWindowTree(nullptr);
EXPECT_EQ(kInitialClientIdDecrement - 1,
WindowTreeTestHelper(tree.get()).client_id());
}
TEST(WindowServiceTest, ScheduleEmbedForExistingClientUsingLocalWindow) {
WindowServiceTestSetup setup;
// Schedule an embed in the tree created by |setup|.
base::UnguessableToken token;
const uint32_t window_id_in_child = 149;
setup.window_tree_test_helper()
->window_tree()
->ScheduleEmbedForExistingClient(
window_id_in_child, base::BindOnce(&ScheduleEmbedCallback, &token));
EXPECT_FALSE(token.is_empty());
// Create a window that will serve as the parent for the remote window and
// complete the embedding.
std::unique_ptr<aura::Window> local_window =
std::make_unique<aura::Window>(nullptr);
local_window->Init(ui::LAYER_NOT_DRAWN);
ASSERT_TRUE(setup.service()->CompleteScheduleEmbedForExistingClient(
local_window.get(), token, /* embed_flags */ 0));
EXPECT_TRUE(WindowService::IsProxyWindow(local_window.get()));
}
TEST(WindowServiceTest,
ScheduleEmbedForExistingClientUsingLocalWindowResetOnTreeDeleted) {
WindowServiceTestSetup setup;
TestWindowTreeClient window_tree_client2;
std::unique_ptr<WindowTree> window_tree2 =
setup.service()->CreateWindowTree(&window_tree_client2);
window_tree2->InitFromFactory();
// Schedule an embed in |window_tree2|.
base::UnguessableToken token;
const uint32_t window_id_in_child = 212;
WindowTreeTestHelper(window_tree2.get())
.window_tree()
->ScheduleEmbedForExistingClient(
window_id_in_child, base::BindOnce(&ScheduleEmbedCallback, &token));
EXPECT_FALSE(token.is_empty());
// Create a window that will serve as the parent for the remote window and
// complete the embedding.
std::unique_ptr<aura::Window> local_window =
std::make_unique<aura::Window>(nullptr);
local_window->Init(ui::LAYER_NOT_DRAWN);
ASSERT_TRUE(setup.service()->CompleteScheduleEmbedForExistingClient(
local_window.get(), token, /* embed_flags */ 0));
EXPECT_TRUE(WindowService::IsProxyWindow(local_window.get()));
// Deleting |window_tree2| should make |local_window| no longer a proxy.
window_tree2.reset();
EXPECT_FALSE(WindowService::IsProxyWindow(local_window.get()));
}
} // namespace ws