| // 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/event_queue.h" |
| |
| #include <string> |
| |
| #include "base/test/bind_test_util.h" |
| #include "services/ws/event_queue.h" |
| #include "services/ws/event_queue_test_helper.h" |
| #include "services/ws/window_service.h" |
| #include "services/ws/window_service_test_setup.h" |
| #include "services/ws/window_tree_test_helper.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/aura/client/aura_constants.h" |
| #include "ui/aura/mus/property_converter.h" |
| #include "ui/aura/window.h" |
| #include "ui/aura/window_observer.h" |
| #include "ui/aura/window_tracker.h" |
| #include "ui/events/event.h" |
| #include "ui/events/test/event_generator.h" |
| |
| namespace ws { |
| namespace { |
| |
| TEST(EventQueueTest, DontQueueEventsToLocalWindow) { |
| WindowServiceTestSetup setup; |
| setup.set_ack_events_immediately(false); |
| |
| aura::Window* window = new aura::Window(nullptr); |
| window->Init(ui::LAYER_NOT_DRAWN); |
| setup.root()->AddChild(window); |
| window->Show(); |
| window->Focus(); |
| EXPECT_TRUE(window->HasFocus()); |
| |
| setup.changes()->clear(); |
| EventQueueTestHelper event_queue_test_helper(setup.service()->event_queue()); |
| ui::test::EventGenerator event_generator(setup.root()); |
| event_generator.PressKey(ui::VKEY_A, ui::EF_NONE); |
| EXPECT_FALSE(event_queue_test_helper.HasInFlightEvent()); |
| } |
| |
| TEST(EventQueueTest, Basic) { |
| WindowServiceTestSetup setup; |
| setup.set_ack_events_immediately(false); |
| |
| // Events are only queued if they target a window with a remote client. |
| aura::Window* top_level = |
| setup.window_tree_test_helper()->NewTopLevelWindow(); |
| ASSERT_TRUE(top_level); |
| top_level->Show(); |
| top_level->Focus(); |
| EXPECT_TRUE(top_level->HasFocus()); |
| |
| // Generate a single key event. |
| setup.changes()->clear(); |
| EventQueueTestHelper event_queue_test_helper(setup.service()->event_queue()); |
| ui::test::EventGenerator event_generator(setup.root()); |
| event_generator.PressKey(ui::VKEY_A, ui::EF_NONE); |
| EXPECT_TRUE(event_queue_test_helper.HasInFlightEvent()); |
| ASSERT_EQ(1u, setup.changes()->size()); |
| EXPECT_EQ(CHANGE_TYPE_INPUT_EVENT, (*setup.changes())[0].type); |
| setup.changes()->clear(); |
| |
| // Generate another key event. As the client has not yet responded to the |
| // first event, this event should be queued. |
| event_generator.PressKey(ui::VKEY_B, ui::EF_NONE); |
| EXPECT_TRUE(event_queue_test_helper.HasInFlightEvent()); |
| EXPECT_TRUE(setup.changes()->empty()); |
| |
| // Ack the first event, which should then send the second. |
| event_queue_test_helper.AckInFlightEvent(); |
| EXPECT_TRUE(event_queue_test_helper.HasInFlightEvent()); |
| ASSERT_EQ(1u, setup.changes()->size()); |
| EXPECT_EQ(CHANGE_TYPE_INPUT_EVENT, (*setup.changes())[0].type); |
| setup.changes()->clear(); |
| |
| // Acking the second should mean no more in flight events. |
| event_queue_test_helper.AckInFlightEvent(); |
| EXPECT_FALSE(event_queue_test_helper.HasInFlightEvent()); |
| EXPECT_TRUE(setup.changes()->empty()); |
| } |
| |
| TEST(EventQueueTest, NotifyWhenReadyToDispatch) { |
| WindowServiceTestSetup setup; |
| setup.set_ack_events_immediately(false); |
| |
| bool was_dispatch_closure_run = false; |
| setup.service()->event_queue()->NotifyWhenReadyToDispatch( |
| base::BindLambdaForTesting([&]() { was_dispatch_closure_run = true; })); |
| EXPECT_TRUE(was_dispatch_closure_run); |
| was_dispatch_closure_run = false; |
| |
| // Events are only queued if they target a window with a remote client. |
| aura::Window* top_level = |
| setup.window_tree_test_helper()->NewTopLevelWindow(); |
| ASSERT_TRUE(top_level); |
| top_level->Show(); |
| top_level->Focus(); |
| EXPECT_TRUE(top_level->HasFocus()); |
| |
| // Generate a single key event. |
| EventQueueTestHelper event_queue_test_helper(setup.service()->event_queue()); |
| ui::test::EventGenerator event_generator(setup.root()); |
| event_generator.PressKey(ui::VKEY_A, ui::EF_NONE); |
| EXPECT_TRUE(event_queue_test_helper.HasInFlightEvent()); |
| |
| // Set another closure. The closure should not be run immediately. |
| setup.service()->event_queue()->NotifyWhenReadyToDispatch( |
| base::BindLambdaForTesting([&]() { was_dispatch_closure_run = true; })); |
| EXPECT_FALSE(was_dispatch_closure_run); |
| |
| // Ack the event, which should notify the closure. |
| event_queue_test_helper.AckInFlightEvent(); |
| EXPECT_TRUE(was_dispatch_closure_run); |
| } |
| |
| TEST(EventQueueTest, Timeout) { |
| WindowServiceTestSetup setup; |
| setup.set_ack_events_immediately(false); |
| |
| // Events are only queued if they target a window with a remote client. |
| aura::Window* top_level = |
| setup.window_tree_test_helper()->NewTopLevelWindow(); |
| ASSERT_TRUE(top_level); |
| top_level->Show(); |
| top_level->Focus(); |
| EXPECT_TRUE(top_level->HasFocus()); |
| |
| // Generate a single key event. |
| EventQueueTestHelper event_queue_test_helper(setup.service()->event_queue()); |
| ui::test::EventGenerator event_generator(setup.root()); |
| event_generator.PressKey(ui::VKEY_A, ui::EF_NONE); |
| EXPECT_TRUE(event_queue_test_helper.HasInFlightEvent()); |
| |
| // Add a closure to be run when the event is acked, or the timeout occurs. |
| bool was_dispatch_closure_run = false; |
| setup.service()->event_queue()->NotifyWhenReadyToDispatch( |
| base::BindLambdaForTesting([&]() { was_dispatch_closure_run = true; })); |
| EXPECT_FALSE(was_dispatch_closure_run); |
| |
| event_queue_test_helper.RunAckTimer(); |
| EXPECT_TRUE(was_dispatch_closure_run); |
| } |
| |
| TEST(EventQueueTest, HostDestroyedWhileEventQueued) { |
| WindowServiceTestSetup setup; |
| setup.set_ack_events_immediately(false); |
| |
| // Events are only queued if they target a window with a remote client. |
| aura::Window* top_level = |
| setup.window_tree_test_helper()->NewTopLevelWindow(); |
| ASSERT_TRUE(top_level); |
| top_level->Show(); |
| top_level->Focus(); |
| EXPECT_TRUE(top_level->HasFocus()); |
| |
| // Generate a single key event. |
| setup.changes()->clear(); |
| EventQueueTestHelper event_queue_test_helper(setup.service()->event_queue()); |
| ui::test::EventGenerator event_generator(setup.root()); |
| event_generator.PressKey(ui::VKEY_A, ui::EF_NONE); |
| EXPECT_TRUE(event_queue_test_helper.HasInFlightEvent()); |
| ASSERT_EQ(1u, setup.changes()->size()); |
| EXPECT_EQ(CHANGE_TYPE_INPUT_EVENT, (*setup.changes())[0].type); |
| setup.changes()->clear(); |
| |
| // Generate another key event. As the client has not yet responded to the |
| // first event, this event should be queued. |
| event_generator.PressKey(ui::VKEY_B, ui::EF_NONE); |
| EXPECT_TRUE(event_queue_test_helper.HasInFlightEvent()); |
| EXPECT_TRUE(setup.changes()->empty()); |
| |
| // Destroy the window and its host. |
| setup.window_tree_test_helper()->DeleteWindow(top_level); |
| setup.changes()->clear(); |
| |
| // Ack the first event, the second event should be safely ignored. |
| event_queue_test_helper.AckInFlightEvent(); |
| EXPECT_FALSE(event_queue_test_helper.HasInFlightEvent()); |
| auto iter = FirstChangeOfType(*setup.changes(), CHANGE_TYPE_INPUT_EVENT); |
| EXPECT_EQ(iter, setup.changes()->end()); |
| } |
| |
| } // namespace |
| } // namespace ws |