Home | History | Annotate | Download | only in net
      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.
     55   RelativeTime() : is_null_(true) {
     56   }
     57 
     58   // Constructor for non-null RelativeTimes.
     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.
     65   base::TimeTicks ToTimeTicks(base::TimeTicks base_time) const {
     66     if (is_null_)
     67       return base::TimeTicks();
     68     return base_time + delta_;
     69   }
     70 
     71   bool is_null() const { return is_null_; }
     72 
     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_);
     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:
    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:
    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 
    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()) {
    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.
    202   virtual ~MockUrlRequestJobWithTiming() {}
    203 
    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:
    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 
    228   virtual ~TestProtocolHandler() {
    229     EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
    230   }
    231 
    232   // Registers |this| with the URLRequestFilter, which takes ownership of it.
    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|.
    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:
    249   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:
    270   LoadTimingBrowserTest() {
    271   }
    272 
    273   virtual ~LoadTimingBrowserTest() {
    274   }
    275 
    276   // Navigates to |url| and writes the resulting navigation timings to
    277   // |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.
    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.
    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.
    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.
    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.
    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.
    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.
    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.
    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.
    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).
    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.
    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