1 // Copyright (c) 2011 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.
5 #include "chrome/browser/net/pref_proxy_config_tracker_impl.h"
7 #include "base/command_line.h"
8 #include "base/files/file_path.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/prefs/pref_registry_simple.h"
11 #include "base/prefs/testing_pref_service.h"
12 #include "chrome/browser/net/chrome_url_request_context.h"
13 #include "chrome/browser/prefs/pref_service_mock_factory.h"
14 #include "chrome/browser/prefs/proxy_config_dictionary.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "chrome/common/pref_names.h"
17 #include "content/public/test/test_browser_thread.h"
18 #include "net/proxy/proxy_config_service_common_unittest.h"
19 #include "testing/gmock/include/gmock/gmock.h"
20 #include "testing/gtest/include/gtest/gtest.h"
22 using content::BrowserThread
;
28 const char kFixedPacUrl
[] = "http://chromium.org/fixed_pac_url";
30 // Testing proxy config service that allows us to fire notifications at will.
31 class TestProxyConfigService
: public net::ProxyConfigService
{
33 TestProxyConfigService(const net::ProxyConfig
& config
,
34 ConfigAvailability availability
)
36 availability_(availability
) {}
38 void SetProxyConfig(const net::ProxyConfig config
,
39 ConfigAvailability availability
) {
41 availability_
= availability
;
42 FOR_EACH_OBSERVER(net::ProxyConfigService::Observer
, observers_
,
43 OnProxyConfigChanged(config
, availability
));
47 virtual void AddObserver(
48 net::ProxyConfigService::Observer
* observer
) OVERRIDE
{
49 observers_
.AddObserver(observer
);
52 virtual void RemoveObserver(
53 net::ProxyConfigService::Observer
* observer
) OVERRIDE
{
54 observers_
.RemoveObserver(observer
);
57 virtual net::ProxyConfigService::ConfigAvailability
GetLatestProxyConfig(
58 net::ProxyConfig
* config
) OVERRIDE
{
63 net::ProxyConfig config_
;
64 ConfigAvailability availability_
;
65 ObserverList
<net::ProxyConfigService::Observer
, true> observers_
;
68 // A mock observer for capturing callbacks.
69 class MockObserver
: public net::ProxyConfigService::Observer
{
71 MOCK_METHOD2(OnProxyConfigChanged
,
72 void(const net::ProxyConfig
&,
73 net::ProxyConfigService::ConfigAvailability
));
76 template<typename TESTBASE
>
77 class PrefProxyConfigTrackerImplTestBase
: public TESTBASE
{
79 PrefProxyConfigTrackerImplTestBase()
80 : ui_thread_(BrowserThread::UI
, &loop_
),
81 io_thread_(BrowserThread::IO
, &loop_
) {}
83 virtual void Init(PrefService
* pref_service
, PrefRegistrySimple
* registry
) {
84 ASSERT_TRUE(pref_service
);
85 PrefProxyConfigTrackerImpl::RegisterPrefs(registry
);
86 fixed_config_
.set_pac_url(GURL(kFixedPacUrl
));
88 new TestProxyConfigService(fixed_config_
,
89 net::ProxyConfigService::CONFIG_VALID
);
90 proxy_config_tracker_
.reset(new PrefProxyConfigTrackerImpl(pref_service
));
91 proxy_config_service_
=
92 proxy_config_tracker_
->CreateTrackingProxyConfigService(
93 scoped_ptr
<net::ProxyConfigService
>(delegate_service_
));
94 // SetChromeProxyConfigService triggers update of initial prefs proxy
95 // config by tracker to chrome proxy config service, so flush all pending
96 // tasks so that tests start fresh.
100 virtual void TearDown() {
101 proxy_config_tracker_
->DetachFromPrefService();
102 loop_
.RunUntilIdle();
103 proxy_config_tracker_
.reset();
104 proxy_config_service_
.reset();
107 base::MessageLoop loop_
;
108 TestProxyConfigService
* delegate_service_
; // weak
109 scoped_ptr
<net::ProxyConfigService
> proxy_config_service_
;
110 net::ProxyConfig fixed_config_
;
113 scoped_ptr
<PrefProxyConfigTrackerImpl
> proxy_config_tracker_
;
114 content::TestBrowserThread ui_thread_
;
115 content::TestBrowserThread io_thread_
;
118 class PrefProxyConfigTrackerImplTest
119 : public PrefProxyConfigTrackerImplTestBase
<testing::Test
> {
121 virtual void SetUp() {
122 pref_service_
.reset(new TestingPrefServiceSimple());
123 Init(pref_service_
.get(), pref_service_
->registry());
126 scoped_ptr
<TestingPrefServiceSimple
> pref_service_
;
129 TEST_F(PrefProxyConfigTrackerImplTest
, BaseConfiguration
) {
130 net::ProxyConfig actual_config
;
131 EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID
,
132 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
133 EXPECT_EQ(GURL(kFixedPacUrl
), actual_config
.pac_url());
136 TEST_F(PrefProxyConfigTrackerImplTest
, DynamicPrefOverrides
) {
137 pref_service_
->SetManagedPref(prefs::kProxy
,
138 ProxyConfigDictionary::CreateFixedServers(
139 "http://example.com:3128", std::string()));
140 loop_
.RunUntilIdle();
142 net::ProxyConfig actual_config
;
143 EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID
,
144 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
145 EXPECT_FALSE(actual_config
.auto_detect());
146 EXPECT_EQ(net::ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY
,
147 actual_config
.proxy_rules().type
);
148 EXPECT_EQ(actual_config
.proxy_rules().single_proxies
.Get(),
149 net::ProxyServer::FromURI("http://example.com:3128",
150 net::ProxyServer::SCHEME_HTTP
));
152 pref_service_
->SetManagedPref(prefs::kProxy
,
153 ProxyConfigDictionary::CreateAutoDetect());
154 loop_
.RunUntilIdle();
156 EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID
,
157 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
158 EXPECT_TRUE(actual_config
.auto_detect());
161 // Compares proxy configurations, but allows different identifiers.
162 MATCHER_P(ProxyConfigMatches
, config
, "") {
163 net::ProxyConfig
reference(config
);
164 reference
.set_id(arg
.id());
165 return reference
.Equals(arg
);
168 TEST_F(PrefProxyConfigTrackerImplTest
, Observers
) {
169 const net::ProxyConfigService::ConfigAvailability CONFIG_VALID
=
170 net::ProxyConfigService::CONFIG_VALID
;
171 MockObserver observer
;
172 proxy_config_service_
->AddObserver(&observer
);
174 // Firing the observers in the delegate should trigger a notification.
175 net::ProxyConfig config2
;
176 config2
.set_auto_detect(true);
177 EXPECT_CALL(observer
, OnProxyConfigChanged(ProxyConfigMatches(config2
),
178 CONFIG_VALID
)).Times(1);
179 delegate_service_
->SetProxyConfig(config2
, CONFIG_VALID
);
180 loop_
.RunUntilIdle();
181 Mock::VerifyAndClearExpectations(&observer
);
183 // Override configuration, this should trigger a notification.
184 net::ProxyConfig pref_config
;
185 pref_config
.set_pac_url(GURL(kFixedPacUrl
));
187 EXPECT_CALL(observer
, OnProxyConfigChanged(ProxyConfigMatches(pref_config
),
188 CONFIG_VALID
)).Times(1);
189 pref_service_
->SetManagedPref(
191 ProxyConfigDictionary::CreatePacScript(kFixedPacUrl
, false));
192 loop_
.RunUntilIdle();
193 Mock::VerifyAndClearExpectations(&observer
);
195 // Since there are pref overrides, delegate changes should be ignored.
196 net::ProxyConfig config3
;
197 config3
.proxy_rules().ParseFromString("http=config3:80");
198 EXPECT_CALL(observer
, OnProxyConfigChanged(_
, _
)).Times(0);
199 fixed_config_
.set_auto_detect(true);
200 delegate_service_
->SetProxyConfig(config3
, CONFIG_VALID
);
201 loop_
.RunUntilIdle();
202 Mock::VerifyAndClearExpectations(&observer
);
204 // Clear the override should switch back to the fixed configuration.
205 EXPECT_CALL(observer
, OnProxyConfigChanged(ProxyConfigMatches(config3
),
206 CONFIG_VALID
)).Times(1);
207 pref_service_
->RemoveManagedPref(prefs::kProxy
);
208 loop_
.RunUntilIdle();
209 Mock::VerifyAndClearExpectations(&observer
);
211 // Delegate service notifications should show up again.
212 net::ProxyConfig config4
;
213 config4
.proxy_rules().ParseFromString("socks:config4");
214 EXPECT_CALL(observer
, OnProxyConfigChanged(ProxyConfigMatches(config4
),
215 CONFIG_VALID
)).Times(1);
216 delegate_service_
->SetProxyConfig(config4
, CONFIG_VALID
);
217 loop_
.RunUntilIdle();
218 Mock::VerifyAndClearExpectations(&observer
);
220 proxy_config_service_
->RemoveObserver(&observer
);
223 TEST_F(PrefProxyConfigTrackerImplTest
, Fallback
) {
224 const net::ProxyConfigService::ConfigAvailability CONFIG_VALID
=
225 net::ProxyConfigService::CONFIG_VALID
;
226 MockObserver observer
;
227 net::ProxyConfig actual_config
;
228 delegate_service_
->SetProxyConfig(net::ProxyConfig::CreateDirect(),
229 net::ProxyConfigService::CONFIG_UNSET
);
230 proxy_config_service_
->AddObserver(&observer
);
232 // Prepare test data.
233 net::ProxyConfig recommended_config
= net::ProxyConfig::CreateAutoDetect();
234 net::ProxyConfig user_config
=
235 net::ProxyConfig::CreateFromCustomPacURL(GURL(kFixedPacUrl
));
237 // Set a recommended pref.
238 EXPECT_CALL(observer
,
239 OnProxyConfigChanged(ProxyConfigMatches(recommended_config
),
240 CONFIG_VALID
)).Times(1);
241 pref_service_
->SetRecommendedPref(
243 ProxyConfigDictionary::CreateAutoDetect());
244 loop_
.RunUntilIdle();
245 Mock::VerifyAndClearExpectations(&observer
);
246 EXPECT_EQ(CONFIG_VALID
,
247 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
248 EXPECT_TRUE(actual_config
.Equals(recommended_config
));
250 // Override in user prefs.
251 EXPECT_CALL(observer
,
252 OnProxyConfigChanged(ProxyConfigMatches(user_config
),
253 CONFIG_VALID
)).Times(1);
254 pref_service_
->SetManagedPref(
256 ProxyConfigDictionary::CreatePacScript(kFixedPacUrl
, false));
257 loop_
.RunUntilIdle();
258 Mock::VerifyAndClearExpectations(&observer
);
259 EXPECT_EQ(CONFIG_VALID
,
260 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
261 EXPECT_TRUE(actual_config
.Equals(user_config
));
263 // Go back to recommended pref.
264 EXPECT_CALL(observer
,
265 OnProxyConfigChanged(ProxyConfigMatches(recommended_config
),
266 CONFIG_VALID
)).Times(1);
267 pref_service_
->RemoveManagedPref(prefs::kProxy
);
268 loop_
.RunUntilIdle();
269 Mock::VerifyAndClearExpectations(&observer
);
270 EXPECT_EQ(CONFIG_VALID
,
271 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
272 EXPECT_TRUE(actual_config
.Equals(recommended_config
));
274 proxy_config_service_
->RemoveObserver(&observer
);
277 TEST_F(PrefProxyConfigTrackerImplTest
, ExplicitSystemSettings
) {
278 pref_service_
->SetRecommendedPref(
280 ProxyConfigDictionary::CreateAutoDetect());
281 pref_service_
->SetUserPref(
283 ProxyConfigDictionary::CreateSystem());
284 loop_
.RunUntilIdle();
286 // Test if we actually use the system setting, which is |kFixedPacUrl|.
287 net::ProxyConfig actual_config
;
288 EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID
,
289 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
290 EXPECT_EQ(GURL(kFixedPacUrl
), actual_config
.pac_url());
293 // Test parameter object for testing command line proxy configuration.
294 struct CommandLineTestParams
{
295 // Explicit assignment operator, so testing::TestWithParam works with MSVC.
296 CommandLineTestParams
& operator=(const CommandLineTestParams
& other
) {
297 description
= other
.description
;
298 for (unsigned int i
= 0; i
< arraysize(switches
); i
++)
299 switches
[i
] = other
.switches
[i
];
300 is_null
= other
.is_null
;
301 auto_detect
= other
.auto_detect
;
302 pac_url
= other
.pac_url
;
303 proxy_rules
= other
.proxy_rules
;
307 // Short description to identify the test.
308 const char* description
;
310 // The command line to build a ProxyConfig from.
316 // Expected outputs (fields of the ProxyConfig).
320 net::ProxyRulesExpectation proxy_rules
;
323 void PrintTo(const CommandLineTestParams
& params
, std::ostream
* os
) {
324 *os
<< params
.description
;
327 class PrefProxyConfigTrackerImplCommandLineTest
328 : public PrefProxyConfigTrackerImplTestBase
<
329 testing::TestWithParam
<CommandLineTestParams
> > {
331 PrefProxyConfigTrackerImplCommandLineTest()
332 : command_line_(CommandLine::NO_PROGRAM
) {}
334 virtual void SetUp() {
335 for (size_t i
= 0; i
< arraysize(GetParam().switches
); i
++) {
336 const char* name
= GetParam().switches
[i
].name
;
337 const char* value
= GetParam().switches
[i
].value
;
339 command_line_
.AppendSwitchASCII(name
, value
);
341 command_line_
.AppendSwitch(name
);
343 scoped_refptr
<PrefRegistrySimple
> registry
= new PrefRegistrySimple
;
344 PrefServiceMockFactory factory
;
345 factory
.SetCommandLine(&command_line_
);
346 pref_service_
= factory
.Create(registry
.get()).Pass();
347 Init(pref_service_
.get(), registry
.get());
351 CommandLine command_line_
;
352 scoped_ptr
<PrefService
> pref_service_
;
355 TEST_P(PrefProxyConfigTrackerImplCommandLineTest
, CommandLine
) {
356 net::ProxyConfig config
;
357 EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID
,
358 proxy_config_service_
->GetLatestProxyConfig(&config
));
360 if (GetParam().is_null
) {
361 EXPECT_EQ(GURL(kFixedPacUrl
), config
.pac_url());
363 EXPECT_NE(GURL(kFixedPacUrl
), config
.pac_url());
364 EXPECT_EQ(GetParam().auto_detect
, config
.auto_detect());
365 EXPECT_EQ(GetParam().pac_url
, config
.pac_url());
366 EXPECT_TRUE(GetParam().proxy_rules
.Matches(config
.proxy_rules()));
370 static const CommandLineTestParams kCommandLineTestParams
[] = {
372 "Empty command line",
377 false, // auto_detect
379 net::ProxyRulesExpectation::Empty(),
385 { switches::kNoProxyServer
, NULL
},
389 false, // auto_detect
391 net::ProxyRulesExpectation::Empty(),
394 "No proxy with extra parameters.",
397 { switches::kNoProxyServer
, NULL
},
398 { switches::kProxyServer
, "http://proxy:8888" },
402 false, // auto_detect
404 net::ProxyRulesExpectation::Empty(),
410 { switches::kProxyServer
, "http://proxy:8888" },
414 false, // auto_detect
416 net::ProxyRulesExpectation::Single(
417 "proxy:8888", // single proxy
424 { switches::kProxyServer
, "http=httpproxy:8888;ftp=ftpproxy:8889" },
428 false, // auto_detect
430 net::ProxyRulesExpectation::PerScheme(
431 "httpproxy:8888", // http
433 "ftpproxy:8889", // ftp
437 "Per scheme proxy with bypass URLs.",
440 { switches::kProxyServer
, "http=httpproxy:8888;ftp=ftpproxy:8889" },
441 { switches::kProxyBypassList
,
442 ".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8" },
446 false, // auto_detect
448 net::ProxyRulesExpectation::PerScheme(
449 "httpproxy:8888", // http
451 "ftpproxy:8889", // ftp
452 "*.google.com,foo.com:99,1.2.3.4:22,127.0.0.1/8"),
458 { switches::kProxyPacUrl
, "http://wpad/wpad.dat" },
462 false, // auto_detect
463 GURL("http://wpad/wpad.dat"), // pac_url
464 net::ProxyRulesExpectation::Empty(),
470 { switches::kProxyAutoDetect
, NULL
},
476 net::ProxyRulesExpectation::Empty(),
480 INSTANTIATE_TEST_CASE_P(
481 PrefProxyConfigTrackerImplCommandLineTestInstance
,
482 PrefProxyConfigTrackerImplCommandLineTest
,
483 testing::ValuesIn(kCommandLineTestParams
));