page_load_tracker_decorator_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  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/decorators/page_load_tracker_decorator.h"
  5. #include <memory>
  6. #include <type_traits>
  7. #include <utility>
  8. #include "base/memory/ptr_util.h"
  9. #include "base/memory/raw_ptr.h"
  10. #include "base/time/time.h"
  11. #include "components/performance_manager/graph/frame_node_impl.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/test_support/graph_test_harness.h"
  15. #include "components/performance_manager/test_support/mock_graphs.h"
  16. #include "testing/gmock/include/gmock/gmock.h"
  17. #include "testing/gtest/include/gtest/gtest.h"
  18. namespace performance_manager {
  19. // Aliasing these here makes this unittest much more legible.
  20. using Data = PageLoadTrackerDecorator::Data;
  21. using LIS = Data::LoadIdleState;
  22. using LS = PageNode::LoadingState;
  23. class PageLoadTrackerDecoratorTest : public GraphTestHarness {
  24. public:
  25. PageLoadTrackerDecoratorTest(const PageLoadTrackerDecoratorTest&) = delete;
  26. PageLoadTrackerDecoratorTest& operator=(const PageLoadTrackerDecoratorTest&) =
  27. delete;
  28. protected:
  29. using Super = GraphTestHarness;
  30. PageLoadTrackerDecoratorTest() = default;
  31. ~PageLoadTrackerDecoratorTest() override = default;
  32. void SetUp() override {
  33. Super::SetUp();
  34. pltd_ = new PageLoadTrackerDecorator();
  35. graph()->PassToGraph(base::WrapUnique(pltd_.get()));
  36. }
  37. void TestPageAlmostIdleTransitions(bool timeout_waiting_for_response,
  38. bool timeout_waiting_for_idle);
  39. bool IsIdling(const PageNodeImpl* page_node) const {
  40. return PageLoadTrackerDecorator::IsIdling(page_node);
  41. }
  42. static constexpr base::TimeDelta GetWaitingForIdleTimeout() {
  43. return PageLoadTrackerDecorator::kWaitingForIdleTimeout;
  44. }
  45. raw_ptr<PageLoadTrackerDecorator> pltd_ = nullptr;
  46. };
  47. void PageLoadTrackerDecoratorTest::TestPageAlmostIdleTransitions(
  48. bool timeout_waiting_for_response,
  49. bool timeout_waiting_for_idle) {
  50. static const base::TimeDelta kLoadedAndIdlingTimeout =
  51. PageLoadTrackerDecorator::kLoadedAndIdlingTimeout;
  52. static const base::TimeDelta kWaitingForIdleTimeout =
  53. PageLoadTrackerDecorator::kWaitingForIdleTimeout;
  54. MockSinglePageInSingleProcessGraph mock_graph(graph());
  55. auto* frame_node = mock_graph.frame.get();
  56. auto* page_node = mock_graph.page.get();
  57. auto* proc_node = mock_graph.process.get();
  58. // Initially the page should be in a loading not started state.
  59. EXPECT_FALSE(Data::GetForTesting(page_node));
  60. EXPECT_EQ(LS::kLoadingNotStarted, page_node->loading_state());
  61. // The state should transition to loading when DidStartLoading() is called to
  62. // indicate that loading starts.
  63. PageLoadTrackerDecorator::DidStartLoading(page_node);
  64. auto* page_data = Data::GetForTesting(page_node);
  65. ASSERT_TRUE(page_data);
  66. EXPECT_EQ(LIS::kWaitingForNavigation, page_data->load_idle_state());
  67. EXPECT_EQ(LS::kLoading, page_node->loading_state());
  68. EXPECT_TRUE(page_data->timer_.IsRunning());
  69. EXPECT_EQ(page_data->timer_.GetCurrentDelay(),
  70. PageLoadTrackerDecorator::kWaitingForNavigationTimeout);
  71. if (timeout_waiting_for_response) {
  72. // Let the timeout run down. The page should transition to loading timed
  73. // out.
  74. task_env().FastForwardBy(
  75. PageLoadTrackerDecorator::kWaitingForNavigationTimeout);
  76. EXPECT_EQ(LIS::kWaitingForNavigationTimedOut, page_data->load_idle_state());
  77. EXPECT_EQ(LS::kLoadingTimedOut, page_node->loading_state());
  78. EXPECT_FALSE(page_data->timer_.IsRunning());
  79. }
  80. // Indicate that a page change was committed. The state should transition to
  81. // kLoading (no matter whether the kWaitingForNavigationTimeout expired since
  82. // load started).
  83. PageLoadTrackerDecorator::PrimaryPageChanged(page_node);
  84. EXPECT_EQ(LIS::kLoading, page_data->load_idle_state());
  85. EXPECT_EQ(LS::kLoading, page_node->loading_state());
  86. EXPECT_FALSE(page_data->timer_.IsRunning());
  87. // Mark the page as idling. It should transition from
  88. // kLoading directly to kLoadedAndIdling after this.
  89. frame_node->SetNetworkAlmostIdle();
  90. proc_node->SetMainThreadTaskLoadIsLow(true);
  91. PageLoadTrackerDecorator::DidStopLoading(page_node);
  92. EXPECT_EQ(LIS::kLoadedAndIdling, page_data->load_idle_state());
  93. EXPECT_EQ(LS::kLoadedBusy, page_node->loading_state());
  94. EXPECT_TRUE(page_data->timer_.IsRunning());
  95. // Go back to not idling. We should transition back to kLoadedNotIdling, and
  96. // a timer should still be running.
  97. frame_node->OnNavigationCommitted(GURL(), false);
  98. EXPECT_FALSE(frame_node->network_almost_idle());
  99. EXPECT_EQ(LIS::kLoadedNotIdling, page_data->load_idle_state());
  100. EXPECT_TRUE(page_data->timer_.IsRunning());
  101. if (timeout_waiting_for_idle) {
  102. // Let the timeout run down. The final state transition should occur.
  103. task_env().FastForwardBy(kWaitingForIdleTimeout);
  104. EXPECT_FALSE(Data::GetForTesting(page_node));
  105. EXPECT_EQ(LS::kLoadedIdle, page_node->loading_state());
  106. } else {
  107. // Go back to idling.
  108. frame_node->SetNetworkAlmostIdle();
  109. EXPECT_TRUE(frame_node->network_almost_idle());
  110. EXPECT_EQ(LIS::kLoadedAndIdling, page_data->load_idle_state());
  111. EXPECT_EQ(LS::kLoadedBusy, page_node->loading_state());
  112. EXPECT_TRUE(page_data->timer_.IsRunning());
  113. // Let the idle timer evaluate. The final state transition should occur.
  114. task_env().FastForwardBy(kLoadedAndIdlingTimeout);
  115. EXPECT_FALSE(Data::GetForTesting(page_node));
  116. EXPECT_EQ(LS::kLoadedIdle, page_node->loading_state());
  117. }
  118. // Firing other signals should not change the state at all.
  119. proc_node->SetMainThreadTaskLoadIsLow(false);
  120. EXPECT_FALSE(Data::GetForTesting(page_node));
  121. EXPECT_EQ(LS::kLoadedIdle, page_node->loading_state());
  122. frame_node->OnNavigationCommitted(GURL(), false);
  123. EXPECT_FALSE(frame_node->network_almost_idle());
  124. EXPECT_FALSE(Data::GetForTesting(page_node));
  125. EXPECT_EQ(LS::kLoadedIdle, page_node->loading_state());
  126. }
  127. TEST_F(PageLoadTrackerDecoratorTest, TestTransitionsNoTimeout) {
  128. TestPageAlmostIdleTransitions(false, false);
  129. }
  130. TEST_F(PageLoadTrackerDecoratorTest, TestTransitionsTimeoutWaitingForResponse) {
  131. TestPageAlmostIdleTransitions(true, false);
  132. }
  133. TEST_F(PageLoadTrackerDecoratorTest, TestTransitionsTimeoutWaitingForIdle) {
  134. TestPageAlmostIdleTransitions(false, true);
  135. }
  136. TEST_F(PageLoadTrackerDecoratorTest,
  137. TestTransitionsTimeoutWaitingForResponseAndWaitingForIdle) {
  138. TestPageAlmostIdleTransitions(true, true);
  139. }
  140. TEST_F(PageLoadTrackerDecoratorTest, TestTransitionsNotIdlingOnDidStopLoading) {
  141. MockSinglePageInSingleProcessGraph mock_graph(graph());
  142. auto* frame_node = mock_graph.frame.get();
  143. auto* page_node = mock_graph.page.get();
  144. auto* proc_node = mock_graph.process.get();
  145. // Initially the page should be in a loading not started state.
  146. EXPECT_FALSE(Data::GetForTesting(page_node));
  147. EXPECT_EQ(LS::kLoadingNotStarted, page_node->loading_state());
  148. // The state should transition to loading when PrimaryPageChanged() is called
  149. // to indicate that loading starts.
  150. PageLoadTrackerDecorator::DidStartLoading(page_node);
  151. PageLoadTrackerDecorator::PrimaryPageChanged(page_node);
  152. auto* page_data = Data::GetForTesting(page_node);
  153. ASSERT_TRUE(page_data);
  154. EXPECT_EQ(LIS::kLoading, page_data->load_idle_state());
  155. EXPECT_EQ(LS::kLoading, page_node->loading_state());
  156. EXPECT_FALSE(page_data->timer_.IsRunning());
  157. // Mark the page as not idling.
  158. frame_node->OnNavigationCommitted(GURL(), false);
  159. proc_node->SetMainThreadTaskLoadIsLow(false);
  160. EXPECT_FALSE(IsIdling(page_node));
  161. // DidStopLoading() should cause a transition to kLoadedNotIdling.
  162. PageLoadTrackerDecorator::DidStopLoading(page_node);
  163. EXPECT_EQ(LIS::kLoadedNotIdling, page_data->load_idle_state());
  164. EXPECT_EQ(LS::kLoadedBusy, page_node->loading_state());
  165. EXPECT_TRUE(page_data->timer_.IsRunning());
  166. }
  167. TEST_F(PageLoadTrackerDecoratorTest, TestStartLoadingAgainBeforeIdle) {
  168. MockSinglePageInSingleProcessGraph mock_graph(graph());
  169. auto* frame_node = mock_graph.frame.get();
  170. auto* page_node = mock_graph.page.get();
  171. auto* proc_node = mock_graph.process.get();
  172. // Initially the page should be in a loading not started state.
  173. EXPECT_FALSE(Data::GetForTesting(page_node));
  174. EXPECT_EQ(LS::kLoadingNotStarted, page_node->loading_state());
  175. // The state should transition to loading when PrimaryPageChanged() is called
  176. // to indicate that loading starts.
  177. PageLoadTrackerDecorator::DidStartLoading(page_node);
  178. PageLoadTrackerDecorator::PrimaryPageChanged(page_node);
  179. auto* page_data = Data::GetForTesting(page_node);
  180. ASSERT_TRUE(page_data);
  181. EXPECT_EQ(LIS::kLoading, page_data->load_idle_state());
  182. EXPECT_EQ(LS::kLoading, page_node->loading_state());
  183. // Mark the page as not idling.
  184. frame_node->OnNavigationCommitted(GURL(), false);
  185. proc_node->SetMainThreadTaskLoadIsLow(false);
  186. EXPECT_FALSE(IsIdling(page_node));
  187. // DidStopLoading() should cause a transition to kLoadedNotIdling.
  188. PageLoadTrackerDecorator::DidStopLoading(page_node);
  189. EXPECT_EQ(LIS::kLoadedNotIdling, page_data->load_idle_state());
  190. EXPECT_EQ(LS::kLoadedBusy, page_node->loading_state());
  191. // The state should transition to loading if DidStartLoading() is invoked
  192. // again, before the page reaches an idle state.
  193. PageLoadTrackerDecorator::DidStartLoading(page_node);
  194. EXPECT_EQ(LIS::kWaitingForNavigation, page_data->load_idle_state());
  195. EXPECT_EQ(LS::kLoading, page_node->loading_state());
  196. // Test transitions until the page is loaded and idle.
  197. PageLoadTrackerDecorator::PrimaryPageChanged(page_node);
  198. EXPECT_EQ(LIS::kLoading, page_data->load_idle_state());
  199. EXPECT_EQ(LS::kLoading, page_node->loading_state());
  200. PageLoadTrackerDecorator::DidStopLoading(page_node);
  201. EXPECT_EQ(LIS::kLoadedNotIdling, page_data->load_idle_state());
  202. EXPECT_EQ(LS::kLoadedBusy, page_node->loading_state());
  203. task_env().FastForwardBy(GetWaitingForIdleTimeout());
  204. EXPECT_FALSE(Data::GetForTesting(page_node));
  205. EXPECT_EQ(LS::kLoadedIdle, page_node->loading_state());
  206. }
  207. TEST_F(PageLoadTrackerDecoratorTest, IsIdling) {
  208. MockSinglePageInSingleProcessGraph mock_graph(graph());
  209. auto* frame_node = mock_graph.frame.get();
  210. auto* page_node = mock_graph.page.get();
  211. auto* proc_node = mock_graph.process.get();
  212. // Neither of the idling properties are set, so IsIdling should return false.
  213. EXPECT_FALSE(IsIdling(page_node));
  214. // Should still return false after main thread task is low.
  215. proc_node->SetMainThreadTaskLoadIsLow(true);
  216. EXPECT_FALSE(IsIdling(page_node));
  217. // Should return true when network is idle.
  218. frame_node->SetNetworkAlmostIdle();
  219. EXPECT_TRUE(IsIdling(page_node));
  220. // Should toggle with main thread task low.
  221. proc_node->SetMainThreadTaskLoadIsLow(false);
  222. EXPECT_FALSE(IsIdling(page_node));
  223. proc_node->SetMainThreadTaskLoadIsLow(true);
  224. EXPECT_TRUE(IsIdling(page_node));
  225. // Should return false when network is no longer idle.
  226. frame_node->OnNavigationCommitted(GURL(), false);
  227. EXPECT_FALSE(IsIdling(page_node));
  228. // And should stay false if main thread task also goes low again.
  229. proc_node->SetMainThreadTaskLoadIsLow(false);
  230. EXPECT_FALSE(IsIdling(page_node));
  231. }
  232. } // namespace performance_manager