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