1 // Copyright (c) 2012 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/chromeos/proxy_config_service_impl.h"
9 #include "base/format_macros.h"
10 #include "base/json/json_writer.h"
11 #include "base/logging.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/prefs/testing_pref_service.h"
14 #include "base/strings/stringprintf.h"
15 #include "chrome/browser/chromeos/net/proxy_config_handler.h"
16 #include "chrome/browser/chromeos/settings/cros_settings.h"
17 #include "chrome/browser/chromeos/settings/device_settings_service.h"
18 #include "chrome/browser/chromeos/ui_proxy_config.h"
19 #include "chrome/common/pref_names.h"
20 #include "chromeos/dbus/dbus_thread_manager.h"
21 #include "chromeos/dbus/shill_profile_client.h"
22 #include "chromeos/dbus/shill_service_client.h"
23 #include "chromeos/network/network_handler.h"
24 #include "chromeos/network/network_profile_handler.h"
25 #include "chromeos/network/network_state.h"
26 #include "chromeos/network/network_state_handler.h"
27 #include "chromeos/network/onc/onc_utils.h"
28 #include "components/pref_registry/testing_pref_service_syncable.h"
29 #include "components/proxy_config/proxy_config_pref_names.h"
30 #include "content/public/test/test_browser_thread.h"
31 #include "net/proxy/proxy_config.h"
32 #include "net/proxy/proxy_config_service_common_unittest.h"
33 #include "testing/gtest/include/gtest/gtest.h"
34 #include "third_party/cros_system_api/dbus/service_constants.h"
36 using content::BrowserThread
;
43 UIProxyConfig::Mode mode
;
46 std::string bypass_rules
;
49 // Builds an identifier for each test in an array.
50 #define TEST_DESC(desc) base::StringPrintf("at line %d <%s>", __LINE__, desc)
52 // Shortcuts to declare enums within chromeos's ProxyConfig.
53 #define MK_MODE(mode) UIProxyConfig::MODE_##mode
55 // Inspired from net/proxy/proxy_config_service_linux_unittest.cc.
56 const struct TestParams
{
57 // Short description to identify the test
58 std::string description
;
62 // Expected outputs from fields of net::ProxyConfig (via IO).
65 net::ProxyRulesExpectation proxy_rules
;
68 TEST_DESC("No proxying"),
71 MK_MODE(DIRECT
), // mode
77 net::ProxyRulesExpectation::Empty(), // proxy_rules
81 TEST_DESC("Auto detect"),
84 MK_MODE(AUTO_DETECT
), // mode
90 net::ProxyRulesExpectation::Empty(), // proxy_rules
94 TEST_DESC("Valid PAC URL"),
97 MK_MODE(PAC_SCRIPT
), // mode
98 "http://wpad/wpad.dat", // pac_url
102 false, // auto_detect
103 GURL("http://wpad/wpad.dat"), // pac_url
104 net::ProxyRulesExpectation::Empty(), // proxy_rules
108 TEST_DESC("Invalid PAC URL"),
111 MK_MODE(PAC_SCRIPT
), // mode
112 "wpad.dat", // pac_url
116 false, // auto_detect
118 net::ProxyRulesExpectation::Empty(), // proxy_rules
122 TEST_DESC("Single-host in proxy list"),
125 MK_MODE(SINGLE_PROXY
), // mode
127 "www.google.com", // server
131 false, // auto_detect
133 net::ProxyRulesExpectation::Single( // proxy_rules
134 "www.google.com:80", // single proxy
135 "<local>"), // bypass rules
139 TEST_DESC("Single-host, different port"),
142 MK_MODE(SINGLE_PROXY
), // mode
144 "www.google.com:99", // server
148 false, // auto_detect
150 net::ProxyRulesExpectation::Single( // proxy_rules
151 "www.google.com:99", // single
152 "<local>"), // bypass rules
156 TEST_DESC("Tolerate a scheme"),
159 MK_MODE(SINGLE_PROXY
), // mode
161 "http://www.google.com:99", // server
165 false, // auto_detect
167 net::ProxyRulesExpectation::Single( // proxy_rules
168 "www.google.com:99", // single proxy
169 "<local>"), // bypass rules
173 TEST_DESC("Per-scheme proxy rules"),
176 MK_MODE(PROXY_PER_SCHEME
), // mode
178 "http=www.google.com:80;https=https://www.foo.com:110;"
179 "ftp=ftp.foo.com:121;socks=socks5://socks.com:888", // server
183 false, // auto_detect
185 net::ProxyRulesExpectation::PerSchemeWithSocks( // proxy_rules
186 "www.google.com:80", // http
187 "https://www.foo.com:110", // https
188 "ftp.foo.com:121", // ftp
189 "socks5://socks.com:888", // fallback proxy
190 "<local>"), // bypass rules
194 TEST_DESC("Bypass rules"),
197 MK_MODE(SINGLE_PROXY
), // mode
199 "www.google.com", // server
200 "*.google.com, *foo.com:99, 1.2.3.4:22, 127.0.0.1/8", // bypass_rules
204 false, // auto_detect
206 net::ProxyRulesExpectation::Single( // proxy_rules
207 "www.google.com:80", // single proxy
209 "*.google.com,*foo.com:99,1.2.3.4:22,127.0.0.1/8,<local>"),
213 const char kEthernetPolicy
[] =
214 " { \"GUID\": \"{485d6076-dd44-6b6d-69787465725f5040}\","
215 " \"Type\": \"Ethernet\","
216 " \"Name\": \"MyEthernet\","
218 " \"Authentication\": \"None\" },"
219 " \"ProxySettings\": {"
220 " \"PAC\": \"http://domain.com/x\","
221 " \"Type\": \"PAC\" }"
224 const char kUserProfilePath
[] = "user_profile";
228 class ProxyConfigServiceImplTest
: public testing::Test
{
230 ProxyConfigServiceImplTest()
231 : ui_thread_(BrowserThread::UI
, &loop_
),
232 io_thread_(BrowserThread::IO
, &loop_
) {}
234 void SetUp() override
{
235 DBusThreadManager::Initialize();
236 NetworkHandler::Initialize();
238 PrefProxyConfigTrackerImpl::RegisterPrefs(pref_service_
.registry());
239 chromeos::proxy_config::RegisterPrefs(pref_service_
.registry());
240 PrefProxyConfigTrackerImpl::RegisterProfilePrefs(profile_prefs_
.registry());
241 chromeos::proxy_config::RegisterProfilePrefs(profile_prefs_
.registry());
244 void SetUpProxyConfigService(PrefService
* profile_prefs
) {
245 config_service_impl_
.reset(
246 new ProxyConfigServiceImpl(profile_prefs
, &pref_service_
));
247 proxy_config_service_
=
248 config_service_impl_
->CreateTrackingProxyConfigService(
249 scoped_ptr
<net::ProxyConfigService
>());
251 // CreateTrackingProxyConfigService triggers update of initial prefs proxy
252 // config by tracker to chrome proxy config service, so flush all pending
253 // tasks so that tests start fresh.
254 loop_
.RunUntilIdle();
257 void SetUpPrivateWiFi() {
258 ShillProfileClient::TestInterface
* profile_test
=
259 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface();
260 ShillServiceClient::TestInterface
* service_test
=
261 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
263 // Process any pending notifications before clearing services.
264 loop_
.RunUntilIdle();
265 service_test
->ClearServices();
267 // Sends a notification about the added profile.
268 profile_test
->AddProfile(kUserProfilePath
, "user_hash");
270 service_test
->AddService("/service/stub_wifi2",
271 "stub_wifi2" /* guid */,
273 shill::kTypeWifi
, shill::kStateOnline
,
275 profile_test
->AddService(kUserProfilePath
, "/service/stub_wifi2");
277 loop_
.RunUntilIdle();
280 void SetUpSharedEthernet() {
281 ShillProfileClient::TestInterface
* profile_test
=
282 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface();
283 ShillServiceClient::TestInterface
* service_test
=
284 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
286 // Process any pending notifications before clearing services.
287 loop_
.RunUntilIdle();
288 service_test
->ClearServices();
290 // Sends a notification about the added profile.
291 profile_test
->AddProfile(kUserProfilePath
, "user_hash");
293 service_test
->AddService("/service/ethernet", "stub_ethernet" /* guid */,
294 "eth0", shill::kTypeEthernet
, shill::kStateOnline
,
296 profile_test
->AddService(NetworkProfileHandler::GetSharedProfilePath(),
297 "/service/ethernet");
299 loop_
.RunUntilIdle();
302 void TearDown() override
{
303 config_service_impl_
->DetachFromPrefService();
304 loop_
.RunUntilIdle();
305 config_service_impl_
.reset();
306 proxy_config_service_
.reset();
307 NetworkHandler::Shutdown();
308 DBusThreadManager::Shutdown();
311 void InitConfigWithTestInput(const Input
& input
,
312 base::DictionaryValue
* result
) {
313 scoped_ptr
<base::DictionaryValue
> new_config
;
314 switch (input
.mode
) {
315 case MK_MODE(DIRECT
):
316 new_config
.reset(ProxyConfigDictionary::CreateDirect());
318 case MK_MODE(AUTO_DETECT
):
319 new_config
.reset(ProxyConfigDictionary::CreateAutoDetect());
321 case MK_MODE(PAC_SCRIPT
):
323 ProxyConfigDictionary::CreatePacScript(input
.pac_url
, false));
325 case MK_MODE(SINGLE_PROXY
):
326 case MK_MODE(PROXY_PER_SCHEME
):
327 new_config
.reset(ProxyConfigDictionary::CreateFixedServers(
328 input
.server
, input
.bypass_rules
));
331 result
->Swap(new_config
.get());
334 void SetUserConfigInShill(base::DictionaryValue
* pref_proxy_config_dict
) {
335 std::string proxy_config
;
336 if (pref_proxy_config_dict
)
337 base::JSONWriter::Write(*pref_proxy_config_dict
, &proxy_config
);
339 NetworkStateHandler
* network_state_handler
=
340 NetworkHandler::Get()->network_state_handler();
341 const NetworkState
* network
= network_state_handler
->DefaultNetwork();
342 ASSERT_TRUE(network
);
343 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface()->
344 SetServiceProperty(network
->path(),
345 shill::kProxyConfigProperty
,
346 base::StringValue(proxy_config
));
349 // Synchronously gets the latest proxy config.
350 void SyncGetLatestProxyConfig(net::ProxyConfig
* config
) {
351 *config
= net::ProxyConfig();
352 // Let message loop process all messages. This will run
353 // ChromeProxyConfigService::UpdateProxyConfig, which is posted on IO from
354 // PrefProxyConfigTrackerImpl::OnProxyConfigChanged.
355 loop_
.RunUntilIdle();
356 net::ProxyConfigService::ConfigAvailability availability
=
357 proxy_config_service_
->GetLatestProxyConfig(config
);
359 EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID
, availability
);
362 base::MessageLoop loop_
;
363 scoped_ptr
<net::ProxyConfigService
> proxy_config_service_
;
364 scoped_ptr
<ProxyConfigServiceImpl
> config_service_impl_
;
365 TestingPrefServiceSimple pref_service_
;
366 user_prefs::TestingPrefServiceSyncable profile_prefs_
;
369 ScopedTestDeviceSettingsService test_device_settings_service_
;
370 ScopedTestCrosSettings test_cros_settings_
;
371 content::TestBrowserThread ui_thread_
;
372 content::TestBrowserThread io_thread_
;
375 TEST_F(ProxyConfigServiceImplTest
, NetworkProxy
) {
377 // Create a ProxyConfigServiceImpl like for the system request context.
378 SetUpProxyConfigService(nullptr /* no profile prefs */);
379 for (size_t i
= 0; i
< arraysize(tests
); ++i
) {
380 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS
"] %s", i
,
381 tests
[i
].description
.c_str()));
383 base::DictionaryValue test_config
;
384 InitConfigWithTestInput(tests
[i
].input
, &test_config
);
385 SetUserConfigInShill(&test_config
);
387 net::ProxyConfig config
;
388 SyncGetLatestProxyConfig(&config
);
390 EXPECT_EQ(tests
[i
].auto_detect
, config
.auto_detect());
391 EXPECT_EQ(tests
[i
].pac_url
, config
.pac_url());
392 EXPECT_TRUE(tests
[i
].proxy_rules
.Matches(config
.proxy_rules()));
396 TEST_F(ProxyConfigServiceImplTest
, DynamicPrefsOverride
) {
398 // Create a ProxyConfigServiceImpl like for the system request context.
399 SetUpProxyConfigService(nullptr /* no profile prefs */);
400 // Groupings of 3 test inputs to use for managed, recommended and network
401 // proxies respectively. Only valid and non-direct test inputs are used.
402 const size_t proxies
[][3] = {
424 for (size_t i
= 0; i
< arraysize(proxies
); ++i
) {
425 const TestParams
& managed_params
= tests
[proxies
[i
][0]];
426 const TestParams
& recommended_params
= tests
[proxies
[i
][1]];
427 const TestParams
& network_params
= tests
[proxies
[i
][2]];
429 SCOPED_TRACE(base::StringPrintf(
430 "Test[%" PRIuS
"] managed=[%s], recommended=[%s], network=[%s]", i
,
431 managed_params
.description
.c_str(),
432 recommended_params
.description
.c_str(),
433 network_params
.description
.c_str()));
435 base::DictionaryValue managed_config
;
436 InitConfigWithTestInput(managed_params
.input
, &managed_config
);
437 base::DictionaryValue recommended_config
;
438 InitConfigWithTestInput(recommended_params
.input
, &recommended_config
);
439 base::DictionaryValue network_config
;
440 InitConfigWithTestInput(network_params
.input
, &network_config
);
442 // Managed proxy pref should take effect over recommended proxy and
443 // non-existent network proxy.
444 SetUserConfigInShill(nullptr);
445 pref_service_
.SetManagedPref(::proxy_config::prefs::kProxy
,
446 managed_config
.DeepCopy());
447 pref_service_
.SetRecommendedPref(::proxy_config::prefs::kProxy
,
448 recommended_config
.DeepCopy());
449 net::ProxyConfig actual_config
;
450 SyncGetLatestProxyConfig(&actual_config
);
451 EXPECT_EQ(managed_params
.auto_detect
, actual_config
.auto_detect());
452 EXPECT_EQ(managed_params
.pac_url
, actual_config
.pac_url());
453 EXPECT_TRUE(managed_params
.proxy_rules
.Matches(
454 actual_config
.proxy_rules()));
456 // Recommended proxy pref should take effect when managed proxy pref is
458 pref_service_
.RemoveManagedPref(::proxy_config::prefs::kProxy
);
459 SyncGetLatestProxyConfig(&actual_config
);
460 EXPECT_EQ(recommended_params
.auto_detect
, actual_config
.auto_detect());
461 EXPECT_EQ(recommended_params
.pac_url
, actual_config
.pac_url());
462 EXPECT_TRUE(recommended_params
.proxy_rules
.Matches(
463 actual_config
.proxy_rules()));
465 // Network proxy should take take effect over recommended proxy pref.
466 SetUserConfigInShill(&network_config
);
467 SyncGetLatestProxyConfig(&actual_config
);
468 EXPECT_EQ(network_params
.auto_detect
, actual_config
.auto_detect());
469 EXPECT_EQ(network_params
.pac_url
, actual_config
.pac_url());
470 EXPECT_TRUE(network_params
.proxy_rules
.Matches(
471 actual_config
.proxy_rules()));
473 // Managed proxy pref should take effect over network proxy.
474 pref_service_
.SetManagedPref(::proxy_config::prefs::kProxy
,
475 managed_config
.DeepCopy());
476 SyncGetLatestProxyConfig(&actual_config
);
477 EXPECT_EQ(managed_params
.auto_detect
, actual_config
.auto_detect());
478 EXPECT_EQ(managed_params
.pac_url
, actual_config
.pac_url());
479 EXPECT_TRUE(managed_params
.proxy_rules
.Matches(
480 actual_config
.proxy_rules()));
482 // Network proxy should take effect over recommended proxy pref when managed
483 // proxy pref is removed.
484 pref_service_
.RemoveManagedPref(::proxy_config::prefs::kProxy
);
485 SyncGetLatestProxyConfig(&actual_config
);
486 EXPECT_EQ(network_params
.auto_detect
, actual_config
.auto_detect());
487 EXPECT_EQ(network_params
.pac_url
, actual_config
.pac_url());
488 EXPECT_TRUE(network_params
.proxy_rules
.Matches(
489 actual_config
.proxy_rules()));
491 // Removing recommended proxy pref should have no effect on network proxy.
492 pref_service_
.RemoveRecommendedPref(::proxy_config::prefs::kProxy
);
493 SyncGetLatestProxyConfig(&actual_config
);
494 EXPECT_EQ(network_params
.auto_detect
, actual_config
.auto_detect());
495 EXPECT_EQ(network_params
.pac_url
, actual_config
.pac_url());
496 EXPECT_TRUE(network_params
.proxy_rules
.Matches(
497 actual_config
.proxy_rules()));
501 // Tests whether the proxy settings from user policy are used for ethernet even
502 // if 'UseSharedProxies' is set to false.
503 // See https://crbug.com/454966 .
504 TEST_F(ProxyConfigServiceImplTest
, SharedEthernetAndUserPolicy
) {
505 SetUpSharedEthernet();
506 SetUpProxyConfigService(&profile_prefs_
);
508 scoped_ptr
<base::DictionaryValue
> ethernet_policy(
509 chromeos::onc::ReadDictionaryFromJson(kEthernetPolicy
));
511 scoped_ptr
<base::ListValue
> network_configs(new base::ListValue
);
512 network_configs
->Append(ethernet_policy
.release());
514 profile_prefs_
.SetUserPref(prefs::kUseSharedProxies
,
515 new base::FundamentalValue(false));
516 profile_prefs_
.SetManagedPref(prefs::kOpenNetworkConfiguration
,
517 network_configs
.release());
519 net::ProxyConfig actual_config
;
520 SyncGetLatestProxyConfig(&actual_config
);
521 net::ProxyConfig expected_config
=
522 net::ProxyConfig::CreateFromCustomPacURL(GURL("http://domain.com/x"));
523 EXPECT_TRUE(expected_config
.Equals(actual_config
));
526 } // namespace chromeos