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
5 #include "chrome/browser/page_load_metrics/observers/android_page_load_metrics_observer.h"
6
7 #include "base/memory/ptr_util.h"
8 #include "chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h"
9 #include "chrome/browser/profiles/profile.h"
10 #include "components/page_load_metrics/browser/page_load_tracker.h"
11 #include "components/page_load_metrics/common/test/page_load_metrics_test_util.h"
12 #include "content/public/browser/web_contents.h"
13 #include "content/public/test/navigation_simulator.h"
14 #include "net/base/ip_endpoint.h"
15 #include "services/network/public/cpp/network_quality_tracker.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17
18 using testing::AnyNumber;
19 using testing::Return;
20
21 class MockNetworkQualityTracker : public network::NetworkQualityTracker {
22 public:
23 MOCK_CONST_METHOD0(GetEffectiveConnectionType,
24 net::EffectiveConnectionType());
25 MOCK_CONST_METHOD0(GetHttpRTT, base::TimeDelta());
26 MOCK_CONST_METHOD0(GetTransportRTT, base::TimeDelta());
27 MOCK_CONST_METHOD0(GetDownstreamThroughputKbps, int32_t());
28 };
29
30 class TestAndroidPageLoadMetricsObserver
31 : public AndroidPageLoadMetricsObserver {
32 public:
TestAndroidPageLoadMetricsObserver(network::NetworkQualityTracker * network_quality_tracker)33 TestAndroidPageLoadMetricsObserver(
34 network::NetworkQualityTracker* network_quality_tracker)
35 : AndroidPageLoadMetricsObserver(network_quality_tracker) {}
36
reported_connection_type() const37 net::EffectiveConnectionType reported_connection_type() const {
38 return reported_connection_type_;
39 }
40
reported_http_rtt_ms() const41 int64_t reported_http_rtt_ms() const { return reported_http_rtt_ms_; }
42
reported_transport_rtt_ms() const43 int64_t reported_transport_rtt_ms() const {
44 return reported_transport_rtt_ms_;
45 }
46
reported_first_contentful_paint_ms() const47 int64_t reported_first_contentful_paint_ms() const {
48 return reported_first_contentful_paint_ms_;
49 }
50
reported_navigation_start_tick_fcp() const51 int64_t reported_navigation_start_tick_fcp() const {
52 return reported_navigation_start_tick_fcp_;
53 }
54
reported_navigation_start_tick_load() const55 int64_t reported_navigation_start_tick_load() const {
56 return reported_navigation_start_tick_load_;
57 }
58
reported_load_event_start_ms() const59 int64_t reported_load_event_start_ms() const {
60 return reported_load_event_start_ms_;
61 }
62
reported_dns_start_ms() const63 int64_t reported_dns_start_ms() const { return reported_dns_start_ms_; }
64
65 protected:
ReportNetworkQualityEstimate(net::EffectiveConnectionType connection_type,int64_t http_rtt_ms,int64_t transport_rtt_ms)66 void ReportNetworkQualityEstimate(
67 net::EffectiveConnectionType connection_type,
68 int64_t http_rtt_ms,
69 int64_t transport_rtt_ms) override {
70 reported_connection_type_ = connection_type;
71 reported_http_rtt_ms_ = http_rtt_ms;
72 reported_transport_rtt_ms_ = transport_rtt_ms;
73 }
74
ReportFirstContentfulPaint(int64_t navigation_start_tick,int64_t first_contentful_paint_ms)75 void ReportFirstContentfulPaint(int64_t navigation_start_tick,
76 int64_t first_contentful_paint_ms) override {
77 reported_navigation_start_tick_fcp_ = navigation_start_tick;
78 reported_first_contentful_paint_ms_ = first_contentful_paint_ms;
79 }
80
ReportLoadEventStart(int64_t navigation_start_tick,int64_t load_event_start_ms)81 void ReportLoadEventStart(int64_t navigation_start_tick,
82 int64_t load_event_start_ms) override {
83 reported_navigation_start_tick_load_ = navigation_start_tick;
84 reported_load_event_start_ms_ = load_event_start_ms;
85 }
86
ReportLoadedMainResource(int64_t dns_start_ms,int64_t dns_end_ms,int64_t connect_start_ms,int64_t connect_end_ms,int64_t request_start_ms,int64_t send_start_ms,int64_t send_end_ms)87 void ReportLoadedMainResource(int64_t dns_start_ms,
88 int64_t dns_end_ms,
89 int64_t connect_start_ms,
90 int64_t connect_end_ms,
91 int64_t request_start_ms,
92 int64_t send_start_ms,
93 int64_t send_end_ms) override {
94 reported_dns_start_ms_ = dns_start_ms;
95 }
96
97 private:
98 net::EffectiveConnectionType reported_connection_type_ =
99 net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
100 int64_t reported_http_rtt_ms_ = 0;
101 int64_t reported_transport_rtt_ms_ = 0;
102 int64_t reported_first_contentful_paint_ms_ = 0;
103 int64_t reported_navigation_start_tick_fcp_ = 0;
104 int64_t reported_navigation_start_tick_load_ = 0;
105 int64_t reported_load_event_start_ms_ = 0;
106 int64_t reported_dns_start_ms_ = 0;
107 };
108
109 class AndroidPageLoadMetricsObserverTest
110 : public page_load_metrics::PageLoadMetricsObserverTestHarness {
111 public:
AndroidPageLoadMetricsObserverTest()112 AndroidPageLoadMetricsObserverTest() {}
113
SetUp()114 void SetUp() override {
115 PageLoadMetricsObserverTestHarness::SetUp();
116 // Save observer_ptr_ so we can query for test results, while the
117 // PageLoadTracker owns it.
118 observer_ptr_ =
119 new TestAndroidPageLoadMetricsObserver(&mock_network_quality_tracker_);
120 observer_ = base::WrapUnique<page_load_metrics::PageLoadMetricsObserver>(
121 observer_ptr_);
122 }
123
observer() const124 TestAndroidPageLoadMetricsObserver* observer() const { return observer_ptr_; }
125
GetNavigationStartMicroseconds() const126 int64_t GetNavigationStartMicroseconds() const {
127 return (navigation_start_ - base::TimeTicks()).InMicroseconds();
128 }
129
SetNetworkQualityMock()130 void SetNetworkQualityMock() {
131 EXPECT_CALL(mock_network_quality_tracker(), GetEffectiveConnectionType())
132 .Times(AnyNumber())
133 .WillRepeatedly(Return(net::EFFECTIVE_CONNECTION_TYPE_3G));
134 EXPECT_CALL(mock_network_quality_tracker(), GetHttpRTT())
135 .Times(AnyNumber())
136 .WillRepeatedly(Return(base::TimeDelta::FromMilliseconds(3)));
137 EXPECT_CALL(mock_network_quality_tracker(), GetTransportRTT())
138 .Times(AnyNumber())
139 .WillRepeatedly(Return(base::TimeDelta::FromMilliseconds(4)));
140 }
141
mock_network_quality_tracker()142 MockNetworkQualityTracker& mock_network_quality_tracker() {
143 return mock_network_quality_tracker_;
144 }
145
RegisterObservers(page_load_metrics::PageLoadTracker * tracker)146 void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override {
147 navigation_start_ = tracker->navigation_start();
148 tracker->AddObserver(std::move(observer_));
149 }
150
151 private:
152 std::unique_ptr<page_load_metrics::PageLoadMetricsObserver> observer_;
153 TestAndroidPageLoadMetricsObserver* observer_ptr_;
154 MockNetworkQualityTracker mock_network_quality_tracker_;
155 base::TimeTicks navigation_start_;
156 };
157
TEST_F(AndroidPageLoadMetricsObserverTest,NetworkQualityEstimate)158 TEST_F(AndroidPageLoadMetricsObserverTest, NetworkQualityEstimate) {
159 SetNetworkQualityMock();
160 NavigateAndCommit(GURL("https://www.example.com"));
161 EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_3G,
162 observer()->reported_connection_type());
163 EXPECT_EQ(3L, observer()->reported_http_rtt_ms());
164 EXPECT_EQ(4L, observer()->reported_transport_rtt_ms());
165 }
166
TEST_F(AndroidPageLoadMetricsObserverTest,MissingNetworkQualityEstimate)167 TEST_F(AndroidPageLoadMetricsObserverTest, MissingNetworkQualityEstimate) {
168 EXPECT_CALL(mock_network_quality_tracker(), GetEffectiveConnectionType())
169 .Times(AnyNumber())
170 .WillRepeatedly(Return(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN));
171 EXPECT_CALL(mock_network_quality_tracker(), GetHttpRTT())
172 .Times(AnyNumber())
173 .WillRepeatedly(Return(base::TimeDelta()));
174 EXPECT_CALL(mock_network_quality_tracker(), GetTransportRTT())
175 .Times(AnyNumber())
176 .WillRepeatedly(Return(base::TimeDelta()));
177 NavigateAndCommit(GURL("https://www.example.com"));
178 EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
179 observer()->reported_connection_type());
180 EXPECT_EQ(0L, observer()->reported_http_rtt_ms());
181 EXPECT_EQ(0L, observer()->reported_transport_rtt_ms());
182 }
183
TEST_F(AndroidPageLoadMetricsObserverTest,LoadTimingInfo)184 TEST_F(AndroidPageLoadMetricsObserverTest, LoadTimingInfo) {
185 SetNetworkQualityMock();
186 auto navigation_simulator =
187 content::NavigationSimulator::CreateRendererInitiated(
188 GURL("https://www.example.com"), web_contents()->GetMainFrame());
189 navigation_simulator->Start();
190 int frame_tree_node_id =
191 navigation_simulator->GetNavigationHandle()->GetFrameTreeNodeId();
192 navigation_simulator->Commit();
193
194 auto load_timing_info = std::make_unique<net::LoadTimingInfo>();
195 const base::TimeTicks kNow = base::TimeTicks::Now();
196 load_timing_info->connect_timing.dns_start = kNow;
197 page_load_metrics::ExtraRequestCompleteInfo info(
198 url::Origin::Create(GURL("https://ignored.com")), net::IPEndPoint(),
199 frame_tree_node_id, false, /* cached */
200 10 * 1024 /* size */, 0 /* original_network_content_length */,
201 nullptr /* data_reduction_proxy_data */,
202 network::mojom::RequestDestination::kDocument, 0,
203 std::move(load_timing_info));
204 tester()->SimulateLoadedResource(info,
205 navigation_simulator->GetGlobalRequestID());
206 EXPECT_EQ(kNow.since_origin().InMilliseconds(),
207 observer()->reported_dns_start_ms());
208 }
209
TEST_F(AndroidPageLoadMetricsObserverTest,LoadEvents)210 TEST_F(AndroidPageLoadMetricsObserverTest, LoadEvents) {
211 SetNetworkQualityMock();
212 page_load_metrics::mojom::PageLoadTiming timing;
213 page_load_metrics::InitPageLoadTimingForTest(&timing);
214 // Note this navigation start does not effect the start that is reported to
215 // us.
216 timing.navigation_start = base::Time::FromDoubleT(1);
217 timing.document_timing->load_event_start =
218 base::TimeDelta::FromMilliseconds(30);
219 timing.parse_timing->parse_start = base::TimeDelta::FromMilliseconds(20);
220 timing.paint_timing->first_contentful_paint =
221 base::TimeDelta::FromMilliseconds(20);
222 PopulateRequiredTimingFields(&timing);
223 NavigateAndCommit(GURL("https://www.example.com"));
224 tester()->SimulateTimingUpdate(timing);
225 EXPECT_EQ(30, observer()->reported_load_event_start_ms());
226 EXPECT_EQ(GetNavigationStartMicroseconds(),
227 observer()->reported_navigation_start_tick_load());
228 EXPECT_EQ(20, observer()->reported_first_contentful_paint_ms());
229 EXPECT_EQ(GetNavigationStartMicroseconds(),
230 observer()->reported_navigation_start_tick_fcp());
231 }
232