| Index: content/renderer/mus/compositor_mus_connection_unittest.cc
|
| diff --git a/content/renderer/mus/compositor_mus_connection_unittest.cc b/content/renderer/mus/compositor_mus_connection_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0b75f2f4f1a9cdbcafa056104adc9cefabc078b8
|
| --- /dev/null
|
| +++ b/content/renderer/mus/compositor_mus_connection_unittest.cc
|
| @@ -0,0 +1,466 @@
|
| +// Copyright 2016 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/renderer/mus/compositor_mus_connection.h"
|
| +
|
| +#include "base/macros.h"
|
| +#include "base/memory/ref_counted.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/test/test_simple_task_runner.h"
|
| +#include "base/time/time.h"
|
| +#include "components/mus/public/cpp/tests/test_window.h"
|
| +#include "components/mus/public/interfaces/input_event_constants.mojom.h"
|
| +#include "components/mus/public/interfaces/input_events.mojom.h"
|
| +#include "components/mus/public/interfaces/input_key_codes.mojom.h"
|
| +#include "content/common/input/did_overscroll_params.h"
|
| +#include "content/common/input/input_event_ack.h"
|
| +#include "content/common/input/input_event_ack_state.h"
|
| +#include "content/public/test/mock_render_thread.h"
|
| +#include "content/renderer/input/input_handler_manager.h"
|
| +#include "content/renderer/input/input_handler_manager_client.h"
|
| +#include "content/renderer/input/render_widget_input_handler.h"
|
| +#include "content/renderer/mus/render_widget_mus_connection.h"
|
| +#include "content/renderer/render_widget.h"
|
| +#include "content/test/fake_compositor_dependencies.h"
|
| +#include "content/test/fake_renderer_scheduler.h"
|
| +#include "mojo/public/cpp/bindings/interface_request.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +namespace {
|
| +
|
| +// Wrapper for the callback provided to
|
| +// CompositorMusConnection:OnWindowInputEvent. This tracks whether the it was
|
| +// called, along with the result.
|
| +class TestCallback : public base::RefCounted<TestCallback> {
|
| + public:
|
| + TestCallback() : called_(false), result_(false) {}
|
| +
|
| + bool called() { return called_; }
|
| + bool result() { return result_; }
|
| +
|
| + void BoolCallback(bool result) {
|
| + called_ = true;
|
| + result_ = result;
|
| + }
|
| +
|
| + private:
|
| + friend class base::RefCounted<TestCallback>;
|
| +
|
| + ~TestCallback() {}
|
| +
|
| + bool called_;
|
| + bool result_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(TestCallback);
|
| +};
|
| +
|
| +// Allows for overriding the behaviour of HandleInputEvent, to simulate input
|
| +// handlers which consume events before they are sent to the renderer.
|
| +class TestInputHandlerManager : public content::InputHandlerManager {
|
| + public:
|
| + TestInputHandlerManager(
|
| + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
|
| + content::InputHandlerManagerClient* client,
|
| + scheduler::RendererScheduler* renderer_scheduler)
|
| + : InputHandlerManager(task_runner, client, renderer_scheduler),
|
| + override_result_(false),
|
| + result_(content::InputEventAckState::INPUT_EVENT_ACK_STATE_UNKNOWN) {}
|
| + ~TestInputHandlerManager() override {}
|
| +
|
| + // Stops overriding the behaviour of HandleInputEvent
|
| + void ClearHandleInputEventOverride();
|
| +
|
| + // Overrides the behaviour of HandleInputEvent, returing |result|.
|
| + void SetHandleInputEventResult(content::InputEventAckState result);
|
| +
|
| + // content::InputHandlerManager:
|
| + content::InputEventAckState HandleInputEvent(
|
| + int routing_id,
|
| + const blink::WebInputEvent* input_event,
|
| + ui::LatencyInfo* latency_info) override;
|
| +
|
| + private:
|
| + // If true content::InputHandlerManager::HandleInputEvent is not called.
|
| + bool override_result_;
|
| +
|
| + // The result to return in HandleInputEvent if |override_result_|.
|
| + content::InputEventAckState result_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(TestInputHandlerManager);
|
| +};
|
| +
|
| +void TestInputHandlerManager::ClearHandleInputEventOverride() {
|
| + override_result_ = false;
|
| +}
|
| +
|
| +void TestInputHandlerManager::SetHandleInputEventResult(
|
| + content::InputEventAckState result) {
|
| + override_result_ = true;
|
| + result_ = result;
|
| +}
|
| +
|
| +content::InputEventAckState TestInputHandlerManager::HandleInputEvent(
|
| + int routing_id,
|
| + const blink::WebInputEvent* input_event,
|
| + ui::LatencyInfo* latency_info) {
|
| + if (override_result_)
|
| + return result_;
|
| + return content::InputHandlerManager::HandleInputEvent(routing_id, input_event,
|
| + latency_info);
|
| +}
|
| +
|
| +// Empty implementation of InputHandlerManagerClient.
|
| +class TestInputHandlerManagerClient
|
| + : public content::InputHandlerManagerClient {
|
| + public:
|
| + TestInputHandlerManagerClient() {}
|
| + ~TestInputHandlerManagerClient() override{};
|
| +
|
| + // content::InputHandlerManagerClient:
|
| + void SetBoundHandler(const Handler& handler) override {}
|
| + void DidAddInputHandler(
|
| + int routing_id,
|
| + ui::SynchronousInputHandlerProxy* synchronous_handler) override {}
|
| + void DidRemoveInputHandler(int routing_id) override {}
|
| + void DidOverscroll(int routing_id,
|
| + const content::DidOverscrollParams& params) override {}
|
| + void DidStopFlinging(int routing_id) override {}
|
| + void NonBlockingInputEventHandled(int routing_id,
|
| + blink::WebInputEvent::Type type) override {}
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(TestInputHandlerManagerClient);
|
| +};
|
| +
|
| +// Implementation of RenderWidget for testing, performs no initialization.
|
| +class TestRenderWidget : public content::RenderWidget {
|
| + public:
|
| + explicit TestRenderWidget(content::CompositorDependencies* compositor_deps)
|
| + : content::RenderWidget(compositor_deps,
|
| + blink::WebPopupTypeNone,
|
| + blink::WebScreenInfo(),
|
| + true,
|
| + false,
|
| + false) {}
|
| +
|
| + protected:
|
| + ~TestRenderWidget() override {}
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(TestRenderWidget);
|
| +};
|
| +
|
| +// Test override of RenderWidgetInputHandler to allow the control of
|
| +// HandleInputEvent. This will perform no actions on input until a
|
| +// RenderWidgetInputHandlerDelegate is set. Once set this will always ack
|
| +// received events.
|
| +class TestRenderWidgetInputHandler : public content::RenderWidgetInputHandler {
|
| + public:
|
| + TestRenderWidgetInputHandler(content::RenderWidget* render_widget);
|
| + ~TestRenderWidgetInputHandler() override {}
|
| +
|
| + void set_delegate(content::RenderWidgetInputHandlerDelegate* delegate) {
|
| + delegate_ = delegate;
|
| + }
|
| + void set_state(content::InputEventAckState state) { state_ = state; }
|
| +
|
| + // content::RenderWidgetInputHandler:
|
| + void HandleInputEvent(const blink::WebInputEvent& input_event,
|
| + const ui::LatencyInfo& latency_info,
|
| + content::InputEventDispatchType dispatch_type) override;
|
| +
|
| + private:
|
| + // The input delegate which receives event acks.
|
| + content::RenderWidgetInputHandlerDelegate* delegate_;
|
| +
|
| + // The result of input handling to send to |delegate_| during the ack.
|
| + content::InputEventAckState state_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(TestRenderWidgetInputHandler);
|
| +};
|
| +
|
| +TestRenderWidgetInputHandler::TestRenderWidgetInputHandler(
|
| + content::RenderWidget* render_widget)
|
| + : content::RenderWidgetInputHandler(render_widget, render_widget),
|
| + delegate_(nullptr),
|
| + state_(content::InputEventAckState::INPUT_EVENT_ACK_STATE_UNKNOWN) {}
|
| +
|
| +void TestRenderWidgetInputHandler::HandleInputEvent(
|
| + const blink::WebInputEvent& input_event,
|
| + const ui::LatencyInfo& latency_info,
|
| + content::InputEventDispatchType dispatch_type) {
|
| + if (delegate_) {
|
| + scoped_ptr<content::InputEventAck> ack(
|
| + new content::InputEventAck(input_event.type, state_));
|
| + delegate_->OnInputEventAck(std::move(ack));
|
| + }
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +namespace content {
|
| +
|
| +// Test suite for CompositorMusConnection, this does not setup a full renderer
|
| +// environment. This does not establish a connection to a mus server, nor does
|
| +// it initialize one.
|
| +class CompositorMusConnectionTest : public testing::Test {
|
| + public:
|
| + CompositorMusConnectionTest() {}
|
| + ~CompositorMusConnectionTest() override {}
|
| +
|
| + // Initializes |event| with valid parameters for a key event, so that it can
|
| + // be converted to a web event by CompositorMusConnection.
|
| + void GenerateKeyEvent(mus::mojom::EventPtr& event);
|
| +
|
| + // Calls CompositorMusConnection::OnWindowInputEvent.
|
| + void OnWindowInputEvent(mus::Window* window,
|
| + mus::mojom::EventPtr event,
|
| + scoped_ptr<base::Callback<void(bool)>>* ack_callback);
|
| +
|
| + // Confirms the state of pending tasks enqueued on each task runner, and runs
|
| + // until idle.
|
| + void VerifyAndRunQueues(bool main_task_runner_enqueued,
|
| + bool compositor_task_runner_enqueued);
|
| +
|
| + CompositorMusConnection* compositor_connection() {
|
| + return compositor_connection_.get();
|
| + }
|
| + RenderWidgetMusConnection* connection() { return connection_; }
|
| + TestInputHandlerManager* input_handler_manager() {
|
| + return input_handler_manager_.get();
|
| + }
|
| + TestRenderWidgetInputHandler* render_widget_input_handler() {
|
| + return render_widget_input_handler_.get();
|
| + }
|
| +
|
| + // testing::Test:
|
| + void SetUp() override;
|
| + void TearDown() override;
|
| +
|
| + private:
|
| + // Mocks/Fakes of the testing environment.
|
| + TestInputHandlerManagerClient input_handler_manager_client_;
|
| + FakeCompositorDependencies compositor_dependencies_;
|
| + FakeRendererScheduler renderer_scheduler_;
|
| + MockRenderThread render_thread_;
|
| + scoped_refptr<TestRenderWidget> render_widget_;
|
| + mojo::InterfaceRequest<mus::mojom::WindowTreeClient> request_;
|
| +
|
| + // Not owned, RenderWidgetMusConnection tracks in static state. Cleared during
|
| + // TearDown.
|
| + RenderWidgetMusConnection* connection_;
|
| +
|
| + // Test versions of task runners, see VerifyAndRunQueues to use in testing.
|
| + scoped_refptr<base::TestSimpleTaskRunner> main_task_runner_;
|
| + scoped_refptr<base::TestSimpleTaskRunner> compositor_task_runner_;
|
| +
|
| + // Actual CompositorMusConnection for testing.
|
| + scoped_refptr<CompositorMusConnection> compositor_connection_;
|
| +
|
| + // Test implementations, to control input given to |compositor_connection_|.
|
| + scoped_ptr<TestInputHandlerManager> input_handler_manager_;
|
| + scoped_ptr<TestRenderWidgetInputHandler> render_widget_input_handler_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(CompositorMusConnectionTest);
|
| +};
|
| +
|
| +void CompositorMusConnectionTest::GenerateKeyEvent(
|
| + mus::mojom::EventPtr& event) {
|
| + event->action = mus::mojom::EventType::KEY_PRESSED;
|
| + event->time_stamp = base::TimeTicks::Now().ToInternalValue();
|
| + event->key_data = mus::mojom::KeyData::New();
|
| + event->key_data->is_char = true;
|
| + event->key_data->windows_key_code = mus::mojom::KeyboardCode::A;
|
| +}
|
| +
|
| +void CompositorMusConnectionTest::OnWindowInputEvent(
|
| + mus::Window* window,
|
| + mus::mojom::EventPtr event,
|
| + scoped_ptr<base::Callback<void(bool)>>* ack_callback) {
|
| + compositor_connection_->OnWindowInputEvent(window, std::move(event),
|
| + ack_callback);
|
| +}
|
| +
|
| +void CompositorMusConnectionTest::VerifyAndRunQueues(
|
| + bool main_task_runner_enqueued,
|
| + bool compositor_task_runner_enqueued) {
|
| + // Run through the enqueued actions.
|
| + EXPECT_EQ(main_task_runner_enqueued, main_task_runner_->HasPendingTask());
|
| + main_task_runner_->RunUntilIdle();
|
| +
|
| + EXPECT_EQ(compositor_task_runner_enqueued,
|
| + compositor_task_runner_->HasPendingTask());
|
| + compositor_task_runner_->RunUntilIdle();
|
| +}
|
| +
|
| +void CompositorMusConnectionTest::SetUp() {
|
| + testing::Test::SetUp();
|
| +
|
| + main_task_runner_ = new base::TestSimpleTaskRunner();
|
| + compositor_task_runner_ = new base::TestSimpleTaskRunner();
|
| +
|
| + input_handler_manager_.reset(new TestInputHandlerManager(
|
| + compositor_task_runner_, &input_handler_manager_client_,
|
| + &renderer_scheduler_));
|
| +
|
| + const int routing_id = 42;
|
| + compositor_connection_ = new CompositorMusConnection(
|
| + routing_id, main_task_runner_, compositor_task_runner_,
|
| + std::move(request_), input_handler_manager_.get());
|
| +
|
| + // CompositorMusConnection attempts to create connection to the non-existant
|
| + // server. Clear that.
|
| + compositor_task_runner_->ClearPendingTasks();
|
| +
|
| + render_widget_ = new TestRenderWidget(&compositor_dependencies_);
|
| + render_widget_input_handler_.reset(
|
| + new TestRenderWidgetInputHandler(render_widget_.get()));
|
| + connection_ = RenderWidgetMusConnection::GetOrCreate(routing_id);
|
| + connection_->SetInputHandler(render_widget_input_handler_.get());
|
| +}
|
| +
|
| +void CompositorMusConnectionTest::TearDown() {
|
| + // Clear static state.
|
| + connection_->OnConnectionLost();
|
| + testing::Test::TearDown();
|
| +}
|
| +
|
| +// Tests that for events which the renderer will ack, yet not consume, that
|
| +// CompositorMusConnection consumes the ack during OnWindowInputEvent, and calls
|
| +// it with the correct state once processed.
|
| +TEST_F(CompositorMusConnectionTest, NotConsumed) {
|
| + TestRenderWidgetInputHandler* input_handler = render_widget_input_handler();
|
| + input_handler->set_delegate(connection());
|
| + input_handler->set_state(
|
| + InputEventAckState::INPUT_EVENT_ACK_STATE_NOT_CONSUMED);
|
| +
|
| + mus::TestWindow test_window;
|
| + mus::mojom::EventPtr event = mus::mojom::Event::New();
|
| + GenerateKeyEvent(event);
|
| + scoped_refptr<TestCallback> test_callback(new TestCallback);
|
| + scoped_ptr<base::Callback<void(bool)>> ack_callback(
|
| + new base::Callback<void(bool)>(
|
| + base::Bind(&::TestCallback::BoolCallback, test_callback)));
|
| +
|
| + OnWindowInputEvent(&test_window, std::move(event), &ack_callback);
|
| + // OnWindowInputEvent is expected to clear the callback if it plans on
|
| + // handling the ack.
|
| + EXPECT_FALSE(ack_callback.get());
|
| +
|
| + VerifyAndRunQueues(true, true);
|
| +
|
| + // The ack callback should have been called
|
| + EXPECT_TRUE(test_callback->called());
|
| + EXPECT_FALSE(test_callback->result());
|
| +}
|
| +
|
| +// Tests that for events which the renderer will ack, and consume, that
|
| +// CompositorMusConnection consumes the ack during OnWindowInputEvent, and calls
|
| +// it with the correct state once processed.
|
| +TEST_F(CompositorMusConnectionTest, Consumed) {
|
| + TestRenderWidgetInputHandler* input_handler = render_widget_input_handler();
|
| + input_handler->set_delegate(connection());
|
| + input_handler->set_state(InputEventAckState::INPUT_EVENT_ACK_STATE_CONSUMED);
|
| +
|
| + mus::TestWindow test_window;
|
| + mus::mojom::EventPtr event = mus::mojom::Event::New();
|
| + GenerateKeyEvent(event);
|
| + scoped_refptr<TestCallback> test_callback(new TestCallback);
|
| + scoped_ptr<base::Callback<void(bool)>> ack_callback(
|
| + new base::Callback<void(bool)>(
|
| + base::Bind(&::TestCallback::BoolCallback, test_callback)));
|
| +
|
| + OnWindowInputEvent(&test_window, std::move(event), &ack_callback);
|
| + // OnWindowInputEvent is expected to clear the callback if it plans on
|
| + // handling the ack.
|
| + EXPECT_FALSE(ack_callback.get());
|
| +
|
| + VerifyAndRunQueues(true, true);
|
| +
|
| + // The ack callback should have been called
|
| + EXPECT_TRUE(test_callback->called());
|
| + EXPECT_TRUE(test_callback->result());
|
| +}
|
| +
|
| +// Tests that when the RenderWidgetInputHandler does not ack before a new event
|
| +// arrives, that only the most recent ack is fired.
|
| +TEST_F(CompositorMusConnectionTest, LostAck) {
|
| + mus::TestWindow test_window;
|
| + mus::mojom::EventPtr event1 = mus::mojom::Event::New();
|
| + GenerateKeyEvent(event1);
|
| + scoped_refptr<TestCallback> test_callback1(new TestCallback);
|
| + scoped_ptr<base::Callback<void(bool)>> ack_callback1(
|
| + new base::Callback<void(bool)>(
|
| + base::Bind(&::TestCallback::BoolCallback, test_callback1)));
|
| +
|
| + OnWindowInputEvent(&test_window, std::move(event1), &ack_callback1);
|
| + EXPECT_FALSE(ack_callback1.get());
|
| + // When simulating the timeout the ack is never enqueued
|
| + VerifyAndRunQueues(true, false);
|
| +
|
| + // Setting a delegate will lead to the next event being acked. Having a
|
| + // cleared queue simulates the input handler timing out on an event.
|
| + TestRenderWidgetInputHandler* input_handler = render_widget_input_handler();
|
| + input_handler->set_delegate(connection());
|
| + input_handler->set_state(InputEventAckState::INPUT_EVENT_ACK_STATE_CONSUMED);
|
| +
|
| + mus::mojom::EventPtr event2 = mus::mojom::Event::New();
|
| + GenerateKeyEvent(event2);
|
| + scoped_refptr<TestCallback> test_callback2(new TestCallback);
|
| + scoped_ptr<base::Callback<void(bool)>> ack_callback2(
|
| + new base::Callback<void(bool)>(
|
| + base::Bind(&::TestCallback::BoolCallback, test_callback2)));
|
| + OnWindowInputEvent(&test_window, std::move(event2), &ack_callback2);
|
| + EXPECT_FALSE(ack_callback2.get());
|
| +
|
| + VerifyAndRunQueues(true, true);
|
| +
|
| + // Only the most recent ack was called.
|
| + EXPECT_FALSE(test_callback1->called());
|
| + EXPECT_TRUE(test_callback2->called());
|
| + EXPECT_TRUE(test_callback2->result());
|
| +}
|
| +
|
| +// Tests that when an input handler consumes the event, that
|
| +// CompositorMusConnection does not consume the ack, nor calls it.
|
| +TEST_F(CompositorMusConnectionTest, InputHandlerConsumes) {
|
| + input_handler_manager()->SetHandleInputEventResult(
|
| + InputEventAckState::INPUT_EVENT_ACK_STATE_CONSUMED);
|
| + mus::TestWindow test_window;
|
| + mus::mojom::EventPtr event = mus::mojom::Event::New();
|
| + GenerateKeyEvent(event);
|
| + scoped_refptr<TestCallback> test_callback(new TestCallback);
|
| + scoped_ptr<base::Callback<void(bool)>> ack_callback(
|
| + new base::Callback<void(bool)>(
|
| + base::Bind(&::TestCallback::BoolCallback, test_callback)));
|
| +
|
| + OnWindowInputEvent(&test_window, std::move(event), &ack_callback);
|
| +
|
| + EXPECT_TRUE(ack_callback.get());
|
| + VerifyAndRunQueues(false, false);
|
| + EXPECT_FALSE(test_callback->called());
|
| +}
|
| +
|
| +// Tests that when the renderer will not ack an event, that
|
| +// CompositorMusConnection does not consume the ack, nor calls it.
|
| +TEST_F(CompositorMusConnectionTest, RendererWillNotSendAck) {
|
| + mus::TestWindow test_window;
|
| + mus::mojom::EventPtr event = mus::mojom::Event::New();
|
| + event->action = mus::mojom::EventType::POINTER_DOWN;
|
| + event->time_stamp = base::TimeTicks::Now().ToInternalValue();
|
| + event->pointer_data = mus::mojom::PointerData::New();
|
| +
|
| + scoped_refptr<TestCallback> test_callback(new TestCallback);
|
| + scoped_ptr<base::Callback<void(bool)>> ack_callback(
|
| + new base::Callback<void(bool)>(
|
| + base::Bind(&::TestCallback::BoolCallback, test_callback)));
|
| +
|
| + OnWindowInputEvent(&test_window, std::move(event), &ack_callback);
|
| + EXPECT_TRUE(ack_callback.get());
|
| +
|
| + VerifyAndRunQueues(true, false);
|
| + EXPECT_FALSE(test_callback->called());
|
| +}
|
| +
|
| +} // namespace content
|
|
|