1 // Copyright (c) 2013 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.
7 #include "base/basictypes.h"
9 #include "base/compiler_specific.h"
10 #include "base/files/file_path.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/memory/weak_ptr.h"
13 #include "base/message_loop/message_loop.h"
14 #include "base/path_service.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/threading/sequenced_worker_pool.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/tabs/tab_strip_model.h"
19 #include "chrome/common/chrome_paths.h"
20 #include "chrome/test/base/in_process_browser_test.h"
21 #include "chrome/test/base/ui_test_utils.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/test/browser_test_utils.h"
24 #include "net/base/load_timing_info.h"
25 #include "net/test/spawned_test_server/spawned_test_server.h"
26 #include "net/url_request/url_request_file_job.h"
27 #include "net/url_request/url_request_filter.h"
28 #include "net/url_request/url_request_interceptor.h"
31 // This file tests that net::LoadTimingInfo is correctly hooked up to the
32 // NavigationTiming API. It depends on behavior in a large number of files
33 // spread across multiple projects, so is somewhat arbitrarily put in
34 // chrome/browser/net.
36 using content::BrowserThread
;
40 const char kTestDomain
[] = "test.com";
41 const char kTestUrl
[] = "http://test.com/";
43 // Relative times need to be used because:
44 // 1) ExecuteScriptAndExtractInt does not support 64-bit integers.
45 // 2) Times for tests are set before the request has been started, but need to
46 // be set relative to the start time.
48 // Since some tests need to test negative time deltas (preconnected sockets)
49 // and others need to test NULL times (events that don't apply), this class has
50 // to be able to handle all cases: positive deltas, negative deltas, no
51 // delta, and null times.
54 // Constructor for null RelativeTimes.
55 RelativeTime() : is_null_(true) {
58 // Constructor for non-null RelativeTimes.
59 explicit RelativeTime(int delta_ms
)
61 delta_(base::TimeDelta::FromMilliseconds(delta_ms
)) {
64 // Given a base time, returns the TimeTicks |this| identifies.
65 base::TimeTicks
ToTimeTicks(base::TimeTicks base_time
) const {
67 return base::TimeTicks();
68 return base_time
+ delta_
;
71 bool is_null() const { return is_null_
; }
73 base::TimeDelta
GetDelta() const {
74 // This allows tests to compare times that shouldn't be null without
75 // explicitly null-testing them all first.
76 EXPECT_FALSE(is_null_
);
83 // Must be 0 when |is_null| is true.
84 base::TimeDelta delta_
;
86 // This class is copyable and assignable.
89 // Structure used for both setting the LoadTimingInfo used by mock requests
90 // and for times retrieved from the renderer process.
92 // Times used for mock requests are all expressed as TimeDeltas relative to
93 // when the Job starts. Null RelativeTimes correspond to null TimeTicks().
95 // Times read from the renderer are expressed relative to fetchStart (Which is
96 // not the same as request_start). Null RelativeTimes correspond to times that
97 // either cannot be retrieved (proxy times, send end) or times that are 0 (SSL
98 // time when no new SSL connection was established).
100 RelativeTime proxy_resolve_start
;
101 RelativeTime proxy_resolve_end
;
102 RelativeTime dns_start
;
103 RelativeTime dns_end
;
104 RelativeTime connect_start
;
105 RelativeTime ssl_start
;
106 RelativeTime connect_end
;
107 RelativeTime send_start
;
108 RelativeTime send_end
;
110 // Must be non-negative and greater than all other times. May only be null if
111 // all other times are as well.
112 RelativeTime receive_headers_end
;
115 // Mock UrlRequestJob that returns the contents of a specified file and
116 // provides the specified load timing information when queried.
117 class MockUrlRequestJobWithTiming
: public net::URLRequestFileJob
{
119 MockUrlRequestJobWithTiming(net::URLRequest
* request
,
120 net::NetworkDelegate
* network_delegate
,
121 const base::FilePath
& path
,
122 const TimingDeltas
& load_timing_deltas
)
123 : net::URLRequestFileJob(
124 request
, network_delegate
, path
,
125 content::BrowserThread::GetBlockingPool()->
126 GetTaskRunnerWithShutdownBehavior(
127 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN
)),
128 load_timing_deltas_(load_timing_deltas
),
129 weak_factory_(this) {}
131 // net::URLRequestFileJob implementation:
132 virtual void Start() override
{
133 base::TimeDelta time_to_wait
;
134 start_time_
= base::TimeTicks::Now();
135 if (!load_timing_deltas_
.receive_headers_end
.is_null()) {
136 // Need to delay starting until the largest of the times has elapsed.
137 // Wait a little longer than necessary, to be on the safe side.
138 time_to_wait
= load_timing_deltas_
.receive_headers_end
.GetDelta() +
139 base::TimeDelta::FromMilliseconds(100);
142 base::MessageLoop::current()->PostDelayedTask(
144 base::Bind(&MockUrlRequestJobWithTiming::DelayedStart
,
145 weak_factory_
.GetWeakPtr()),
149 virtual void GetLoadTimingInfo(
150 net::LoadTimingInfo
* load_timing_info
) const override
{
151 // Make sure enough time has elapsed since start was called. If this
152 // fails, the test fixture itself is flaky.
153 if (!load_timing_deltas_
.receive_headers_end
.is_null()) {
155 start_time_
+ load_timing_deltas_
.receive_headers_end
.GetDelta(),
156 base::TimeTicks::Now());
159 // If there are no connect times, but there is a receive headers end time,
160 // then assume the socket is reused. This shouldn't affect the load timing
161 // information the test checks, just done for completeness.
162 load_timing_info
->socket_reused
= false;
163 if (load_timing_deltas_
.connect_start
.is_null() &&
164 !load_timing_deltas_
.receive_headers_end
.is_null()) {
165 load_timing_info
->socket_reused
= true;
168 load_timing_info
->proxy_resolve_start
=
169 load_timing_deltas_
.proxy_resolve_start
.ToTimeTicks(start_time_
);
170 load_timing_info
->proxy_resolve_end
=
171 load_timing_deltas_
.proxy_resolve_end
.ToTimeTicks(start_time_
);
173 load_timing_info
->connect_timing
.dns_start
=
174 load_timing_deltas_
.dns_start
.ToTimeTicks(start_time_
);
175 load_timing_info
->connect_timing
.dns_end
=
176 load_timing_deltas_
.dns_end
.ToTimeTicks(start_time_
);
177 load_timing_info
->connect_timing
.connect_start
=
178 load_timing_deltas_
.connect_start
.ToTimeTicks(start_time_
);
179 load_timing_info
->connect_timing
.ssl_start
=
180 load_timing_deltas_
.ssl_start
.ToTimeTicks(start_time_
);
181 load_timing_info
->connect_timing
.connect_end
=
182 load_timing_deltas_
.connect_end
.ToTimeTicks(start_time_
);
184 // If there's an SSL start time, use connect end as the SSL end time.
185 // The NavigationTiming API does not have a corresponding field, and there's
186 // no need to test the case when the values are both non-NULL and different.
187 if (!load_timing_deltas_
.ssl_start
.is_null()) {
188 load_timing_info
->connect_timing
.ssl_end
=
189 load_timing_info
->connect_timing
.connect_end
;
192 load_timing_info
->send_start
=
193 load_timing_deltas_
.send_start
.ToTimeTicks(start_time_
);
194 load_timing_info
->send_end
=
195 load_timing_deltas_
.send_end
.ToTimeTicks(start_time_
);
196 load_timing_info
->receive_headers_end
=
197 load_timing_deltas_
.receive_headers_end
.ToTimeTicks(start_time_
);
201 // Parent class is reference counted, so need to have a private destructor.
202 virtual ~MockUrlRequestJobWithTiming() {}
204 void DelayedStart() {
205 net::URLRequestFileJob::Start();
208 // Load times to use, relative to |start_time_|.
209 const TimingDeltas load_timing_deltas_
;
210 base::TimeTicks start_time_
;
212 base::WeakPtrFactory
<MockUrlRequestJobWithTiming
> weak_factory_
;
214 DISALLOW_COPY_AND_ASSIGN(MockUrlRequestJobWithTiming
);
217 // AURLRequestInterceptor that returns mock URLRequestJobs that return the
218 // specified file with the given timings. Constructed on the UI thread, but
219 // after that, lives and is destroyed on the IO thread.
220 class TestInterceptor
: public net::URLRequestInterceptor
{
222 TestInterceptor(const base::FilePath
& path
,
223 const TimingDeltas
& load_timing_deltas
)
224 : path_(path
), load_timing_deltas_(load_timing_deltas
) {
225 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI
));
228 virtual ~TestInterceptor() {
229 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
232 // Registers |this| with the URLRequestFilter, which takes ownership of it.
234 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
235 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
236 "http", kTestDomain
, scoped_ptr
<net::URLRequestInterceptor
>(this));
239 // Unregisters |this| with the URLRequestFilter, which should then delete
242 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
243 net::URLRequestFilter::GetInstance()->RemoveHostnameHandler(
244 "http", kTestDomain
);
247 // net::URLRequestJobFactory::ProtocolHandler implementation:
248 virtual net::URLRequestJob
* MaybeInterceptRequest(
249 net::URLRequest
* request
,
250 net::NetworkDelegate
* network_delegate
) const override
{
251 EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO
));
253 return new MockUrlRequestJobWithTiming(request
, network_delegate
, path_
,
254 load_timing_deltas_
);
258 // Path of the file to use as the response body.
259 const base::FilePath path_
;
261 // Load times for each request to use, relative to when the Job starts.
262 const TimingDeltas load_timing_deltas_
;
264 DISALLOW_COPY_AND_ASSIGN(TestInterceptor
);
267 class LoadTimingBrowserTest
: public InProcessBrowserTest
{
269 LoadTimingBrowserTest() {
272 virtual ~LoadTimingBrowserTest() {
275 // Navigates to |url| and writes the resulting navigation timings to
276 // |navigation_deltas|.
277 void RunTestWithUrl(const GURL
& url
, TimingDeltas
* navigation_deltas
) {
278 ui_test_utils::NavigateToURL(browser(), url
);
279 GetResultDeltas(navigation_deltas
);
282 // Navigates to a url that returns the timings indicated by
283 // |load_timing_deltas| and writes the resulting navigation timings to
284 // |navigation_deltas|. Uses a generic test page.
285 void RunTest(const TimingDeltas
& load_timing_deltas
,
286 TimingDeltas
* navigation_deltas
) {
287 // None of the tests care about the contents of the test page. Just do
288 // this here because PathService has thread restrictions on some platforms.
290 PathService::Get(chrome::DIR_TEST_DATA
, &path
);
291 path
= path
.AppendASCII("title1.html");
293 // Create and register request interceptor.
294 TestInterceptor
* test_interceptor
=
295 new TestInterceptor(path
, load_timing_deltas
);
296 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
297 base::Bind(&TestInterceptor::Register
,
298 base::Unretained(test_interceptor
)));
300 // Navigate to the page.
301 RunTestWithUrl(GURL(kTestUrl
), navigation_deltas
);
303 // Once navigation is complete, unregister the protocol handler.
304 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
305 base::Bind(&TestInterceptor::Unregister
,
306 base::Unretained(test_interceptor
)));
310 // Reads applicable times from performance.timing and writes them to
311 // |navigation_deltas|. Proxy times and send end cannot be read from the
312 // Navigation Timing API, so those are all left as null.
313 void GetResultDeltas(TimingDeltas
* navigation_deltas
) {
314 *navigation_deltas
= TimingDeltas();
316 navigation_deltas
->dns_start
= GetResultDelta("domainLookupStart");
317 navigation_deltas
->dns_end
= GetResultDelta("domainLookupEnd");
318 navigation_deltas
->connect_start
= GetResultDelta("connectStart");
319 navigation_deltas
->connect_end
= GetResultDelta("connectEnd");
320 navigation_deltas
->send_start
= GetResultDelta("requestStart");
321 navigation_deltas
->receive_headers_end
= GetResultDelta("responseStart");
323 // Unlike the above times, secureConnectionStart will be zero when not
324 // applicable. In that case, leave ssl_start as null.
325 bool ssl_start_zero
= false;
326 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
327 browser()->tab_strip_model()->GetActiveWebContents(),
328 "window.domAutomationController.send("
329 "performance.timing.secureConnectionStart == 0);",
332 navigation_deltas
->ssl_start
= GetResultDelta("secureConnectionStart");
334 // Simple sanity checks. Make sure times that correspond to LoadTimingInfo
335 // occur between fetchStart and loadEventEnd. Relationships between
336 // intervening times are handled by the test bodies.
338 RelativeTime fetch_start
= GetResultDelta("fetchStart");
339 // While the input dns_start is sometimes null, when read from the
340 // NavigationTiming API, it's always non-null.
341 EXPECT_LE(fetch_start
.GetDelta(), navigation_deltas
->dns_start
.GetDelta());
343 RelativeTime load_event_end
= GetResultDelta("loadEventEnd");
344 EXPECT_LE(navigation_deltas
->receive_headers_end
.GetDelta(),
345 load_event_end
.GetDelta());
348 // Returns the time between performance.timing.fetchStart and the time with
349 // the specified name. This time must be non-negative.
350 RelativeTime
GetResultDelta(const std::string
& name
) {
352 std::string
command(base::StringPrintf(
353 "window.domAutomationController.send("
354 "performance.timing.%s - performance.timing.fetchStart);",
356 EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
357 browser()->tab_strip_model()->GetActiveWebContents(),
361 // Basic sanity check.
362 EXPECT_GE(time_ms
, 0);
364 return RelativeTime(time_ms
);
368 // Test case when no times are given, except the request start times. This
369 // happens with FTP, cached responses, responses handled by something other than
370 // the network stack, RedirectJobs, HSTs, etc.
371 IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest
, NoTimes
) {
372 TimingDeltas load_timing_deltas
;
373 TimingDeltas navigation_deltas
;
374 RunTest(load_timing_deltas
, &navigation_deltas
);
376 // When there are no times, all read times should be the same as fetchStart,
377 // except SSL start, which should be 0.
378 EXPECT_EQ(base::TimeDelta(), navigation_deltas
.dns_start
.GetDelta());
379 EXPECT_EQ(base::TimeDelta(), navigation_deltas
.dns_end
.GetDelta());
380 EXPECT_EQ(base::TimeDelta(), navigation_deltas
.connect_start
.GetDelta());
381 EXPECT_EQ(base::TimeDelta(), navigation_deltas
.connect_end
.GetDelta());
382 EXPECT_EQ(base::TimeDelta(), navigation_deltas
.send_start
.GetDelta());
383 EXPECT_EQ(base::TimeDelta(),
384 navigation_deltas
.receive_headers_end
.GetDelta());
386 EXPECT_TRUE(navigation_deltas
.ssl_start
.is_null());
389 // Standard case - new socket, no PAC, no preconnect, no SSL.
390 IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest
, Basic
) {
391 TimingDeltas load_timing_deltas
;
392 load_timing_deltas
.dns_start
= RelativeTime(0);
393 load_timing_deltas
.dns_end
= RelativeTime(100);
394 load_timing_deltas
.connect_start
= RelativeTime(200);
395 load_timing_deltas
.connect_end
= RelativeTime(300);
396 load_timing_deltas
.send_start
= RelativeTime(400);
397 load_timing_deltas
.send_end
= RelativeTime(500);
398 load_timing_deltas
.receive_headers_end
= RelativeTime(600);
400 TimingDeltas navigation_deltas
;
401 RunTest(load_timing_deltas
, &navigation_deltas
);
403 // Due to potential roundoff issues, never check exact differences.
404 EXPECT_LT(navigation_deltas
.dns_start
.GetDelta(),
405 navigation_deltas
.dns_end
.GetDelta());
406 EXPECT_LT(navigation_deltas
.dns_end
.GetDelta(),
407 navigation_deltas
.connect_start
.GetDelta());
408 EXPECT_LT(navigation_deltas
.connect_start
.GetDelta(),
409 navigation_deltas
.connect_end
.GetDelta());
410 EXPECT_LT(navigation_deltas
.connect_end
.GetDelta(),
411 navigation_deltas
.send_start
.GetDelta());
412 EXPECT_LT(navigation_deltas
.send_start
.GetDelta(),
413 navigation_deltas
.receive_headers_end
.GetDelta());
415 EXPECT_TRUE(navigation_deltas
.ssl_start
.is_null());
419 IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest
, Ssl
) {
420 TimingDeltas load_timing_deltas
;
421 load_timing_deltas
.dns_start
= RelativeTime(0);
422 load_timing_deltas
.dns_end
= RelativeTime(100);
423 load_timing_deltas
.connect_start
= RelativeTime(200);
424 load_timing_deltas
.ssl_start
= RelativeTime(300);
425 load_timing_deltas
.connect_end
= RelativeTime(400);
426 load_timing_deltas
.send_start
= RelativeTime(500);
427 load_timing_deltas
.send_end
= RelativeTime(600);
428 load_timing_deltas
.receive_headers_end
= RelativeTime(700);
430 TimingDeltas navigation_deltas
;
431 RunTest(load_timing_deltas
, &navigation_deltas
);
433 // Due to potential roundoff issues, never check exact differences.
434 EXPECT_LT(navigation_deltas
.dns_start
.GetDelta(),
435 navigation_deltas
.dns_end
.GetDelta());
436 EXPECT_LT(navigation_deltas
.dns_end
.GetDelta(),
437 navigation_deltas
.connect_start
.GetDelta());
438 EXPECT_LT(navigation_deltas
.connect_start
.GetDelta(),
439 navigation_deltas
.ssl_start
.GetDelta());
440 EXPECT_LT(navigation_deltas
.ssl_start
.GetDelta(),
441 navigation_deltas
.connect_end
.GetDelta());
442 EXPECT_LT(navigation_deltas
.connect_end
.GetDelta(),
443 navigation_deltas
.send_start
.GetDelta());
444 EXPECT_LT(navigation_deltas
.send_start
.GetDelta(),
445 navigation_deltas
.receive_headers_end
.GetDelta());
448 // All times are the same.
449 IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest
, EverythingAtOnce
) {
450 TimingDeltas load_timing_deltas
;
451 load_timing_deltas
.dns_start
= RelativeTime(100);
452 load_timing_deltas
.dns_end
= RelativeTime(100);
453 load_timing_deltas
.connect_start
= RelativeTime(100);
454 load_timing_deltas
.ssl_start
= RelativeTime(100);
455 load_timing_deltas
.connect_end
= RelativeTime(100);
456 load_timing_deltas
.send_start
= RelativeTime(100);
457 load_timing_deltas
.send_end
= RelativeTime(100);
458 load_timing_deltas
.receive_headers_end
= RelativeTime(100);
460 TimingDeltas navigation_deltas
;
461 RunTest(load_timing_deltas
, &navigation_deltas
);
463 EXPECT_EQ(navigation_deltas
.dns_start
.GetDelta(),
464 navigation_deltas
.dns_end
.GetDelta());
465 EXPECT_EQ(navigation_deltas
.dns_end
.GetDelta(),
466 navigation_deltas
.connect_start
.GetDelta());
467 EXPECT_EQ(navigation_deltas
.connect_start
.GetDelta(),
468 navigation_deltas
.ssl_start
.GetDelta());
469 EXPECT_EQ(navigation_deltas
.ssl_start
.GetDelta(),
470 navigation_deltas
.connect_end
.GetDelta());
471 EXPECT_EQ(navigation_deltas
.connect_end
.GetDelta(),
472 navigation_deltas
.send_start
.GetDelta());
473 EXPECT_EQ(navigation_deltas
.send_start
.GetDelta(),
474 navigation_deltas
.receive_headers_end
.GetDelta());
478 IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest
, ReuseSocket
) {
479 TimingDeltas load_timing_deltas
;
480 load_timing_deltas
.send_start
= RelativeTime(0);
481 load_timing_deltas
.send_end
= RelativeTime(100);
482 load_timing_deltas
.receive_headers_end
= RelativeTime(200);
484 TimingDeltas navigation_deltas
;
485 RunTest(load_timing_deltas
, &navigation_deltas
);
487 // Connect times should all be the same as fetchStart.
488 EXPECT_EQ(base::TimeDelta(), navigation_deltas
.dns_start
.GetDelta());
489 EXPECT_EQ(base::TimeDelta(), navigation_deltas
.dns_end
.GetDelta());
490 EXPECT_EQ(base::TimeDelta(), navigation_deltas
.connect_start
.GetDelta());
491 EXPECT_EQ(base::TimeDelta(), navigation_deltas
.connect_end
.GetDelta());
493 // Connect end may be less than send start, since connect end defaults to
494 // fetchStart, which is often less than request_start.
495 EXPECT_LE(navigation_deltas
.connect_end
.GetDelta(),
496 navigation_deltas
.send_start
.GetDelta());
498 EXPECT_LT(navigation_deltas
.send_start
.GetDelta(),
499 navigation_deltas
.receive_headers_end
.GetDelta());
501 EXPECT_TRUE(navigation_deltas
.ssl_start
.is_null());
504 // Preconnect case. Connect times are all before the request was started.
505 IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest
, Preconnect
) {
506 TimingDeltas load_timing_deltas
;
507 load_timing_deltas
.dns_start
= RelativeTime(-1000300);
508 load_timing_deltas
.dns_end
= RelativeTime(-1000200);
509 load_timing_deltas
.connect_start
= RelativeTime(-1000100);
510 load_timing_deltas
.connect_end
= RelativeTime(-1000000);
511 load_timing_deltas
.send_start
= RelativeTime(0);
512 load_timing_deltas
.send_end
= RelativeTime(100);
513 load_timing_deltas
.receive_headers_end
= RelativeTime(200);
515 TimingDeltas navigation_deltas
;
516 RunTest(load_timing_deltas
, &navigation_deltas
);
518 // Connect times should all be the same as request_start.
519 EXPECT_EQ(navigation_deltas
.dns_start
.GetDelta(),
520 navigation_deltas
.dns_end
.GetDelta());
521 EXPECT_EQ(navigation_deltas
.dns_start
.GetDelta(),
522 navigation_deltas
.connect_start
.GetDelta());
523 EXPECT_EQ(navigation_deltas
.dns_start
.GetDelta(),
524 navigation_deltas
.connect_end
.GetDelta());
526 EXPECT_LE(navigation_deltas
.dns_start
.GetDelta(),
527 navigation_deltas
.send_start
.GetDelta());
529 EXPECT_LT(navigation_deltas
.send_start
.GetDelta(),
530 navigation_deltas
.receive_headers_end
.GetDelta());
531 EXPECT_LT(navigation_deltas
.send_start
.GetDelta(),
532 navigation_deltas
.receive_headers_end
.GetDelta());
534 EXPECT_TRUE(navigation_deltas
.ssl_start
.is_null());
537 // Preconnect case with a proxy. Connect times are all before the proxy lookup
538 // finished (Or at the same time).
539 IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest
, PreconnectProxySsl
) {
540 TimingDeltas load_timing_deltas
;
541 load_timing_deltas
.proxy_resolve_start
= RelativeTime(0);
542 load_timing_deltas
.proxy_resolve_end
= RelativeTime(100);
543 load_timing_deltas
.dns_start
= RelativeTime(-3000000);
544 load_timing_deltas
.dns_end
= RelativeTime(-2000000);
545 load_timing_deltas
.connect_start
= RelativeTime(-1000000);
546 load_timing_deltas
.ssl_start
= RelativeTime(0);
547 load_timing_deltas
.connect_end
= RelativeTime(100);
548 load_timing_deltas
.send_start
= RelativeTime(100);
549 load_timing_deltas
.send_end
= RelativeTime(200);
550 load_timing_deltas
.receive_headers_end
= RelativeTime(300);
552 TimingDeltas navigation_deltas
;
553 RunTest(load_timing_deltas
, &navigation_deltas
);
555 // Connect times should all be the same as proxy_end, which is also the
556 // same as send_start.
557 EXPECT_EQ(navigation_deltas
.dns_start
.GetDelta(),
558 navigation_deltas
.dns_end
.GetDelta());
559 EXPECT_EQ(navigation_deltas
.dns_start
.GetDelta(),
560 navigation_deltas
.connect_start
.GetDelta());
561 EXPECT_EQ(navigation_deltas
.dns_start
.GetDelta(),
562 navigation_deltas
.ssl_start
.GetDelta());
563 EXPECT_EQ(navigation_deltas
.dns_start
.GetDelta(),
564 navigation_deltas
.connect_end
.GetDelta());
565 EXPECT_EQ(navigation_deltas
.dns_start
.GetDelta(),
566 navigation_deltas
.send_start
.GetDelta());
568 EXPECT_LT(navigation_deltas
.send_start
.GetDelta(),
569 navigation_deltas
.receive_headers_end
.GetDelta());
570 EXPECT_LT(navigation_deltas
.send_start
.GetDelta(),
571 navigation_deltas
.receive_headers_end
.GetDelta());
574 // Integration test with a real network response.
575 IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest
, Integration
) {
576 ASSERT_TRUE(test_server()->Start());
577 TimingDeltas navigation_deltas
;
578 RunTestWithUrl(test_server()->GetURL("chunked?waitBeforeHeaders=100"),
581 // Due to potential roundoff issues, never check exact differences.
582 EXPECT_LE(navigation_deltas
.dns_start
.GetDelta(),
583 navigation_deltas
.dns_end
.GetDelta());
584 EXPECT_LE(navigation_deltas
.dns_end
.GetDelta(),
585 navigation_deltas
.connect_start
.GetDelta());
586 EXPECT_LE(navigation_deltas
.connect_start
.GetDelta(),
587 navigation_deltas
.connect_end
.GetDelta());
588 EXPECT_LE(navigation_deltas
.connect_end
.GetDelta(),
589 navigation_deltas
.send_start
.GetDelta());
590 // The only times that are guaranteed to be distinct are send_start and
591 // received_headers_end.
592 EXPECT_LT(navigation_deltas
.send_start
.GetDelta(),
593 navigation_deltas
.receive_headers_end
.GetDelta());
595 EXPECT_TRUE(navigation_deltas
.ssl_start
.is_null());