Index: services/resource_coordinator/coordination_unit/coordination_unit_graph_observer_unittest.cc |
diff --git a/services/resource_coordinator/coordination_unit/coordination_unit_graph_observer_unittest.cc b/services/resource_coordinator/coordination_unit/coordination_unit_graph_observer_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..5fbcb57447de9812b9a85cec04061f15bca637a6 |
--- /dev/null |
+++ b/services/resource_coordinator/coordination_unit/coordination_unit_graph_observer_unittest.cc |
@@ -0,0 +1,337 @@ |
+// Copyright 2017 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 <string> |
+#include <utility> |
+ |
+#include "base/memory/ptr_util.h" |
+#include "base/process/process_handle.h" |
+#include "base/run_loop.h" |
+#include "services/resource_coordinator/coordination_unit/coordination_unit_factory.h" |
+#include "services/resource_coordinator/coordination_unit/coordination_unit_graph_observer.h" |
+#include "services/resource_coordinator/coordination_unit/coordination_unit_impl.h" |
+#include "services/resource_coordinator/coordination_unit/coordination_unit_impl_unittest_util.h" |
+#include "services/resource_coordinator/coordination_unit/coordination_unit_manager.h" |
+#include "services/resource_coordinator/public/cpp/coordination_unit_id.h" |
+#include "services/resource_coordinator/public/cpp/coordination_unit_types.h" |
+#include "services/resource_coordinator/public/interfaces/coordination_unit.mojom.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace resource_coordinator { |
+ |
+namespace { |
+ |
+class CoordinationUnitGraphObserverTest : public CoordinationUnitImplTestBase { |
+}; |
+ |
+class TestBasicAPICoordinationUnitGraphObserver |
+ : public CoordinationUnitGraphObserver { |
+ public: |
+ TestBasicAPICoordinationUnitGraphObserver() |
+ : TestBasicAPICoordinationUnitGraphObserver( |
+ CoordinationUnitType::kInvalidType) {} |
+ |
+ void OnCoordinationUnitCreated( |
+ CoordinationUnitImpl* coordination_unit) override { |
+ ++on_coordination_unit_created_invocations_; |
+ |
+ coordination_unit->on_add_child_event_listeners().AddListener(base::Bind( |
+ &TestBasicAPICoordinationUnitGraphObserver::OnAddChildListenerInvoked, |
+ base::Unretained(this))); |
+ coordination_unit->on_add_parent_event_listeners().AddListener(base::Bind( |
+ &TestBasicAPICoordinationUnitGraphObserver::OnAddParentListenerInvoked, |
+ base::Unretained(this))); |
+ coordination_unit->on_property_changed_event_listeners().AddListener( |
+ base::Bind(&TestBasicAPICoordinationUnitGraphObserver:: |
+ OnPropertyChangedListenerInvoked, |
+ base::Unretained(this))); |
+ coordination_unit->on_remove_child_event_listeners().AddListener( |
+ base::Bind(&TestBasicAPICoordinationUnitGraphObserver:: |
+ OnRemoveChildListenerInvoked, |
+ base::Unretained(this))); |
+ coordination_unit->on_remove_parent_event_listeners().AddListener( |
+ base::Bind(&TestBasicAPICoordinationUnitGraphObserver:: |
+ OnRemoveParentListenerInvoked, |
+ base::Unretained(this))); |
+ coordination_unit->on_will_be_destroyed_event_listeners().AddListener( |
+ base::Bind(&TestBasicAPICoordinationUnitGraphObserver:: |
+ OnWillBeDestroyedListenerInvoked, |
+ base::Unretained(this))); |
+ } |
+ |
+ size_t on_add_child_listener_invocations() { |
+ return on_add_child_listener_invocations_; |
+ } |
+ size_t on_add_parent_listener_invocations() { |
+ return on_add_parent_listener_invocations_; |
+ } |
+ size_t on_coordination_unit_created_invocations() { |
+ return on_coordination_unit_created_invocations_; |
+ } |
+ size_t on_property_changed_listener_invocations() { |
+ return on_property_changed_listener_invocations_; |
+ } |
+ size_t on_remove_child_listener_invocations() { |
+ return on_remove_child_listener_invocations_; |
+ } |
+ size_t on_remove_parent_listener_invocations() { |
+ return on_remove_parent_listener_invocations_; |
+ } |
+ size_t on_will_be_destroyed_listener_invocations() { |
+ return on_will_be_destroyed_listener_invocations_; |
+ } |
+ |
+ void OnAddChildListenerInvoked( |
+ const CoordinationUnitImpl* coordination_unit, |
+ const CoordinationUnitImpl* child_coordination_unit) { |
+ ++on_add_child_listener_invocations_; |
+ } |
+ void OnAddParentListenerInvoked( |
+ const CoordinationUnitImpl* coordination_unit, |
+ const CoordinationUnitImpl* parent_coordination_unit) { |
+ ++on_add_parent_listener_invocations_; |
+ } |
+ void OnPropertyChangedListenerInvoked( |
+ const CoordinationUnitImpl* coordination_unit, |
+ mojom::PropertyType property) { |
+ ++on_property_changed_listener_invocations_; |
+ } |
+ void OnRemoveChildListenerInvoked( |
+ const CoordinationUnitImpl* coordination_unit, |
+ const CoordinationUnitImpl* former_child_coordination_unit) { |
+ ++on_remove_child_listener_invocations_; |
+ } |
+ void OnRemoveParentListenerInvoked( |
+ const CoordinationUnitImpl* coordination_unit, |
+ const CoordinationUnitImpl* former_parent_coordination_unit) { |
+ ++on_remove_parent_listener_invocations_; |
+ } |
+ void OnWillBeDestroyedListenerInvoked( |
+ const CoordinationUnitImpl* coordination_unit) { |
+ ++on_will_be_destroyed_listener_invocations_; |
+ } |
+ |
+ protected: |
+ explicit TestBasicAPICoordinationUnitGraphObserver( |
+ CoordinationUnitType filter) |
+ : CoordinationUnitGraphObserver(filter), |
+ on_add_child_listener_invocations_(0u), |
+ on_add_parent_listener_invocations_(0u), |
+ on_coordination_unit_created_invocations_(0u), |
+ on_property_changed_listener_invocations_(0u), |
+ on_remove_child_listener_invocations_(0u), |
+ on_remove_parent_listener_invocations_(0u), |
+ on_will_be_destroyed_listener_invocations_(0u) {} |
+ |
+ size_t on_add_child_listener_invocations_; |
+ size_t on_add_parent_listener_invocations_; |
+ size_t on_coordination_unit_created_invocations_; |
+ size_t on_property_changed_listener_invocations_; |
+ size_t on_remove_child_listener_invocations_; |
+ size_t on_remove_parent_listener_invocations_; |
+ size_t on_will_be_destroyed_listener_invocations_; |
+}; |
+ |
+class TestFilterAPICoordinationUnitGraphObserver |
+ : public TestBasicAPICoordinationUnitGraphObserver { |
+ public: |
+ explicit TestFilterAPICoordinationUnitGraphObserver( |
+ CoordinationUnitType filter) |
+ : TestBasicAPICoordinationUnitGraphObserver(filter) {} |
+ |
+ void OnCoordinationUnitCreated( |
+ CoordinationUnitImpl* coordination_unit) override { |
+ ++on_coordination_unit_created_invocations_; |
+ |
+ coordination_unit->on_add_child_event_listeners().AddListener( |
+ base::Bind(&TestBasicAPICoordinationUnitGraphObserver:: |
+ OnAddChildListenerInvoked, |
+ base::Unretained(this)), |
+ CoordinationUnitType::kFrame); |
+ coordination_unit->on_add_parent_event_listeners().AddListener( |
+ base::Bind(&TestBasicAPICoordinationUnitGraphObserver:: |
+ OnAddParentListenerInvoked, |
+ base::Unretained(this)), |
+ CoordinationUnitType::kProcess); |
+ // TODO(matthalp) Use property mojom::PropertyType enum once it is created. |
+ // Currently the only enum is mojom::PropertyType::kTest which is mean to |
+ // be filtered out in the test this observer class is used in. |
+ coordination_unit->on_property_changed_event_listeners().AddListener( |
+ base::Bind(&TestBasicAPICoordinationUnitGraphObserver:: |
+ OnPropertyChangedListenerInvoked, |
+ base::Unretained(this)), |
+ static_cast<mojom::PropertyType>(1)); |
+ coordination_unit->on_remove_child_event_listeners().AddListener( |
+ base::Bind(&TestBasicAPICoordinationUnitGraphObserver:: |
+ OnRemoveChildListenerInvoked, |
+ base::Unretained(this)), |
+ CoordinationUnitType::kNavigation); |
+ coordination_unit->on_remove_parent_event_listeners().AddListener( |
+ base::Bind(&TestBasicAPICoordinationUnitGraphObserver:: |
+ OnRemoveParentListenerInvoked, |
+ base::Unretained(this)), |
+ CoordinationUnitType::kWebContents); |
+ coordination_unit->on_will_be_destroyed_event_listeners().AddListener( |
+ base::Bind(&TestBasicAPICoordinationUnitGraphObserver:: |
+ OnWillBeDestroyedListenerInvoked, |
+ base::Unretained(this))); |
+ } |
+}; |
+ |
+} // namespace |
+ |
+TEST_F(CoordinationUnitGraphObserverTest, CallbacksInvokedNoFilters) { |
+ TestBasicAPICoordinationUnitGraphObserver* observer = |
+ new TestBasicAPICoordinationUnitGraphObserver(); |
+ |
+ // The observer will be deleted after this test executes when the |
+ // CoordinationUnitManager object goes out of scope and destructs. |
+ coordination_unit_manager()->RegisterObserver( |
+ std::unique_ptr<TestBasicAPICoordinationUnitGraphObserver>(observer)); |
+ |
+ // The CoordinationUnit types are intentionally different to make |
+ // sure filtering, which is not disabled, does not occur. |
+ CoordinationUnitID parent_cu_id(CoordinationUnitType::kWebContents, |
+ std::string()); |
+ CoordinationUnitID child_cu_id(CoordinationUnitType::kFrame, std::string()); |
+ |
+ std::unique_ptr<CoordinationUnitImpl> parent_coordination_unit = |
+ coordination_unit_factory::CreateCoordinationUnit( |
+ parent_cu_id, service_context_ref_factory()->CreateRef()); |
+ std::unique_ptr<CoordinationUnitImpl> child_coordination_unit = |
+ coordination_unit_factory::CreateCoordinationUnit( |
+ child_cu_id, service_context_ref_factory()->CreateRef()); |
+ |
+ coordination_unit_manager()->NotifyObserversCoordinationUnitCreated( |
+ parent_coordination_unit.get()); |
+ coordination_unit_manager()->NotifyObserversCoordinationUnitCreated( |
+ child_coordination_unit.get()); |
+ |
+ parent_coordination_unit->AddChild(child_coordination_unit->id()); |
+ parent_coordination_unit->RemoveChild(child_coordination_unit->id()); |
+ |
+ parent_coordination_unit->SetProperty(mojom::PropertyType::kTest, |
+ base::Value(42)); |
+ |
+ child_coordination_unit->WillBeDestroyed(); |
+ parent_coordination_unit->WillBeDestroyed(); |
+ |
+ EXPECT_EQ(2u, observer->on_coordination_unit_created_invocations()); |
+ EXPECT_EQ(1u, observer->on_add_child_listener_invocations()); |
+ EXPECT_EQ(1u, observer->on_add_parent_listener_invocations()); |
+ EXPECT_EQ(1u, observer->on_property_changed_listener_invocations()); |
+ EXPECT_EQ(1u, observer->on_remove_child_listener_invocations()); |
+ EXPECT_EQ(1u, observer->on_remove_parent_listener_invocations()); |
+ EXPECT_EQ(2u, observer->on_will_be_destroyed_listener_invocations()); |
+} |
+ |
+TEST_F(CoordinationUnitGraphObserverTest, CallbacksInvokedWithoutFilters) { |
+ TestFilterAPICoordinationUnitGraphObserver* observer = |
+ new TestFilterAPICoordinationUnitGraphObserver( |
+ CoordinationUnitType::kFrame); |
+ coordination_unit_manager()->RegisterObserver( |
+ std::unique_ptr<TestFilterAPICoordinationUnitGraphObserver>(observer)); |
+ |
+ // The CoordinationUnit types are intentionally different to test |
+ // that filtering is working correctly. |
+ CoordinationUnitID process_cu_id(CoordinationUnitType::kProcess, |
+ std::string()); |
+ CoordinationUnitID tab_cu_id(CoordinationUnitType::kWebContents, |
+ std::string()); |
+ CoordinationUnitID root_frame_cu_id(CoordinationUnitType::kFrame, |
+ std::string()); |
+ CoordinationUnitID frame_cu_id(CoordinationUnitType::kFrame, std::string()); |
+ CoordinationUnitID navigation_cu_id(CoordinationUnitType::kNavigation, |
+ std::string()); |
+ |
+ std::unique_ptr<CoordinationUnitImpl> process_coordination_unit = |
+ coordination_unit_factory::CreateCoordinationUnit( |
+ process_cu_id, service_context_ref_factory()->CreateRef()); |
+ std::unique_ptr<CoordinationUnitImpl> tab_coordination_unit = |
+ coordination_unit_factory::CreateCoordinationUnit( |
+ tab_cu_id, service_context_ref_factory()->CreateRef()); |
+ std::unique_ptr<CoordinationUnitImpl> root_frame_coordination_unit = |
+ coordination_unit_factory::CreateCoordinationUnit( |
+ root_frame_cu_id, service_context_ref_factory()->CreateRef()); |
+ std::unique_ptr<CoordinationUnitImpl> frame_coordination_unit = |
+ coordination_unit_factory::CreateCoordinationUnit( |
+ frame_cu_id, service_context_ref_factory()->CreateRef()); |
+ std::unique_ptr<CoordinationUnitImpl> navigation_coordination_unit = |
+ coordination_unit_factory::CreateCoordinationUnit( |
+ navigation_cu_id, service_context_ref_factory()->CreateRef()); |
+ |
+ // Should only invoke the OnCoordinationUnitCreated listener for |
+ // the root_frame and frame CoordinationUnits because the observer |
+ // filter is set to CoordinationUnitType::kFrame. |
+ coordination_unit_manager()->NotifyObserversCoordinationUnitCreated( |
+ process_coordination_unit.get()); |
+ coordination_unit_manager()->NotifyObserversCoordinationUnitCreated( |
+ tab_coordination_unit.get()); |
+ coordination_unit_manager()->NotifyObserversCoordinationUnitCreated( |
+ root_frame_coordination_unit.get()); |
+ coordination_unit_manager()->NotifyObserversCoordinationUnitCreated( |
+ frame_coordination_unit.get()); |
+ coordination_unit_manager()->NotifyObserversCoordinationUnitCreated( |
+ navigation_coordination_unit.get()); |
+ |
+ // Test AddChild filtering. The AddChild filter for the frame |
+ // CoordinationUnit has been set to only execute when the child |
+ // is a CoordinationUnitType::kFrame so the callback will execute. |
+ root_frame_coordination_unit->AddChild(frame_coordination_unit->id()); |
+ // The child is CoordinationUnitType::kNavigation so the callback |
+ // should not be executed. The navigation Coordination Unit is not |
+ // actually a child of a frame in practice, but is being used here to |
+ // check filtering on OnAddChild. |
+ root_frame_coordination_unit->AddChild(navigation_coordination_unit->id()); |
+ |
+ // Test AddParent filtering. The AddParent filter for the frame |
+ // CoordinationUnit has been set to only execute when the parent |
+ // is a CoordinationUnitType::kProcess so the callback will execute. |
+ // Note that AddParent is called within Add child. |
+ process_coordination_unit->AddChild(root_frame_coordination_unit->id()); |
+ // The parent is CoordinationUnitType::kFrame so the callback |
+ // should not be executed. |
+ tab_coordination_unit->AddChild(root_frame_coordination_unit->id()); |
+ |
+ // Test RemoveChild filtering. The RemoveChild filter for the frame |
+ // CoordinationUnit has been set to only execute when the child |
+ // is a CoordinationUnitType::kFrame so the callback will execute. |
+ root_frame_coordination_unit->RemoveChild(frame_coordination_unit->id()); |
+ // The child is CoordinationUnitType::kNavigation so the callback |
+ // should not be executed. The navigation Coordination Unit is not |
+ // actually a child of a frame in practice, but is being used here to |
+ // check filtering on OnRemoveChild. |
+ root_frame_coordination_unit->RemoveChild(navigation_coordination_unit->id()); |
+ |
+ // Test RemoveParent filtering. The RemoveParent filter for the frame |
+ // CoordinationUnit has been set to only execute when the parent |
+ // is a CoordinationUnitType::kProcess so the callback will execute. |
+ // Note that RemoveParent is called within Remove child. |
+ process_coordination_unit->RemoveChild(root_frame_coordination_unit->id()); |
+ // The parent is CoordinationUnitType::kFrame so the callback |
+ // should not be executed. |
+ tab_coordination_unit->RemoveChild(root_frame_coordination_unit->id()); |
+ |
+ // TODO(matthalp) Implement this another SetProperty once an additional |
+ // mojom::PropertyType has been implemented so that the SetProperty |
+ // filtering API can be tested. |
+ root_frame_coordination_unit->SetProperty(mojom::PropertyType::kTest, |
+ base::Value(42)); |
+ |
+ process_coordination_unit->WillBeDestroyed(); |
+ tab_coordination_unit->WillBeDestroyed(); |
+ root_frame_coordination_unit->WillBeDestroyed(); |
+ frame_coordination_unit->WillBeDestroyed(); |
+ navigation_coordination_unit->WillBeDestroyed(); |
+ |
+ EXPECT_EQ(1u, observer->on_add_child_listener_invocations()); |
+ EXPECT_EQ(1u, observer->on_add_parent_listener_invocations()); |
+ EXPECT_EQ(2u, observer->on_coordination_unit_created_invocations()); |
+ EXPECT_EQ(0u, observer->on_property_changed_listener_invocations()); |
+ EXPECT_EQ(1u, observer->on_remove_child_listener_invocations()); |
+ EXPECT_EQ(1u, observer->on_remove_parent_listener_invocations()); |
+ EXPECT_EQ(2u, observer->on_will_be_destroyed_listener_invocations()); |
+} |
+ |
+} // namespace resource_coordinator |