Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(46)

Unified Diff: content/renderer/mus/compositor_mus_connection_unittest.cc

Issue 1749323002: Update WindowTree::OnWindowInputEventAck to include handled (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Missing Component Build DEPS Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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
« no previous file with comments | « content/renderer/mus/compositor_mus_connection.cc ('k') | content/renderer/mus/render_widget_mus_connection.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698