OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/data_reduction_proxy/browser/data_reduction_proxy_usage_sta
ts.h" | 5 #include "components/data_reduction_proxy/browser/data_reduction_proxy_usage_sta
ts.h" |
6 | 6 |
| 7 #include <string> |
| 8 |
7 #include "base/bind.h" | 9 #include "base/bind.h" |
8 #include "base/memory/scoped_ptr.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_te
st_utils.h" |
9 #include "net/base/host_port_pair.h" | 14 #include "net/base/host_port_pair.h" |
10 #include "net/base/request_priority.h" | 15 #include "net/base/request_priority.h" |
| 16 #include "net/http/http_response_headers.h" |
| 17 #include "net/http/http_util.h" |
11 #include "net/url_request/url_request.h" | 18 #include "net/url_request/url_request.h" |
| 19 #include "net/url_request/url_request_job_factory_impl.h" |
12 #include "net/url_request/url_request_status.h" | 20 #include "net/url_request/url_request_status.h" |
| 21 #include "net/url_request/url_request_test_job.h" |
13 #include "net/url_request/url_request_test_util.h" | 22 #include "net/url_request/url_request_test_util.h" |
14 #include "testing/gmock/include/gmock/gmock.h" | 23 #include "testing/gmock/include/gmock/gmock.h" |
15 #include "testing/gtest/include/gtest/gtest.h" | 24 #include "testing/gtest/include/gtest/gtest.h" |
16 | 25 |
17 using testing::Return; | 26 using testing::Return; |
18 | 27 |
19 namespace { | 28 namespace { |
20 | 29 |
21 class DataReductionProxyParamsMock : | 30 class DataReductionProxyParamsMock : |
22 public data_reduction_proxy::DataReductionProxyParams { | 31 public data_reduction_proxy::DataReductionProxyParams { |
(...skipping 19 matching lines...) Expand all Loading... |
42 | 51 |
43 namespace data_reduction_proxy { | 52 namespace data_reduction_proxy { |
44 | 53 |
45 class DataReductionProxyUsageStatsTest : public testing::Test { | 54 class DataReductionProxyUsageStatsTest : public testing::Test { |
46 public: | 55 public: |
47 DataReductionProxyUsageStatsTest() | 56 DataReductionProxyUsageStatsTest() |
48 : loop_proxy_(base::MessageLoopProxy::current().get()), | 57 : loop_proxy_(base::MessageLoopProxy::current().get()), |
49 context_(true), | 58 context_(true), |
50 unavailable_(false) { | 59 unavailable_(false) { |
51 context_.Init(); | 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 |
52 mock_url_request_ = context_.CreateRequest(GURL(), net::IDLE, &delegate_, | 69 mock_url_request_ = context_.CreateRequest(GURL(), net::IDLE, &delegate_, |
53 NULL); | 70 NULL); |
54 } | 71 } |
55 | 72 |
56 void NotifyUnavailable(bool unavailable) { | 73 void NotifyUnavailable(bool unavailable) { |
57 unavailable_ = unavailable; | 74 unavailable_ = unavailable; |
58 } | 75 } |
59 | 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 |
60 // Required for base::MessageLoopProxy::current(). | 99 // Required for base::MessageLoopProxy::current(). |
61 base::MessageLoopForUI loop_; | 100 base::MessageLoopForUI loop_; |
62 base::MessageLoopProxy* loop_proxy_; | 101 base::MessageLoopProxy* loop_proxy_; |
63 | 102 |
64 protected: | 103 protected: |
65 net::TestURLRequestContext context_; | 104 net::TestURLRequestContext context_; |
66 net::TestDelegate delegate_; | 105 net::TestDelegate delegate_; |
67 DataReductionProxyParamsMock mock_params_; | 106 DataReductionProxyParamsMock mock_params_; |
68 scoped_ptr<net::URLRequest> mock_url_request_; | 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_; |
69 bool unavailable_; | 111 bool unavailable_; |
70 }; | 112 }; |
71 | 113 |
72 TEST_F(DataReductionProxyUsageStatsTest, IsDataReductionProxyUnreachable) { | 114 TEST_F(DataReductionProxyUsageStatsTest, IsDataReductionProxyUnreachable) { |
73 net::ProxyServer fallback_proxy_server = | 115 net::ProxyServer fallback_proxy_server = |
74 net::ProxyServer::FromURI("foo.com", net::ProxyServer::SCHEME_HTTP); | 116 net::ProxyServer::FromURI("foo.com", net::ProxyServer::SCHEME_HTTP); |
75 data_reduction_proxy::DataReductionProxyTypeInfo proxy_info; | 117 data_reduction_proxy::DataReductionProxyTypeInfo proxy_info; |
76 struct TestCase { | 118 struct TestCase { |
77 bool fallback_proxy_server_is_data_reduction_proxy; | 119 bool fallback_proxy_server_is_data_reduction_proxy; |
78 bool was_proxy_used; | 120 bool was_proxy_used; |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 usage_stats->OnProxyFallback(fallback_proxy_server, | 222 usage_stats->OnProxyFallback(fallback_proxy_server, |
181 net::ERR_PROXY_CONNECTION_FAILED); | 223 net::ERR_PROXY_CONNECTION_FAILED); |
182 usage_stats->OnProxyFallback(fallback_proxy_server, | 224 usage_stats->OnProxyFallback(fallback_proxy_server, |
183 net::ERR_PROXY_CONNECTION_FAILED); | 225 net::ERR_PROXY_CONNECTION_FAILED); |
184 usage_stats->OnProxyFallback(fallback_proxy_server, | 226 usage_stats->OnProxyFallback(fallback_proxy_server, |
185 net::ERR_PROXY_CONNECTION_FAILED); | 227 net::ERR_PROXY_CONNECTION_FAILED); |
186 base::MessageLoop::current()->RunUntilIdle(); | 228 base::MessageLoop::current()->RunUntilIdle(); |
187 EXPECT_TRUE(unavailable_); | 229 EXPECT_TRUE(unavailable_); |
188 } | 230 } |
189 | 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 |
190 } // namespace data_reduction_proxy | 443 } // namespace data_reduction_proxy |
OLD | NEW |