page_timing_metrics_sender_unittest.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. // Copyright 2015 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/page_load_metrics/renderer/page_timing_metrics_sender.h"
  5. #include "base/time/time.h"
  6. #include "base/timer/mock_timer.h"
  7. #include "components/page_load_metrics/common/page_load_metrics.mojom.h"
  8. #include "components/page_load_metrics/renderer/fake_page_timing_sender.h"
  9. #include "testing/gtest/include/gtest/gtest.h"
  10. #include "third_party/blink/public/common/use_counter/use_counter_feature.h"
  11. #include "third_party/blink/public/mojom/use_counter/use_counter_feature.mojom-shared.h"
  12. using CSSSampleId = blink::mojom::CSSSampleId;
  13. namespace page_load_metrics {
  14. // Thin wrapper around PageTimingMetricsSender that provides access to the
  15. // MockOneShotTimer instance.
  16. class TestPageTimingMetricsSender : public PageTimingMetricsSender {
  17. public:
  18. explicit TestPageTimingMetricsSender(
  19. std::unique_ptr<PageTimingSender> page_timing_sender,
  20. mojom::PageLoadTimingPtr initial_timing,
  21. const PageTimingMetadataRecorder::MonotonicTiming& monotonic_timing)
  22. : PageTimingMetricsSender(std::move(page_timing_sender),
  23. std::make_unique<base::MockOneShotTimer>(),
  24. std::move(initial_timing),
  25. monotonic_timing,
  26. std::make_unique<PageResourceDataUse>()) {}
  27. base::MockOneShotTimer* mock_timer() const {
  28. return static_cast<base::MockOneShotTimer*>(timer());
  29. }
  30. };
  31. class PageTimingMetricsSenderTest : public testing::Test {
  32. public:
  33. PageTimingMetricsSenderTest()
  34. : metrics_sender_(new TestPageTimingMetricsSender(
  35. std::make_unique<FakePageTimingSender>(&validator_),
  36. mojom::PageLoadTiming::New(),
  37. PageTimingMetadataRecorder::MonotonicTiming())) {}
  38. protected:
  39. FakePageTimingSender::PageTimingValidator validator_;
  40. std::unique_ptr<TestPageTimingMetricsSender> metrics_sender_;
  41. };
  42. TEST_F(PageTimingMetricsSenderTest, Basic) {
  43. base::Time nav_start = base::Time::FromDoubleT(10);
  44. mojom::PageLoadTiming timing;
  45. InitPageLoadTimingForTest(&timing);
  46. timing.navigation_start = nav_start;
  47. metrics_sender_->Update(timing.Clone(),
  48. PageTimingMetadataRecorder::MonotonicTiming());
  49. // Firing the timer should trigger sending of an SendTiming call.
  50. validator_.ExpectPageLoadTiming(timing);
  51. ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning());
  52. metrics_sender_->mock_timer()->Fire();
  53. EXPECT_FALSE(metrics_sender_->mock_timer()->IsRunning());
  54. // At this point, we should have triggered the send of the SendTiming call.
  55. validator_.VerifyExpectedTimings();
  56. // Attempt to send the same timing instance again. The send should be
  57. // suppressed, since the timing instance hasn't changed since the last send.
  58. metrics_sender_->Update(timing.Clone(),
  59. PageTimingMetadataRecorder::MonotonicTiming());
  60. EXPECT_FALSE(metrics_sender_->mock_timer()->IsRunning());
  61. }
  62. TEST_F(PageTimingMetricsSenderTest, CoalesceMultipleTimings) {
  63. base::Time nav_start = base::Time::FromDoubleT(10);
  64. base::TimeDelta load_event = base::Milliseconds(4);
  65. mojom::PageLoadTiming timing;
  66. InitPageLoadTimingForTest(&timing);
  67. timing.navigation_start = nav_start;
  68. metrics_sender_->Update(timing.Clone(),
  69. PageTimingMetadataRecorder::MonotonicTiming());
  70. ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning());
  71. // Send an updated PageLoadTiming before the timer has fired. When the timer
  72. // fires, the updated PageLoadTiming should be sent.
  73. timing.document_timing->load_event_start = load_event;
  74. metrics_sender_->Update(timing.Clone(),
  75. PageTimingMetadataRecorder::MonotonicTiming());
  76. // Firing the timer should trigger sending of the SendTiming call with
  77. // the most recently provided PageLoadTiming instance.
  78. validator_.ExpectPageLoadTiming(timing);
  79. metrics_sender_->mock_timer()->Fire();
  80. EXPECT_FALSE(metrics_sender_->mock_timer()->IsRunning());
  81. }
  82. TEST_F(PageTimingMetricsSenderTest, MultipleTimings) {
  83. base::Time nav_start = base::Time::FromDoubleT(10);
  84. base::TimeDelta load_event = base::Milliseconds(4);
  85. mojom::PageLoadTiming timing;
  86. InitPageLoadTimingForTest(&timing);
  87. timing.navigation_start = nav_start;
  88. metrics_sender_->Update(timing.Clone(),
  89. PageTimingMetadataRecorder::MonotonicTiming());
  90. ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning());
  91. validator_.ExpectPageLoadTiming(timing);
  92. metrics_sender_->mock_timer()->Fire();
  93. EXPECT_FALSE(metrics_sender_->mock_timer()->IsRunning());
  94. validator_.VerifyExpectedTimings();
  95. // Send an updated PageLoadTiming after the timer for the first send request
  96. // has fired, and verify that a second timing is sent.
  97. timing.document_timing->load_event_start = load_event;
  98. metrics_sender_->Update(timing.Clone(),
  99. PageTimingMetadataRecorder::MonotonicTiming());
  100. ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning());
  101. validator_.ExpectPageLoadTiming(timing);
  102. metrics_sender_->mock_timer()->Fire();
  103. EXPECT_FALSE(metrics_sender_->mock_timer()->IsRunning());
  104. }
  105. TEST_F(PageTimingMetricsSenderTest, SendTimingOnSendLatest) {
  106. mojom::PageLoadTiming timing;
  107. InitPageLoadTimingForTest(&timing);
  108. timing.navigation_start = base::Time::FromDoubleT(10);
  109. // This test wants to verify behavior in the PageTimingMetricsSender
  110. // destructor. The EXPECT_CALL will be satisfied when the |metrics_sender_|
  111. // is destroyed below.
  112. metrics_sender_->Update(timing.Clone(),
  113. PageTimingMetadataRecorder::MonotonicTiming());
  114. validator_.ExpectPageLoadTiming(timing);
  115. ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning());
  116. metrics_sender_->SendLatest();
  117. }
  118. TEST_F(PageTimingMetricsSenderTest, SendInputEvents) {
  119. mojom::PageLoadTiming timing;
  120. InitPageLoadTimingForTest(&timing);
  121. base::TimeDelta input_delay_1 = base::Milliseconds(40);
  122. base::TimeDelta input_delay_2 = base::Milliseconds(60);
  123. metrics_sender_->Update(timing.Clone(),
  124. PageTimingMetadataRecorder::MonotonicTiming());
  125. validator_.ExpectPageLoadTiming(timing);
  126. metrics_sender_->DidObserveInputDelay(input_delay_1);
  127. validator_.UpdateExpectedInputTiming(input_delay_1);
  128. metrics_sender_->DidObserveInputDelay(input_delay_2);
  129. validator_.UpdateExpectedInputTiming(input_delay_2);
  130. // Fire the timer to trigger sending of features via an SendTiming call.
  131. metrics_sender_->mock_timer()->Fire();
  132. validator_.VerifyExpectedInputTiming();
  133. }
  134. TEST_F(PageTimingMetricsSenderTest, SendMobileFriendlinessEvents) {
  135. mojom::PageLoadTiming timing;
  136. blink::MobileFriendliness mobile_friendliness;
  137. mobile_friendliness.viewport_hardcoded_width = 480;
  138. mobile_friendliness.allow_user_zoom = true;
  139. InitPageLoadTimingForTest(&timing);
  140. metrics_sender_->Update(timing.Clone(),
  141. PageTimingMetadataRecorder::MonotonicTiming());
  142. validator_.ExpectPageLoadTiming(timing);
  143. metrics_sender_->DidObserveMobileFriendlinessChanged(mobile_friendliness);
  144. blink::MobileFriendliness expected_mf;
  145. expected_mf.viewport_hardcoded_width = 480;
  146. expected_mf.allow_user_zoom = true;
  147. validator_.UpdateExpectedMobileFriendliness(expected_mf);
  148. metrics_sender_->mock_timer()->Fire();
  149. validator_.VerifyExpectedMobileFriendliness();
  150. }
  151. TEST_F(PageTimingMetricsSenderTest, SendSingleFeature) {
  152. mojom::PageLoadTiming timing;
  153. InitPageLoadTimingForTest(&timing);
  154. blink::UseCounterFeature feature = {
  155. blink::mojom::UseCounterFeatureType::kWebFeature, 0};
  156. metrics_sender_->Update(timing.Clone(),
  157. PageTimingMetadataRecorder::MonotonicTiming());
  158. validator_.ExpectPageLoadTiming(timing);
  159. // Observe a single feature, update expected features sent across IPC.
  160. metrics_sender_->DidObserveNewFeatureUsage(feature);
  161. validator_.UpdateExpectPageLoadFeatures(feature);
  162. // Fire the timer to trigger sending of features via an SendTiming call.
  163. metrics_sender_->mock_timer()->Fire();
  164. validator_.VerifyExpectedFeatures();
  165. }
  166. TEST_F(PageTimingMetricsSenderTest, SendMultipleFeatures) {
  167. mojom::PageLoadTiming timing;
  168. InitPageLoadTimingForTest(&timing);
  169. blink::UseCounterFeature feature_0 = {
  170. blink::mojom::UseCounterFeatureType::kWebFeature, 0};
  171. blink::UseCounterFeature feature_1 = {
  172. blink::mojom::UseCounterFeatureType::kCssProperty, 1};
  173. blink::UseCounterFeature feature_2 = {
  174. blink::mojom::UseCounterFeatureType::kAnimatedCssProperty, 2};
  175. metrics_sender_->Update(timing.Clone(),
  176. PageTimingMetadataRecorder::MonotonicTiming());
  177. validator_.ExpectPageLoadTiming(timing);
  178. // Observe the first feature, update expected features sent across IPC.
  179. metrics_sender_->DidObserveNewFeatureUsage(feature_0);
  180. validator_.UpdateExpectPageLoadFeatures(feature_0);
  181. // Observe the second feature, update expected features sent across IPC.
  182. metrics_sender_->DidObserveNewFeatureUsage(feature_1);
  183. validator_.UpdateExpectPageLoadFeatures(feature_1);
  184. // Observe the third feature, update expected features sent across IPC.
  185. metrics_sender_->DidObserveNewFeatureUsage(feature_2);
  186. validator_.UpdateExpectPageLoadFeatures(feature_2);
  187. // Fire the timer to trigger sending of features via an SendTiming call.
  188. metrics_sender_->mock_timer()->Fire();
  189. validator_.VerifyExpectedFeatures();
  190. }
  191. TEST_F(PageTimingMetricsSenderTest, SendDuplicatedFeatures) {
  192. mojom::PageLoadTiming timing;
  193. InitPageLoadTimingForTest(&timing);
  194. blink::UseCounterFeature feature = {
  195. blink::mojom::UseCounterFeatureType::kWebFeature, 0};
  196. metrics_sender_->Update(timing.Clone(),
  197. PageTimingMetadataRecorder::MonotonicTiming());
  198. validator_.ExpectPageLoadTiming(timing);
  199. metrics_sender_->DidObserveNewFeatureUsage(feature);
  200. validator_.UpdateExpectPageLoadFeatures(feature);
  201. // Observe a duplicated feature usage, without updating expected features sent
  202. // across IPC.
  203. metrics_sender_->DidObserveNewFeatureUsage(feature);
  204. // Fire the timer to trigger sending of features via an SendTiming call.
  205. metrics_sender_->mock_timer()->Fire();
  206. validator_.VerifyExpectedFeatures();
  207. }
  208. TEST_F(PageTimingMetricsSenderTest, SendMultipleFeaturesTwice) {
  209. mojom::PageLoadTiming timing;
  210. InitPageLoadTimingForTest(&timing);
  211. blink::UseCounterFeature feature_0 = {
  212. blink::mojom::UseCounterFeatureType::kWebFeature, 0};
  213. blink::UseCounterFeature feature_1 = {
  214. blink::mojom::UseCounterFeatureType::kCssProperty, 1};
  215. blink::UseCounterFeature feature_2 = {
  216. blink::mojom::UseCounterFeatureType::kAnimatedCssProperty, 2};
  217. metrics_sender_->Update(timing.Clone(),
  218. PageTimingMetadataRecorder::MonotonicTiming());
  219. validator_.ExpectPageLoadTiming(timing);
  220. // Observe the first feature, update expected features sent across IPC.
  221. metrics_sender_->DidObserveNewFeatureUsage(feature_0);
  222. validator_.UpdateExpectPageLoadFeatures(feature_0);
  223. // Observe the second feature, update expected features sent across IPC.
  224. metrics_sender_->DidObserveNewFeatureUsage(feature_1);
  225. validator_.UpdateExpectPageLoadFeatures(feature_1);
  226. // Observe a duplicated feature usage, without updating expected features sent
  227. // across IPC.
  228. metrics_sender_->DidObserveNewFeatureUsage(feature_0);
  229. // Fire the timer to trigger sending of features via an SendTiming call.
  230. metrics_sender_->mock_timer()->Fire();
  231. validator_.VerifyExpectedFeatures();
  232. base::TimeDelta load_event = base::Milliseconds(4);
  233. // Send an updated PageLoadTiming after the timer for the first send request
  234. // has fired, and verify that a second list of features is sent.
  235. timing.document_timing->load_event_start = load_event;
  236. metrics_sender_->Update(timing.Clone(),
  237. PageTimingMetadataRecorder::MonotonicTiming());
  238. validator_.ExpectPageLoadTiming(timing);
  239. // Observe duplicated feature usage, without updating expected features sent
  240. // across IPC.
  241. metrics_sender_->DidObserveNewFeatureUsage(feature_0);
  242. metrics_sender_->DidObserveNewFeatureUsage(feature_1);
  243. // Observe an additional feature usage, update expected features sent across
  244. // IPC.
  245. metrics_sender_->DidObserveNewFeatureUsage(feature_2);
  246. validator_.UpdateExpectPageLoadFeatures(feature_2);
  247. // Fire the timer to trigger another sending of features via the second
  248. // SendTiming call.
  249. metrics_sender_->mock_timer()->Fire();
  250. validator_.VerifyExpectedFeatures();
  251. }
  252. TEST_F(PageTimingMetricsSenderTest, SendPageRenderData) {
  253. mojom::PageLoadTiming timing;
  254. InitPageLoadTimingForTest(&timing);
  255. // We need to send the PageLoadTiming here even though it is not really
  256. // related to the PageRenderData. This is because metrics_sender_ sends
  257. // its last_timing_ when the mock timer fires, causing the validator to
  258. // look for a matching expectation.
  259. metrics_sender_->Update(timing.Clone(),
  260. PageTimingMetadataRecorder::MonotonicTiming());
  261. validator_.ExpectPageLoadTiming(timing);
  262. metrics_sender_->DidObserveLayoutShift(0.5, false);
  263. metrics_sender_->DidObserveLayoutShift(0.5, false);
  264. metrics_sender_->DidObserveLayoutNg(3, 2, 10, 4);
  265. metrics_sender_->DidObserveLayoutNg(2, 0, 7, 5);
  266. metrics_sender_->DidObserveLayoutShift(0.5, true);
  267. mojom::FrameRenderDataUpdate render_data(1.5, 1.0, 5, 2, 17, 9, {});
  268. validator_.UpdateExpectFrameRenderDataUpdate(render_data);
  269. metrics_sender_->mock_timer()->Fire();
  270. validator_.VerifyExpectedRenderData();
  271. }
  272. TEST_F(PageTimingMetricsSenderTest, SendMainFrameIntersectionRect) {
  273. mojom::PageLoadTiming timing;
  274. InitPageLoadTimingForTest(&timing);
  275. metrics_sender_->Update(timing.Clone(),
  276. PageTimingMetadataRecorder::MonotonicTiming());
  277. validator_.ExpectPageLoadTiming(timing);
  278. metrics_sender_->OnMainFrameIntersectionChanged(gfx::Rect(0, 0, 1, 1));
  279. validator_.UpdateExpectedMainFrameIntersectionRect(gfx::Rect(0, 0, 1, 1));
  280. metrics_sender_->mock_timer()->Fire();
  281. validator_.VerifyExpectedMainFrameIntersectionRect();
  282. }
  283. TEST_F(PageTimingMetricsSenderTest, SendMainFrameViewportRect) {
  284. mojom::PageLoadTiming timing;
  285. InitPageLoadTimingForTest(&timing);
  286. metrics_sender_->Update(timing.Clone(),
  287. PageTimingMetadataRecorder::MonotonicTiming());
  288. validator_.ExpectPageLoadTiming(timing);
  289. metrics_sender_->OnMainFrameViewportRectangleChanged(gfx::Rect(2, 2, 1, 1));
  290. validator_.UpdateExpectedMainFrameViewportRect(gfx::Rect(2, 2, 1, 1));
  291. metrics_sender_->mock_timer()->Fire();
  292. validator_.VerifyExpectedMainFrameViewportRect();
  293. }
  294. TEST_F(PageTimingMetricsSenderTest, FirstContentfulPaintForcesSend) {
  295. mojom::PageLoadTiming timing;
  296. InitPageLoadTimingForTest(&timing);
  297. timing.paint_timing->first_contentful_paint = base::Seconds(1);
  298. validator_.ExpectPageLoadTiming(timing);
  299. // Updating when |timing| has FCP will cause the metrics to be sent urgently.
  300. metrics_sender_->Update(timing.Clone(),
  301. PageTimingMetadataRecorder::MonotonicTiming());
  302. EXPECT_EQ(metrics_sender_->mock_timer()->GetCurrentDelay(),
  303. base::Milliseconds(0));
  304. metrics_sender_->mock_timer()->Fire();
  305. }
  306. } // namespace page_load_metrics