frame_node_impl_unittest.cc 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. // Copyright 2017 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/graph/frame_node_impl.h"
  5. #include "base/containers/contains.h"
  6. #include "base/memory/raw_ptr.h"
  7. #include "base/test/gmock_callback_support.h"
  8. #include "base/test/gtest_util.h"
  9. #include "components/performance_manager/graph/page_node_impl.h"
  10. #include "components/performance_manager/graph/process_node_impl.h"
  11. #include "components/performance_manager/public/render_process_host_id.h"
  12. #include "components/performance_manager/public/render_process_host_proxy.h"
  13. #include "components/performance_manager/test_support/graph_test_harness.h"
  14. #include "components/performance_manager/test_support/mock_graphs.h"
  15. #include "testing/gmock/include/gmock/gmock.h"
  16. #include "testing/gtest/include/gtest/gtest.h"
  17. namespace performance_manager {
  18. namespace {
  19. using FrameNodeImplTest = GraphTestHarness;
  20. const FrameNode* ToPublic(FrameNodeImpl* frame_node) {
  21. return frame_node;
  22. }
  23. const PageNode* ToPublic(PageNodeImpl* page_node) {
  24. return page_node;
  25. }
  26. } // namespace
  27. TEST_F(FrameNodeImplTest, SafeDowncast) {
  28. auto process = CreateNode<ProcessNodeImpl>();
  29. auto page = CreateNode<PageNodeImpl>();
  30. auto frame = CreateFrameNodeAutoId(process.get(), page.get());
  31. FrameNode* node = frame.get();
  32. EXPECT_EQ(frame.get(), FrameNodeImpl::FromNode(node));
  33. NodeBase* base = frame.get();
  34. EXPECT_EQ(base, NodeBase::FromNode(node));
  35. EXPECT_EQ(static_cast<Node*>(node), base->ToNode());
  36. }
  37. using FrameNodeImplDeathTest = FrameNodeImplTest;
  38. TEST_F(FrameNodeImplDeathTest, SafeDowncast) {
  39. auto process = CreateNode<ProcessNodeImpl>();
  40. auto page = CreateNode<PageNodeImpl>();
  41. auto frame = CreateFrameNodeAutoId(process.get(), page.get());
  42. ASSERT_DEATH_IF_SUPPORTED(PageNodeImpl::FromNodeBase(frame.get()), "");
  43. }
  44. TEST_F(FrameNodeImplTest, AddFrameHierarchyBasic) {
  45. auto process = CreateNode<ProcessNodeImpl>();
  46. auto page = CreateNode<PageNodeImpl>();
  47. auto parent_node = CreateFrameNodeAutoId(process.get(), page.get());
  48. auto child2_node =
  49. CreateFrameNodeAutoId(process.get(), page.get(), parent_node.get());
  50. auto child3_node =
  51. CreateFrameNodeAutoId(process.get(), page.get(), parent_node.get());
  52. EXPECT_EQ(nullptr, parent_node->parent_frame_node());
  53. EXPECT_EQ(2u, parent_node->child_frame_nodes().size());
  54. EXPECT_EQ(parent_node.get(), child2_node->parent_frame_node());
  55. EXPECT_EQ(parent_node.get(), child3_node->parent_frame_node());
  56. }
  57. TEST_F(FrameNodeImplTest, GetFrameNodeById) {
  58. auto process_a = CreateNode<ProcessNodeImpl>(
  59. content::PROCESS_TYPE_RENDERER,
  60. RenderProcessHostProxy::CreateForTesting(RenderProcessHostId(42)));
  61. auto process_b = CreateNode<ProcessNodeImpl>(
  62. content::PROCESS_TYPE_RENDERER,
  63. RenderProcessHostProxy::CreateForTesting(RenderProcessHostId(43)));
  64. auto page = CreateNode<PageNodeImpl>();
  65. auto frame_a1 = CreateFrameNodeAutoId(process_a.get(), page.get());
  66. auto frame_a2 = CreateFrameNodeAutoId(process_a.get(), page.get());
  67. auto frame_b1 = CreateFrameNodeAutoId(process_b.get(), page.get());
  68. EXPECT_EQ(graph()->GetFrameNodeById(process_a->GetRenderProcessId(),
  69. frame_a1->render_frame_id()),
  70. frame_a1.get());
  71. EXPECT_EQ(graph()->GetFrameNodeById(process_a->GetRenderProcessId(),
  72. frame_a2->render_frame_id()),
  73. frame_a2.get());
  74. EXPECT_EQ(graph()->GetFrameNodeById(process_b->GetRenderProcessId(),
  75. frame_b1->render_frame_id()),
  76. frame_b1.get());
  77. }
  78. TEST_F(FrameNodeImplTest, NavigationCommitted_SameDocument) {
  79. auto process = CreateNode<ProcessNodeImpl>();
  80. auto page = CreateNode<PageNodeImpl>();
  81. auto frame_node = CreateFrameNodeAutoId(process.get(), page.get());
  82. EXPECT_TRUE(frame_node->url().is_empty());
  83. const GURL url("http://www.foo.com/");
  84. frame_node->OnNavigationCommitted(url, /* same_document */ true);
  85. EXPECT_EQ(url, frame_node->url());
  86. }
  87. TEST_F(FrameNodeImplTest, NavigationCommitted_DifferentDocument) {
  88. auto process = CreateNode<ProcessNodeImpl>();
  89. auto page = CreateNode<PageNodeImpl>();
  90. auto frame_node = CreateFrameNodeAutoId(process.get(), page.get());
  91. EXPECT_TRUE(frame_node->url().is_empty());
  92. const GURL url("http://www.foo.com/");
  93. frame_node->OnNavigationCommitted(url, /* same_document */ false);
  94. EXPECT_EQ(url, frame_node->url());
  95. }
  96. TEST_F(FrameNodeImplTest, RemoveChildFrame) {
  97. auto process = CreateNode<ProcessNodeImpl>();
  98. auto page = CreateNode<PageNodeImpl>();
  99. auto parent_frame_node = CreateFrameNodeAutoId(process.get(), page.get());
  100. auto child_frame_node =
  101. CreateFrameNodeAutoId(process.get(), page.get(), parent_frame_node.get());
  102. // Ensure correct Parent-child relationships have been established.
  103. EXPECT_EQ(1u, parent_frame_node->child_frame_nodes().size());
  104. EXPECT_TRUE(!parent_frame_node->parent_frame_node());
  105. EXPECT_EQ(0u, child_frame_node->child_frame_nodes().size());
  106. EXPECT_EQ(parent_frame_node.get(), child_frame_node->parent_frame_node());
  107. child_frame_node.reset();
  108. // Parent-child relationships should no longer exist.
  109. EXPECT_EQ(0u, parent_frame_node->child_frame_nodes().size());
  110. EXPECT_TRUE(!parent_frame_node->parent_frame_node());
  111. }
  112. namespace {
  113. class LenientMockObserver : public FrameNodeImpl::Observer {
  114. public:
  115. LenientMockObserver() = default;
  116. ~LenientMockObserver() override = default;
  117. MOCK_METHOD1(OnFrameNodeAdded, void(const FrameNode*));
  118. MOCK_METHOD1(OnBeforeFrameNodeRemoved, void(const FrameNode*));
  119. MOCK_METHOD1(OnIsCurrentChanged, void(const FrameNode*));
  120. MOCK_METHOD1(OnNetworkAlmostIdleChanged, void(const FrameNode*));
  121. MOCK_METHOD1(OnFrameLifecycleStateChanged, void(const FrameNode*));
  122. MOCK_METHOD2(OnURLChanged, void(const FrameNode*, const GURL&));
  123. MOCK_METHOD1(OnIsAdFrameChanged, void(const FrameNode*));
  124. MOCK_METHOD1(OnFrameIsHoldingWebLockChanged, void(const FrameNode*));
  125. MOCK_METHOD1(OnFrameIsHoldingIndexedDBLockChanged, void(const FrameNode*));
  126. MOCK_METHOD2(OnPriorityAndReasonChanged,
  127. void(const FrameNode*, const PriorityAndReason& previous_value));
  128. MOCK_METHOD1(OnHadFormInteractionChanged, void(const FrameNode*));
  129. MOCK_METHOD1(OnIsAudibleChanged, void(const FrameNode*));
  130. MOCK_METHOD1(OnViewportIntersectionChanged, void(const FrameNode*));
  131. MOCK_METHOD2(OnFrameVisibilityChanged,
  132. void(const FrameNode*, FrameNode::Visibility));
  133. MOCK_METHOD1(OnNonPersistentNotificationCreated, void(const FrameNode*));
  134. MOCK_METHOD2(OnFirstContentfulPaint, void(const FrameNode*, base::TimeDelta));
  135. void SetCreatedFrameNode(const FrameNode* frame_node) {
  136. created_frame_node_ = frame_node;
  137. }
  138. const FrameNode* created_frame_node() { return created_frame_node_; }
  139. private:
  140. raw_ptr<const FrameNode> created_frame_node_ = nullptr;
  141. };
  142. using MockObserver = ::testing::StrictMock<LenientMockObserver>;
  143. using testing::_;
  144. using testing::Invoke;
  145. } // namespace
  146. TEST_F(FrameNodeImplTest, ObserverWorks) {
  147. auto process = CreateNode<ProcessNodeImpl>();
  148. auto page = CreateNode<PageNodeImpl>();
  149. MockObserver obs;
  150. graph()->AddFrameNodeObserver(&obs);
  151. // Create a frame node and expect a matching call to "OnFrameNodeAdded".
  152. EXPECT_CALL(obs, OnFrameNodeAdded(_))
  153. .WillOnce(Invoke(&obs, &MockObserver::SetCreatedFrameNode));
  154. auto frame_node = CreateFrameNodeAutoId(process.get(), page.get());
  155. testing::Mock::VerifyAndClear(&obs);
  156. const FrameNode* raw_frame_node = frame_node.get();
  157. EXPECT_EQ(raw_frame_node, obs.created_frame_node());
  158. // Invoke "SetIsCurrent" and expect a "OnIsCurrentChanged" callback.
  159. EXPECT_CALL(obs, OnIsCurrentChanged(raw_frame_node));
  160. frame_node->SetIsCurrent(true);
  161. testing::Mock::VerifyAndClear(&obs);
  162. // Invoke "SetNetworkAlmostIdle" and expect an "OnNetworkAlmostIdleChanged"
  163. // callback.
  164. EXPECT_CALL(obs, OnNetworkAlmostIdleChanged(raw_frame_node));
  165. frame_node->SetNetworkAlmostIdle();
  166. testing::Mock::VerifyAndClear(&obs);
  167. // Invoke "SetLifecycleState" and expect an "OnFrameLifecycleStateChanged"
  168. // callback.
  169. EXPECT_CALL(obs, OnFrameLifecycleStateChanged(raw_frame_node));
  170. frame_node->SetLifecycleState(mojom::LifecycleState::kFrozen);
  171. testing::Mock::VerifyAndClear(&obs);
  172. // Invoke "OnNonPersistentNotificationCreated" and expect an
  173. // "OnNonPersistentNotificationCreated" callback.
  174. EXPECT_CALL(obs, OnNonPersistentNotificationCreated(raw_frame_node));
  175. frame_node->OnNonPersistentNotificationCreated();
  176. testing::Mock::VerifyAndClear(&obs);
  177. // Invoke "OnNavigationCommitted" and expect an "OnURLChanged" callback.
  178. EXPECT_CALL(obs, OnURLChanged(raw_frame_node, _));
  179. frame_node->OnNavigationCommitted(GURL("https://foo.com/"), true);
  180. testing::Mock::VerifyAndClear(&obs);
  181. // Release the frame node and expect a call to "OnBeforeFrameNodeRemoved".
  182. EXPECT_CALL(obs, OnBeforeFrameNodeRemoved(raw_frame_node));
  183. frame_node.reset();
  184. testing::Mock::VerifyAndClear(&obs);
  185. graph()->RemoveFrameNodeObserver(&obs);
  186. }
  187. // This is an end-to-end test of the logic that explodes when recursive
  188. // notifications are dispatched during node creation and removal. There are
  189. // other tests of the individual pieces of logic in NodeBase and
  190. // ObservedProperty.
  191. TEST_F(FrameNodeImplDeathTest, SetPropertyDuringNodeCreation) {
  192. MockObserver obs;
  193. graph()->AddFrameNodeObserver(&obs);
  194. auto process = CreateNode<ProcessNodeImpl>();
  195. auto page = CreateNode<PageNodeImpl>();
  196. // Modifying a property during node addition should explode.
  197. bool set_property = true;
  198. EXPECT_CALL(obs, OnFrameNodeAdded(_))
  199. .WillOnce(Invoke([&](const FrameNode* frame_node) {
  200. if (set_property) {
  201. auto* impl = FrameNodeImpl::FromNode(frame_node);
  202. impl->SetIsAdFrame(true);
  203. }
  204. }));
  205. EXPECT_DCHECK_DEATH(auto frame =
  206. CreateFrameNodeAutoId(process.get(), page.get()));
  207. // Now create the node but don't modify a property so that the mock
  208. // expectation is satisfied.
  209. set_property = false;
  210. auto frame = CreateFrameNodeAutoId(process.get(), page.get());
  211. // Modifying a property during node removal should explode.
  212. set_property = true;
  213. EXPECT_CALL(obs, OnBeforeFrameNodeRemoved(_))
  214. .WillOnce(Invoke([&](const FrameNode* frame_node) {
  215. if (set_property) {
  216. auto* impl = FrameNodeImpl::FromNode(frame_node);
  217. impl->SetIsAdFrame(true);
  218. }
  219. }));
  220. EXPECT_DCHECK_DEATH(frame.reset());
  221. // Now remove the node but don't modify a property so that the mock
  222. // expectation is satisfied.
  223. set_property = false;
  224. frame.reset();
  225. graph()->RemoveFrameNodeObserver(&obs);
  226. }
  227. TEST_F(FrameNodeImplTest, IsAdFrame) {
  228. auto process = CreateNode<ProcessNodeImpl>();
  229. auto page = CreateNode<PageNodeImpl>();
  230. auto frame_node = CreateFrameNodeAutoId(process.get(), page.get());
  231. MockObserver obs;
  232. graph()->AddFrameNodeObserver(&obs);
  233. // Observer will be notified once when IsAdFrame goes from false to true, and
  234. // again when it goes from true to false.
  235. EXPECT_CALL(obs, OnIsAdFrameChanged(frame_node.get())).Times(2);
  236. EXPECT_FALSE(frame_node->is_ad_frame());
  237. frame_node->SetIsAdFrame(true);
  238. EXPECT_TRUE(frame_node->is_ad_frame());
  239. frame_node->SetIsAdFrame(true);
  240. EXPECT_TRUE(frame_node->is_ad_frame());
  241. frame_node->SetIsAdFrame(false);
  242. EXPECT_FALSE(frame_node->is_ad_frame());
  243. graph()->RemoveFrameNodeObserver(&obs);
  244. }
  245. TEST_F(FrameNodeImplTest, IsHoldingWebLock) {
  246. auto process = CreateNode<ProcessNodeImpl>();
  247. auto page = CreateNode<PageNodeImpl>();
  248. auto frame_node = CreateFrameNodeAutoId(process.get(), page.get());
  249. MockObserver obs;
  250. graph()->AddFrameNodeObserver(&obs);
  251. EXPECT_FALSE(frame_node->is_holding_weblock());
  252. EXPECT_CALL(obs, OnFrameIsHoldingWebLockChanged(frame_node.get()));
  253. frame_node->SetIsHoldingWebLock(true);
  254. EXPECT_TRUE(frame_node->is_holding_weblock());
  255. EXPECT_CALL(obs, OnFrameIsHoldingWebLockChanged(frame_node.get()));
  256. frame_node->SetIsHoldingWebLock(false);
  257. EXPECT_FALSE(frame_node->is_holding_weblock());
  258. graph()->RemoveFrameNodeObserver(&obs);
  259. }
  260. TEST_F(FrameNodeImplTest, IsHoldingIndexedDBLock) {
  261. auto process = CreateNode<ProcessNodeImpl>();
  262. auto page = CreateNode<PageNodeImpl>();
  263. auto frame_node = CreateFrameNodeAutoId(process.get(), page.get());
  264. MockObserver obs;
  265. graph()->AddFrameNodeObserver(&obs);
  266. EXPECT_CALL(obs, OnFrameIsHoldingIndexedDBLockChanged(frame_node.get()));
  267. frame_node->SetIsHoldingIndexedDBLock(true);
  268. EXPECT_TRUE(frame_node->is_holding_indexeddb_lock());
  269. EXPECT_CALL(obs, OnFrameIsHoldingIndexedDBLockChanged(frame_node.get()));
  270. frame_node->SetIsHoldingIndexedDBLock(false);
  271. EXPECT_FALSE(frame_node->is_holding_indexeddb_lock());
  272. graph()->RemoveFrameNodeObserver(&obs);
  273. }
  274. TEST_F(FrameNodeImplTest, Priority) {
  275. using PriorityAndReason = execution_context_priority::PriorityAndReason;
  276. auto process = CreateNode<ProcessNodeImpl>();
  277. auto page = CreateNode<PageNodeImpl>();
  278. auto frame_node = CreateFrameNodeAutoId(process.get(), page.get());
  279. MockObserver obs;
  280. graph()->AddFrameNodeObserver(&obs);
  281. // By default the priority should be "lowest".
  282. EXPECT_EQ(base::TaskPriority::LOWEST,
  283. frame_node->priority_and_reason().priority());
  284. // Changed the reason only.
  285. static const char kDummyReason[] = "this is a reason!";
  286. EXPECT_CALL(obs,
  287. OnPriorityAndReasonChanged(
  288. frame_node.get(),
  289. PriorityAndReason(base::TaskPriority::LOWEST,
  290. FrameNodeImpl::kDefaultPriorityReason)));
  291. frame_node->SetPriorityAndReason(
  292. PriorityAndReason(base::TaskPriority::LOWEST, kDummyReason));
  293. EXPECT_EQ(PriorityAndReason(base::TaskPriority::LOWEST, kDummyReason),
  294. frame_node->priority_and_reason());
  295. testing::Mock::VerifyAndClear(&obs);
  296. // Change the priority only.
  297. EXPECT_CALL(obs,
  298. OnPriorityAndReasonChanged(
  299. frame_node.get(),
  300. PriorityAndReason(base::TaskPriority::LOWEST, kDummyReason)));
  301. frame_node->SetPriorityAndReason(
  302. PriorityAndReason(base::TaskPriority::HIGHEST, kDummyReason));
  303. EXPECT_EQ(PriorityAndReason(base::TaskPriority::HIGHEST, kDummyReason),
  304. frame_node->priority_and_reason());
  305. testing::Mock::VerifyAndClear(&obs);
  306. // Change neither.
  307. frame_node->SetPriorityAndReason(
  308. PriorityAndReason(base::TaskPriority::HIGHEST, kDummyReason));
  309. EXPECT_EQ(PriorityAndReason(base::TaskPriority::HIGHEST, kDummyReason),
  310. frame_node->priority_and_reason());
  311. testing::Mock::VerifyAndClear(&obs);
  312. // Change both the priority and the reason.
  313. EXPECT_CALL(
  314. obs, OnPriorityAndReasonChanged(
  315. frame_node.get(),
  316. PriorityAndReason(base::TaskPriority::HIGHEST, kDummyReason)));
  317. frame_node->SetPriorityAndReason(
  318. PriorityAndReason(base::TaskPriority::LOWEST, nullptr));
  319. EXPECT_EQ(PriorityAndReason(base::TaskPriority::LOWEST, nullptr),
  320. frame_node->priority_and_reason());
  321. testing::Mock::VerifyAndClear(&obs);
  322. graph()->RemoveFrameNodeObserver(&obs);
  323. }
  324. TEST_F(FrameNodeImplTest, FormInteractions) {
  325. auto process = CreateNode<ProcessNodeImpl>();
  326. auto page = CreateNode<PageNodeImpl>();
  327. auto frame_node = CreateFrameNodeAutoId(process.get(), page.get());
  328. MockObserver obs;
  329. graph()->AddFrameNodeObserver(&obs);
  330. EXPECT_CALL(obs, OnHadFormInteractionChanged(frame_node.get()));
  331. frame_node->SetHadFormInteraction();
  332. EXPECT_TRUE(frame_node->had_form_interaction());
  333. graph()->RemoveFrameNodeObserver(&obs);
  334. }
  335. TEST_F(FrameNodeImplTest, IsAudible) {
  336. auto process = CreateNode<ProcessNodeImpl>();
  337. auto page = CreateNode<PageNodeImpl>();
  338. auto frame_node = CreateFrameNodeAutoId(process.get(), page.get());
  339. EXPECT_FALSE(frame_node->is_audible());
  340. MockObserver obs;
  341. graph()->AddFrameNodeObserver(&obs);
  342. EXPECT_CALL(obs, OnIsAudibleChanged(frame_node.get()));
  343. frame_node->SetIsAudible(true);
  344. EXPECT_TRUE(frame_node->is_audible());
  345. graph()->RemoveFrameNodeObserver(&obs);
  346. }
  347. TEST_F(FrameNodeImplTest, ViewportIntersection) {
  348. auto process = CreateNode<ProcessNodeImpl>();
  349. auto page = CreateNode<PageNodeImpl>();
  350. // A child frame node is used because the main frame does not have a viewport
  351. // intersection.
  352. auto main_frame_node = CreateFrameNodeAutoId(process.get(), page.get());
  353. auto child_frame_node =
  354. CreateFrameNodeAutoId(process.get(), page.get(), main_frame_node.get());
  355. MockObserver obs;
  356. graph()->AddFrameNodeObserver(&obs);
  357. EXPECT_CALL(obs, OnViewportIntersectionChanged(child_frame_node.get()));
  358. gfx::Rect kViewportIntersection(25, 25, 100, 100);
  359. child_frame_node->SetViewportIntersection(kViewportIntersection);
  360. EXPECT_EQ(child_frame_node->viewport_intersection(), kViewportIntersection);
  361. graph()->RemoveFrameNodeObserver(&obs);
  362. }
  363. TEST_F(FrameNodeImplTest, Visibility) {
  364. auto process = CreateNode<ProcessNodeImpl>();
  365. auto page = CreateNode<PageNodeImpl>();
  366. auto frame_node = CreateFrameNodeAutoId(process.get(), page.get());
  367. MockObserver obs;
  368. graph()->AddFrameNodeObserver(&obs);
  369. EXPECT_CALL(obs, OnFrameVisibilityChanged(
  370. frame_node.get(), FrameNode::Visibility::kNotVisible));
  371. frame_node->SetVisibility(FrameNode::Visibility::kVisible);
  372. EXPECT_EQ(frame_node->visibility(), FrameNode::Visibility::kVisible);
  373. graph()->RemoveFrameNodeObserver(&obs);
  374. }
  375. TEST_F(FrameNodeImplTest, FirstContentfulPaint) {
  376. auto process = CreateNode<ProcessNodeImpl>();
  377. auto page = CreateNode<PageNodeImpl>();
  378. auto frame_node = CreateFrameNodeAutoId(process.get(), page.get());
  379. MockObserver obs;
  380. graph()->AddFrameNodeObserver(&obs);
  381. base::TimeDelta fcp = base::Milliseconds(1364);
  382. EXPECT_CALL(obs, OnFirstContentfulPaint(frame_node.get(), fcp));
  383. frame_node->OnFirstContentfulPaint(fcp);
  384. graph()->RemoveFrameNodeObserver(&obs);
  385. }
  386. TEST_F(FrameNodeImplTest, PublicInterface) {
  387. auto process = CreateNode<ProcessNodeImpl>();
  388. auto page = CreateNode<PageNodeImpl>();
  389. auto frame_node = CreateFrameNodeAutoId(process.get(), page.get());
  390. auto child_frame_node =
  391. CreateFrameNodeAutoId(process.get(), page.get(), frame_node.get());
  392. const FrameNode* public_frame_node = frame_node.get();
  393. const FrameNode* public_child_frame_node = child_frame_node.get();
  394. // Simply test that the public interface impls yield the same result as their
  395. // private counterpart.
  396. EXPECT_EQ(static_cast<const FrameNode*>(frame_node->parent_frame_node()),
  397. public_frame_node->GetParentFrameNode());
  398. EXPECT_EQ(static_cast<const PageNode*>(frame_node->page_node()),
  399. public_frame_node->GetPageNode());
  400. EXPECT_EQ(static_cast<const ProcessNode*>(frame_node->process_node()),
  401. public_frame_node->GetProcessNode());
  402. EXPECT_EQ(frame_node->frame_token(), public_frame_node->GetFrameToken());
  403. EXPECT_EQ(frame_node->browsing_instance_id(),
  404. public_frame_node->GetBrowsingInstanceId());
  405. EXPECT_EQ(frame_node->site_instance_id(),
  406. public_frame_node->GetSiteInstanceId());
  407. auto child_frame_nodes = public_frame_node->GetChildFrameNodes();
  408. for (auto* child : frame_node->child_frame_nodes())
  409. EXPECT_TRUE(base::Contains(child_frame_nodes, child));
  410. EXPECT_EQ(child_frame_nodes.size(), frame_node->child_frame_nodes().size());
  411. EXPECT_EQ(frame_node->lifecycle_state(),
  412. public_frame_node->GetLifecycleState());
  413. EXPECT_EQ(frame_node->has_nonempty_beforeunload(),
  414. public_frame_node->HasNonemptyBeforeUnload());
  415. EXPECT_EQ(frame_node->url(), public_frame_node->GetURL());
  416. EXPECT_EQ(frame_node->is_current(), public_frame_node->IsCurrent());
  417. EXPECT_EQ(frame_node->network_almost_idle(),
  418. public_frame_node->GetNetworkAlmostIdle());
  419. EXPECT_EQ(frame_node->is_ad_frame(), public_frame_node->IsAdFrame());
  420. EXPECT_EQ(frame_node->is_holding_weblock(),
  421. public_frame_node->IsHoldingWebLock());
  422. EXPECT_EQ(frame_node->is_holding_indexeddb_lock(),
  423. public_frame_node->IsHoldingIndexedDBLock());
  424. EXPECT_EQ(frame_node->had_form_interaction(),
  425. public_frame_node->HadFormInteraction());
  426. // Use the child frame node to test the viewport intersection because the
  427. // viewport intersection of the main frame is not tracked.
  428. EXPECT_EQ(child_frame_node->viewport_intersection(),
  429. public_child_frame_node->GetViewportIntersection());
  430. EXPECT_EQ(frame_node->visibility(), public_frame_node->GetVisibility());
  431. }
  432. TEST_F(FrameNodeImplTest, VisitChildFrameNodes) {
  433. auto process = CreateNode<ProcessNodeImpl>();
  434. auto page = CreateNode<PageNodeImpl>();
  435. auto frame1 = CreateFrameNodeAutoId(process.get(), page.get());
  436. auto frame2 = CreateFrameNodeAutoId(process.get(), page.get(), frame1.get());
  437. auto frame3 = CreateFrameNodeAutoId(process.get(), page.get(), frame1.get());
  438. std::set<const FrameNode*> visited;
  439. EXPECT_TRUE(
  440. ToPublic(frame1.get())
  441. ->VisitChildFrameNodes(base::BindRepeating(
  442. [](std::set<const FrameNode*>* visited, const FrameNode* frame) {
  443. EXPECT_TRUE(visited->insert(frame).second);
  444. return true;
  445. },
  446. base::Unretained(&visited))));
  447. EXPECT_THAT(visited, testing::UnorderedElementsAre(ToPublic(frame2.get()),
  448. ToPublic(frame3.get())));
  449. // Do an aborted visit.
  450. visited.clear();
  451. EXPECT_FALSE(
  452. ToPublic(frame1.get())
  453. ->VisitChildFrameNodes(base::BindRepeating(
  454. [](std::set<const FrameNode*>* visited, const FrameNode* frame) {
  455. EXPECT_TRUE(visited->insert(frame).second);
  456. return false;
  457. },
  458. base::Unretained(&visited))));
  459. EXPECT_EQ(1u, visited.size());
  460. }
  461. namespace {
  462. class LenientMockPageObserver : public PageNode::ObserverDefaultImpl {
  463. public:
  464. LenientMockPageObserver() = default;
  465. ~LenientMockPageObserver() override = default;
  466. MOCK_METHOD1(OnBeforePageNodeRemoved, void(const PageNode* page_node));
  467. // Note that embedder functionality is actually tested in the
  468. // performance_manager_browsertest.
  469. MOCK_METHOD2(OnOpenerFrameNodeChanged,
  470. void(const PageNode*, const FrameNode*));
  471. MOCK_METHOD3(OnEmbedderFrameNodeChanged,
  472. void(const PageNode*, const FrameNode*, EmbeddingType));
  473. };
  474. using MockPageObserver = ::testing::StrictMock<LenientMockPageObserver>;
  475. } // namespace
  476. TEST_F(FrameNodeImplTest, PageRelationships) {
  477. using EmbeddingType = PageNode::EmbeddingType;
  478. auto process = CreateNode<ProcessNodeImpl>();
  479. auto pageA = CreateNode<PageNodeImpl>();
  480. auto frameA1 = CreateFrameNodeAutoId(process.get(), pageA.get());
  481. auto frameA2 =
  482. CreateFrameNodeAutoId(process.get(), pageA.get(), frameA1.get());
  483. auto pageB = CreateNode<PageNodeImpl>();
  484. auto frameB1 = CreateFrameNodeAutoId(process.get(), pageB.get());
  485. auto pageC = CreateNode<PageNodeImpl>();
  486. auto frameC1 = CreateFrameNodeAutoId(process.get(), pageC.get());
  487. // Use these to test the public APIs as well.
  488. const FrameNode* pframeA1 = static_cast<const FrameNode*>(frameA1.get());
  489. const PageNode* ppageB = static_cast<const PageNode*>(pageB.get());
  490. MockPageObserver obs;
  491. graph()->AddPageNodeObserver(&obs);
  492. // You can always call the pre-delete embedder clearing helper, even if you
  493. // have no such relationships.
  494. frameB1->SeverPageRelationshipsAndMaybeReparentForTesting();
  495. // You can't clear an embedder if you don't already have one.
  496. EXPECT_DCHECK_DEATH(pageB->ClearEmbedderFrameNodeAndEmbeddingType());
  497. // You can't be an embedder for your own frame tree.
  498. EXPECT_DCHECK_DEATH(pageA->SetEmbedderFrameNodeAndEmbeddingType(
  499. frameA1.get(), EmbeddingType::kPortal));
  500. // You can't set a null embedder or an invalid embedded type.
  501. EXPECT_DCHECK_DEATH(pageB->SetEmbedderFrameNodeAndEmbeddingType(
  502. nullptr, EmbeddingType::kInvalid));
  503. EXPECT_DCHECK_DEATH(pageB->SetEmbedderFrameNodeAndEmbeddingType(
  504. frameA1.get(), EmbeddingType::kInvalid));
  505. EXPECT_EQ(nullptr, pageB->embedder_frame_node());
  506. EXPECT_EQ(nullptr, ppageB->GetEmbedderFrameNode());
  507. EXPECT_EQ(EmbeddingType::kInvalid, pageB->embedding_type());
  508. EXPECT_EQ(EmbeddingType::kInvalid, ppageB->GetEmbeddingType());
  509. EXPECT_TRUE(frameA1->embedded_page_nodes().empty());
  510. EXPECT_TRUE(pframeA1->GetEmbeddedPageNodes().empty());
  511. // Set an embedder relationship.
  512. EXPECT_CALL(obs, OnEmbedderFrameNodeChanged(pageB.get(), nullptr,
  513. EmbeddingType::kInvalid));
  514. pageB->SetEmbedderFrameNodeAndEmbeddingType(frameA1.get(),
  515. EmbeddingType::kGuestView);
  516. EXPECT_EQ(frameA1.get(), pageB->embedder_frame_node());
  517. EXPECT_EQ(frameA1.get(), ppageB->GetEmbedderFrameNode());
  518. EXPECT_EQ(EmbeddingType::kGuestView, pageB->embedding_type());
  519. EXPECT_EQ(EmbeddingType::kGuestView, ppageB->GetEmbeddingType());
  520. EXPECT_EQ(1u, frameA1->embedded_page_nodes().size());
  521. EXPECT_EQ(1u, pframeA1->GetEmbeddedPageNodes().size());
  522. EXPECT_EQ(1u, frameA1->embedded_page_nodes().count(pageB.get()));
  523. EXPECT_EQ(1u, pframeA1->GetEmbeddedPageNodes().count(pageB.get()));
  524. testing::Mock::VerifyAndClear(&obs);
  525. // Set an opener relationship.
  526. EXPECT_CALL(obs, OnOpenerFrameNodeChanged(pageC.get(), nullptr));
  527. pageC->SetOpenerFrameNode(frameA1.get());
  528. EXPECT_EQ(frameA1.get(), pageC->opener_frame_node());
  529. EXPECT_EQ(1u, frameA1->embedded_page_nodes().size());
  530. EXPECT_EQ(1u, frameA1->opened_page_nodes().size());
  531. EXPECT_EQ(1u, frameA1->embedded_page_nodes().count(pageB.get()));
  532. testing::Mock::VerifyAndClear(&obs);
  533. // Do an embedded page traversal.
  534. std::set<const PageNode*> visited;
  535. EXPECT_TRUE(
  536. ToPublic(frameA1.get())
  537. ->VisitEmbeddedPageNodes(base::BindRepeating(
  538. [](std::set<const PageNode*>* visited, const PageNode* page) {
  539. EXPECT_TRUE(visited->insert(page).second);
  540. return true;
  541. },
  542. base::Unretained(&visited))));
  543. EXPECT_THAT(visited, testing::UnorderedElementsAre(ToPublic(pageB.get())));
  544. // Do an opened page traversal.
  545. visited.clear();
  546. EXPECT_TRUE(
  547. ToPublic(frameA1.get())
  548. ->VisitOpenedPageNodes(base::BindRepeating(
  549. [](std::set<const PageNode*>* visited, const PageNode* page) {
  550. EXPECT_TRUE(visited->insert(page).second);
  551. return true;
  552. },
  553. base::Unretained(&visited))));
  554. EXPECT_THAT(visited, testing::UnorderedElementsAre(ToPublic(pageC.get())));
  555. // Do an aborted visit.
  556. visited.clear();
  557. EXPECT_FALSE(
  558. ToPublic(frameA1.get())
  559. ->VisitEmbeddedPageNodes(base::BindRepeating(
  560. [](std::set<const PageNode*>* visited, const PageNode* page) {
  561. EXPECT_TRUE(visited->insert(page).second);
  562. return false;
  563. },
  564. base::Unretained(&visited))));
  565. EXPECT_EQ(1u, visited.size());
  566. // Manually clear the embedder relationship (initiated from the page).
  567. EXPECT_CALL(obs, OnEmbedderFrameNodeChanged(pageB.get(), frameA1.get(),
  568. EmbeddingType::kGuestView));
  569. pageB->ClearEmbedderFrameNodeAndEmbeddingType();
  570. EXPECT_EQ(nullptr, pageB->embedder_frame_node());
  571. EXPECT_EQ(EmbeddingType::kInvalid, pageB->embedding_type());
  572. EXPECT_EQ(frameA1.get(), pageC->opener_frame_node());
  573. EXPECT_TRUE(frameA1->embedded_page_nodes().empty());
  574. testing::Mock::VerifyAndClear(&obs);
  575. // Clear the opener relationship.
  576. EXPECT_CALL(obs, OnOpenerFrameNodeChanged(pageC.get(), frameA1.get()));
  577. frameA1->SeverPageRelationshipsAndMaybeReparentForTesting();
  578. EXPECT_EQ(nullptr, pageC->embedder_frame_node());
  579. EXPECT_EQ(EmbeddingType::kInvalid, pageC->embedding_type());
  580. EXPECT_TRUE(frameA1->opened_page_nodes().empty());
  581. EXPECT_TRUE(frameA1->embedded_page_nodes().empty());
  582. testing::Mock::VerifyAndClear(&obs);
  583. // Set a popup relationship on node A2.
  584. EXPECT_CALL(obs, OnOpenerFrameNodeChanged(pageB.get(), nullptr));
  585. pageB->SetOpenerFrameNode(frameA2.get());
  586. EXPECT_EQ(frameA2.get(), pageB->opener_frame_node());
  587. EXPECT_TRUE(frameA1->opened_page_nodes().empty());
  588. EXPECT_TRUE(frameA1->embedded_page_nodes().empty());
  589. EXPECT_EQ(1u, frameA2->opened_page_nodes().size());
  590. EXPECT_TRUE(frameA2->embedded_page_nodes().empty());
  591. EXPECT_EQ(1u, frameA2->opened_page_nodes().count(pageB.get()));
  592. testing::Mock::VerifyAndClear(&obs);
  593. // Clear it with the helper, and expect it to be reparented to node A1.
  594. EXPECT_CALL(obs, OnOpenerFrameNodeChanged(pageB.get(), frameA2.get()));
  595. frameA2->SeverPageRelationshipsAndMaybeReparentForTesting();
  596. EXPECT_EQ(frameA1.get(), pageB->opener_frame_node());
  597. EXPECT_EQ(1u, frameA1->opened_page_nodes().size());
  598. EXPECT_EQ(1u, frameA1->opened_page_nodes().count(pageB.get()));
  599. EXPECT_TRUE(frameA2->opened_page_nodes().empty());
  600. testing::Mock::VerifyAndClear(&obs);
  601. // Clear it again with the helper. This time reparenting can't happen, as it
  602. // was already parented to the root.
  603. EXPECT_CALL(obs, OnOpenerFrameNodeChanged(pageB.get(), frameA1.get()));
  604. frameA1->SeverPageRelationshipsAndMaybeReparentForTesting();
  605. EXPECT_EQ(nullptr, pageB->opener_frame_node());
  606. EXPECT_TRUE(frameA1->opened_page_nodes().empty());
  607. EXPECT_TRUE(frameA2->opened_page_nodes().empty());
  608. testing::Mock::VerifyAndClear(&obs);
  609. // verify that the embedder relationship is torn down before any node removal
  610. // notification arrives.
  611. EXPECT_CALL(obs, OnOpenerFrameNodeChanged(pageB.get(), nullptr));
  612. pageB->SetOpenerFrameNode(frameA2.get());
  613. EXPECT_EQ(frameA2.get(), pageB->opener_frame_node());
  614. EXPECT_TRUE(frameA1->opened_page_nodes().empty());
  615. EXPECT_EQ(1u, frameA2->opened_page_nodes().size());
  616. EXPECT_EQ(1u, frameA2->opened_page_nodes().count(pageB.get()));
  617. testing::Mock::VerifyAndClear(&obs);
  618. {
  619. ::testing::InSequence seq;
  620. // These must occur in sequence.
  621. EXPECT_CALL(obs, OnOpenerFrameNodeChanged(pageB.get(), frameA2.get()));
  622. EXPECT_CALL(obs, OnBeforePageNodeRemoved(pageB.get()));
  623. }
  624. frameB1.reset();
  625. pageB.reset();
  626. testing::Mock::VerifyAndClear(&obs);
  627. graph()->RemovePageNodeObserver(&obs);
  628. }
  629. } // namespace performance_manager