• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include <string>
6 
7 #include "base/basictypes.h"
8 #include "base/bind.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_job_factory.h"
29 #include "url/gurl.h"
30 
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.
35 
36 using content::BrowserThread;
37 
38 namespace {
39 
40 const char kTestDomain[] = "test.com";
41 const char kTestUrl[] = "http://test.com/";
42 
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.
47 //
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.
52 class RelativeTime {
53  public:
54   // Constructor for null RelativeTimes.
RelativeTime()55   RelativeTime() : is_null_(true) {
56   }
57 
58   // Constructor for non-null RelativeTimes.
RelativeTime(int delta_ms)59   explicit RelativeTime(int delta_ms)
60       : is_null_(false),
61         delta_(base::TimeDelta::FromMilliseconds(delta_ms)) {
62   }
63 
64   // Given a base time, returns the TimeTicks |this| identifies.
ToTimeTicks(base::TimeTicks base_time) const65   base::TimeTicks ToTimeTicks(base::TimeTicks base_time) const {
66     if (is_null_)
67       return base::TimeTicks();
68     return base_time + delta_;
69   }
70 
is_null() const71   bool is_null() const { return is_null_; }
72 
GetDelta() const73   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_);
77     return delta_;
78   }
79 
80  private:
81   bool is_null_;
82 
83   // Must be 0 when |is_null| is true.
84   base::TimeDelta delta_;
85 
86   // This class is copyable and assignable.
87 };
88 
89 // Structure used for both setting the LoadTimingInfo used by mock requests
90 // and for times retrieved from the renderer process.
91 //
92 // Times used for mock requests are all expressed as TimeDeltas relative to
93 // when the Job starts.  Null RelativeTimes correspond to null TimeTicks().
94 //
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).
99 struct TimingDeltas {
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;
109 
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;
113 };
114 
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 {
118  public:
MockUrlRequestJobWithTiming(net::URLRequest * request,net::NetworkDelegate * network_delegate,const base::FilePath & path,const TimingDeltas & load_timing_deltas)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) {}
130 
131   // net::URLRequestFileJob implementation:
Start()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);
140     }
141 
142     base::MessageLoop::current()->PostDelayedTask(
143         FROM_HERE,
144         base::Bind(&MockUrlRequestJobWithTiming::DelayedStart,
145                    weak_factory_.GetWeakPtr()),
146         time_to_wait);
147   }
148 
GetLoadTimingInfo(net::LoadTimingInfo * load_timing_info) const149   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()) {
154       EXPECT_LE(
155           start_time_ + load_timing_deltas_.receive_headers_end.GetDelta(),
156           base::TimeTicks::Now());
157     }
158 
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;
166     }
167 
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_);
172 
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_);
183 
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;
190     }
191 
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_);
198   }
199 
200  private:
201   // Parent class is reference counted, so need to have a private destructor.
~MockUrlRequestJobWithTiming()202   virtual ~MockUrlRequestJobWithTiming() {}
203 
DelayedStart()204   void DelayedStart() {
205     net::URLRequestFileJob::Start();
206   }
207 
208   // Load times to use, relative to |start_time_|.
209   const TimingDeltas load_timing_deltas_;
210   base::TimeTicks start_time_;
211 
212   base::WeakPtrFactory<MockUrlRequestJobWithTiming> weak_factory_;
213 
214   DISALLOW_COPY_AND_ASSIGN(MockUrlRequestJobWithTiming);
215 };
216 
217 // A protocol handler that returns mock URLRequestJobs that return the specified
218 // file with the given timings.  Constructed on the UI thread, but after that,
219 // lives and is destroyed on the IO thread.
220 class TestProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler {
221  public:
TestProtocolHandler(const base::FilePath & path,const TimingDeltas & load_timing_deltas)222   TestProtocolHandler(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));
226   }
227 
~TestProtocolHandler()228   virtual ~TestProtocolHandler() {
229     EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
230   }
231 
232   // Registers |this| with the URLRequestFilter, which takes ownership of it.
Register()233   void Register() {
234     EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
235     net::URLRequestFilter::GetInstance()->AddHostnameProtocolHandler(
236         "http", kTestDomain,
237         scoped_ptr<net::URLRequestJobFactory::ProtocolHandler>(this));
238   }
239 
240   // Unregisters |this| with the URLRequestFilter, which should then delete
241   // |this|.
Unregister()242   void Unregister() {
243     EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
244     net::URLRequestFilter::GetInstance()->RemoveHostnameHandler(
245         "http", kTestDomain);
246   }
247 
248   // net::URLRequestJobFactory::ProtocolHandler implementation:
MaybeCreateJob(net::URLRequest * request,net::NetworkDelegate * network_delegate) const249   virtual net::URLRequestJob* MaybeCreateJob(
250       net::URLRequest* request,
251       net::NetworkDelegate* network_delegate) const OVERRIDE {
252     EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
253 
254     return new MockUrlRequestJobWithTiming(request, network_delegate, path_,
255                                            load_timing_deltas_);
256   }
257 
258  private:
259   // Path of the file to use as the response body.
260   const base::FilePath path_;
261 
262   // Load times for each request to use, relative to when the Job starts.
263   const TimingDeltas load_timing_deltas_;
264 
265   DISALLOW_COPY_AND_ASSIGN(TestProtocolHandler);
266 };
267 
268 class LoadTimingBrowserTest : public InProcessBrowserTest {
269  public:
LoadTimingBrowserTest()270   LoadTimingBrowserTest() {
271   }
272 
~LoadTimingBrowserTest()273   virtual ~LoadTimingBrowserTest() {
274   }
275 
276   // Navigates to |url| and writes the resulting navigation timings to
277   // |navigation_deltas|.
RunTestWithUrl(const GURL & url,TimingDeltas * navigation_deltas)278   void RunTestWithUrl(const GURL& url, TimingDeltas* navigation_deltas) {
279     ui_test_utils::NavigateToURL(browser(), url);
280     GetResultDeltas(navigation_deltas);
281   }
282 
283   // Navigates to a url that returns the timings indicated by
284   // |load_timing_deltas| and writes the resulting navigation timings to
285   // |navigation_deltas|.  Uses a generic test page.
RunTest(const TimingDeltas & load_timing_deltas,TimingDeltas * navigation_deltas)286   void RunTest(const TimingDeltas& load_timing_deltas,
287                TimingDeltas* navigation_deltas) {
288     // None of the tests care about the contents of the test page.  Just do
289     // this here because PathService has thread restrictions on some platforms.
290     base::FilePath path;
291     PathService::Get(chrome::DIR_TEST_DATA, &path);
292     path = path.AppendASCII("title1.html");
293 
294     // Create and register protocol handler.
295     TestProtocolHandler* protocol_handler =
296         new TestProtocolHandler(path, load_timing_deltas);
297     BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
298                             base::Bind(&TestProtocolHandler::Register,
299                                        base::Unretained(protocol_handler)));
300 
301     // Navigate to the page.
302     RunTestWithUrl(GURL(kTestUrl), navigation_deltas);
303 
304     // Once navigation is complete, unregister the protocol handler.
305     BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
306                             base::Bind(&TestProtocolHandler::Unregister,
307                                         base::Unretained(protocol_handler)));
308   }
309 
310  private:
311   // Reads applicable times from performance.timing and writes them to
312   // |navigation_deltas|.  Proxy times and send end cannot be read from the
313   // Navigation Timing API, so those are all left as null.
GetResultDeltas(TimingDeltas * navigation_deltas)314   void GetResultDeltas(TimingDeltas* navigation_deltas) {
315     *navigation_deltas = TimingDeltas();
316 
317     navigation_deltas->dns_start = GetResultDelta("domainLookupStart");
318     navigation_deltas->dns_end = GetResultDelta("domainLookupEnd");
319     navigation_deltas->connect_start = GetResultDelta("connectStart");
320     navigation_deltas->connect_end = GetResultDelta("connectEnd");
321     navigation_deltas->send_start = GetResultDelta("requestStart");
322     navigation_deltas->receive_headers_end = GetResultDelta("responseStart");
323 
324     // Unlike the above times, secureConnectionStart will be zero when not
325     // applicable.  In that case, leave ssl_start as null.
326     bool ssl_start_zero = false;
327     ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
328                     browser()->tab_strip_model()->GetActiveWebContents(),
329                     "window.domAutomationController.send("
330                         "performance.timing.secureConnectionStart == 0);",
331                     &ssl_start_zero));
332     if (!ssl_start_zero)
333       navigation_deltas->ssl_start = GetResultDelta("secureConnectionStart");
334 
335     // Simple sanity checks.  Make sure times that correspond to LoadTimingInfo
336     // occur between fetchStart and loadEventEnd.  Relationships between
337     // intervening times are handled by the test bodies.
338 
339     RelativeTime fetch_start = GetResultDelta("fetchStart");
340     // While the input dns_start is sometimes null, when read from the
341     // NavigationTiming API, it's always non-null.
342     EXPECT_LE(fetch_start.GetDelta(), navigation_deltas->dns_start.GetDelta());
343 
344     RelativeTime load_event_end = GetResultDelta("loadEventEnd");
345     EXPECT_LE(navigation_deltas->receive_headers_end.GetDelta(),
346               load_event_end.GetDelta());
347   }
348 
349   // Returns the time between performance.timing.fetchStart and the time with
350   // the specified name.  This time must be non-negative.
GetResultDelta(const std::string & name)351   RelativeTime GetResultDelta(const std::string& name) {
352     int time_ms = 0;
353     std::string command(base::StringPrintf(
354         "window.domAutomationController.send("
355             "performance.timing.%s - performance.timing.fetchStart);",
356         name.c_str()));
357     EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
358                     browser()->tab_strip_model()->GetActiveWebContents(),
359                     command.c_str(),
360                     &time_ms));
361 
362     // Basic sanity check.
363     EXPECT_GE(time_ms, 0);
364 
365     return RelativeTime(time_ms);
366   }
367 };
368 
369 // Test case when no times are given, except the request start times.  This
370 // happens with FTP, cached responses, responses handled by something other than
371 // the network stack, RedirectJobs, HSTs, etc.
IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest,NoTimes)372 IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest, NoTimes) {
373   TimingDeltas load_timing_deltas;
374   TimingDeltas navigation_deltas;
375   RunTest(load_timing_deltas, &navigation_deltas);
376 
377   // When there are no times, all read times should be the same as fetchStart,
378   // except SSL start, which should be 0.
379   EXPECT_EQ(base::TimeDelta(), navigation_deltas.dns_start.GetDelta());
380   EXPECT_EQ(base::TimeDelta(), navigation_deltas.dns_end.GetDelta());
381   EXPECT_EQ(base::TimeDelta(), navigation_deltas.connect_start.GetDelta());
382   EXPECT_EQ(base::TimeDelta(), navigation_deltas.connect_end.GetDelta());
383   EXPECT_EQ(base::TimeDelta(), navigation_deltas.send_start.GetDelta());
384   EXPECT_EQ(base::TimeDelta(),
385             navigation_deltas.receive_headers_end.GetDelta());
386 
387   EXPECT_TRUE(navigation_deltas.ssl_start.is_null());
388 }
389 
390 // Standard case - new socket, no PAC, no preconnect, no SSL.
IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest,Basic)391 IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest, Basic) {
392   TimingDeltas load_timing_deltas;
393   load_timing_deltas.dns_start = RelativeTime(0);
394   load_timing_deltas.dns_end = RelativeTime(100);
395   load_timing_deltas.connect_start = RelativeTime(200);
396   load_timing_deltas.connect_end = RelativeTime(300);
397   load_timing_deltas.send_start = RelativeTime(400);
398   load_timing_deltas.send_end = RelativeTime(500);
399   load_timing_deltas.receive_headers_end = RelativeTime(600);
400 
401   TimingDeltas navigation_deltas;
402   RunTest(load_timing_deltas, &navigation_deltas);
403 
404   // Due to potential roundoff issues, never check exact differences.
405   EXPECT_LT(navigation_deltas.dns_start.GetDelta(),
406             navigation_deltas.dns_end.GetDelta());
407   EXPECT_LT(navigation_deltas.dns_end.GetDelta(),
408             navigation_deltas.connect_start.GetDelta());
409   EXPECT_LT(navigation_deltas.connect_start.GetDelta(),
410             navigation_deltas.connect_end.GetDelta());
411   EXPECT_LT(navigation_deltas.connect_end.GetDelta(),
412             navigation_deltas.send_start.GetDelta());
413   EXPECT_LT(navigation_deltas.send_start.GetDelta(),
414             navigation_deltas.receive_headers_end.GetDelta());
415 
416   EXPECT_TRUE(navigation_deltas.ssl_start.is_null());
417 }
418 
419 // Basic SSL case.
IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest,Ssl)420 IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest, Ssl) {
421   TimingDeltas load_timing_deltas;
422   load_timing_deltas.dns_start = RelativeTime(0);
423   load_timing_deltas.dns_end = RelativeTime(100);
424   load_timing_deltas.connect_start = RelativeTime(200);
425   load_timing_deltas.ssl_start = RelativeTime(300);
426   load_timing_deltas.connect_end = RelativeTime(400);
427   load_timing_deltas.send_start = RelativeTime(500);
428   load_timing_deltas.send_end = RelativeTime(600);
429   load_timing_deltas.receive_headers_end = RelativeTime(700);
430 
431   TimingDeltas navigation_deltas;
432   RunTest(load_timing_deltas, &navigation_deltas);
433 
434   // Due to potential roundoff issues, never check exact differences.
435   EXPECT_LT(navigation_deltas.dns_start.GetDelta(),
436             navigation_deltas.dns_end.GetDelta());
437   EXPECT_LT(navigation_deltas.dns_end.GetDelta(),
438             navigation_deltas.connect_start.GetDelta());
439   EXPECT_LT(navigation_deltas.connect_start.GetDelta(),
440             navigation_deltas.ssl_start.GetDelta());
441   EXPECT_LT(navigation_deltas.ssl_start.GetDelta(),
442             navigation_deltas.connect_end.GetDelta());
443   EXPECT_LT(navigation_deltas.connect_end.GetDelta(),
444             navigation_deltas.send_start.GetDelta());
445   EXPECT_LT(navigation_deltas.send_start.GetDelta(),
446             navigation_deltas.receive_headers_end.GetDelta());
447 }
448 
449 // All times are the same.
IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest,EverythingAtOnce)450 IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest, EverythingAtOnce) {
451   TimingDeltas load_timing_deltas;
452   load_timing_deltas.dns_start = RelativeTime(100);
453   load_timing_deltas.dns_end = RelativeTime(100);
454   load_timing_deltas.connect_start = RelativeTime(100);
455   load_timing_deltas.ssl_start = RelativeTime(100);
456   load_timing_deltas.connect_end = RelativeTime(100);
457   load_timing_deltas.send_start = RelativeTime(100);
458   load_timing_deltas.send_end = RelativeTime(100);
459   load_timing_deltas.receive_headers_end = RelativeTime(100);
460 
461   TimingDeltas navigation_deltas;
462   RunTest(load_timing_deltas, &navigation_deltas);
463 
464   EXPECT_EQ(navigation_deltas.dns_start.GetDelta(),
465             navigation_deltas.dns_end.GetDelta());
466   EXPECT_EQ(navigation_deltas.dns_end.GetDelta(),
467             navigation_deltas.connect_start.GetDelta());
468   EXPECT_EQ(navigation_deltas.connect_start.GetDelta(),
469             navigation_deltas.ssl_start.GetDelta());
470   EXPECT_EQ(navigation_deltas.ssl_start.GetDelta(),
471             navigation_deltas.connect_end.GetDelta());
472   EXPECT_EQ(navigation_deltas.connect_end.GetDelta(),
473             navigation_deltas.send_start.GetDelta());
474   EXPECT_EQ(navigation_deltas.send_start.GetDelta(),
475             navigation_deltas.receive_headers_end.GetDelta());
476 }
477 
478 // Reuse case.
IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest,ReuseSocket)479 IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest, ReuseSocket) {
480   TimingDeltas load_timing_deltas;
481   load_timing_deltas.send_start = RelativeTime(0);
482   load_timing_deltas.send_end = RelativeTime(100);
483   load_timing_deltas.receive_headers_end = RelativeTime(200);
484 
485   TimingDeltas navigation_deltas;
486   RunTest(load_timing_deltas, &navigation_deltas);
487 
488   // Connect times should all be the same as fetchStart.
489   EXPECT_EQ(base::TimeDelta(), navigation_deltas.dns_start.GetDelta());
490   EXPECT_EQ(base::TimeDelta(), navigation_deltas.dns_end.GetDelta());
491   EXPECT_EQ(base::TimeDelta(), navigation_deltas.connect_start.GetDelta());
492   EXPECT_EQ(base::TimeDelta(), navigation_deltas.connect_end.GetDelta());
493 
494   // Connect end may be less than send start, since connect end defaults to
495   // fetchStart, which is often less than request_start.
496   EXPECT_LE(navigation_deltas.connect_end.GetDelta(),
497             navigation_deltas.send_start.GetDelta());
498 
499   EXPECT_LT(navigation_deltas.send_start.GetDelta(),
500             navigation_deltas.receive_headers_end.GetDelta());
501 
502   EXPECT_TRUE(navigation_deltas.ssl_start.is_null());
503 }
504 
505 // Preconnect case.  Connect times are all before the request was started.
IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest,Preconnect)506 IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest, Preconnect) {
507   TimingDeltas load_timing_deltas;
508   load_timing_deltas.dns_start = RelativeTime(-1000300);
509   load_timing_deltas.dns_end = RelativeTime(-1000200);
510   load_timing_deltas.connect_start = RelativeTime(-1000100);
511   load_timing_deltas.connect_end = RelativeTime(-1000000);
512   load_timing_deltas.send_start = RelativeTime(0);
513   load_timing_deltas.send_end = RelativeTime(100);
514   load_timing_deltas.receive_headers_end = RelativeTime(200);
515 
516   TimingDeltas navigation_deltas;
517   RunTest(load_timing_deltas, &navigation_deltas);
518 
519   // Connect times should all be the same as request_start.
520   EXPECT_EQ(navigation_deltas.dns_start.GetDelta(),
521             navigation_deltas.dns_end.GetDelta());
522   EXPECT_EQ(navigation_deltas.dns_start.GetDelta(),
523             navigation_deltas.connect_start.GetDelta());
524   EXPECT_EQ(navigation_deltas.dns_start.GetDelta(),
525             navigation_deltas.connect_end.GetDelta());
526 
527   EXPECT_LE(navigation_deltas.dns_start.GetDelta(),
528             navigation_deltas.send_start.GetDelta());
529 
530   EXPECT_LT(navigation_deltas.send_start.GetDelta(),
531             navigation_deltas.receive_headers_end.GetDelta());
532   EXPECT_LT(navigation_deltas.send_start.GetDelta(),
533             navigation_deltas.receive_headers_end.GetDelta());
534 
535   EXPECT_TRUE(navigation_deltas.ssl_start.is_null());
536 }
537 
538 // Preconnect case with a proxy.  Connect times are all before the proxy lookup
539 // finished (Or at the same time).
IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest,PreconnectProxySsl)540 IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest, PreconnectProxySsl) {
541   TimingDeltas load_timing_deltas;
542   load_timing_deltas.proxy_resolve_start = RelativeTime(0);
543   load_timing_deltas.proxy_resolve_end = RelativeTime(100);
544   load_timing_deltas.dns_start = RelativeTime(-3000000);
545   load_timing_deltas.dns_end = RelativeTime(-2000000);
546   load_timing_deltas.connect_start = RelativeTime(-1000000);
547   load_timing_deltas.ssl_start = RelativeTime(0);
548   load_timing_deltas.connect_end = RelativeTime(100);
549   load_timing_deltas.send_start = RelativeTime(100);
550   load_timing_deltas.send_end = RelativeTime(200);
551   load_timing_deltas.receive_headers_end = RelativeTime(300);
552 
553   TimingDeltas navigation_deltas;
554   RunTest(load_timing_deltas, &navigation_deltas);
555 
556   // Connect times should all be the same as proxy_end, which is also the
557   // same as send_start.
558   EXPECT_EQ(navigation_deltas.dns_start.GetDelta(),
559             navigation_deltas.dns_end.GetDelta());
560   EXPECT_EQ(navigation_deltas.dns_start.GetDelta(),
561             navigation_deltas.connect_start.GetDelta());
562   EXPECT_EQ(navigation_deltas.dns_start.GetDelta(),
563             navigation_deltas.ssl_start.GetDelta());
564   EXPECT_EQ(navigation_deltas.dns_start.GetDelta(),
565             navigation_deltas.connect_end.GetDelta());
566   EXPECT_EQ(navigation_deltas.dns_start.GetDelta(),
567             navigation_deltas.send_start.GetDelta());
568 
569   EXPECT_LT(navigation_deltas.send_start.GetDelta(),
570             navigation_deltas.receive_headers_end.GetDelta());
571   EXPECT_LT(navigation_deltas.send_start.GetDelta(),
572             navigation_deltas.receive_headers_end.GetDelta());
573 }
574 
575 // Integration test with a real network response.
IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest,Integration)576 IN_PROC_BROWSER_TEST_F(LoadTimingBrowserTest, Integration) {
577   ASSERT_TRUE(test_server()->Start());
578   TimingDeltas navigation_deltas;
579   RunTestWithUrl(test_server()->GetURL("chunked?waitBeforeHeaders=100"),
580                  &navigation_deltas);
581 
582   // Due to potential roundoff issues, never check exact differences.
583   EXPECT_LE(navigation_deltas.dns_start.GetDelta(),
584             navigation_deltas.dns_end.GetDelta());
585   EXPECT_LE(navigation_deltas.dns_end.GetDelta(),
586             navigation_deltas.connect_start.GetDelta());
587   EXPECT_LE(navigation_deltas.connect_start.GetDelta(),
588             navigation_deltas.connect_end.GetDelta());
589   EXPECT_LE(navigation_deltas.connect_end.GetDelta(),
590             navigation_deltas.send_start.GetDelta());
591   // The only times that are guaranteed to be distinct are send_start and
592   // received_headers_end.
593   EXPECT_LT(navigation_deltas.send_start.GetDelta(),
594             navigation_deltas.receive_headers_end.GetDelta());
595 
596   EXPECT_TRUE(navigation_deltas.ssl_start.is_null());
597 }
598 
599 }  // namespace
600