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 "content/public/test/test_browser_thread.h"
30 #include "net/proxy/proxy_config.h"
31 #include "net/proxy/proxy_config_service_common_unittest.h"
32 #include "testing/gtest/include/gtest/gtest.h"
33 #include "third_party/cros_system_api/dbus/service_constants.h"
35 using content::BrowserThread
;
42 UIProxyConfig::Mode mode
;
45 std::string bypass_rules
;
48 // Builds an identifier for each test in an array.
49 #define TEST_DESC(desc) base::StringPrintf("at line %d <%s>", __LINE__, desc)
51 // Shortcuts to declare enums within chromeos's ProxyConfig.
52 #define MK_MODE(mode) UIProxyConfig::MODE_##mode
54 // Inspired from net/proxy/proxy_config_service_linux_unittest.cc.
55 const struct TestParams
{
56 // Short description to identify the test
57 std::string description
;
61 // Expected outputs from fields of net::ProxyConfig (via IO).
64 net::ProxyRulesExpectation proxy_rules
;
67 TEST_DESC("No proxying"),
70 MK_MODE(DIRECT
), // mode
76 net::ProxyRulesExpectation::Empty(), // proxy_rules
80 TEST_DESC("Auto detect"),
83 MK_MODE(AUTO_DETECT
), // mode
89 net::ProxyRulesExpectation::Empty(), // proxy_rules
93 TEST_DESC("Valid PAC URL"),
96 MK_MODE(PAC_SCRIPT
), // mode
97 "http://wpad/wpad.dat", // pac_url
101 false, // auto_detect
102 GURL("http://wpad/wpad.dat"), // pac_url
103 net::ProxyRulesExpectation::Empty(), // proxy_rules
107 TEST_DESC("Invalid PAC URL"),
110 MK_MODE(PAC_SCRIPT
), // mode
111 "wpad.dat", // pac_url
115 false, // auto_detect
117 net::ProxyRulesExpectation::Empty(), // proxy_rules
121 TEST_DESC("Single-host in proxy list"),
124 MK_MODE(SINGLE_PROXY
), // mode
126 "www.google.com", // server
130 false, // auto_detect
132 net::ProxyRulesExpectation::Single( // proxy_rules
133 "www.google.com:80", // single proxy
134 "<local>"), // bypass rules
138 TEST_DESC("Single-host, different port"),
141 MK_MODE(SINGLE_PROXY
), // mode
143 "www.google.com:99", // server
147 false, // auto_detect
149 net::ProxyRulesExpectation::Single( // proxy_rules
150 "www.google.com:99", // single
151 "<local>"), // bypass rules
155 TEST_DESC("Tolerate a scheme"),
158 MK_MODE(SINGLE_PROXY
), // mode
160 "http://www.google.com:99", // server
164 false, // auto_detect
166 net::ProxyRulesExpectation::Single( // proxy_rules
167 "www.google.com:99", // single proxy
168 "<local>"), // bypass rules
172 TEST_DESC("Per-scheme proxy rules"),
175 MK_MODE(PROXY_PER_SCHEME
), // mode
177 "http=www.google.com:80;https=https://www.foo.com:110;"
178 "ftp=ftp.foo.com:121;socks=socks5://socks.com:888", // server
182 false, // auto_detect
184 net::ProxyRulesExpectation::PerSchemeWithSocks( // proxy_rules
185 "www.google.com:80", // http
186 "https://www.foo.com:110", // https
187 "ftp.foo.com:121", // ftp
188 "socks5://socks.com:888", // fallback proxy
189 "<local>"), // bypass rules
193 TEST_DESC("Bypass rules"),
196 MK_MODE(SINGLE_PROXY
), // mode
198 "www.google.com", // server
199 "*.google.com, *foo.com:99, 1.2.3.4:22, 127.0.0.1/8", // bypass_rules
203 false, // auto_detect
205 net::ProxyRulesExpectation::Single( // proxy_rules
206 "www.google.com:80", // single proxy
208 "*.google.com,*foo.com:99,1.2.3.4:22,127.0.0.1/8,<local>"),
212 const char kEthernetPolicy
[] =
213 " { \"GUID\": \"{485d6076-dd44-6b6d-69787465725f5040}\","
214 " \"Type\": \"Ethernet\","
215 " \"Name\": \"MyEthernet\","
217 " \"Authentication\": \"None\" },"
218 " \"ProxySettings\": {"
219 " \"PAC\": \"http://domain.com/x\","
220 " \"Type\": \"PAC\" }"
223 const char kUserProfilePath
[] = "user_profile";
227 class ProxyConfigServiceImplTest
: public testing::Test
{
229 ProxyConfigServiceImplTest()
230 : ui_thread_(BrowserThread::UI
, &loop_
),
231 io_thread_(BrowserThread::IO
, &loop_
) {}
233 void SetUp() override
{
234 DBusThreadManager::Initialize();
235 NetworkHandler::Initialize();
237 PrefProxyConfigTrackerImpl::RegisterPrefs(pref_service_
.registry());
238 chromeos::proxy_config::RegisterPrefs(pref_service_
.registry());
239 PrefProxyConfigTrackerImpl::RegisterProfilePrefs(profile_prefs_
.registry());
240 chromeos::proxy_config::RegisterProfilePrefs(profile_prefs_
.registry());
243 void SetUpProxyConfigService(PrefService
* profile_prefs
) {
244 config_service_impl_
.reset(
245 new ProxyConfigServiceImpl(profile_prefs
, &pref_service_
));
246 proxy_config_service_
=
247 config_service_impl_
->CreateTrackingProxyConfigService(
248 scoped_ptr
<net::ProxyConfigService
>());
250 // CreateTrackingProxyConfigService triggers update of initial prefs proxy
251 // config by tracker to chrome proxy config service, so flush all pending
252 // tasks so that tests start fresh.
253 loop_
.RunUntilIdle();
256 void SetUpPrivateWiFi() {
257 ShillProfileClient::TestInterface
* profile_test
=
258 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface();
259 ShillServiceClient::TestInterface
* service_test
=
260 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
262 // Process any pending notifications before clearing services.
263 loop_
.RunUntilIdle();
264 service_test
->ClearServices();
266 // Sends a notification about the added profile.
267 profile_test
->AddProfile(kUserProfilePath
, "user_hash");
269 service_test
->AddService("/service/stub_wifi2",
270 "stub_wifi2" /* guid */,
272 shill::kTypeWifi
, shill::kStateOnline
,
274 profile_test
->AddService(kUserProfilePath
, "/service/stub_wifi2");
276 loop_
.RunUntilIdle();
279 void SetUpSharedEthernet() {
280 ShillProfileClient::TestInterface
* profile_test
=
281 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface();
282 ShillServiceClient::TestInterface
* service_test
=
283 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
285 // Process any pending notifications before clearing services.
286 loop_
.RunUntilIdle();
287 service_test
->ClearServices();
289 // Sends a notification about the added profile.
290 profile_test
->AddProfile(kUserProfilePath
, "user_hash");
292 service_test
->AddService("/service/ethernet", "stub_ethernet" /* guid */,
293 "eth0", shill::kTypeEthernet
, shill::kStateOnline
,
295 profile_test
->AddService(NetworkProfileHandler::GetSharedProfilePath(),
296 "/service/ethernet");
298 loop_
.RunUntilIdle();
301 void TearDown() override
{
302 config_service_impl_
->DetachFromPrefService();
303 loop_
.RunUntilIdle();
304 config_service_impl_
.reset();
305 proxy_config_service_
.reset();
306 NetworkHandler::Shutdown();
307 DBusThreadManager::Shutdown();
310 void InitConfigWithTestInput(const Input
& input
,
311 base::DictionaryValue
* result
) {
312 scoped_ptr
<base::DictionaryValue
> new_config
;
313 switch (input
.mode
) {
314 case MK_MODE(DIRECT
):
315 new_config
.reset(ProxyConfigDictionary::CreateDirect());
317 case MK_MODE(AUTO_DETECT
):
318 new_config
.reset(ProxyConfigDictionary::CreateAutoDetect());
320 case MK_MODE(PAC_SCRIPT
):
322 ProxyConfigDictionary::CreatePacScript(input
.pac_url
, false));
324 case MK_MODE(SINGLE_PROXY
):
325 case MK_MODE(PROXY_PER_SCHEME
):
326 new_config
.reset(ProxyConfigDictionary::CreateFixedServers(
327 input
.server
, input
.bypass_rules
));
330 result
->Swap(new_config
.get());
333 void SetUserConfigInShill(base::DictionaryValue
* pref_proxy_config_dict
) {
334 std::string proxy_config
;
335 if (pref_proxy_config_dict
)
336 base::JSONWriter::Write(*pref_proxy_config_dict
, &proxy_config
);
338 NetworkStateHandler
* network_state_handler
=
339 NetworkHandler::Get()->network_state_handler();
340 const NetworkState
* network
= network_state_handler
->DefaultNetwork();
341 ASSERT_TRUE(network
);
342 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface()->
343 SetServiceProperty(network
->path(),
344 shill::kProxyConfigProperty
,
345 base::StringValue(proxy_config
));
348 // Synchronously gets the latest proxy config.
349 void SyncGetLatestProxyConfig(net::ProxyConfig
* config
) {
350 *config
= net::ProxyConfig();
351 // Let message loop process all messages. This will run
352 // ChromeProxyConfigService::UpdateProxyConfig, which is posted on IO from
353 // PrefProxyConfigTrackerImpl::OnProxyConfigChanged.
354 loop_
.RunUntilIdle();
355 net::ProxyConfigService::ConfigAvailability availability
=
356 proxy_config_service_
->GetLatestProxyConfig(config
);
358 EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID
, availability
);
361 base::MessageLoop loop_
;
362 scoped_ptr
<net::ProxyConfigService
> proxy_config_service_
;
363 scoped_ptr
<ProxyConfigServiceImpl
> config_service_impl_
;
364 TestingPrefServiceSimple pref_service_
;
365 user_prefs::TestingPrefServiceSyncable profile_prefs_
;
368 ScopedTestDeviceSettingsService test_device_settings_service_
;
369 ScopedTestCrosSettings test_cros_settings_
;
370 content::TestBrowserThread ui_thread_
;
371 content::TestBrowserThread io_thread_
;
374 TEST_F(ProxyConfigServiceImplTest
, NetworkProxy
) {
376 // Create a ProxyConfigServiceImpl like for the system request context.
377 SetUpProxyConfigService(nullptr /* no profile prefs */);
378 for (size_t i
= 0; i
< arraysize(tests
); ++i
) {
379 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS
"] %s", i
,
380 tests
[i
].description
.c_str()));
382 base::DictionaryValue test_config
;
383 InitConfigWithTestInput(tests
[i
].input
, &test_config
);
384 SetUserConfigInShill(&test_config
);
386 net::ProxyConfig config
;
387 SyncGetLatestProxyConfig(&config
);
389 EXPECT_EQ(tests
[i
].auto_detect
, config
.auto_detect());
390 EXPECT_EQ(tests
[i
].pac_url
, config
.pac_url());
391 EXPECT_TRUE(tests
[i
].proxy_rules
.Matches(config
.proxy_rules()));
395 TEST_F(ProxyConfigServiceImplTest
, DynamicPrefsOverride
) {
397 // Create a ProxyConfigServiceImpl like for the system request context.
398 SetUpProxyConfigService(nullptr /* no profile prefs */);
399 // Groupings of 3 test inputs to use for managed, recommended and network
400 // proxies respectively. Only valid and non-direct test inputs are used.
401 const size_t proxies
[][3] = {
423 for (size_t i
= 0; i
< arraysize(proxies
); ++i
) {
424 const TestParams
& managed_params
= tests
[proxies
[i
][0]];
425 const TestParams
& recommended_params
= tests
[proxies
[i
][1]];
426 const TestParams
& network_params
= tests
[proxies
[i
][2]];
428 SCOPED_TRACE(base::StringPrintf(
429 "Test[%" PRIuS
"] managed=[%s], recommended=[%s], network=[%s]", i
,
430 managed_params
.description
.c_str(),
431 recommended_params
.description
.c_str(),
432 network_params
.description
.c_str()));
434 base::DictionaryValue managed_config
;
435 InitConfigWithTestInput(managed_params
.input
, &managed_config
);
436 base::DictionaryValue recommended_config
;
437 InitConfigWithTestInput(recommended_params
.input
, &recommended_config
);
438 base::DictionaryValue network_config
;
439 InitConfigWithTestInput(network_params
.input
, &network_config
);
441 // Managed proxy pref should take effect over recommended proxy and
442 // non-existent network proxy.
443 SetUserConfigInShill(nullptr);
444 pref_service_
.SetManagedPref(prefs::kProxy
, managed_config
.DeepCopy());
445 pref_service_
.SetRecommendedPref(prefs::kProxy
,
446 recommended_config
.DeepCopy());
447 net::ProxyConfig actual_config
;
448 SyncGetLatestProxyConfig(&actual_config
);
449 EXPECT_EQ(managed_params
.auto_detect
, actual_config
.auto_detect());
450 EXPECT_EQ(managed_params
.pac_url
, actual_config
.pac_url());
451 EXPECT_TRUE(managed_params
.proxy_rules
.Matches(
452 actual_config
.proxy_rules()));
454 // Recommended proxy pref should take effect when managed proxy pref is
456 pref_service_
.RemoveManagedPref(prefs::kProxy
);
457 SyncGetLatestProxyConfig(&actual_config
);
458 EXPECT_EQ(recommended_params
.auto_detect
, actual_config
.auto_detect());
459 EXPECT_EQ(recommended_params
.pac_url
, actual_config
.pac_url());
460 EXPECT_TRUE(recommended_params
.proxy_rules
.Matches(
461 actual_config
.proxy_rules()));
463 // Network proxy should take take effect over recommended proxy pref.
464 SetUserConfigInShill(&network_config
);
465 SyncGetLatestProxyConfig(&actual_config
);
466 EXPECT_EQ(network_params
.auto_detect
, actual_config
.auto_detect());
467 EXPECT_EQ(network_params
.pac_url
, actual_config
.pac_url());
468 EXPECT_TRUE(network_params
.proxy_rules
.Matches(
469 actual_config
.proxy_rules()));
471 // Managed proxy pref should take effect over network proxy.
472 pref_service_
.SetManagedPref(prefs::kProxy
, managed_config
.DeepCopy());
473 SyncGetLatestProxyConfig(&actual_config
);
474 EXPECT_EQ(managed_params
.auto_detect
, actual_config
.auto_detect());
475 EXPECT_EQ(managed_params
.pac_url
, actual_config
.pac_url());
476 EXPECT_TRUE(managed_params
.proxy_rules
.Matches(
477 actual_config
.proxy_rules()));
479 // Network proxy should take effect over recommended proxy pref when managed
480 // proxy pref is removed.
481 pref_service_
.RemoveManagedPref(prefs::kProxy
);
482 SyncGetLatestProxyConfig(&actual_config
);
483 EXPECT_EQ(network_params
.auto_detect
, actual_config
.auto_detect());
484 EXPECT_EQ(network_params
.pac_url
, actual_config
.pac_url());
485 EXPECT_TRUE(network_params
.proxy_rules
.Matches(
486 actual_config
.proxy_rules()));
488 // Removing recommended proxy pref should have no effect on network proxy.
489 pref_service_
.RemoveRecommendedPref(prefs::kProxy
);
490 SyncGetLatestProxyConfig(&actual_config
);
491 EXPECT_EQ(network_params
.auto_detect
, actual_config
.auto_detect());
492 EXPECT_EQ(network_params
.pac_url
, actual_config
.pac_url());
493 EXPECT_TRUE(network_params
.proxy_rules
.Matches(
494 actual_config
.proxy_rules()));
498 // Tests whether the proxy settings from user policy are used for ethernet even
499 // if 'UseSharedProxies' is set to false.
500 // See https://crbug.com/454966 .
501 TEST_F(ProxyConfigServiceImplTest
, SharedEthernetAndUserPolicy
) {
502 SetUpSharedEthernet();
503 SetUpProxyConfigService(&profile_prefs_
);
505 scoped_ptr
<base::DictionaryValue
> ethernet_policy(
506 chromeos::onc::ReadDictionaryFromJson(kEthernetPolicy
));
508 scoped_ptr
<base::ListValue
> network_configs(new base::ListValue
);
509 network_configs
->Append(ethernet_policy
.release());
511 profile_prefs_
.SetUserPref(prefs::kUseSharedProxies
,
512 new base::FundamentalValue(false));
513 profile_prefs_
.SetManagedPref(prefs::kOpenNetworkConfiguration
,
514 network_configs
.release());
516 net::ProxyConfig actual_config
;
517 SyncGetLatestProxyConfig(&actual_config
);
518 net::ProxyConfig expected_config
=
519 net::ProxyConfig::CreateFromCustomPacURL(GURL("http://domain.com/x"));
520 EXPECT_TRUE(expected_config
.Equals(actual_config
));
523 } // namespace chromeos