- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / net / http_pipelining_compatibility_client_unittest.cc
1 // Copyright (c) 2012 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/http_pipelining_compatibility_client.h"
6
7 #include <map>
8 #include <string>
9 #include <vector>
10
11 #include "base/basictypes.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/metrics/histogram.h"
14 #include "base/metrics/histogram_samples.h"
15 #include "base/metrics/statistics_recorder.h"
16 #include "base/run_loop.h"
17 #include "base/stl_util.h"
18 #include "base/strings/stringprintf.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/test/test_browser_thread_bundle.h"
21 #include "net/base/net_errors.h"
22 #include "net/base/test_completion_callback.h"
23 #include "net/test/spawned_test_server/spawned_test_server.h"
24 #include "net/url_request/url_request_context_getter.h"
25 #include "net/url_request/url_request_test_util.h"
26 #include "testing/gmock/include/gmock/gmock.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28
29 using base::HistogramBase;
30 using base::HistogramSamples;
31
32 namespace chrome_browser_net {
33
34 namespace {
35
36 static const char* const kHistogramNames[] = {
37   "NetConnectivity.Pipeline.CanarySuccess",
38   "NetConnectivity.Pipeline.Depth",
39   "NetConnectivity.Pipeline.AllHTTP11",
40   "NetConnectivity.Pipeline.Success",
41   "NetConnectivity.Pipeline.0.NetworkError",
42   "NetConnectivity.Pipeline.0.ResponseCode",
43   "NetConnectivity.Pipeline.0.Status",
44   "NetConnectivity.Pipeline.1.NetworkError",
45   "NetConnectivity.Pipeline.1.ResponseCode",
46   "NetConnectivity.Pipeline.1.Status",
47   "NetConnectivity.Pipeline.2.NetworkError",
48   "NetConnectivity.Pipeline.2.ResponseCode",
49   "NetConnectivity.Pipeline.2.Status",
50 };
51
52 enum HistogramField {
53   FIELD_CANARY,
54   FIELD_DEPTH,
55   FIELD_HTTP_1_1,
56   FIELD_NETWORK_ERROR,
57   FIELD_RESPONSE_CODE,
58   FIELD_STATUS,
59   FIELD_SUCCESS,
60 };
61
62 class MockFactory : public internal::PipelineTestRequest::Factory {
63  public:
64   MOCK_METHOD6(NewRequest, internal::PipelineTestRequest*(
65       int, const std::string&, const RequestInfo&,
66       internal::PipelineTestRequest::Delegate*, net::URLRequestContext*,
67       internal::PipelineTestRequest::Type));
68 };
69
70 class MockRequest : public internal::PipelineTestRequest {
71  public:
72   MOCK_METHOD0(Start, void());
73 };
74
75 using content::BrowserThread;
76 using testing::_;
77 using testing::Field;
78 using testing::Invoke;
79 using testing::Return;
80 using testing::StrEq;
81
82 class HttpPipeliningCompatibilityClientTest : public testing::Test {
83  public:
84   HttpPipeliningCompatibilityClientTest()
85       : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
86         test_server_(net::SpawnedTestServer::TYPE_HTTP,
87                      net::SpawnedTestServer::kLocalhost,
88                      base::FilePath(FILE_PATH_LITERAL(
89                          "chrome/test/data/http_pipelining"))) {
90   }
91
92  protected:
93   virtual void SetUp() OVERRIDE {
94     // Start up a histogram recorder.
95     // TODO(rtenneti): Leaks StatisticsRecorder and will update suppressions.
96     base::StatisticsRecorder::Initialize();
97     ASSERT_TRUE(test_server_.Start());
98     context_ = new net::TestURLRequestContextGetter(
99         BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
100     context_->AddRef();
101
102     for (size_t i = 0; i < arraysize(kHistogramNames); ++i) {
103       const char* name = kHistogramNames[i];
104       scoped_ptr<HistogramSamples> samples = GetHistogram(name);
105       if (samples.get() && samples->TotalCount() > 0) {
106         original_samples_[name] = samples.release();
107       }
108     }
109   }
110
111   virtual void TearDown() OVERRIDE {
112     BrowserThread::ReleaseSoon(BrowserThread::IO, FROM_HERE, context_);
113     base::RunLoop().RunUntilIdle();
114     STLDeleteValues(&original_samples_);
115   }
116
117   void RunTest(
118       std::vector<RequestInfo> requests,
119       HttpPipeliningCompatibilityClient::Options options) {
120     HttpPipeliningCompatibilityClient client(NULL);
121     net::TestCompletionCallback callback;
122     client.Start(test_server_.GetURL(std::string()).spec(),
123                  requests,
124                  options,
125                  callback.callback(),
126                  context_->GetURLRequestContext());
127     callback.WaitForResult();
128   }
129
130   void ExpectHistogramCount(int expected_count,
131                             int expected_value,
132                             HistogramField field) {
133     const char* name;
134
135     switch (field) {
136       case FIELD_CANARY:
137         name = "NetConnectivity.Pipeline.CanarySuccess";
138         break;
139
140       case FIELD_DEPTH:
141         name = "NetConnectivity.Pipeline.Depth";
142         break;
143
144       case FIELD_HTTP_1_1:
145         name = "NetConnectivity.Pipeline.AllHTTP11";
146         break;
147
148       case FIELD_SUCCESS:
149         name = "NetConnectivity.Pipeline.Success";
150         break;
151
152       default:
153         FAIL() << "Unexpected field: " << field;
154     }
155
156     scoped_ptr<HistogramSamples> samples = GetHistogram(name);
157     if (!samples.get())
158       return;
159
160     if (ContainsKey(original_samples_, name)) {
161       samples->Subtract((*original_samples_[name]));
162     }
163
164     EXPECT_EQ(expected_count, samples->TotalCount()) << name;
165     if (expected_count > 0) {
166       EXPECT_EQ(expected_count, samples->GetCount(expected_value)) << name;
167     }
168   }
169
170   void ExpectRequestHistogramCount(int expected_count,
171                                    int expected_value,
172                                    int request_id,
173                                    HistogramField field) {
174     const char* field_str = "";
175     switch (field) {
176       case FIELD_STATUS:
177         field_str = "Status";
178         break;
179
180       case FIELD_NETWORK_ERROR:
181         field_str = "NetworkError";
182         break;
183
184       case FIELD_RESPONSE_CODE:
185         field_str = "ResponseCode";
186         break;
187
188       default:
189         FAIL() << "Unexpected field: " << field;
190     }
191
192     std::string name = base::StringPrintf("NetConnectivity.Pipeline.%d.%s",
193                                           request_id, field_str);
194     scoped_ptr<HistogramSamples> samples = GetHistogram(name.c_str());
195     if (!samples.get())
196       return;
197
198     if (ContainsKey(original_samples_, name)) {
199       samples->Subtract(*(original_samples_[name]));
200     }
201
202     EXPECT_EQ(expected_count, samples->TotalCount()) << name;
203     if (expected_count > 0) {
204       EXPECT_EQ(expected_count, samples->GetCount(expected_value)) << name;
205     }
206   }
207
208   content::TestBrowserThreadBundle thread_bundle_;
209   net::SpawnedTestServer test_server_;
210   net::TestURLRequestContextGetter* context_;
211
212  private:
213   scoped_ptr<HistogramSamples> GetHistogram(const char* name) {
214     scoped_ptr<HistogramSamples> samples;
215     HistogramBase* cached_histogram = NULL;
216     HistogramBase* current_histogram =
217         base::StatisticsRecorder::FindHistogram(name);
218     if (ContainsKey(histograms_, name)) {
219       cached_histogram = histograms_[name];
220     }
221
222     // This is to work around the CACHE_HISTOGRAM_* macros caching the last used
223     // histogram by name. So, even though we throw out the StatisticsRecorder
224     // between tests, the CACHE_HISTOGRAM_* might still write into the old
225     // Histogram if it has the same name as the last run. We keep a cache of the
226     // last used Histogram and then update the cache if it's different than the
227     // current Histogram.
228     if (cached_histogram && current_histogram) {
229       samples = cached_histogram->SnapshotSamples();
230       if (cached_histogram != current_histogram) {
231         samples->Add(*(current_histogram->SnapshotSamples()));
232         histograms_[name] = current_histogram;
233       }
234     } else if (current_histogram) {
235       samples = current_histogram->SnapshotSamples();
236       histograms_[name] = current_histogram;
237     } else if (cached_histogram) {
238       samples = cached_histogram->SnapshotSamples();
239     }
240     return samples.Pass();
241   }
242
243   static std::map<std::string, HistogramBase*> histograms_;
244   std::map<std::string, HistogramSamples*> original_samples_;
245 };
246
247 // static
248 std::map<std::string, HistogramBase*>
249     HttpPipeliningCompatibilityClientTest::histograms_;
250
251 TEST_F(HttpPipeliningCompatibilityClientTest, Success) {
252   RequestInfo info;
253   info.filename = "files/alphabet.txt";
254   info.expected_response = "abcdefghijklmnopqrstuvwxyz";
255   std::vector<RequestInfo> requests;
256   requests.push_back(info);
257
258   RunTest(requests, HttpPipeliningCompatibilityClient::PIPE_TEST_DEFAULTS);
259
260   ExpectHistogramCount(1, true, FIELD_SUCCESS);
261   ExpectHistogramCount(0, 0, FIELD_DEPTH);
262   ExpectHistogramCount(0, 0, FIELD_HTTP_1_1);
263   ExpectRequestHistogramCount(
264       1, internal::PipelineTestRequest::STATUS_SUCCESS, 0, FIELD_STATUS);
265   ExpectRequestHistogramCount(0, 0, 0, FIELD_NETWORK_ERROR);
266   ExpectRequestHistogramCount(1, 200, 0, FIELD_RESPONSE_CODE);
267 }
268
269 TEST_F(HttpPipeliningCompatibilityClientTest, TooSmall) {
270   RequestInfo info;
271   info.filename = "files/alphabet.txt";
272   info.expected_response = "abcdefghijklmnopqrstuvwxyz26";
273   std::vector<RequestInfo> requests;
274   requests.push_back(info);
275
276   RunTest(requests, HttpPipeliningCompatibilityClient::PIPE_TEST_DEFAULTS);
277
278   ExpectHistogramCount(1, false, FIELD_SUCCESS);
279   ExpectRequestHistogramCount(
280       1, internal::PipelineTestRequest::STATUS_TOO_SMALL, 0, FIELD_STATUS);
281   ExpectRequestHistogramCount(0, 0, 0, FIELD_NETWORK_ERROR);
282   ExpectRequestHistogramCount(1, 200, 0, FIELD_RESPONSE_CODE);
283 }
284
285 TEST_F(HttpPipeliningCompatibilityClientTest, TooLarge) {
286   RequestInfo info;
287   info.filename = "files/alphabet.txt";
288   info.expected_response = "abc";
289   std::vector<RequestInfo> requests;
290   requests.push_back(info);
291
292   RunTest(requests, HttpPipeliningCompatibilityClient::PIPE_TEST_DEFAULTS);
293
294   ExpectHistogramCount(1, false, FIELD_SUCCESS);
295   ExpectRequestHistogramCount(
296       1, internal::PipelineTestRequest::STATUS_TOO_LARGE, 0, FIELD_STATUS);
297   ExpectRequestHistogramCount(0, 0, 0, FIELD_NETWORK_ERROR);
298   ExpectRequestHistogramCount(1, 200, 0, FIELD_RESPONSE_CODE);
299 }
300
301 TEST_F(HttpPipeliningCompatibilityClientTest, Mismatch) {
302   RequestInfo info;
303   info.filename = "files/alphabet.txt";
304   info.expected_response = "zyxwvutsrqponmlkjihgfedcba";
305   std::vector<RequestInfo> requests;
306   requests.push_back(info);
307
308   RunTest(requests, HttpPipeliningCompatibilityClient::PIPE_TEST_DEFAULTS);
309
310   ExpectHistogramCount(1, false, FIELD_SUCCESS);
311   ExpectRequestHistogramCount(
312       1, internal::PipelineTestRequest::STATUS_CONTENT_MISMATCH,
313       0, FIELD_STATUS);
314   ExpectRequestHistogramCount(0, 0, 0, FIELD_NETWORK_ERROR);
315   ExpectRequestHistogramCount(1, 200, 0, FIELD_RESPONSE_CODE);
316 }
317
318 TEST_F(HttpPipeliningCompatibilityClientTest, Redirect) {
319   RequestInfo info;
320   info.filename = "server-redirect?http://foo.bar/asdf";
321   info.expected_response = "shouldn't matter";
322   std::vector<RequestInfo> requests;
323   requests.push_back(info);
324
325   RunTest(requests, HttpPipeliningCompatibilityClient::PIPE_TEST_DEFAULTS);
326
327   ExpectHistogramCount(1, false, FIELD_SUCCESS);
328   ExpectRequestHistogramCount(
329       1, internal::PipelineTestRequest::STATUS_REDIRECTED, 0, FIELD_STATUS);
330   ExpectRequestHistogramCount(0, 0, 0, FIELD_NETWORK_ERROR);
331   ExpectRequestHistogramCount(0, 0, 0, FIELD_RESPONSE_CODE);
332 }
333
334 TEST_F(HttpPipeliningCompatibilityClientTest, AuthRequired) {
335   RequestInfo info;
336   info.filename = "auth-basic";
337   info.expected_response = "shouldn't matter";
338   std::vector<RequestInfo> requests;
339   requests.push_back(info);
340
341   RunTest(requests, HttpPipeliningCompatibilityClient::PIPE_TEST_DEFAULTS);
342
343   ExpectHistogramCount(1, false, FIELD_SUCCESS);
344   ExpectRequestHistogramCount(
345       1, internal::PipelineTestRequest::STATUS_BAD_RESPONSE_CODE,
346       0, FIELD_STATUS);
347   ExpectRequestHistogramCount(0, 0, 0, FIELD_NETWORK_ERROR);
348   ExpectRequestHistogramCount(1, 401, 0, FIELD_RESPONSE_CODE);
349 }
350
351 TEST_F(HttpPipeliningCompatibilityClientTest, NoContent) {
352   RequestInfo info;
353   info.filename = "nocontent";
354   info.expected_response = "shouldn't matter";
355   std::vector<RequestInfo> requests;
356   requests.push_back(info);
357
358   RunTest(requests, HttpPipeliningCompatibilityClient::PIPE_TEST_DEFAULTS);
359
360   ExpectHistogramCount(1, false, FIELD_SUCCESS);
361   ExpectRequestHistogramCount(
362       1, internal::PipelineTestRequest::STATUS_BAD_RESPONSE_CODE,
363       0, FIELD_STATUS);
364   ExpectRequestHistogramCount(0, 0, 0, FIELD_NETWORK_ERROR);
365   ExpectRequestHistogramCount(1, 204, 0, FIELD_RESPONSE_CODE);
366 }
367
368 TEST_F(HttpPipeliningCompatibilityClientTest, CloseSocket) {
369   RequestInfo info;
370   info.filename = "close-socket";
371   info.expected_response = "shouldn't matter";
372   std::vector<RequestInfo> requests;
373   requests.push_back(info);
374
375   RunTest(requests, HttpPipeliningCompatibilityClient::PIPE_TEST_DEFAULTS);
376
377   ExpectHistogramCount(1, false, FIELD_SUCCESS);
378   ExpectRequestHistogramCount(
379       1, internal::PipelineTestRequest::STATUS_NETWORK_ERROR, 0, FIELD_STATUS);
380   ExpectRequestHistogramCount(
381       1, -net::ERR_EMPTY_RESPONSE, 0, FIELD_NETWORK_ERROR);
382   ExpectRequestHistogramCount(0, 0, 0, FIELD_RESPONSE_CODE);
383 }
384
385 TEST_F(HttpPipeliningCompatibilityClientTest, OldHttpVersion) {
386   RequestInfo info;
387   info.filename = "http-1.0";
388   info.expected_response = "abcdefghijklmnopqrstuvwxyz";
389   std::vector<RequestInfo> requests;
390   requests.push_back(info);
391
392   RunTest(requests, HttpPipeliningCompatibilityClient::PIPE_TEST_DEFAULTS);
393
394   ExpectHistogramCount(1, false, FIELD_SUCCESS);
395   ExpectRequestHistogramCount(
396       1, internal::PipelineTestRequest::STATUS_BAD_HTTP_VERSION,
397       0, FIELD_STATUS);
398   ExpectRequestHistogramCount(0, 0, 0, FIELD_NETWORK_ERROR);
399   ExpectRequestHistogramCount(1, 200, 0, FIELD_RESPONSE_CODE);
400 }
401
402 #if defined(OS_CHROMEOS)
403 // http://crbug.com/147903: test fails on ChromeOS
404 #define MAYBE_MultipleRequests DISABLED_MultipleRequests
405 #else
406 #define MAYBE_MultipleRequests MultipleRequests
407 #endif
408 TEST_F(HttpPipeliningCompatibilityClientTest, MAYBE_MultipleRequests) {
409   std::vector<RequestInfo> requests;
410
411   RequestInfo info1;
412   info1.filename = "files/alphabet.txt";
413   info1.expected_response = "abcdefghijklmnopqrstuvwxyz";
414   requests.push_back(info1);
415
416   RequestInfo info2;
417   info2.filename = "close-socket";
418   info2.expected_response = "shouldn't matter";
419   requests.push_back(info2);
420
421   RequestInfo info3;
422   info3.filename = "auth-basic";
423   info3.expected_response = "shouldn't matter";
424   requests.push_back(info3);
425
426   RunTest(requests,
427           HttpPipeliningCompatibilityClient::PIPE_TEST_COLLECT_SERVER_STATS);
428
429   ExpectHistogramCount(1, false, FIELD_SUCCESS);
430
431   ExpectRequestHistogramCount(
432       1, internal::PipelineTestRequest::STATUS_SUCCESS, 0, FIELD_STATUS);
433   ExpectRequestHistogramCount(0, 0, 0, FIELD_NETWORK_ERROR);
434   ExpectRequestHistogramCount(1, 200, 0, FIELD_RESPONSE_CODE);
435
436   ExpectRequestHistogramCount(
437       1, internal::PipelineTestRequest::STATUS_NETWORK_ERROR, 1, FIELD_STATUS);
438   ExpectRequestHistogramCount(
439       1, -net::ERR_PIPELINE_EVICTION, 1, FIELD_NETWORK_ERROR);
440   ExpectRequestHistogramCount(0, 0, 1, FIELD_RESPONSE_CODE);
441
442   ExpectRequestHistogramCount(
443       1, internal::PipelineTestRequest::STATUS_NETWORK_ERROR, 2, FIELD_STATUS);
444   ExpectRequestHistogramCount(
445       1, -net::ERR_PIPELINE_EVICTION, 2, FIELD_NETWORK_ERROR);
446   ExpectRequestHistogramCount(0, 0, 2, FIELD_RESPONSE_CODE);
447
448   ExpectRequestHistogramCount(
449       1, internal::PipelineTestRequest::STATUS_NETWORK_ERROR, 3, FIELD_STATUS);
450   ExpectRequestHistogramCount(
451       1, -net::ERR_PIPELINE_EVICTION, 3, FIELD_NETWORK_ERROR);
452   ExpectRequestHistogramCount(0, 0, 3, FIELD_RESPONSE_CODE);
453 }
454
455 TEST_F(HttpPipeliningCompatibilityClientTest, StatsOk) {
456   EXPECT_EQ(internal::PipelineTestRequest::STATUS_SUCCESS,
457             internal::ProcessStatsResponse(
458                 "max_pipeline_depth:3,were_all_requests_http_1_1:0"));
459   ExpectHistogramCount(1, 3, FIELD_DEPTH);
460   ExpectHistogramCount(1, 0, FIELD_HTTP_1_1);
461 }
462
463 TEST_F(HttpPipeliningCompatibilityClientTest, StatsIndifferentToOrder) {
464   EXPECT_EQ(internal::PipelineTestRequest::STATUS_SUCCESS,
465             internal::ProcessStatsResponse(
466                 "were_all_requests_http_1_1:1,max_pipeline_depth:2"));
467   ExpectHistogramCount(1, 2, FIELD_DEPTH);
468   ExpectHistogramCount(1, 1, FIELD_HTTP_1_1);
469 }
470
471 #if defined(OS_CHROMEOS)
472 // http://crbug.com/147903: test fails on ChromeOS
473 #define MAYBE_StatsBadField DISABLED_StatsBadField
474 #else
475 #define MAYBE_StatsBadField StatsBadField
476 #endif
477 TEST_F(HttpPipeliningCompatibilityClientTest, MAYBE_StatsBadField) {
478   EXPECT_EQ(internal::PipelineTestRequest::STATUS_CORRUPT_STATS,
479             internal::ProcessStatsResponse(
480                 "foo:3,were_all_requests_http_1_1:1"));
481   ExpectHistogramCount(0, 0, FIELD_DEPTH);
482   ExpectHistogramCount(0, 0, FIELD_HTTP_1_1);
483 }
484
485 TEST_F(HttpPipeliningCompatibilityClientTest, StatsTooShort) {
486   EXPECT_EQ(internal::PipelineTestRequest::STATUS_CORRUPT_STATS,
487             internal::ProcessStatsResponse("were_all_requests_http_1_1:1"));
488   ExpectHistogramCount(0, 0, FIELD_DEPTH);
489   ExpectHistogramCount(0, 0, FIELD_HTTP_1_1);
490 }
491
492 TEST_F(HttpPipeliningCompatibilityClientTest, WaitForCanary) {
493   MockFactory* factory = new MockFactory;
494   HttpPipeliningCompatibilityClient client(factory);
495
496   MockRequest* request = new MockRequest;
497   base::Closure request_cb = base::Bind(
498       &internal::PipelineTestRequest::Delegate::OnRequestFinished,
499       base::Unretained(&client), 0,
500       internal::PipelineTestRequest::STATUS_SUCCESS);
501
502   MockRequest* canary = new MockRequest;
503   base::Closure canary_cb = base::Bind(
504       &internal::PipelineTestRequest::Delegate::OnCanaryFinished,
505       base::Unretained(&client), internal::PipelineTestRequest::STATUS_SUCCESS);
506
507   EXPECT_CALL(*factory, NewRequest(
508       0, _, Field(&RequestInfo::filename, StrEq("request.txt")), _, _,
509       internal::PipelineTestRequest::TYPE_PIPELINED))
510       .Times(1)
511       .WillOnce(Return(request));
512   EXPECT_CALL(*factory, NewRequest(
513       999, _, Field(&RequestInfo::filename, StrEq("index.html")), _, _,
514       internal::PipelineTestRequest::TYPE_CANARY))
515       .Times(1)
516       .WillOnce(Return(canary));
517
518   EXPECT_CALL(*canary, Start())
519       .Times(1)
520       .WillOnce(Invoke(&canary_cb, &base::Closure::Run));
521   EXPECT_CALL(*request, Start())
522       .Times(1)
523       .WillOnce(Invoke(&request_cb, &base::Closure::Run));
524
525   std::vector<RequestInfo> requests;
526
527   RequestInfo info1;
528   info1.filename = "request.txt";
529   requests.push_back(info1);
530
531   net::TestCompletionCallback callback;
532   client.Start("http://base/", requests,
533                HttpPipeliningCompatibilityClient::PIPE_TEST_RUN_CANARY_REQUEST,
534                callback.callback(), context_->GetURLRequestContext());
535   callback.WaitForResult();
536
537   ExpectHistogramCount(1, true, FIELD_CANARY);
538   ExpectHistogramCount(1, true, FIELD_SUCCESS);
539   ExpectRequestHistogramCount(
540       1, internal::PipelineTestRequest::STATUS_SUCCESS, 0, FIELD_STATUS);
541 }
542
543 #if defined(OS_CHROMEOS)
544 // http://crbug.com/147903: test fails on ChromeOS
545 #define MAYBE_CanaryFailure DISABLED_CanaryFailure
546 #else
547 #define MAYBE_CanaryFailure CanaryFailure
548 #endif
549 TEST_F(HttpPipeliningCompatibilityClientTest, MAYBE_CanaryFailure) {
550   MockFactory* factory = new MockFactory;
551   HttpPipeliningCompatibilityClient client(factory);
552
553   MockRequest* request = new MockRequest;
554
555   MockRequest* canary = new MockRequest;
556   base::Closure canary_cb = base::Bind(
557       &internal::PipelineTestRequest::Delegate::OnCanaryFinished,
558       base::Unretained(&client),
559       internal::PipelineTestRequest::STATUS_REDIRECTED);
560
561   EXPECT_CALL(*factory, NewRequest(
562       0, _, Field(&RequestInfo::filename, StrEq("request.txt")), _, _,
563       internal::PipelineTestRequest::TYPE_PIPELINED))
564       .Times(1)
565       .WillOnce(Return(request));
566   EXPECT_CALL(*factory, NewRequest(
567       999, _, Field(&RequestInfo::filename, StrEq("index.html")), _, _,
568       internal::PipelineTestRequest::TYPE_CANARY))
569       .Times(1)
570       .WillOnce(Return(canary));
571
572   EXPECT_CALL(*canary, Start())
573       .Times(1)
574       .WillOnce(Invoke(&canary_cb, &base::Closure::Run));
575   EXPECT_CALL(*request, Start())
576       .Times(0);
577
578   std::vector<RequestInfo> requests;
579
580   RequestInfo info1;
581   info1.filename = "request.txt";
582   requests.push_back(info1);
583
584   net::TestCompletionCallback callback;
585   client.Start("http://base/", requests,
586                HttpPipeliningCompatibilityClient::PIPE_TEST_RUN_CANARY_REQUEST,
587                callback.callback(), context_->GetURLRequestContext());
588   callback.WaitForResult();
589
590   ExpectHistogramCount(1, false, FIELD_CANARY);
591   ExpectHistogramCount(0, false, FIELD_SUCCESS);
592   ExpectHistogramCount(0, true, FIELD_SUCCESS);
593 }
594
595 }  // anonymous namespace
596
597 }  // namespace chrome_browser_net