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