passive_log_collector_unittest.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1// Copyright (c) 2010 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 "chrome/browser/net/passive_log_collector.h" 6 7#include "base/compiler_specific.h" 8#include "base/format_macros.h" 9#include "base/string_util.h" 10#include "net/url_request/url_request_netlog_params.h" 11#include "testing/gtest/include/gtest/gtest.h" 12 13namespace { 14 15typedef PassiveLogCollector::RequestTracker RequestTracker; 16typedef PassiveLogCollector::SourceInfoList SourceInfoList; 17typedef PassiveLogCollector::SocketTracker SocketTracker; 18using net::NetLog; 19 20const NetLog::SourceType kSourceType = NetLog::SOURCE_NONE; 21 22PassiveLogCollector::Entry MakeStartLogEntryWithURL(int source_id, 23 const std::string& url) { 24 return PassiveLogCollector::Entry( 25 0, 26 NetLog::TYPE_URL_REQUEST_START_JOB, 27 base::TimeTicks(), 28 NetLog::Source(kSourceType, source_id), 29 NetLog::PHASE_BEGIN, 30 new URLRequestStartEventParameters(GURL(url), "GET", 0, net::LOW)); 31} 32 33PassiveLogCollector::Entry MakeStartLogEntry(int source_id) { 34 return MakeStartLogEntryWithURL(source_id, 35 StringPrintf("http://req%d", source_id)); 36} 37 38PassiveLogCollector::Entry MakeEndLogEntry(int source_id) { 39 return PassiveLogCollector::Entry( 40 0, 41 NetLog::TYPE_REQUEST_ALIVE, 42 base::TimeTicks(), 43 NetLog::Source(kSourceType, source_id), 44 NetLog::PHASE_END, 45 NULL); 46} 47 48void AddStartURLRequestEntries(PassiveLogCollector* collector, uint32 id) { 49 collector->OnAddEntry(NetLog::TYPE_REQUEST_ALIVE, base::TimeTicks(), 50 NetLog::Source(NetLog::SOURCE_URL_REQUEST, id), 51 NetLog::PHASE_BEGIN, NULL); 52 collector->OnAddEntry(NetLog::TYPE_URL_REQUEST_START_JOB, base::TimeTicks(), 53 NetLog::Source(NetLog::SOURCE_URL_REQUEST, id), 54 NetLog::PHASE_BEGIN, new URLRequestStartEventParameters( 55 GURL(StringPrintf("http://req%d", id)), "GET", 0, 56 net::LOW)); 57} 58 59void AddEndURLRequestEntries(PassiveLogCollector* collector, uint32 id) { 60 collector->OnAddEntry(NetLog::TYPE_REQUEST_ALIVE, base::TimeTicks(), 61 NetLog::Source(NetLog::SOURCE_URL_REQUEST, id), 62 NetLog::PHASE_END, NULL); 63} 64 65std::string GetStringParam(const PassiveLogCollector::Entry& entry) { 66 return static_cast<net::NetLogStringParameter*>( 67 entry.params.get())->value(); 68} 69 70bool OrderBySourceID(const PassiveLogCollector::SourceInfo& a, 71 const PassiveLogCollector::SourceInfo& b) { 72 return a.source_id < b.source_id; 73} 74 75SourceInfoList GetLiveSources( 76 const PassiveLogCollector::SourceTracker& tracker) { 77 SourceInfoList result = tracker.GetAllDeadOrAliveSources(true); 78 std::sort(result.begin(), result.end(), &OrderBySourceID); 79 return result; 80} 81 82SourceInfoList GetDeadSources( 83 const PassiveLogCollector::SourceTracker& tracker) { 84 SourceInfoList result = tracker.GetAllDeadOrAliveSources(false); 85 std::sort(result.begin(), result.end(), &OrderBySourceID); 86 return result; 87} 88 89static const int kMaxNumLoadLogEntries = 1; 90 91} // namespace 92 93// Test that once the tracker contains a total maximum amount of data 94// (graveyard + live requests), it resets itself to avoid growing unbounded. 95TEST(RequestTrackerTest, DropsAfterMaximumSize) { 96 RequestTracker tracker(NULL); 97 98 // Fill the source tracker with as many sources as it can hold. 99 for (size_t i = 0; i < RequestTracker::kMaxNumSources; ++i) 100 tracker.OnAddEntry(MakeStartLogEntry(i)); 101 102 EXPECT_EQ(RequestTracker::kMaxNumSources, GetLiveSources(tracker).size()); 103 104 // Add 1 more -- this should cause it to exceed its expected peak, and 105 // therefore reset all of its data. 106 tracker.OnAddEntry( 107 MakeStartLogEntry(1 + RequestTracker::kMaxNumSources)); 108 109 EXPECT_EQ(1u, GetLiveSources(tracker).size()); 110} 111 112TEST(RequestTrackerTest, BasicBounded) { 113 RequestTracker tracker(NULL); 114 EXPECT_EQ(0u, GetLiveSources(tracker).size()); 115 EXPECT_EQ(0u, GetDeadSources(tracker).size()); 116 117 tracker.OnAddEntry(MakeStartLogEntry(1)); 118 tracker.OnAddEntry(MakeStartLogEntry(2)); 119 tracker.OnAddEntry(MakeStartLogEntry(3)); 120 tracker.OnAddEntry(MakeStartLogEntry(4)); 121 tracker.OnAddEntry(MakeStartLogEntry(5)); 122 123 SourceInfoList live_reqs = GetLiveSources(tracker); 124 125 ASSERT_EQ(5u, live_reqs.size()); 126 EXPECT_EQ("http://req1/", live_reqs[0].GetURL()); 127 EXPECT_EQ("http://req2/", live_reqs[1].GetURL()); 128 EXPECT_EQ("http://req3/", live_reqs[2].GetURL()); 129 EXPECT_EQ("http://req4/", live_reqs[3].GetURL()); 130 EXPECT_EQ("http://req5/", live_reqs[4].GetURL()); 131 132 tracker.OnAddEntry(MakeEndLogEntry(1)); 133 tracker.OnAddEntry(MakeEndLogEntry(5)); 134 tracker.OnAddEntry(MakeEndLogEntry(3)); 135 136 ASSERT_EQ(3u, GetDeadSources(tracker).size()); 137 138 live_reqs = GetLiveSources(tracker); 139 140 ASSERT_EQ(2u, live_reqs.size()); 141 EXPECT_EQ("http://req2/", live_reqs[0].GetURL()); 142 EXPECT_EQ("http://req4/", live_reqs[1].GetURL()); 143} 144 145TEST(RequestTrackerTest, GraveyardBounded) { 146 RequestTracker tracker(NULL); 147 EXPECT_EQ(0u, GetLiveSources(tracker).size()); 148 EXPECT_EQ(0u, GetDeadSources(tracker).size()); 149 150 // Add twice as many requests as will fit in the graveyard. 151 for (size_t i = 0; i < RequestTracker::kMaxGraveyardSize * 2; ++i) { 152 tracker.OnAddEntry(MakeStartLogEntry(i)); 153 tracker.OnAddEntry(MakeEndLogEntry(i)); 154 } 155 156 EXPECT_EQ(0u, GetLiveSources(tracker).size()); 157 158 // Check that only the last |kMaxGraveyardSize| requests are in-memory. 159 160 SourceInfoList recent = GetDeadSources(tracker); 161 162 ASSERT_EQ(RequestTracker::kMaxGraveyardSize, recent.size()); 163 164 for (size_t i = 0; i < RequestTracker::kMaxGraveyardSize; ++i) { 165 size_t req_number = i + RequestTracker::kMaxGraveyardSize; 166 std::string url = StringPrintf("http://req%" PRIuS "/", req_number); 167 EXPECT_EQ(url, recent[i].GetURL()); 168 } 169} 170 171// Check that we exclude "chrome://" URLs from being saved into the recent 172// requests list (graveyard). 173TEST(RequestTrackerTest, GraveyardIsFiltered) { 174 RequestTracker tracker(NULL); 175 176 // This will be excluded. 177 std::string url1 = "chrome://dontcare/"; 178 tracker.OnAddEntry(MakeStartLogEntryWithURL(1, url1)); 179 tracker.OnAddEntry(MakeEndLogEntry(1)); 180 181 // This will be be added to graveyard. 182 std::string url2 = "chrome2://dontcare/"; 183 tracker.OnAddEntry(MakeStartLogEntryWithURL(2, url2)); 184 tracker.OnAddEntry(MakeEndLogEntry(2)); 185 186 // This will be be added to graveyard. 187 std::string url3 = "http://foo/"; 188 tracker.OnAddEntry(MakeStartLogEntryWithURL(3, url3)); 189 tracker.OnAddEntry(MakeEndLogEntry(3)); 190 191 ASSERT_EQ(2u, GetDeadSources(tracker).size()); 192 EXPECT_EQ(url2, GetDeadSources(tracker)[0].GetURL()); 193 EXPECT_EQ(url3, GetDeadSources(tracker)[1].GetURL()); 194} 195 196TEST(SpdySessionTracker, MovesToGraveyard) { 197 PassiveLogCollector::SpdySessionTracker tracker; 198 EXPECT_EQ(0u, GetLiveSources(tracker).size()); 199 EXPECT_EQ(0u, GetDeadSources(tracker).size()); 200 201 PassiveLogCollector::Entry begin( 202 0u, 203 NetLog::TYPE_SPDY_SESSION, 204 base::TimeTicks(), 205 NetLog::Source(NetLog::SOURCE_SPDY_SESSION, 1), 206 NetLog::PHASE_BEGIN, 207 NULL); 208 209 tracker.OnAddEntry(begin); 210 EXPECT_EQ(1u, GetLiveSources(tracker).size()); 211 EXPECT_EQ(0u, GetDeadSources(tracker).size()); 212 213 PassiveLogCollector::Entry end( 214 0u, 215 NetLog::TYPE_SPDY_SESSION, 216 base::TimeTicks(), 217 NetLog::Source(NetLog::SOURCE_SPDY_SESSION, 1), 218 NetLog::PHASE_END, 219 NULL); 220 221 tracker.OnAddEntry(end); 222 EXPECT_EQ(0u, GetLiveSources(tracker).size()); 223 EXPECT_EQ(1u, GetDeadSources(tracker).size()); 224} 225 226// Test that when a SOURCE_SOCKET is connected to a SOURCE_URL_REQUEST 227// (via the TYPE_SOCKET_POOL_BOUND_TO_SOCKET event), it holds a reference 228// to the SOURCE_SOCKET preventing it from getting deleted as long as the 229// SOURCE_URL_REQUEST is still around. 230TEST(PassiveLogCollectorTest, HoldReferenceToDependentSource) { 231 PassiveLogCollector log; 232 233 EXPECT_EQ(0u, GetLiveSources(log.url_request_tracker_).size()); 234 EXPECT_EQ(0u, GetLiveSources(log.socket_tracker_).size()); 235 236 uint32 next_id = 0; 237 NetLog::Source socket_source(NetLog::SOURCE_SOCKET, next_id++); 238 NetLog::Source url_request_source(NetLog::SOURCE_URL_REQUEST, next_id++); 239 240 // Start a SOURCE_SOCKET. 241 log.OnAddEntry(NetLog::TYPE_SOCKET_ALIVE, 242 base::TimeTicks(), 243 socket_source, 244 NetLog::PHASE_BEGIN, 245 NULL); 246 247 EXPECT_EQ(0u, GetLiveSources(log.url_request_tracker_).size()); 248 EXPECT_EQ(1u, GetLiveSources(log.socket_tracker_).size()); 249 250 // Start a SOURCE_URL_REQUEST. 251 log.OnAddEntry(NetLog::TYPE_REQUEST_ALIVE, 252 base::TimeTicks(), 253 url_request_source, 254 NetLog::PHASE_BEGIN, 255 NULL); 256 257 // Check that there is no association between the SOURCE_URL_REQUEST and the 258 // SOURCE_SOCKET yet. 259 ASSERT_EQ(1u, GetLiveSources(log.url_request_tracker_).size()); 260 { 261 PassiveLogCollector::SourceInfo info = 262 GetLiveSources(log.url_request_tracker_)[0]; 263 EXPECT_EQ(0, info.reference_count); 264 EXPECT_EQ(0u, info.dependencies.size()); 265 } 266 ASSERT_EQ(1u, GetLiveSources(log.socket_tracker_).size()); 267 { 268 PassiveLogCollector::SourceInfo info = 269 GetLiveSources(log.socket_tracker_)[0]; 270 EXPECT_EQ(0, info.reference_count); 271 EXPECT_EQ(0u, info.dependencies.size()); 272 } 273 274 // Associate the SOURCE_SOCKET with the SOURCE_URL_REQUEST. 275 log.OnAddEntry(NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET, 276 base::TimeTicks(), 277 url_request_source, 278 NetLog::PHASE_NONE, 279 new net::NetLogSourceParameter("x", socket_source)); 280 281 // Check that an associate was made -- the SOURCE_URL_REQUEST should have 282 // added a reference to the SOURCE_SOCKET. 283 ASSERT_EQ(1u, GetLiveSources(log.url_request_tracker_).size()); 284 { 285 PassiveLogCollector::SourceInfo info = 286 GetLiveSources(log.url_request_tracker_)[0]; 287 EXPECT_EQ(0, info.reference_count); 288 EXPECT_EQ(1u, info.dependencies.size()); 289 EXPECT_EQ(socket_source.id, info.dependencies[0].id); 290 } 291 ASSERT_EQ(1u, GetLiveSources(log.socket_tracker_).size()); 292 { 293 PassiveLogCollector::SourceInfo info = 294 GetLiveSources(log.socket_tracker_)[0]; 295 EXPECT_EQ(1, info.reference_count); 296 EXPECT_EQ(0u, info.dependencies.size()); 297 } 298 299 // Now end both |source_socket| and |source_url_request|. This sends them 300 // to deletion queue, and they will be deleted once space runs out. 301 302 log.OnAddEntry(NetLog::TYPE_REQUEST_ALIVE, 303 base::TimeTicks(), 304 url_request_source, 305 NetLog::PHASE_END, 306 NULL); 307 308 log.OnAddEntry(NetLog::TYPE_SOCKET_ALIVE, 309 base::TimeTicks(), 310 socket_source, 311 NetLog::PHASE_END, 312 NULL); 313 314 // Verify that both sources are in fact dead, and that |source_url_request| 315 // still holds a reference to |source_socket|. 316 ASSERT_EQ(0u, GetLiveSources(log.url_request_tracker_).size()); 317 ASSERT_EQ(1u, GetDeadSources(log.url_request_tracker_).size()); 318 { 319 PassiveLogCollector::SourceInfo info = 320 GetDeadSources(log.url_request_tracker_)[0]; 321 EXPECT_EQ(0, info.reference_count); 322 EXPECT_EQ(1u, info.dependencies.size()); 323 EXPECT_EQ(socket_source.id, info.dependencies[0].id); 324 } 325 EXPECT_EQ(0u, GetLiveSources(log.socket_tracker_).size()); 326 ASSERT_EQ(1u, GetDeadSources(log.socket_tracker_).size()); 327 { 328 PassiveLogCollector::SourceInfo info = 329 GetDeadSources(log.socket_tracker_)[0]; 330 EXPECT_EQ(1, info.reference_count); 331 EXPECT_EQ(0u, info.dependencies.size()); 332 } 333 334 // Cycle through a bunch of SOURCE_SOCKET -- if it were not referenced, this 335 // loop will have deleted it. 336 for (size_t i = 0; i < SocketTracker::kMaxGraveyardSize; ++i) { 337 log.OnAddEntry(NetLog::TYPE_SOCKET_ALIVE, 338 base::TimeTicks(), 339 NetLog::Source(NetLog::SOURCE_SOCKET, next_id++), 340 NetLog::PHASE_END, 341 NULL); 342 } 343 344 EXPECT_EQ(0u, GetLiveSources(log.socket_tracker_).size()); 345 ASSERT_EQ(SocketTracker::kMaxGraveyardSize + 1, 346 GetDeadSources(log.socket_tracker_).size()); 347 { 348 PassiveLogCollector::SourceInfo info = 349 GetDeadSources(log.socket_tracker_)[0]; 350 EXPECT_EQ(socket_source.id, info.source_id); 351 EXPECT_EQ(1, info.reference_count); 352 EXPECT_EQ(0u, info.dependencies.size()); 353 } 354 355 // Cycle through a bunch of SOURCE_URL_REQUEST -- this will cause 356 // |source_url_request| to be freed, which in turn should release the final 357 // reference to |source_socket| cause it to be freed as well. 358 for (size_t i = 0; i < RequestTracker::kMaxGraveyardSize; ++i) { 359 log.OnAddEntry(NetLog::TYPE_REQUEST_ALIVE, 360 base::TimeTicks(), 361 NetLog::Source(NetLog::SOURCE_URL_REQUEST, next_id++), 362 NetLog::PHASE_END, 363 NULL); 364 } 365 366 EXPECT_EQ(0u, GetLiveSources(log.url_request_tracker_).size()); 367 EXPECT_EQ(RequestTracker::kMaxGraveyardSize, 368 GetDeadSources(log.url_request_tracker_).size()); 369 370 EXPECT_EQ(0u, GetLiveSources(log.socket_tracker_).size()); 371 EXPECT_EQ(SocketTracker::kMaxGraveyardSize, 372 GetDeadSources(log.socket_tracker_).size()); 373} 374 375// Have a URL_REQUEST hold a reference to a SOCKET. Then cause the SOCKET to 376// get evicted (by exceeding maximum sources limit). Now the URL_REQUEST is 377// referencing a non-existant SOCKET. Lastly, evict the URL_REQUEST so it 378// tries to drop all of its references. Make sure that in releasing its 379// non-existant reference it doesn't trip any DCHECKs. 380TEST(PassiveLogCollectorTest, HoldReferenceToDeletedSource) { 381 PassiveLogCollector log; 382 383 EXPECT_EQ(0u, GetLiveSources(log.url_request_tracker_).size()); 384 EXPECT_EQ(0u, GetLiveSources(log.socket_tracker_).size()); 385 386 uint32 next_id = 0; 387 NetLog::Source socket_source(NetLog::SOURCE_SOCKET, next_id++); 388 NetLog::Source url_request_source(NetLog::SOURCE_URL_REQUEST, next_id++); 389 390 // Start a SOURCE_SOCKET. 391 log.OnAddEntry(NetLog::TYPE_SOCKET_ALIVE, 392 base::TimeTicks(), 393 socket_source, 394 NetLog::PHASE_BEGIN, 395 NULL); 396 397 EXPECT_EQ(0u, GetLiveSources(log.url_request_tracker_).size()); 398 EXPECT_EQ(1u, GetLiveSources(log.socket_tracker_).size()); 399 400 // Start a SOURCE_URL_REQUEST. 401 log.OnAddEntry(NetLog::TYPE_REQUEST_ALIVE, 402 base::TimeTicks(), 403 url_request_source, 404 NetLog::PHASE_BEGIN, 405 NULL); 406 407 // Associate the SOURCE_SOCKET with the SOURCE_URL_REQUEST. 408 log.OnAddEntry(NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET, 409 base::TimeTicks(), 410 url_request_source, 411 NetLog::PHASE_NONE, 412 new net::NetLogSourceParameter("x", socket_source)); 413 414 // Check that an associate was made -- the SOURCE_URL_REQUEST should have 415 // added a reference to the SOURCE_SOCKET. 416 ASSERT_EQ(1u, GetLiveSources(log.url_request_tracker_).size()); 417 { 418 PassiveLogCollector::SourceInfo info = 419 GetLiveSources(log.url_request_tracker_)[0]; 420 EXPECT_EQ(0, info.reference_count); 421 EXPECT_EQ(1u, info.dependencies.size()); 422 EXPECT_EQ(socket_source.id, info.dependencies[0].id); 423 } 424 ASSERT_EQ(1u, GetLiveSources(log.socket_tracker_).size()); 425 { 426 PassiveLogCollector::SourceInfo info = 427 GetLiveSources(log.socket_tracker_)[0]; 428 EXPECT_EQ(1, info.reference_count); 429 EXPECT_EQ(0u, info.dependencies.size()); 430 } 431 432 // Add lots of sources to the socket tracker. This is just enough to cause 433 // the tracker to reach its peak, and reset all of its data as a safeguard. 434 for (size_t i = 0; i < SocketTracker::kMaxNumSources; ++i) { 435 log.OnAddEntry(NetLog::TYPE_SOCKET_ALIVE, 436 base::TimeTicks(), 437 NetLog::Source(NetLog::SOURCE_SOCKET, next_id++), 438 NetLog::PHASE_BEGIN, 439 NULL); 440 } 441 ASSERT_EQ(1u, GetLiveSources(log.socket_tracker_).size()); 442 443 // End the original request. Then saturate the graveyard with enough other 444 // requests to cause it to be deleted. Once that source is deleted, it will 445 // try to give up its reference to the SOCKET. However that socket_id no 446 // longer exists -- should not DCHECK(). 447 log.OnAddEntry(NetLog::TYPE_REQUEST_ALIVE, 448 base::TimeTicks(), 449 url_request_source, 450 NetLog::PHASE_END, 451 NULL); 452 for (size_t i = 0; i < RequestTracker::kMaxGraveyardSize; ++i) { 453 log.OnAddEntry(NetLog::TYPE_REQUEST_ALIVE, 454 base::TimeTicks(), 455 NetLog::Source(NetLog::SOURCE_URL_REQUEST, next_id++), 456 NetLog::PHASE_END, 457 NULL); 458 } 459 EXPECT_EQ(RequestTracker::kMaxGraveyardSize, 460 GetDeadSources(log.url_request_tracker_).size()); 461} 462 463