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.h"
13 #include "base/prefs/testing_pref_service.h"
14 #include "base/strings/stringprintf.h"
15 #include "chrome/browser/chromeos/settings/cros_settings.h"
16 #include "chrome/browser/chromeos/settings/device_settings_service.h"
17 #include "chrome/browser/chromeos/ui_proxy_config.h"
18 #include "chrome/common/pref_names.h"
19 #include "chromeos/dbus/dbus_thread_manager.h"
20 #include "chromeos/dbus/shill_profile_client.h"
21 #include "chromeos/dbus/shill_service_client.h"
22 #include "chromeos/network/network_handler.h"
23 #include "chromeos/network/network_state.h"
24 #include "chromeos/network/network_state_handler.h"
25 #include "content/public/test/test_browser_thread.h"
26 #include "net/proxy/proxy_config_service_common_unittest.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28 #include "third_party/cros_system_api/dbus/service_constants.h"
30 using content::BrowserThread
;
37 UIProxyConfig::Mode mode
;
40 std::string bypass_rules
;
43 // Builds an identifier for each test in an array.
44 #define TEST_DESC(desc) base::StringPrintf("at line %d <%s>", __LINE__, desc)
46 // Shortcuts to declare enums within chromeos's ProxyConfig.
47 #define MK_MODE(mode) UIProxyConfig::MODE_##mode
49 // Inspired from net/proxy/proxy_config_service_linux_unittest.cc.
50 const struct TestParams
{
51 // Short description to identify the test
52 std::string description
;
56 // Expected outputs from fields of net::ProxyConfig (via IO).
59 net::ProxyRulesExpectation proxy_rules
;
62 TEST_DESC("No proxying"),
65 MK_MODE(DIRECT
), // mode
71 net::ProxyRulesExpectation::Empty(), // proxy_rules
75 TEST_DESC("Auto detect"),
78 MK_MODE(AUTO_DETECT
), // mode
84 net::ProxyRulesExpectation::Empty(), // proxy_rules
88 TEST_DESC("Valid PAC URL"),
91 MK_MODE(PAC_SCRIPT
), // mode
92 "http://wpad/wpad.dat", // pac_url
97 GURL("http://wpad/wpad.dat"), // pac_url
98 net::ProxyRulesExpectation::Empty(), // proxy_rules
102 TEST_DESC("Invalid PAC URL"),
105 MK_MODE(PAC_SCRIPT
), // mode
106 "wpad.dat", // pac_url
110 false, // auto_detect
112 net::ProxyRulesExpectation::Empty(), // proxy_rules
116 TEST_DESC("Single-host in proxy list"),
119 MK_MODE(SINGLE_PROXY
), // mode
121 "www.google.com", // server
125 false, // auto_detect
127 net::ProxyRulesExpectation::Single( // proxy_rules
128 "www.google.com:80", // single proxy
129 "<local>"), // bypass rules
133 TEST_DESC("Single-host, different port"),
136 MK_MODE(SINGLE_PROXY
), // mode
138 "www.google.com:99", // server
142 false, // auto_detect
144 net::ProxyRulesExpectation::Single( // proxy_rules
145 "www.google.com:99", // single
146 "<local>"), // bypass rules
150 TEST_DESC("Tolerate a scheme"),
153 MK_MODE(SINGLE_PROXY
), // mode
155 "http://www.google.com:99", // server
159 false, // auto_detect
161 net::ProxyRulesExpectation::Single( // proxy_rules
162 "www.google.com:99", // single proxy
163 "<local>"), // bypass rules
167 TEST_DESC("Per-scheme proxy rules"),
170 MK_MODE(PROXY_PER_SCHEME
), // mode
172 "http=www.google.com:80;https=https://www.foo.com:110;"
173 "ftp=ftp.foo.com:121;socks=socks5://socks.com:888", // server
177 false, // auto_detect
179 net::ProxyRulesExpectation::PerSchemeWithSocks( // proxy_rules
180 "www.google.com:80", // http
181 "https://www.foo.com:110", // https
182 "ftp.foo.com:121", // ftp
183 "socks5://socks.com:888", // fallback proxy
184 "<local>"), // bypass rules
188 TEST_DESC("Bypass rules"),
191 MK_MODE(SINGLE_PROXY
), // mode
193 "www.google.com", // server
194 "*.google.com, *foo.com:99, 1.2.3.4:22, 127.0.0.1/8", // bypass_rules
198 false, // auto_detect
200 net::ProxyRulesExpectation::Single( // proxy_rules
201 "www.google.com:80", // single proxy
203 "*.google.com,*foo.com:99,1.2.3.4:22,127.0.0.1/8,<local>"),
207 const char* kUserProfilePath
= "user_profile";
211 class ProxyConfigServiceImplTest
: public testing::Test
{
213 ProxyConfigServiceImplTest()
214 : ui_thread_(BrowserThread::UI
, &loop_
),
215 io_thread_(BrowserThread::IO
, &loop_
) {}
217 virtual void SetUp() {
218 DBusThreadManager::InitializeWithStub();
219 NetworkHandler::Initialize();
223 PrefProxyConfigTrackerImpl::RegisterPrefs(pref_service_
.registry());
224 ProxyConfigServiceImpl::RegisterPrefs(pref_service_
.registry());
225 proxy_config_service_
.reset(new ChromeProxyConfigService(NULL
));
226 config_service_impl_
.reset(new ProxyConfigServiceImpl(&pref_service_
));
227 config_service_impl_
->SetChromeProxyConfigService(
228 proxy_config_service_
.get());
229 // SetChromeProxyConfigService triggers update of initial prefs proxy
230 // config by tracker to chrome proxy config service, so flush all pending
231 // tasks so that tests start fresh.
232 loop_
.RunUntilIdle();
235 void SetUpNetwork() {
236 ShillProfileClient::TestInterface
* profile_test
=
237 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface();
238 ShillServiceClient::TestInterface
* service_test
=
239 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
241 service_test
->ClearServices();
243 // Sends a notification about the added profile.
244 profile_test
->AddProfile(kUserProfilePath
, "user_hash");
246 service_test
->AddService("stub_wifi2", "wifi2_PSK",
247 flimflam::kTypeWifi
, flimflam::kStateOnline
,
248 true /* add to watchlist */);
249 service_test
->SetServiceProperty("stub_wifi2",
250 flimflam::kGuidProperty
,
251 base::StringValue("stub_wifi2"));
252 service_test
->SetServiceProperty("stub_wifi2",
253 flimflam::kProfileProperty
,
254 base::StringValue(kUserProfilePath
));
255 profile_test
->AddService("stub_wifi2");
257 loop_
.RunUntilIdle();
260 virtual void TearDown() {
261 config_service_impl_
->DetachFromPrefService();
262 loop_
.RunUntilIdle();
263 config_service_impl_
.reset();
264 proxy_config_service_
.reset();
265 NetworkHandler::Shutdown();
266 DBusThreadManager::Shutdown();
269 void InitConfigWithTestInput(const Input
& input
,
270 base::DictionaryValue
* result
) {
271 base::DictionaryValue
* new_config
= NULL
;
272 switch (input
.mode
) {
273 case MK_MODE(DIRECT
):
274 new_config
= ProxyConfigDictionary::CreateDirect();
276 case MK_MODE(AUTO_DETECT
):
277 new_config
= ProxyConfigDictionary::CreateAutoDetect();
279 case MK_MODE(PAC_SCRIPT
):
281 ProxyConfigDictionary::CreatePacScript(input
.pac_url
, false);
283 case MK_MODE(SINGLE_PROXY
):
284 case MK_MODE(PROXY_PER_SCHEME
):
286 ProxyConfigDictionary::CreateFixedServers(input
.server
,
290 result
->Swap(new_config
);
294 void SetConfig(base::DictionaryValue
* pref_proxy_config_dict
) {
295 std::string proxy_config
;
296 if (pref_proxy_config_dict
)
297 base::JSONWriter::Write(pref_proxy_config_dict
, &proxy_config
);
299 NetworkStateHandler
* network_state_handler
=
300 NetworkHandler::Get()->network_state_handler();
301 const NetworkState
* network
= network_state_handler
->DefaultNetwork();
302 ASSERT_TRUE(network
);
303 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface()->
304 SetServiceProperty(network
->path(),
305 flimflam::kProxyConfigProperty
,
306 StringValue(proxy_config
));
309 // Synchronously gets the latest proxy config.
310 void SyncGetLatestProxyConfig(net::ProxyConfig
* config
) {
311 *config
= net::ProxyConfig();
312 // Let message loop process all messages. This will run
313 // ChromeProxyConfigService::UpdateProxyConfig, which is posted on IO from
314 // PrefProxyConfigTrackerImpl::OnProxyConfigChanged.
315 loop_
.RunUntilIdle();
316 net::ProxyConfigService::ConfigAvailability availability
=
317 proxy_config_service_
->GetLatestProxyConfig(config
);
319 EXPECT_EQ(net::ProxyConfigService::CONFIG_VALID
, availability
);
322 base::MessageLoop loop_
;
323 scoped_ptr
<ChromeProxyConfigService
> proxy_config_service_
;
324 scoped_ptr
<ProxyConfigServiceImpl
> config_service_impl_
;
325 TestingPrefServiceSimple pref_service_
;
328 ScopedTestDeviceSettingsService test_device_settings_service_
;
329 ScopedTestCrosSettings test_cros_settings_
;
330 content::TestBrowserThread ui_thread_
;
331 content::TestBrowserThread io_thread_
;
334 TEST_F(ProxyConfigServiceImplTest
, NetworkProxy
) {
335 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(tests
); ++i
) {
336 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS
"] %s", i
,
337 tests
[i
].description
.c_str()));
339 base::DictionaryValue test_config
;
340 InitConfigWithTestInput(tests
[i
].input
, &test_config
);
341 SetConfig(&test_config
);
343 net::ProxyConfig config
;
344 SyncGetLatestProxyConfig(&config
);
346 EXPECT_EQ(tests
[i
].auto_detect
, config
.auto_detect());
347 EXPECT_EQ(tests
[i
].pac_url
, config
.pac_url());
348 EXPECT_TRUE(tests
[i
].proxy_rules
.Matches(config
.proxy_rules()));
352 TEST_F(ProxyConfigServiceImplTest
, DynamicPrefsOverride
) {
353 // Groupings of 3 test inputs to use for managed, recommended and network
354 // proxies respectively. Only valid and non-direct test inputs are used.
355 const size_t proxies
[][3] = {
377 for (size_t i
= 0; i
< ARRAYSIZE_UNSAFE(proxies
); ++i
) {
378 const TestParams
& managed_params
= tests
[proxies
[i
][0]];
379 const TestParams
& recommended_params
= tests
[proxies
[i
][1]];
380 const TestParams
& network_params
= tests
[proxies
[i
][2]];
382 SCOPED_TRACE(base::StringPrintf(
383 "Test[%" PRIuS
"] managed=[%s], recommended=[%s], network=[%s]", i
,
384 managed_params
.description
.c_str(),
385 recommended_params
.description
.c_str(),
386 network_params
.description
.c_str()));
388 base::DictionaryValue managed_config
;
389 InitConfigWithTestInput(managed_params
.input
, &managed_config
);
390 base::DictionaryValue recommended_config
;
391 InitConfigWithTestInput(recommended_params
.input
, &recommended_config
);
392 base::DictionaryValue network_config
;
393 InitConfigWithTestInput(network_params
.input
, &network_config
);
395 // Managed proxy pref should take effect over recommended proxy and
396 // non-existent network proxy.
398 pref_service_
.SetManagedPref(prefs::kProxy
, managed_config
.DeepCopy());
399 pref_service_
.SetRecommendedPref(prefs::kProxy
,
400 recommended_config
.DeepCopy());
401 net::ProxyConfig actual_config
;
402 SyncGetLatestProxyConfig(&actual_config
);
403 EXPECT_EQ(managed_params
.auto_detect
, actual_config
.auto_detect());
404 EXPECT_EQ(managed_params
.pac_url
, actual_config
.pac_url());
405 EXPECT_TRUE(managed_params
.proxy_rules
.Matches(
406 actual_config
.proxy_rules()));
408 // Recommended proxy pref should take effect when managed proxy pref is
410 pref_service_
.RemoveManagedPref(prefs::kProxy
);
411 SyncGetLatestProxyConfig(&actual_config
);
412 EXPECT_EQ(recommended_params
.auto_detect
, actual_config
.auto_detect());
413 EXPECT_EQ(recommended_params
.pac_url
, actual_config
.pac_url());
414 EXPECT_TRUE(recommended_params
.proxy_rules
.Matches(
415 actual_config
.proxy_rules()));
417 // Network proxy should take take effect over recommended proxy pref.
418 SetConfig(&network_config
);
419 SyncGetLatestProxyConfig(&actual_config
);
420 EXPECT_EQ(network_params
.auto_detect
, actual_config
.auto_detect());
421 EXPECT_EQ(network_params
.pac_url
, actual_config
.pac_url());
422 EXPECT_TRUE(network_params
.proxy_rules
.Matches(
423 actual_config
.proxy_rules()));
425 // Managed proxy pref should take effect over network proxy.
426 pref_service_
.SetManagedPref(prefs::kProxy
, managed_config
.DeepCopy());
427 SyncGetLatestProxyConfig(&actual_config
);
428 EXPECT_EQ(managed_params
.auto_detect
, actual_config
.auto_detect());
429 EXPECT_EQ(managed_params
.pac_url
, actual_config
.pac_url());
430 EXPECT_TRUE(managed_params
.proxy_rules
.Matches(
431 actual_config
.proxy_rules()));
433 // Network proxy should take effect over recommended proxy pref when managed
434 // proxy pref is removed.
435 pref_service_
.RemoveManagedPref(prefs::kProxy
);
436 SyncGetLatestProxyConfig(&actual_config
);
437 EXPECT_EQ(network_params
.auto_detect
, actual_config
.auto_detect());
438 EXPECT_EQ(network_params
.pac_url
, actual_config
.pac_url());
439 EXPECT_TRUE(network_params
.proxy_rules
.Matches(
440 actual_config
.proxy_rules()));
442 // Removing recommended proxy pref should have no effect on network proxy.
443 pref_service_
.RemoveRecommendedPref(prefs::kProxy
);
444 SyncGetLatestProxyConfig(&actual_config
);
445 EXPECT_EQ(network_params
.auto_detect
, actual_config
.auto_detect());
446 EXPECT_EQ(network_params
.pac_url
, actual_config
.pac_url());
447 EXPECT_TRUE(network_params
.proxy_rules
.Matches(
448 actual_config
.proxy_rules()));
452 } // namespace chromeos