62dd6c5b331a967606e9071fc54f6e302d75aa24
[platform/framework/web/crosswalk.git] / src / chrome / browser / net / spdyproxy / data_reduction_proxy_settings_unittest.cc
1 // Copyright 2013 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/spdyproxy/data_reduction_proxy_settings_unittest.h"
6
7 #include "base/command_line.h"
8 #include "base/md5.h"
9 #include "base/metrics/field_trial.h"
10 #include "base/metrics/histogram_samples.h"
11 #include "base/metrics/statistics_recorder.h"
12 #include "base/prefs/pref_registry_simple.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/prefs/scoped_user_pref_update.h"
15 #include "base/prefs/testing_pref_service.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_settings.h"
19 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_settings_android.h"
20 #include "chrome/browser/prefs/proxy_prefs.h"
21 #include "chrome/common/chrome_switches.h"
22 #include "chrome/common/metrics/variations/variations_util.h"
23 #include "chrome/common/pref_names.h"
24 #include "components/variations/entropy_provider.h"
25 #include "net/base/auth.h"
26 #include "net/base/host_port_pair.h"
27 #include "net/http/http_auth.h"
28 #include "net/http/http_auth_cache.h"
29 #include "net/http/http_response_headers.h"
30 #include "net/http/http_status_code.h"
31 #include "net/url_request/test_url_fetcher_factory.h"
32 #include "testing/gmock/include/gmock/gmock.h"
33 #include "testing/gtest/include/gtest/gtest.h"
34 #include "url/gurl.h"
35
36 using testing::_;
37 using testing::AnyNumber;
38 using testing::Return;
39
40 const char kDataReductionProxyOrigin[] = "https://foo.com:443/";
41 const char kDataReductionProxyDevHost[] = "http://foo-dev.com:80";
42 const char kDataReductionProxyFallback[] = "http://bar.com:80";
43 const char kDataReductionProxyAuth[] = "12345";
44
45 const char kProbeURLWithOKResponse[] = "http://ok.org/";
46 const char kProbeURLWithBadResponse[] = "http://bad.org/";
47 const char kProbeURLWithNoResponse[] = "http://no.org/";
48
49 // Transform "normal"-looking headers (\n-separated) to the appropriate
50 // input format for ParseRawHeaders (\0-separated).
51 void HeadersToRaw(std::string* headers) {
52   std::replace(headers->begin(), headers->end(), '\n', '\0');
53   if (!headers->empty())
54     *headers += '\0';
55 }
56
57 ProbeURLFetchResult FetchResult(bool enabled, bool success) {
58   if (enabled) {
59     if (success)
60       return spdyproxy::SUCCEEDED_PROXY_ALREADY_ENABLED;
61     else
62       return spdyproxy::FAILED_PROXY_DISABLED;
63   } else {
64     if (success)
65       return spdyproxy::SUCCEEDED_PROXY_ENABLED;
66     else
67       return spdyproxy::FAILED_PROXY_ALREADY_DISABLED;
68   }
69 }
70
71 DataReductionProxySettingsTestBase::DataReductionProxySettingsTestBase()
72     : testing::Test() {
73 }
74
75 DataReductionProxySettingsTestBase::~DataReductionProxySettingsTestBase() {}
76
77 void DataReductionProxySettingsTestBase::AddProxyToCommandLine() {
78   CommandLine::ForCurrentProcess()->AppendSwitchASCII(
79       switches::kSpdyProxyAuthOrigin, kDataReductionProxyOrigin);
80   CommandLine::ForCurrentProcess()->AppendSwitchASCII(
81       switches::kSpdyProxyAuthFallback, kDataReductionProxyFallback);
82   CommandLine::ForCurrentProcess()->AppendSwitchASCII(
83       switches::kSpdyProxyAuthValue, kDataReductionProxyAuth);
84 }
85
86 // testing::Test implementation:
87 void DataReductionProxySettingsTestBase::SetUp() {
88   PrefRegistrySimple* registry = pref_service_.registry();
89   registry->RegisterListPref(prefs::kDailyHttpOriginalContentLength);
90   registry->RegisterListPref(prefs::kDailyHttpReceivedContentLength);
91   registry->RegisterInt64Pref(
92       prefs::kDailyHttpContentLengthLastUpdateDate, 0L);
93   registry->RegisterDictionaryPref(prefs::kProxy);
94   registry->RegisterBooleanPref(prefs::kSpdyProxyAuthEnabled, false);
95   registry->RegisterBooleanPref(prefs::kSpdyProxyAuthWasEnabledBefore, false);
96   ResetSettings();
97
98   ListPrefUpdate original_update(&pref_service_,
99                                  prefs::kDailyHttpOriginalContentLength);
100   ListPrefUpdate received_update(&pref_service_,
101                                  prefs::kDailyHttpReceivedContentLength);
102   for (int64 i = 0; i < spdyproxy::kNumDaysInHistory; i++) {
103     original_update->Insert(0,
104                             new base::StringValue(base::Int64ToString(2 * i)));
105     received_update->Insert(0, new base::StringValue(base::Int64ToString(i)));
106   }
107   last_update_time_ = base::Time::Now().LocalMidnight();
108   pref_service_.SetInt64(
109       prefs::kDailyHttpContentLengthLastUpdateDate,
110       last_update_time_.ToInternalValue());
111 }
112
113 template <class C>
114 void DataReductionProxySettingsTestBase::ResetSettings() {
115   MockDataReductionProxySettings<C>* settings =
116       new MockDataReductionProxySettings<C>;
117   EXPECT_CALL(*settings, GetOriginalProfilePrefs())
118       .Times(AnyNumber())
119       .WillRepeatedly(Return(&pref_service_));
120   EXPECT_CALL(*settings, GetLocalStatePrefs())
121       .Times(AnyNumber())
122       .WillRepeatedly(Return(&pref_service_));
123   EXPECT_CALL(*settings, GetURLFetcher()).Times(0);
124   EXPECT_CALL(*settings, LogProxyState(_, _, _)).Times(0);
125   settings_.reset(settings);
126 }
127
128 // Explicitly generate required instantiations.
129 template void
130 DataReductionProxySettingsTestBase::ResetSettings<DataReductionProxySettings>();
131 template void
132 DataReductionProxySettingsTestBase::ResetSettings<
133     DataReductionProxySettingsAndroid>();
134
135 template <class C>
136 void DataReductionProxySettingsTestBase::SetProbeResult(
137     const std::string& test_url,
138     const std::string& response,
139     ProbeURLFetchResult result,
140     bool success,
141     int expected_calls)  {
142   MockDataReductionProxySettings<C>* settings =
143       static_cast<MockDataReductionProxySettings<C>*>(settings_.get());
144   if (0 == expected_calls) {
145     EXPECT_CALL(*settings, GetURLFetcher()).Times(0);
146     EXPECT_CALL(*settings, RecordProbeURLFetchResult(_)).Times(0);
147   } else {
148     EXPECT_CALL(*settings, RecordProbeURLFetchResult(result)).Times(1);
149     EXPECT_CALL(*settings, GetURLFetcher())
150         .Times(expected_calls)
151         .WillRepeatedly(Return(new net::FakeURLFetcher(
152             GURL(test_url),
153             settings,
154             response,
155             success ? net::HTTP_OK : net::HTTP_INTERNAL_SERVER_ERROR,
156             success ? net::URLRequestStatus::SUCCESS :
157                       net::URLRequestStatus::FAILED)));
158   }
159 }
160
161 // Explicitly generate required instantiations.
162 template void
163 DataReductionProxySettingsTestBase::SetProbeResult<DataReductionProxySettings>(
164     const std::string& test_url,
165     const std::string& response,
166     ProbeURLFetchResult result,
167     bool success,
168     int expected_calls);
169 template void
170 DataReductionProxySettingsTestBase::SetProbeResult<
171     DataReductionProxySettingsAndroid>(const std::string& test_url,
172                                        const std::string& response,
173                                        ProbeURLFetchResult result,
174                                        bool success,
175                                        int expected_calls);
176
177 void DataReductionProxySettingsTestBase::CheckProxyPref(
178     const std::string& expected_servers,
179     const std::string& expected_mode) {
180   const base::DictionaryValue* dict =
181       pref_service_.GetDictionary(prefs::kProxy);
182   std::string mode;
183   std::string server;
184   dict->GetString("mode", &mode);
185   ASSERT_EQ(expected_mode, mode);
186   dict->GetString("server", &server);
187   ASSERT_EQ(expected_servers, server);
188 }
189
190 void DataReductionProxySettingsTestBase::CheckProxyConfigs(
191     bool expected_enabled, bool expected_restricted) {
192   if (expected_enabled) {
193     std::string main_proxy = kDataReductionProxyOrigin;
194     std::string fallback_proxy = kDataReductionProxyFallback;
195     std::string servers = expected_restricted ?
196         "http=" + fallback_proxy + ",direct://;" :
197         "http=" + main_proxy + "," + fallback_proxy + ",direct://;";
198     CheckProxyPref(servers,
199                    ProxyModeToString(ProxyPrefs::MODE_FIXED_SERVERS));
200   } else {
201     CheckProxyPref(std::string(), ProxyModeToString(ProxyPrefs::MODE_SYSTEM));
202   }
203 }
204
205 void DataReductionProxySettingsTestBase::CheckProbe(
206     bool initially_enabled,
207     const std::string& probe_url,
208     const std::string& response,
209     bool request_succeeded,
210     bool expected_enabled,
211     bool expected_restricted) {
212   pref_service_.SetBoolean(prefs::kSpdyProxyAuthEnabled, initially_enabled);
213   if (initially_enabled)
214     settings_->enabled_by_user_ = true;
215   settings_->restricted_by_carrier_ = false;
216   SetProbeResult(probe_url,
217                  response,
218                  FetchResult(initially_enabled,
219                              request_succeeded && (response == "OK")),
220                  request_succeeded,
221                  initially_enabled ? 1 : 0);
222   settings_->MaybeActivateDataReductionProxy(false);
223   base::MessageLoop::current()->RunUntilIdle();
224   CheckProxyConfigs(expected_enabled, expected_restricted);
225 }
226
227 void DataReductionProxySettingsTestBase::CheckProbeOnIPChange(
228     const std::string& probe_url,
229     const std::string& response,
230     bool request_succeeded,
231     bool expected_restricted) {
232   SetProbeResult(probe_url,
233                  response,
234                  FetchResult(!settings_->restricted_by_carrier_,
235                              request_succeeded && (response == "OK")),
236                  request_succeeded,
237                  1);
238   settings_->OnIPAddressChanged();
239   base::MessageLoop::current()->RunUntilIdle();
240   CheckProxyConfigs(true, expected_restricted);
241 }
242
243 void DataReductionProxySettingsTestBase::CheckOnPrefChange(
244     bool enabled,
245     bool expected_enabled) {
246   // Always have a sucessful probe for pref change tests.
247   SetProbeResult(kProbeURLWithOKResponse,
248                  "OK",
249                  FetchResult(enabled, true),
250                  true,
251                  expected_enabled ? 1 : 0);
252   pref_service_.SetBoolean(prefs::kSpdyProxyAuthEnabled, enabled);
253   base::MessageLoop::current()->RunUntilIdle();
254   // Never expect the proxy to be restricted for pref change tests.
255   CheckProxyConfigs(expected_enabled, false);
256 }
257
258 void DataReductionProxySettingsTestBase::CheckInitDataReductionProxy(
259     bool enabled_at_startup) {
260   AddProxyToCommandLine();
261   base::MessageLoopForUI loop;
262   pref_service_.SetBoolean(prefs::kSpdyProxyAuthEnabled, enabled_at_startup);
263   SetProbeResult(kProbeURLWithOKResponse,
264                  "OK",
265                  FetchResult(enabled_at_startup, true),
266                  true,
267                  enabled_at_startup ? 1 : 0);
268   settings_->InitDataReductionProxySettings();
269   base::MessageLoop::current()->RunUntilIdle();
270   if (enabled_at_startup) {
271     CheckProxyConfigs(enabled_at_startup, false);
272   } else {
273     // This presumes the proxy preference hadn't been set up by Chrome.
274     CheckProxyPref(std::string(), std::string());
275   }
276 }
277
278
279 class DataReductionProxySettingsTest
280     : public ConcreteDataReductionProxySettingsTest<
281         DataReductionProxySettings> {
282 };
283
284
285 TEST_F(DataReductionProxySettingsTest, TestAuthenticationInit) {
286   AddProxyToCommandLine();
287   net::HttpAuthCache cache;
288   DataReductionProxySettings::InitDataReductionAuthentication(&cache);
289   DataReductionProxySettings::DataReductionProxyList proxies =
290       DataReductionProxySettings::GetDataReductionProxies();
291   for (DataReductionProxySettings::DataReductionProxyList::iterator it =
292            proxies.begin();  it != proxies.end(); ++it) {
293     net::HttpAuthCache::Entry* entry = cache.LookupByPath(*it,
294                                                           std::string("/"));
295     EXPECT_TRUE(entry != NULL);
296     EXPECT_EQ(net::HttpAuth::AUTH_SCHEME_SPDYPROXY, entry->scheme());
297     EXPECT_EQ("SpdyProxy", entry->auth_challenge().substr(0,9));
298   }
299   GURL bad_server = GURL("https://bad.proxy.com/");
300   net::HttpAuthCache::Entry* entry =
301       cache.LookupByPath(bad_server, std::string());
302   EXPECT_TRUE(entry == NULL);
303 }
304
305 TEST_F(DataReductionProxySettingsTest, TestGetDataReductionProxyOrigin) {
306   AddProxyToCommandLine();
307   // SetUp() adds the origin to the command line, which should be returned here.
308   std::string result =
309       DataReductionProxySettings::GetDataReductionProxyOrigin();
310   EXPECT_EQ(kDataReductionProxyOrigin, result);
311 }
312
313 TEST_F(DataReductionProxySettingsTest, TestGetDataReductionProxyDevOrigin) {
314   AddProxyToCommandLine();
315   CommandLine::ForCurrentProcess()->AppendSwitchASCII(
316       switches::kSpdyProxyDevAuthOrigin, kDataReductionProxyDevHost);
317   std::string result =
318       DataReductionProxySettings::GetDataReductionProxyOrigin();
319   EXPECT_EQ(kDataReductionProxyDevHost, result);
320 }
321
322 TEST_F(DataReductionProxySettingsTest, TestGetDataReductionProxies) {
323   DataReductionProxySettings::DataReductionProxyList proxies =
324       DataReductionProxySettings::GetDataReductionProxies();
325
326   unsigned int expected_proxy_size = 0u;
327 #if defined(SPDY_PROXY_AUTH_ORIGIN)
328   ++expected_proxy_size;
329 #endif
330 #if defined(DATA_REDUCTION_FALLBACK_HOST)
331   ++expected_proxy_size;
332 #endif
333
334   EXPECT_EQ(expected_proxy_size, proxies.size());
335
336   // Adding just the fallback on the command line shouldn't add a proxy unless
337   // there was already one compiled in.
338   CommandLine::ForCurrentProcess()->AppendSwitchASCII(
339       switches::kSpdyProxyAuthFallback, kDataReductionProxyFallback);
340   proxies = DataReductionProxySettings::GetDataReductionProxies();
341
342   // So: if there weren't any proxies before, there still won't be.
343   // If there were one or two, there will be two now.
344   expected_proxy_size = expected_proxy_size == 0u ? 0u : 2u;
345
346   EXPECT_EQ(expected_proxy_size, proxies.size());
347
348   CommandLine::ForCurrentProcess()->AppendSwitchASCII(
349     switches::kSpdyProxyAuthOrigin, kDataReductionProxyOrigin);
350   proxies = DataReductionProxySettings::GetDataReductionProxies();
351   EXPECT_EQ(2u, proxies.size());
352
353   // Command line proxies have precedence, so even if there were other values
354   // compiled in, these should be the ones in the list.
355   EXPECT_EQ("foo.com", proxies[0].host());
356   EXPECT_EQ(443 ,proxies[0].EffectiveIntPort());
357   EXPECT_EQ("bar.com", proxies[1].host());
358   EXPECT_EQ(80, proxies[1].EffectiveIntPort());
359 }
360
361 TEST_F(DataReductionProxySettingsTest, TestAuthHashGeneration) {
362   AddProxyToCommandLine();
363   std::string salt = "8675309";  // Jenny's number to test the hash generator.
364   std::string salted_key = salt + kDataReductionProxyAuth + salt;
365   base::string16 expected_hash = base::UTF8ToUTF16(base::MD5String(salted_key));
366   EXPECT_EQ(expected_hash,
367             DataReductionProxySettings::AuthHashForSalt(8675309));
368 }
369
370 // Test that the auth key set by preprocessor directive is not used
371 // when an origin is set via a switch. This test only does anything useful in
372 // Chrome builds.
373 TEST_F(DataReductionProxySettingsTest,
374        TestAuthHashGenerationWithOriginSetViaSwitch) {
375   CommandLine::ForCurrentProcess()->AppendSwitchASCII(
376       switches::kSpdyProxyAuthOrigin, kDataReductionProxyOrigin);
377   EXPECT_EQ(base::string16(),
378             DataReductionProxySettings::AuthHashForSalt(8675309));
379 }
380
381
382 TEST_F(DataReductionProxySettingsTest, TestIsProxyEnabledOrManaged) {
383   settings_->InitPrefMembers();
384   EXPECT_FALSE(settings_->IsDataReductionProxyEnabled());
385   EXPECT_FALSE(settings_->IsDataReductionProxyManaged());
386
387   pref_service_.SetBoolean(prefs::kSpdyProxyAuthEnabled, true);
388   EXPECT_TRUE(settings_->IsDataReductionProxyEnabled());
389   EXPECT_FALSE(settings_->IsDataReductionProxyManaged());
390
391   pref_service_.SetManagedPref(prefs::kSpdyProxyAuthEnabled,
392                                base::Value::CreateBooleanValue(true));
393   EXPECT_TRUE(settings_->IsDataReductionProxyEnabled());
394   EXPECT_TRUE(settings_->IsDataReductionProxyManaged());
395 }
396
397
398 TEST_F(DataReductionProxySettingsTest, TestAcceptableChallenges) {
399   AddProxyToCommandLine();
400   typedef struct {
401     std::string host;
402     std::string realm;
403     bool expected_to_succeed;
404   } challenge_test;
405
406   challenge_test tests[] = {
407     {"foo.com:443", "", false},                 // 0. No realm.
408     {"foo.com:443", "xxx", false},              // 1. Wrong realm.
409     {"foo.com:443", "spdyproxy", false},        // 2. Case matters.
410     {"foo.com:443", "SpdyProxy", true},         // 3. OK.
411     {"foo.com:443", "SpdyProxy1234567", true},  // 4. OK
412     {"bar.com:80", "SpdyProxy1234567", true},   // 5. OK.
413     {"foo.com:443", "SpdyProxyxxx", true},      // 6. OK
414     {"", "SpdyProxy1234567", false},            // 7. No challenger.
415     {"xxx.net:443", "SpdyProxy1234567", false}, // 8. Wrong host.
416     {"foo.com", "SpdyProxy1234567", false},     // 9. No port.
417     {"foo.com:80", "SpdyProxy1234567", false},  // 10.Wrong port.
418     {"bar.com:81", "SpdyProxy1234567", false},  // 11.Wrong port.
419   };
420
421   for (int i = 0; i <= 11; ++i) {
422     scoped_refptr<net::AuthChallengeInfo> auth_info(new net::AuthChallengeInfo);
423     auth_info->challenger = net::HostPortPair::FromString(tests[i].host);
424     auth_info->realm = tests[i].realm;
425     EXPECT_EQ(tests[i].expected_to_succeed,
426               settings_->IsAcceptableAuthChallenge(auth_info.get()));
427   }
428 }
429
430 TEST_F(DataReductionProxySettingsTest, TestChallengeTokens) {
431   AddProxyToCommandLine();
432   typedef struct {
433     std::string realm;
434     bool expected_empty_token;
435   } token_test;
436
437   token_test tests[] = {
438     {"", true},                  // 0. No realm.
439     {"xxx", true},               // 1. realm too short.
440     {"spdyproxy", true},         // 2. no salt.
441     {"SpdyProxyxxx", true},      // 3. Salt not an int.
442     {"SpdyProxy1234567", false}, // 4. OK
443   };
444
445   for (int i = 0; i <= 4; ++i) {
446     scoped_refptr<net::AuthChallengeInfo> auth_info(new net::AuthChallengeInfo);
447     auth_info->challenger =
448         net::HostPortPair::FromString(kDataReductionProxyOrigin);
449     auth_info->realm = tests[i].realm;
450     base::string16 token = settings_->GetTokenForAuthChallenge(auth_info.get());
451     EXPECT_EQ(tests[i].expected_empty_token, token.empty());
452   }
453 }
454
455 TEST_F(DataReductionProxySettingsTest, TestResetDataReductionStatistics) {
456   int64 original_content_length;
457   int64 received_content_length;
458   int64 last_update_time;
459   settings_->ResetDataReductionStatistics();
460   settings_->GetContentLengths(spdyproxy::kNumDaysInHistory,
461                                &original_content_length,
462                                &received_content_length,
463                                &last_update_time);
464   EXPECT_EQ(0L, original_content_length);
465   EXPECT_EQ(0L, received_content_length);
466   EXPECT_EQ(last_update_time_.ToInternalValue(), last_update_time);
467 }
468
469 TEST_F(DataReductionProxySettingsTest, TestContentLengths) {
470   int64 original_content_length;
471   int64 received_content_length;
472   int64 last_update_time;
473
474   // Request |kNumDaysInHistory| days.
475   settings_->GetContentLengths(spdyproxy::kNumDaysInHistory,
476                                &original_content_length,
477                                &received_content_length,
478                                &last_update_time);
479   const unsigned int days = spdyproxy::kNumDaysInHistory;
480   // Received content length history values are 0 to |kNumDaysInHistory - 1|.
481   int64 expected_total_received_content_length = (days - 1L) * days / 2;
482   // Original content length history values are 0 to
483   // |2 * (kNumDaysInHistory - 1)|.
484   long expected_total_original_content_length = (days - 1L) * days;
485   EXPECT_EQ(expected_total_original_content_length, original_content_length);
486   EXPECT_EQ(expected_total_received_content_length, received_content_length);
487   EXPECT_EQ(last_update_time_.ToInternalValue(), last_update_time);
488
489   // Request |kNumDaysInHistory - 1| days.
490   settings_->GetContentLengths(spdyproxy::kNumDaysInHistory - 1,
491                                &original_content_length,
492                                &received_content_length,
493                                &last_update_time);
494   expected_total_received_content_length -= (days - 1);
495   expected_total_original_content_length -= 2 * (days - 1);
496   EXPECT_EQ(expected_total_original_content_length, original_content_length);
497   EXPECT_EQ(expected_total_received_content_length, received_content_length);
498
499   // Request 0 days.
500   settings_->GetContentLengths(0,
501                                &original_content_length,
502                                &received_content_length,
503                                &last_update_time);
504   expected_total_received_content_length = 0;
505   expected_total_original_content_length = 0;
506   EXPECT_EQ(expected_total_original_content_length, original_content_length);
507   EXPECT_EQ(expected_total_received_content_length, received_content_length);
508
509   // Request 1 day. First day had 0 bytes so should be same as 0 days.
510   settings_->GetContentLengths(1,
511                                &original_content_length,
512                                &received_content_length,
513                                &last_update_time);
514   EXPECT_EQ(expected_total_original_content_length, original_content_length);
515   EXPECT_EQ(expected_total_received_content_length, received_content_length);
516 }
517
518 // TODO(marq): Add a test to verify that MaybeActivateDataReductionProxy
519 // is called when the pref in |settings_| is enabled.
520 TEST_F(DataReductionProxySettingsTest, TestMaybeActivateDataReductionProxy) {
521   AddProxyToCommandLine();
522
523   // Initialize the pref member in |settings_| without the usual callback
524   // so it won't trigger MaybeActivateDataReductionProxy when the pref value
525   // is set.
526   settings_->spdy_proxy_auth_enabled_.Init(
527       prefs::kSpdyProxyAuthEnabled,
528       settings_->GetOriginalProfilePrefs());
529
530   // TODO(bengr): Test enabling/disabling while a probe is outstanding.
531   base::MessageLoopForUI loop;
532   // The proxy is enabled and unrestructed initially.
533   // Request succeeded but with bad response, expect proxy to be restricted.
534   CheckProbe(true, kProbeURLWithBadResponse, "Bad", true, true, true);
535   // Request succeeded with valid response, expect proxy to be unrestricted.
536   CheckProbe(true, kProbeURLWithOKResponse, "OK", true, true, false);
537   // Request failed, expect proxy to be enabled but restricted.
538   CheckProbe(true, kProbeURLWithNoResponse, "", false, true, true);
539   // The proxy is disabled initially. Probes should not be emitted to change
540   // state.
541   CheckProbe(false, kProbeURLWithOKResponse, "OK", true, false, false);
542 }
543
544 TEST_F(DataReductionProxySettingsTest, TestOnIPAddressChanged) {
545   AddProxyToCommandLine();
546   base::MessageLoopForUI loop;
547   // The proxy is enabled initially.
548   pref_service_.SetBoolean(prefs::kSpdyProxyAuthEnabled, true);
549   settings_->spdy_proxy_auth_enabled_.Init(
550       prefs::kSpdyProxyAuthEnabled,
551       settings_->GetOriginalProfilePrefs());
552   settings_->enabled_by_user_ = true;
553   settings_->restricted_by_carrier_ = false;
554   settings_->SetProxyConfigs(true, false, true);
555   // IP address change triggers a probe that succeeds. Proxy remains
556   // unrestricted.
557   CheckProbeOnIPChange(kProbeURLWithOKResponse, "OK", true, false);
558   // IP address change triggers a probe that fails. Proxy is restricted.
559   CheckProbeOnIPChange(kProbeURLWithBadResponse, "Bad", true, true);
560   // IP address change triggers a probe that fails. Proxy remains restricted.
561   CheckProbeOnIPChange(kProbeURLWithBadResponse, "Bad", true, true);
562   // IP address change triggers a probe that succeed. Proxy is unrestricted.
563   CheckProbeOnIPChange(kProbeURLWithBadResponse, "OK", true, false);
564 }
565
566 TEST_F(DataReductionProxySettingsTest, TestOnProxyEnabledPrefChange) {
567   AddProxyToCommandLine();
568   settings_->InitPrefMembers();
569   base::MessageLoopForUI loop;
570   // The proxy is enabled initially.
571   settings_->enabled_by_user_ = true;
572   settings_->SetProxyConfigs(true, false, true);
573   // The pref is disabled, so correspondingly should be the proxy.
574   CheckOnPrefChange(false, false);
575   // The pref is enabled, so correspondingly should be the proxy.
576   CheckOnPrefChange(true, true);
577 }
578
579 TEST_F(DataReductionProxySettingsTest, TestInitDataReductionProxyOn) {
580   MockSettings* settings = static_cast<MockSettings*>(settings_.get());
581   EXPECT_CALL(*settings, RecordStartupState(spdyproxy::PROXY_ENABLED));
582   CheckInitDataReductionProxy(true);
583 }
584
585 TEST_F(DataReductionProxySettingsTest, TestInitDataReductionProxyOff) {
586   // InitDataReductionProxySettings with the preference off will directly call
587   // LogProxyState.
588   MockSettings* settings = static_cast<MockSettings*>(settings_.get());
589   EXPECT_CALL(*settings, LogProxyState(false, false, true)).Times(1);
590   EXPECT_CALL(*settings, RecordStartupState(spdyproxy::PROXY_DISABLED));
591   CheckInitDataReductionProxy(false);
592 }
593
594 TEST_F(DataReductionProxySettingsTest, TestGetDailyContentLengths) {
595   DataReductionProxySettings::ContentLengthList result =
596       settings_->GetDailyContentLengths(prefs::kDailyHttpOriginalContentLength);
597
598   ASSERT_FALSE(result.empty());
599   ASSERT_EQ(spdyproxy::kNumDaysInHistory, result.size());
600
601   for (size_t i = 0; i < spdyproxy::kNumDaysInHistory; ++i) {
602     long expected_length =
603         static_cast<long>((spdyproxy::kNumDaysInHistory - 1 - i) * 2);
604     ASSERT_EQ(expected_length, result[i]);
605   }
606 }
607
608 TEST_F(DataReductionProxySettingsTest, TestBypassList) {
609   settings_->AddHostPatternToBypass("http://www.google.com");
610   settings_->AddHostPatternToBypass("fefe:13::abc/33");
611   settings_->AddURLPatternToBypass("foo.org/images/*");
612   settings_->AddURLPatternToBypass("http://foo.com/*");
613   settings_->AddURLPatternToBypass("http://baz.com:22/bar/*");
614   settings_->AddURLPatternToBypass("http://*bat.com/bar/*");
615
616   std::string expected[] = {
617     "http://www.google.com",
618     "fefe:13::abc/33",
619     "foo.org",
620     "http://foo.com",
621     "http://baz.com:22",
622     "http://*bat.com"
623   };
624
625   ASSERT_EQ(settings_->bypass_rules_.size(), 6u);
626   int i = 0;
627   for (std::vector<std::string>::iterator it = settings_->bypass_rules_.begin();
628        it != settings_->bypass_rules_.end(); ++it) {
629     EXPECT_EQ(expected[i++], *it);
630   }
631 }
632
633 TEST_F(DataReductionProxySettingsTest, WasFetchedViaProxy) {
634   const struct {
635      const char* headers;
636      bool expected_result;
637   } tests[] = {
638     { "HTTP/1.1 200 OK\n"
639       "Via: 1.1 Chrome Proxy\n",
640       false,
641     },
642     { "HTTP/1.1 200 OK\n"
643       "Via: 1.1 Chrome Compression Proxy\n",
644       true,
645     },
646     { "HTTP/1.1 200 OK\n"
647       "Via: 1.1 Foo Bar, 1.1 Chrome Compression Proxy\n",
648       true,
649     },
650     { "HTTP/1.1 200 OK\n"
651       "Via: 1.1 Chrome Compression Proxy, 1.1 Bar Foo\n",
652       true,
653     },
654     { "HTTP/1.1 200 OK\n"
655       "Via: 1.1 chrome compression proxy\n",
656       false,
657     },
658     { "HTTP/1.1 200 OK\n"
659       "Via: 1.1 Foo Bar\n"
660       "Via: 1.1 Chrome Compression Proxy\n",
661       true,
662     },
663   };
664   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
665     std::string headers(tests[i].headers);
666     HeadersToRaw(&headers);
667     scoped_refptr<net::HttpResponseHeaders> parsed(
668         new net::HttpResponseHeaders(headers));
669
670     EXPECT_EQ(tests[i].expected_result,
671               DataReductionProxySettings::WasFetchedViaProxy(parsed));
672   }
673 }
674
675 TEST_F(DataReductionProxySettingsTest, CheckInitMetricsWhenNotAllowed) {
676   // No call to |AddProxyToCommandLine()| was made, so the proxy feature
677   // should be unavailable.
678   EXPECT_FALSE(DataReductionProxySettings::IsDataReductionProxyAllowed());
679   MockSettings* settings = static_cast<MockSettings*>(settings_.get());
680   EXPECT_CALL(*settings, RecordStartupState(spdyproxy::PROXY_NOT_AVAILABLE));
681   settings_->InitDataReductionProxySettings();
682 }