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/prefs/pref_service_mock_factory.h"
13 #include "chrome/browser/prefs/proxy_config_dictionary.h"
14 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/pref_names.h"
16 #include "content/public/test/test_browser_thread.h"
17 #include "net/proxy/proxy_config_service_common_unittest.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
21 using content::BrowserThread
;
27 const char kFixedPacUrl
[] = "http://chromium.org/fixed_pac_url";
29 // Testing proxy config service that allows us to fire notifications at will.
30 class TestProxyConfigService
: public net::ProxyConfigService
{
32 TestProxyConfigService(const net::ProxyConfig
& config
,
33 ConfigAvailability availability
)
35 availability_(availability
) {}
37 void SetProxyConfig(const net::ProxyConfig config
,
38 ConfigAvailability availability
) {
40 availability_
= availability
;
41 FOR_EACH_OBSERVER(net::ProxyConfigService::Observer
, observers_
,
42 OnProxyConfigChanged(config
, availability
));
46 void AddObserver(net::ProxyConfigService::Observer
* observer
) override
{
47 observers_
.AddObserver(observer
);
50 void RemoveObserver(net::ProxyConfigService::Observer
* observer
) override
{
51 observers_
.RemoveObserver(observer
);
54 net::ProxyConfigService::ConfigAvailability
GetLatestProxyConfig(
55 net::ProxyConfig
* config
) override
{
60 net::ProxyConfig config_
;
61 ConfigAvailability availability_
;
62 ObserverList
<net::ProxyConfigService::Observer
, true> observers_
;
65 // A mock observer for capturing callbacks.
66 class MockObserver
: public net::ProxyConfigService::Observer
{
68 MOCK_METHOD2(OnProxyConfigChanged
,
69 void(const net::ProxyConfig
&,
70 net::ProxyConfigService::ConfigAvailability
));
73 template<typename TESTBASE
>
74 class PrefProxyConfigTrackerImplTestBase
: public TESTBASE
{
76 PrefProxyConfigTrackerImplTestBase()
77 : ui_thread_(BrowserThread::UI
, &loop_
),
78 io_thread_(BrowserThread::IO
, &loop_
) {}
80 virtual void Init(PrefService
* pref_service
, PrefRegistrySimple
* registry
) {
81 ASSERT_TRUE(pref_service
);
82 PrefProxyConfigTrackerImpl::RegisterPrefs(registry
);
83 fixed_config_
.set_pac_url(GURL(kFixedPacUrl
));
85 new TestProxyConfigService(fixed_config_
,
86 net::ProxyConfigService::CONFIG_VALID
);
87 proxy_config_tracker_
.reset(new PrefProxyConfigTrackerImpl(pref_service
));
88 proxy_config_service_
=
89 proxy_config_tracker_
->CreateTrackingProxyConfigService(
90 scoped_ptr
<net::ProxyConfigService
>(delegate_service_
));
91 // SetChromeProxyConfigService triggers update of initial prefs proxy
92 // config by tracker to chrome proxy config service, so flush all pending
93 // tasks so that tests start fresh.
97 virtual void TearDown() {
98 proxy_config_tracker_
->DetachFromPrefService();
100 proxy_config_tracker_
.reset();
101 proxy_config_service_
.reset();
104 base::MessageLoop loop_
;
105 TestProxyConfigService
* delegate_service_
; // weak
106 scoped_ptr
<net::ProxyConfigService
> proxy_config_service_
;
107 net::ProxyConfig fixed_config_
;
110 scoped_ptr
<PrefProxyConfigTrackerImpl
> proxy_config_tracker_
;
111 content::TestBrowserThread ui_thread_
;
112 content::TestBrowserThread io_thread_
;
115 class PrefProxyConfigTrackerImplTest
116 : public PrefProxyConfigTrackerImplTestBase
<testing::Test
> {
118 void SetUp() override
{
119 pref_service_
.reset(new TestingPrefServiceSimple());
120 Init(pref_service_
.get(), pref_service_
->registry());
123 scoped_ptr
<TestingPrefServiceSimple
> pref_service_
;
126 TEST_F(PrefProxyConfigTrackerImplTest
, BaseConfiguration
) {
127 net::ProxyConfig actual_config
;
128 EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID
,
129 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
130 EXPECT_EQ(GURL(kFixedPacUrl
), actual_config
.pac_url());
133 TEST_F(PrefProxyConfigTrackerImplTest
, DynamicPrefOverrides
) {
134 pref_service_
->SetManagedPref(prefs::kProxy
,
135 ProxyConfigDictionary::CreateFixedServers(
136 "http://example.com:3128", std::string()));
137 loop_
.RunUntilIdle();
139 net::ProxyConfig actual_config
;
140 EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID
,
141 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
142 EXPECT_FALSE(actual_config
.auto_detect());
143 EXPECT_EQ(net::ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY
,
144 actual_config
.proxy_rules().type
);
145 EXPECT_EQ(actual_config
.proxy_rules().single_proxies
.Get(),
146 net::ProxyServer::FromURI("http://example.com:3128",
147 net::ProxyServer::SCHEME_HTTP
));
149 pref_service_
->SetManagedPref(prefs::kProxy
,
150 ProxyConfigDictionary::CreateAutoDetect());
151 loop_
.RunUntilIdle();
153 EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID
,
154 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
155 EXPECT_TRUE(actual_config
.auto_detect());
158 // Compares proxy configurations, but allows different identifiers.
159 MATCHER_P(ProxyConfigMatches
, config
, "") {
160 net::ProxyConfig
reference(config
);
161 reference
.set_id(arg
.id());
162 return reference
.Equals(arg
);
165 TEST_F(PrefProxyConfigTrackerImplTest
, Observers
) {
166 const net::ProxyConfigService::ConfigAvailability CONFIG_VALID
=
167 net::ProxyConfigService::CONFIG_VALID
;
168 MockObserver observer
;
169 proxy_config_service_
->AddObserver(&observer
);
171 // Firing the observers in the delegate should trigger a notification.
172 net::ProxyConfig config2
;
173 config2
.set_auto_detect(true);
174 EXPECT_CALL(observer
, OnProxyConfigChanged(ProxyConfigMatches(config2
),
175 CONFIG_VALID
)).Times(1);
176 delegate_service_
->SetProxyConfig(config2
, CONFIG_VALID
);
177 loop_
.RunUntilIdle();
178 Mock::VerifyAndClearExpectations(&observer
);
180 // Override configuration, this should trigger a notification.
181 net::ProxyConfig pref_config
;
182 pref_config
.set_pac_url(GURL(kFixedPacUrl
));
184 EXPECT_CALL(observer
, OnProxyConfigChanged(ProxyConfigMatches(pref_config
),
185 CONFIG_VALID
)).Times(1);
186 pref_service_
->SetManagedPref(
188 ProxyConfigDictionary::CreatePacScript(kFixedPacUrl
, false));
189 loop_
.RunUntilIdle();
190 Mock::VerifyAndClearExpectations(&observer
);
192 // Since there are pref overrides, delegate changes should be ignored.
193 net::ProxyConfig config3
;
194 config3
.proxy_rules().ParseFromString("http=config3:80");
195 EXPECT_CALL(observer
, OnProxyConfigChanged(_
, _
)).Times(0);
196 fixed_config_
.set_auto_detect(true);
197 delegate_service_
->SetProxyConfig(config3
, CONFIG_VALID
);
198 loop_
.RunUntilIdle();
199 Mock::VerifyAndClearExpectations(&observer
);
201 // Clear the override should switch back to the fixed configuration.
202 EXPECT_CALL(observer
, OnProxyConfigChanged(ProxyConfigMatches(config3
),
203 CONFIG_VALID
)).Times(1);
204 pref_service_
->RemoveManagedPref(prefs::kProxy
);
205 loop_
.RunUntilIdle();
206 Mock::VerifyAndClearExpectations(&observer
);
208 // Delegate service notifications should show up again.
209 net::ProxyConfig config4
;
210 config4
.proxy_rules().ParseFromString("socks:config4");
211 EXPECT_CALL(observer
, OnProxyConfigChanged(ProxyConfigMatches(config4
),
212 CONFIG_VALID
)).Times(1);
213 delegate_service_
->SetProxyConfig(config4
, CONFIG_VALID
);
214 loop_
.RunUntilIdle();
215 Mock::VerifyAndClearExpectations(&observer
);
217 proxy_config_service_
->RemoveObserver(&observer
);
220 TEST_F(PrefProxyConfigTrackerImplTest
, Fallback
) {
221 const net::ProxyConfigService::ConfigAvailability CONFIG_VALID
=
222 net::ProxyConfigService::CONFIG_VALID
;
223 MockObserver observer
;
224 net::ProxyConfig actual_config
;
225 delegate_service_
->SetProxyConfig(net::ProxyConfig::CreateDirect(),
226 net::ProxyConfigService::CONFIG_UNSET
);
227 proxy_config_service_
->AddObserver(&observer
);
229 // Prepare test data.
230 net::ProxyConfig recommended_config
= net::ProxyConfig::CreateAutoDetect();
231 net::ProxyConfig user_config
=
232 net::ProxyConfig::CreateFromCustomPacURL(GURL(kFixedPacUrl
));
234 // Set a recommended pref.
235 EXPECT_CALL(observer
,
236 OnProxyConfigChanged(ProxyConfigMatches(recommended_config
),
237 CONFIG_VALID
)).Times(1);
238 pref_service_
->SetRecommendedPref(
240 ProxyConfigDictionary::CreateAutoDetect());
241 loop_
.RunUntilIdle();
242 Mock::VerifyAndClearExpectations(&observer
);
243 EXPECT_EQ(CONFIG_VALID
,
244 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
245 EXPECT_TRUE(actual_config
.Equals(recommended_config
));
247 // Override in user prefs.
248 EXPECT_CALL(observer
,
249 OnProxyConfigChanged(ProxyConfigMatches(user_config
),
250 CONFIG_VALID
)).Times(1);
251 pref_service_
->SetManagedPref(
253 ProxyConfigDictionary::CreatePacScript(kFixedPacUrl
, false));
254 loop_
.RunUntilIdle();
255 Mock::VerifyAndClearExpectations(&observer
);
256 EXPECT_EQ(CONFIG_VALID
,
257 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
258 EXPECT_TRUE(actual_config
.Equals(user_config
));
260 // Go back to recommended pref.
261 EXPECT_CALL(observer
,
262 OnProxyConfigChanged(ProxyConfigMatches(recommended_config
),
263 CONFIG_VALID
)).Times(1);
264 pref_service_
->RemoveManagedPref(prefs::kProxy
);
265 loop_
.RunUntilIdle();
266 Mock::VerifyAndClearExpectations(&observer
);
267 EXPECT_EQ(CONFIG_VALID
,
268 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
269 EXPECT_TRUE(actual_config
.Equals(recommended_config
));
271 proxy_config_service_
->RemoveObserver(&observer
);
274 TEST_F(PrefProxyConfigTrackerImplTest
, ExplicitSystemSettings
) {
275 pref_service_
->SetRecommendedPref(
277 ProxyConfigDictionary::CreateAutoDetect());
278 pref_service_
->SetUserPref(
280 ProxyConfigDictionary::CreateSystem());
281 loop_
.RunUntilIdle();
283 // Test if we actually use the system setting, which is |kFixedPacUrl|.
284 net::ProxyConfig actual_config
;
285 EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID
,
286 proxy_config_service_
->GetLatestProxyConfig(&actual_config
));
287 EXPECT_EQ(GURL(kFixedPacUrl
), actual_config
.pac_url());
290 // Test parameter object for testing command line proxy configuration.
291 struct CommandLineTestParams
{
292 // Explicit assignment operator, so testing::TestWithParam works with MSVC.
293 CommandLineTestParams
& operator=(const CommandLineTestParams
& other
) {
294 description
= other
.description
;
295 for (unsigned int i
= 0; i
< arraysize(switches
); i
++)
296 switches
[i
] = other
.switches
[i
];
297 is_null
= other
.is_null
;
298 auto_detect
= other
.auto_detect
;
299 pac_url
= other
.pac_url
;
300 proxy_rules
= other
.proxy_rules
;
304 // Short description to identify the test.
305 const char* description
;
307 // The command line to build a ProxyConfig from.
313 // Expected outputs (fields of the ProxyConfig).
317 net::ProxyRulesExpectation proxy_rules
;
320 void PrintTo(const CommandLineTestParams
& params
, std::ostream
* os
) {
321 *os
<< params
.description
;
324 class PrefProxyConfigTrackerImplCommandLineTest
325 : public PrefProxyConfigTrackerImplTestBase
<
326 testing::TestWithParam
<CommandLineTestParams
> > {
328 PrefProxyConfigTrackerImplCommandLineTest()
329 : command_line_(base::CommandLine::NO_PROGRAM
) {}
331 void SetUp() override
{
332 for (size_t i
= 0; i
< arraysize(GetParam().switches
); i
++) {
333 const char* name
= GetParam().switches
[i
].name
;
334 const char* value
= GetParam().switches
[i
].value
;
336 command_line_
.AppendSwitchASCII(name
, value
);
338 command_line_
.AppendSwitch(name
);
340 scoped_refptr
<PrefRegistrySimple
> registry
= new PrefRegistrySimple
;
341 PrefServiceMockFactory factory
;
342 factory
.SetCommandLine(&command_line_
);
343 pref_service_
= factory
.Create(registry
.get()).Pass();
344 Init(pref_service_
.get(), registry
.get());
348 base::CommandLine command_line_
;
349 scoped_ptr
<PrefService
> pref_service_
;
352 TEST_P(PrefProxyConfigTrackerImplCommandLineTest
, CommandLine
) {
353 net::ProxyConfig config
;
354 EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID
,
355 proxy_config_service_
->GetLatestProxyConfig(&config
));
357 if (GetParam().is_null
) {
358 EXPECT_EQ(GURL(kFixedPacUrl
), config
.pac_url());
360 EXPECT_NE(GURL(kFixedPacUrl
), config
.pac_url());
361 EXPECT_EQ(GetParam().auto_detect
, config
.auto_detect());
362 EXPECT_EQ(GetParam().pac_url
, config
.pac_url());
363 EXPECT_TRUE(GetParam().proxy_rules
.Matches(config
.proxy_rules()));
367 static const CommandLineTestParams kCommandLineTestParams
[] = {
369 "Empty command line",
374 false, // auto_detect
376 net::ProxyRulesExpectation::Empty(),
382 { switches::kNoProxyServer
, NULL
},
386 false, // auto_detect
388 net::ProxyRulesExpectation::Empty(),
391 "No proxy with extra parameters.",
394 { switches::kNoProxyServer
, NULL
},
395 { switches::kProxyServer
, "http://proxy:8888" },
399 false, // auto_detect
401 net::ProxyRulesExpectation::Empty(),
407 { switches::kProxyServer
, "http://proxy:8888" },
411 false, // auto_detect
413 net::ProxyRulesExpectation::Single(
414 "proxy:8888", // single proxy
421 { switches::kProxyServer
, "http=httpproxy:8888;ftp=ftpproxy:8889" },
425 false, // auto_detect
427 net::ProxyRulesExpectation::PerScheme(
428 "httpproxy:8888", // http
430 "ftpproxy:8889", // ftp
434 "Per scheme proxy with bypass URLs.",
437 { switches::kProxyServer
, "http=httpproxy:8888;ftp=ftpproxy:8889" },
438 { switches::kProxyBypassList
,
439 ".google.com, foo.com:99, 1.2.3.4:22, 127.0.0.1/8" },
443 false, // auto_detect
445 net::ProxyRulesExpectation::PerScheme(
446 "httpproxy:8888", // http
448 "ftpproxy:8889", // ftp
449 "*.google.com,foo.com:99,1.2.3.4:22,127.0.0.1/8"),
455 { switches::kProxyPacUrl
, "http://wpad/wpad.dat" },
459 false, // auto_detect
460 GURL("http://wpad/wpad.dat"), // pac_url
461 net::ProxyRulesExpectation::Empty(),
467 { switches::kProxyAutoDetect
, NULL
},
473 net::ProxyRulesExpectation::Empty(),
477 INSTANTIATE_TEST_CASE_P(
478 PrefProxyConfigTrackerImplCommandLineTestInstance
,
479 PrefProxyConfigTrackerImplCommandLineTest
,
480 testing::ValuesIn(kCommandLineTestParams
));