node_attached_data_unittest.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/performance_manager/public/graph/node_attached_data.h"
  5. #include <utility>
  6. #include "base/memory/raw_ptr.h"
  7. #include "base/test/gtest_util.h"
  8. #include "components/performance_manager/graph/frame_node_impl.h"
  9. #include "components/performance_manager/graph/graph_impl.h"
  10. #include "components/performance_manager/graph/node_attached_data_impl.h"
  11. #include "components/performance_manager/graph/node_base.h"
  12. #include "components/performance_manager/graph/page_node_impl.h"
  13. #include "components/performance_manager/graph/process_node_impl.h"
  14. #include "components/performance_manager/graph/system_node_impl.h"
  15. #include "components/performance_manager/public/graph/node.h"
  16. #include "components/performance_manager/test_support/graph_test_harness.h"
  17. #include "components/performance_manager/test_support/mock_graphs.h"
  18. #include "testing/gmock/include/gmock/gmock.h"
  19. #include "testing/gtest/include/gtest/gtest.h"
  20. namespace performance_manager {
  21. namespace {
  22. // Note that a FooData basically has pointer size, because its an empty class
  23. // with a single vtable pointer.
  24. constexpr size_t kFooDataSize = sizeof(uintptr_t);
  25. // A dummy node type so that we can exercise node attached storage code paths.
  26. class DummyNode : public NodeBase, public Node {
  27. public:
  28. DummyNode() : NodeBase(NodeTypeEnum::kInvalidType) {}
  29. DummyNode(const DummyNode&) = delete;
  30. DummyNode& operator=(const DummyNode&) = delete;
  31. ~DummyNode() override = default;
  32. // NodeBase implementation:
  33. const Node* ToNode() const override { return static_cast<const Node*>(this); }
  34. void RemoveNodeAttachedData() override {}
  35. // Node implementation:
  36. Graph* GetGraph() const override { return graph(); }
  37. NodeState GetNodeState() const override { return NodeState::kActiveInGraph; }
  38. uintptr_t GetImplType() const override {
  39. static const uintptr_t kImplType = reinterpret_cast<uintptr_t>(&kImplType);
  40. return kImplType;
  41. }
  42. const void* GetImpl() const override {
  43. return static_cast<const NodeBase*>(this);
  44. }
  45. static constexpr NodeTypeEnum Type() { return NodeTypeEnum::kInvalidType; }
  46. // Internal storage for DummyData and FooData types. These would normally be
  47. // protected and the data classes friended, but we also want to access these
  48. // in the tests.
  49. std::unique_ptr<NodeAttachedData> dummy_data_;
  50. InternalNodeAttachedDataStorage<kFooDataSize> foo_data_;
  51. };
  52. // A NodeAttachedData class that can only be attached to page and process nodes
  53. // using the map, and to DummyNodes using node owned storage.
  54. class DummyData : public NodeAttachedDataImpl<DummyData> {
  55. public:
  56. struct Traits : public NodeAttachedDataInMap<PageNodeImpl>,
  57. public NodeAttachedDataInMap<ProcessNodeImpl>,
  58. public NodeAttachedDataOwnedByNodeType<DummyNode> {};
  59. DummyData() = default;
  60. explicit DummyData(const PageNodeImpl* page_node) {}
  61. explicit DummyData(const ProcessNodeImpl* process_node) {}
  62. explicit DummyData(const DummyNode* dummy_node) {}
  63. DummyData(const DummyData&) = delete;
  64. DummyData& operator=(const DummyData&) = delete;
  65. ~DummyData() override = default;
  66. // Provides access to storage on DummyNodes.
  67. static std::unique_ptr<NodeAttachedData>* GetUniquePtrStorage(
  68. DummyNode* dummy_node) {
  69. return &dummy_node->dummy_data_;
  70. }
  71. };
  72. // Another NodeAttachedData class that can only be attached to page nodes in the
  73. // map, and to DummyNodes using node internal storage.
  74. class FooData : public NodeAttachedDataImpl<FooData> {
  75. public:
  76. struct Traits : public NodeAttachedDataInMap<PageNodeImpl>,
  77. public NodeAttachedDataInternalOnNodeType<DummyNode> {};
  78. FooData() = default;
  79. explicit FooData(const PageNodeImpl* page_node) {}
  80. explicit FooData(const DummyNode* dummy_node) {}
  81. FooData(const FooData&) = delete;
  82. FooData& operator=(const FooData&) = delete;
  83. ~FooData() override = default;
  84. // Provides access to storage on DummyNodes.
  85. static InternalNodeAttachedDataStorage<kFooDataSize>* GetInternalStorage(
  86. DummyNode* dummy_node) {
  87. return &dummy_node->foo_data_;
  88. }
  89. };
  90. // An implementation of map-stored user-data using the public interface.
  91. class BarData : public ExternalNodeAttachedDataImpl<BarData> {
  92. public:
  93. explicit BarData(const PageNode* page_node) : page_node_(page_node) {}
  94. ~BarData() override = default;
  95. raw_ptr<const PageNode> page_node_ = nullptr;
  96. };
  97. } // namespace
  98. class NodeAttachedDataTest : public GraphTestHarness {
  99. public:
  100. NodeAttachedDataTest() = default;
  101. ~NodeAttachedDataTest() override = default;
  102. static void AttachInMap(const Node* node,
  103. std::unique_ptr<NodeAttachedData> data) {
  104. return NodeAttachedDataMapHelper::AttachInMap(node, std::move(data));
  105. }
  106. // Retrieves the data associated with the provided |node| and |key|. This
  107. // returns nullptr if no data exists.
  108. static NodeAttachedData* GetFromMap(const Node* node, const void* key) {
  109. return NodeAttachedDataMapHelper::GetFromMap(node, key);
  110. }
  111. // Detaches the data associated with the provided |node| and |key|. It is
  112. // harmless to call this when no data exists.
  113. static std::unique_ptr<NodeAttachedData> DetachFromMap(const Node* node,
  114. const void* key) {
  115. return NodeAttachedDataMapHelper::DetachFromMap(node, key);
  116. }
  117. };
  118. TEST_F(NodeAttachedDataTest, UserDataKey) {
  119. std::unique_ptr<NodeAttachedData> data = std::make_unique<DummyData>();
  120. EXPECT_EQ(data->GetKey(), DummyData::UserDataKey());
  121. }
  122. TEST_F(NodeAttachedDataTest, RawAttachDetach) {
  123. MockSinglePageInSingleProcessGraph mock_graph(graph());
  124. auto* page_node = mock_graph.page.get();
  125. static constexpr NodeAttachedData* kNull = nullptr;
  126. std::unique_ptr<DummyData> data = std::make_unique<DummyData>();
  127. auto* raw_data = data.get();
  128. auto* raw_base = static_cast<NodeAttachedData*>(raw_data);
  129. // No data yet exists.
  130. EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
  131. EXPECT_EQ(kNull, GetFromMap(page_node, raw_data->GetKey()));
  132. // Attach the data and look it up again.
  133. AttachInMap(page_node, std::move(data));
  134. EXPECT_EQ(1u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
  135. EXPECT_EQ(raw_base, GetFromMap(page_node, raw_data->GetKey()));
  136. // Detach the data.
  137. std::unique_ptr<NodeAttachedData> base_data =
  138. DetachFromMap(page_node, raw_data->GetKey());
  139. EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
  140. EXPECT_EQ(raw_base, base_data.get());
  141. EXPECT_EQ(kNull, GetFromMap(page_node, raw_data->GetKey()));
  142. }
  143. TEST_F(NodeAttachedDataTest, TypedAttachDetach) {
  144. MockSinglePageInSingleProcessGraph mock_graph(graph());
  145. auto* page_node = mock_graph.page.get();
  146. static constexpr DummyData* kNull = nullptr;
  147. // Lookup non-existent data.
  148. EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
  149. EXPECT_EQ(kNull, DummyData::Get(page_node));
  150. // Create the data and look it up again.
  151. auto* data = DummyData::GetOrCreate(page_node);
  152. EXPECT_EQ(1u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
  153. EXPECT_NE(kNull, data);
  154. EXPECT_EQ(data, DummyData::Get(page_node));
  155. // Destroy the data and expect it to no longer exist.
  156. EXPECT_TRUE(DummyData::Destroy(page_node));
  157. EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
  158. EXPECT_EQ(kNull, DummyData::Get(page_node));
  159. }
  160. TEST_F(NodeAttachedDataTest, NodeDeathDestroysData) {
  161. MockSinglePageInSingleProcessGraph mock_graph(graph());
  162. auto* page_node = mock_graph.page.get();
  163. ProcessNodeImpl* proc_node = mock_graph.process.get();
  164. EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
  165. EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(
  166. page_node, DummyData::UserDataKey()));
  167. EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(
  168. proc_node, DummyData::UserDataKey()));
  169. // Add data to both the process and the page.
  170. DummyData::GetOrCreate(page_node);
  171. FooData::GetOrCreate(page_node);
  172. auto* proc_data = DummyData::GetOrCreate(proc_node);
  173. EXPECT_EQ(3u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
  174. EXPECT_EQ(2u,
  175. graph()->GetNodeAttachedDataCountForTesting(page_node, nullptr));
  176. EXPECT_EQ(1u, graph()->GetNodeAttachedDataCountForTesting(
  177. proc_node, DummyData::UserDataKey()));
  178. // Release the page node and expect the node attached data to have been
  179. // cleaned up.
  180. mock_graph.frame.reset();
  181. mock_graph.page.reset();
  182. EXPECT_EQ(1u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
  183. EXPECT_EQ(0u,
  184. graph()->GetNodeAttachedDataCountForTesting(page_node, nullptr));
  185. EXPECT_EQ(1u, graph()->GetNodeAttachedDataCountForTesting(
  186. proc_node, DummyData::UserDataKey()));
  187. // The process data should still exist.
  188. EXPECT_EQ(proc_data, DummyData::Get(proc_node));
  189. }
  190. TEST_F(NodeAttachedDataTest, NodeOwnedStorage) {
  191. DummyNode dummy_node;
  192. // The storage in the dummy node should not be initialized.
  193. EXPECT_FALSE(dummy_node.dummy_data_.get());
  194. EXPECT_FALSE(DummyData::Get(&dummy_node));
  195. // Creating a DummyData on the DummyNode should not create storage in the map.
  196. EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
  197. DummyData* dummy_data = DummyData::GetOrCreate(&dummy_node);
  198. NodeAttachedData* nad = static_cast<NodeAttachedData*>(dummy_data);
  199. EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
  200. // The storage in the dummy node should now be initialized.
  201. EXPECT_EQ(nad, dummy_node.dummy_data_.get());
  202. EXPECT_EQ(dummy_data, DummyData::Get(&dummy_node));
  203. // Destroying the data should free up the storage.
  204. DummyData::Destroy(&dummy_node);
  205. EXPECT_FALSE(dummy_node.dummy_data_.get());
  206. EXPECT_FALSE(DummyData::Get(&dummy_node));
  207. }
  208. TEST_F(NodeAttachedDataTest, NodeInternalStorage) {
  209. DummyNode dummy_node;
  210. // The storage in the dummy node should not be initialized.
  211. EXPECT_FALSE(dummy_node.foo_data_.Get());
  212. EXPECT_FALSE(FooData::Get(&dummy_node));
  213. // Creating a FooData on the DummyNode should not create storage in the map.
  214. EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
  215. FooData* foo_data = FooData::GetOrCreate(&dummy_node);
  216. NodeAttachedData* nad = static_cast<NodeAttachedData*>(foo_data);
  217. EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
  218. // The storage in the dummy node should now be initialized.
  219. EXPECT_EQ(nad, dummy_node.foo_data_.Get());
  220. EXPECT_EQ(foo_data, FooData::Get(&dummy_node));
  221. // Destroying the data should free up the storage.
  222. FooData::Destroy(&dummy_node);
  223. EXPECT_FALSE(dummy_node.foo_data_.Get());
  224. EXPECT_FALSE(FooData::Get(&dummy_node));
  225. }
  226. TEST_F(NodeAttachedDataTest, PublicNodeAttachedData) {
  227. MockSinglePageInSingleProcessGraph mock_graph(graph());
  228. PageNodeImpl* page_node_impl = mock_graph.page.get();
  229. const PageNode* page_node = page_node_impl;
  230. EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
  231. BarData* bar_data = BarData::Get(page_node);
  232. EXPECT_FALSE(bar_data);
  233. bar_data = BarData::GetOrCreate(page_node);
  234. EXPECT_TRUE(bar_data);
  235. EXPECT_EQ(1u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
  236. EXPECT_EQ(1u, graph()->GetNodeAttachedDataCountForTesting(
  237. page_node_impl, bar_data->GetKey()));
  238. EXPECT_EQ(page_node, bar_data->page_node_);
  239. EXPECT_EQ(bar_data, BarData::Get(page_node));
  240. EXPECT_TRUE(BarData::Destroy(page_node));
  241. EXPECT_EQ(0u, graph()->GetNodeAttachedDataCountForTesting(nullptr, nullptr));
  242. EXPECT_FALSE(BarData::Destroy(page_node));
  243. EXPECT_FALSE(BarData::Get(page_node));
  244. }
  245. } // namespace performance_manager