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