Upstream version 11.39.266.0
[platform/framework/web/crosswalk.git] / src / components / data_reduction_proxy / browser / data_reduction_proxy_usage_stats_unittest.cc
1 // Copyright 2014 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 "components/data_reduction_proxy/browser/data_reduction_proxy_usage_stats.h"
6
7 #include <string>
8
9 #include "base/bind.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/metrics/histogram.h"
12 #include "base/test/histogram_tester.h"
13 #include "components/data_reduction_proxy/common/data_reduction_proxy_headers_test_utils.h"
14 #include "net/base/host_port_pair.h"
15 #include "net/base/request_priority.h"
16 #include "net/http/http_response_headers.h"
17 #include "net/http/http_util.h"
18 #include "net/url_request/url_request.h"
19 #include "net/url_request/url_request_job_factory_impl.h"
20 #include "net/url_request/url_request_status.h"
21 #include "net/url_request/url_request_test_job.h"
22 #include "net/url_request/url_request_test_util.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 using testing::Return;
27
28 namespace {
29
30 class DataReductionProxyParamsMock :
31     public data_reduction_proxy::DataReductionProxyParams {
32  public:
33   DataReductionProxyParamsMock() :
34       data_reduction_proxy::DataReductionProxyParams(0) {}
35   virtual ~DataReductionProxyParamsMock() {}
36
37   MOCK_CONST_METHOD2(
38       IsDataReductionProxy,
39       bool(const net::HostPortPair& host_port_pair,
40            data_reduction_proxy::DataReductionProxyTypeInfo* proxy_info));
41   MOCK_CONST_METHOD2(
42       WasDataReductionProxyUsed,
43       bool(const net::URLRequest*,
44            data_reduction_proxy::DataReductionProxyTypeInfo* proxy_info));
45
46  private:
47   DISALLOW_COPY_AND_ASSIGN(DataReductionProxyParamsMock);
48 };
49
50 }  // namespace
51
52 namespace data_reduction_proxy {
53
54 class DataReductionProxyUsageStatsTest : public testing::Test {
55  public:
56   DataReductionProxyUsageStatsTest()
57       : loop_proxy_(base::MessageLoopProxy::current().get()),
58         context_(true),
59         unavailable_(false) {
60     context_.Init();
61
62     // The |test_job_factory_| takes ownership of the interceptor.
63     test_job_interceptor_ = new net::TestJobInterceptor();
64     EXPECT_TRUE(test_job_factory_.SetProtocolHandler(url::kHttpScheme,
65                                                      test_job_interceptor_));
66
67     context_.set_job_factory(&test_job_factory_);
68
69     mock_url_request_ = context_.CreateRequest(GURL(), net::IDLE, &delegate_,
70                                                NULL);
71   }
72
73   void NotifyUnavailable(bool unavailable) {
74     unavailable_ = unavailable;
75   }
76
77   scoped_ptr<net::URLRequest> CreateURLRequestWithResponseHeaders(
78       const GURL& url,
79       const std::string& raw_response_headers) {
80     scoped_ptr<net::URLRequest> fake_request = context_.CreateRequest(
81         url, net::IDLE, &delegate_, NULL);
82
83     // Create a test job that will fill in the given response headers for the
84     // |fake_request|.
85     scoped_refptr<net::URLRequestTestJob> test_job(
86         new net::URLRequestTestJob(fake_request.get(),
87                                    context_.network_delegate(),
88                                    raw_response_headers, std::string(), true));
89
90     // Configure the interceptor to use the test job to handle the next request.
91     test_job_interceptor_->set_main_intercept_job(test_job.get());
92     fake_request->Start();
93     base::MessageLoop::current()->RunUntilIdle();
94
95     EXPECT_TRUE(fake_request->response_headers() != NULL);
96     return fake_request.Pass();
97   }
98
99   // Required for base::MessageLoopProxy::current().
100   base::MessageLoopForUI loop_;
101   base::MessageLoopProxy* loop_proxy_;
102
103  protected:
104   net::TestURLRequestContext context_;
105   net::TestDelegate delegate_;
106   DataReductionProxyParamsMock mock_params_;
107   scoped_ptr<net::URLRequest> mock_url_request_;
108   // |test_job_interceptor_| is owned by |test_job_factory_|.
109   net::TestJobInterceptor* test_job_interceptor_;
110   net::URLRequestJobFactoryImpl test_job_factory_;
111   bool unavailable_;
112 };
113
114 TEST_F(DataReductionProxyUsageStatsTest, IsDataReductionProxyUnreachable) {
115   net::ProxyServer fallback_proxy_server =
116       net::ProxyServer::FromURI("foo.com", net::ProxyServer::SCHEME_HTTP);
117   data_reduction_proxy::DataReductionProxyTypeInfo proxy_info;
118   struct TestCase {
119     bool fallback_proxy_server_is_data_reduction_proxy;
120     bool was_proxy_used;
121     bool is_unreachable;
122   };
123   const TestCase test_cases[] = {
124     {
125       false,
126       false,
127       false
128     },
129     {
130       false,
131       true,
132       false
133     },
134     {
135       true,
136       true,
137       false
138     },
139     {
140       true,
141       false,
142       true
143     }
144   };
145   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
146     TestCase test_case = test_cases[i];
147
148     EXPECT_CALL(mock_params_, IsDataReductionProxy(testing::_, testing::_))
149         .WillRepeatedly(testing::Return(
150             test_case.fallback_proxy_server_is_data_reduction_proxy));
151     EXPECT_CALL(mock_params_,
152                 WasDataReductionProxyUsed(mock_url_request_.get(), NULL))
153         .WillRepeatedly(testing::Return(test_case.was_proxy_used));
154
155     scoped_ptr<DataReductionProxyUsageStats> usage_stats(
156         new DataReductionProxyUsageStats(
157             &mock_params_, loop_proxy_));
158     usage_stats->set_unavailable_callback(
159         base::Bind(&DataReductionProxyUsageStatsTest::NotifyUnavailable,
160                    base::Unretained(this)));
161
162     usage_stats->OnProxyFallback(fallback_proxy_server,
163                                  net::ERR_PROXY_CONNECTION_FAILED);
164     usage_stats->OnUrlRequestCompleted(mock_url_request_.get(), false);
165     base::MessageLoop::current()->RunUntilIdle();
166
167     EXPECT_EQ(test_case.is_unreachable, unavailable_);
168   }
169 }
170
171 TEST_F(DataReductionProxyUsageStatsTest, ProxyUnreachableThenReachable) {
172   net::ProxyServer fallback_proxy_server =
173       net::ProxyServer::FromURI("foo.com", net::ProxyServer::SCHEME_HTTP);
174   scoped_ptr<DataReductionProxyUsageStats> usage_stats(
175       new DataReductionProxyUsageStats(
176           &mock_params_, loop_proxy_));
177   usage_stats->set_unavailable_callback(
178       base::Bind(&DataReductionProxyUsageStatsTest::NotifyUnavailable,
179                  base::Unretained(this)));
180
181   EXPECT_CALL(mock_params_, IsDataReductionProxy(testing::_, testing::_))
182       .WillOnce(testing::Return(true));
183   EXPECT_CALL(mock_params_,
184               WasDataReductionProxyUsed(mock_url_request_.get(), NULL))
185       .WillOnce(testing::Return(true));
186
187   // proxy falls back
188   usage_stats->OnProxyFallback(fallback_proxy_server,
189                                net::ERR_PROXY_CONNECTION_FAILED);
190   base::MessageLoop::current()->RunUntilIdle();
191   EXPECT_TRUE(unavailable_);
192
193   // proxy succeeds
194   usage_stats->OnUrlRequestCompleted(mock_url_request_.get(), false);
195   base::MessageLoop::current()->RunUntilIdle();
196   EXPECT_FALSE(unavailable_);
197 }
198
199 TEST_F(DataReductionProxyUsageStatsTest, ProxyReachableThenUnreachable) {
200   net::ProxyServer fallback_proxy_server =
201       net::ProxyServer::FromURI("foo.com", net::ProxyServer::SCHEME_HTTP);
202   scoped_ptr<DataReductionProxyUsageStats> usage_stats(
203       new DataReductionProxyUsageStats(
204           &mock_params_, loop_proxy_));
205   usage_stats->set_unavailable_callback(
206       base::Bind(&DataReductionProxyUsageStatsTest::NotifyUnavailable,
207                  base::Unretained(this)));
208   EXPECT_CALL(mock_params_,
209               WasDataReductionProxyUsed(mock_url_request_.get(), NULL))
210       .WillOnce(testing::Return(true));
211   EXPECT_CALL(mock_params_, IsDataReductionProxy(testing::_, testing::_))
212       .WillRepeatedly(testing::Return(true));
213
214   // Proxy succeeds.
215   usage_stats->OnUrlRequestCompleted(mock_url_request_.get(), false);
216   base::MessageLoop::current()->RunUntilIdle();
217   EXPECT_FALSE(unavailable_);
218
219   // Then proxy falls back indefinitely.
220   usage_stats->OnProxyFallback(fallback_proxy_server,
221                                net::ERR_PROXY_CONNECTION_FAILED);
222   usage_stats->OnProxyFallback(fallback_proxy_server,
223                                  net::ERR_PROXY_CONNECTION_FAILED);
224   usage_stats->OnProxyFallback(fallback_proxy_server,
225                                  net::ERR_PROXY_CONNECTION_FAILED);
226   usage_stats->OnProxyFallback(fallback_proxy_server,
227                                  net::ERR_PROXY_CONNECTION_FAILED);
228   base::MessageLoop::current()->RunUntilIdle();
229   EXPECT_TRUE(unavailable_);
230 }
231
232 TEST_F(DataReductionProxyUsageStatsTest,
233        DetectAndRecordMissingViaHeaderResponseCode) {
234   const std::string kPrimaryHistogramName =
235       "DataReductionProxy.MissingViaHeader.ResponseCode.Primary";
236   const std::string kFallbackHistogramName =
237       "DataReductionProxy.MissingViaHeader.ResponseCode.Fallback";
238
239   struct TestCase {
240     bool is_primary;
241     const char* headers;
242     int expected_primary_sample;   // -1 indicates no expected sample.
243     int expected_fallback_sample;  // -1 indicates no expected sample.
244   };
245   const TestCase test_cases[] = {
246     {
247       true,
248       "HTTP/1.1 200 OK\n"
249       "Via: 1.1 Chrome-Compression-Proxy\n",
250       -1,
251       -1
252     },
253     {
254       false,
255       "HTTP/1.1 200 OK\n"
256       "Via: 1.1 Chrome-Compression-Proxy\n",
257       -1,
258       -1
259     },
260     {
261       true,
262       "HTTP/1.1 200 OK\n",
263       200,
264       -1
265     },
266     {
267       false,
268       "HTTP/1.1 200 OK\n",
269       -1,
270       200
271     },
272     {
273       true,
274       "HTTP/1.1 304 Not Modified\n",
275       304,
276       -1
277     },
278     {
279       false,
280       "HTTP/1.1 304 Not Modified\n",
281       -1,
282       304
283     },
284     {
285       true,
286       "HTTP/1.1 404 Not Found\n",
287       404,
288       -1
289     },
290     {
291       false,
292       "HTTP/1.1 404 Not Found\n",
293       -1,
294       404
295     }
296   };
297
298   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
299     base::HistogramTester histogram_tester;
300     std::string raw_headers(test_cases[i].headers);
301     HeadersToRaw(&raw_headers);
302     scoped_refptr<net::HttpResponseHeaders> headers(
303         new net::HttpResponseHeaders(raw_headers));
304
305     DataReductionProxyUsageStats::DetectAndRecordMissingViaHeaderResponseCode(
306         test_cases[i].is_primary, headers.get());
307
308     if (test_cases[i].expected_primary_sample == -1) {
309       histogram_tester.ExpectTotalCount(kPrimaryHistogramName, 0);
310     } else {
311       histogram_tester.ExpectUniqueSample(
312           kPrimaryHistogramName, test_cases[i].expected_primary_sample, 1);
313     }
314
315     if (test_cases[i].expected_fallback_sample == -1) {
316       histogram_tester.ExpectTotalCount(kFallbackHistogramName, 0);
317     } else {
318       histogram_tester.ExpectUniqueSample(
319           kFallbackHistogramName, test_cases[i].expected_fallback_sample, 1);
320     }
321   }
322 }
323
324 TEST_F(DataReductionProxyUsageStatsTest, RecordMissingViaHeaderBytes) {
325   const std::string k4xxHistogramName =
326       "DataReductionProxy.MissingViaHeader.Bytes.4xx";
327   const std::string kOtherHistogramName =
328       "DataReductionProxy.MissingViaHeader.Bytes.Other";
329   const int64 kResponseContentLength = 100;
330
331   struct TestCase {
332     bool was_proxy_used;
333     const char* headers;
334     bool is_4xx_sample_expected;
335     bool is_other_sample_expected;
336   };
337   const TestCase test_cases[] = {
338     // Nothing should be recorded for requests that don't use the proxy.
339     {
340       false,
341       "HTTP/1.1 404 Not Found\n",
342       false,
343       false
344     },
345     {
346       false,
347       "HTTP/1.1 200 OK\n",
348       false,
349       false
350     },
351     // Nothing should be recorded for responses that have the via header.
352     {
353       true,
354       "HTTP/1.1 404 Not Found\n"
355       "Via: 1.1 Chrome-Compression-Proxy\n",
356       false,
357       false
358     },
359     {
360       true,
361       "HTTP/1.1 200 OK\n"
362       "Via: 1.1 Chrome-Compression-Proxy\n",
363       false,
364       false
365     },
366     // 4xx responses that used the proxy and don't have the via header should be
367     // recorded.
368     {
369       true,
370       "HTTP/1.1 404 Not Found\n",
371       true,
372       false
373     },
374     {
375       true,
376       "HTTP/1.1 400 Bad Request\n",
377       true,
378       false
379     },
380     {
381       true,
382       "HTTP/1.1 499 Big Client Error Response Code\n",
383       true,
384       false
385     },
386     // Non-4xx responses that used the proxy and don't have the via header
387     // should be recorded.
388     {
389       true,
390       "HTTP/1.1 200 OK\n",
391       false,
392       true
393     },
394     {
395       true,
396       "HTTP/1.1 399 Big Redirection Response Code\n",
397       false,
398       true
399     },
400     {
401       true,
402       "HTTP/1.1 500 Internal Server Error\n",
403       false,
404       true
405     }
406   };
407
408   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) {
409     base::HistogramTester histogram_tester;
410     scoped_ptr<DataReductionProxyUsageStats> usage_stats(
411         new DataReductionProxyUsageStats(&mock_params_, loop_proxy_));
412
413     std::string raw_headers(test_cases[i].headers);
414     HeadersToRaw(&raw_headers);
415
416     scoped_ptr<net::URLRequest> fake_request(
417         CreateURLRequestWithResponseHeaders(GURL("http://www.google.com/"),
418                                             raw_headers));
419     fake_request->set_received_response_content_length(kResponseContentLength);
420
421     EXPECT_CALL(mock_params_,
422                 WasDataReductionProxyUsed(fake_request.get(), NULL))
423         .WillRepeatedly(Return(test_cases[i].was_proxy_used));
424
425     usage_stats->RecordMissingViaHeaderBytes(fake_request.get());
426
427     if (test_cases[i].is_4xx_sample_expected) {
428       histogram_tester.ExpectUniqueSample(k4xxHistogramName,
429                                           kResponseContentLength, 1);
430     } else {
431       histogram_tester.ExpectTotalCount(k4xxHistogramName, 0);
432     }
433
434     if (test_cases[i].is_other_sample_expected) {
435       histogram_tester.ExpectUniqueSample(kOtherHistogramName,
436                                           kResponseContentLength, 1);
437     } else {
438       histogram_tester.ExpectTotalCount(kOtherHistogramName, 0);
439     }
440   }
441 }
442
443 }  // namespace data_reduction_proxy