proxy_config_service_impl_unittest.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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. 4 5#include "chrome/browser/chromeos/proxy_config_service_impl.h" 6 7#include <map> 8#include <string> 9#include <vector> 10 11#include "base/format_macros.h" 12#include "base/logging.h" 13#include "base/message_loop.h" 14#include "base/prefs/testing_pref_service.h" 15#include "base/string_util.h" 16#include "base/stringprintf.h" 17#include "chrome/browser/chromeos/cros/cros_library.h" 18#include "chrome/common/pref_names.h" 19#include "chromeos/dbus/dbus_thread_manager.h" 20#include "content/public/test/test_browser_thread.h" 21#include "net/proxy/proxy_config_service_common_unittest.h" 22#include "testing/gtest/include/gtest/gtest.h" 23 24using content::BrowserThread; 25 26namespace chromeos { 27 28namespace { 29 30struct Input { // Fields of chromeos::ProxyConfigServiceImpl::ProxyConfig. 31 ProxyConfigServiceImpl::ProxyConfig::Mode mode; 32 const char* pac_url; 33 const char* single_uri; 34 const char* http_uri; 35 const char* https_uri; 36 const char* ftp_uri; 37 const char* socks_uri; 38 const char* bypass_rules; 39}; 40 41// Builds an identifier for each test in an array. 42#define TEST_DESC(desc) base::StringPrintf("at line %d <%s>", __LINE__, desc) 43 44// Shortcuts to declare enums within chromeos's ProxyConfig. 45#define MK_MODE(mode) ProxyConfigServiceImpl::ProxyConfig::MODE_##mode 46#define MK_SCHM(scheme) net::ProxyServer::SCHEME_##scheme 47#define MK_AVAIL(avail) net::ProxyConfigService::CONFIG_##avail 48 49// Inspired from net/proxy/proxy_config_service_linux_unittest.cc. 50const struct TestParams { 51 // Short description to identify the test 52 std::string description; 53 54 bool is_valid; 55 56 Input input; 57 58 // Expected outputs from fields of net::ProxyConfig (via IO). 59 bool auto_detect; 60 GURL pac_url; 61 net::ProxyRulesExpectation proxy_rules; 62} tests[] = { 63 { // 0 64 TEST_DESC("No proxying"), 65 66 true, // is_valid 67 68 { // Input. 69 MK_MODE(DIRECT), // mode 70 }, 71 72 // Expected result. 73 false, // auto_detect 74 GURL(), // pac_url 75 net::ProxyRulesExpectation::Empty(), // proxy_rules 76 }, 77 78 { // 1 79 TEST_DESC("Auto detect"), 80 81 true, // is_valid 82 83 { // Input. 84 MK_MODE(AUTO_DETECT), // mode 85 }, 86 87 // Expected result. 88 true, // auto_detect 89 GURL(), // pac_url 90 net::ProxyRulesExpectation::Empty(), // proxy_rules 91 }, 92 93 { // 2 94 TEST_DESC("Valid PAC URL"), 95 96 true, // is_valid 97 98 { // Input. 99 MK_MODE(PAC_SCRIPT), // mode 100 "http://wpad/wpad.dat", // pac_url 101 }, 102 103 // Expected result. 104 false, // auto_detect 105 GURL("http://wpad/wpad.dat"), // pac_url 106 net::ProxyRulesExpectation::Empty(), // proxy_rules 107 }, 108 109 { // 3 110 TEST_DESC("Invalid PAC URL"), 111 112 false, // is_valid 113 114 { // Input. 115 MK_MODE(PAC_SCRIPT), // mode 116 "wpad.dat", // pac_url 117 }, 118 119 // Expected result. 120 false, // auto_detect 121 GURL(), // pac_url 122 net::ProxyRulesExpectation::Empty(), // proxy_rules 123 }, 124 125 { // 4 126 TEST_DESC("Single-host in proxy list"), 127 128 true, // is_valid 129 130 { // Input. 131 MK_MODE(SINGLE_PROXY), // mode 132 NULL, // pac_url 133 "www.google.com", // single_uri 134 }, 135 136 // Expected result. 137 false, // auto_detect 138 GURL(), // pac_url 139 net::ProxyRulesExpectation::Single( // proxy_rules 140 "www.google.com:80", // single proxy 141 "<local>"), // bypass rules 142 }, 143 144 { // 5 145 TEST_DESC("Single-host, different port"), 146 147 true, // is_valid 148 149 { // Input. 150 MK_MODE(SINGLE_PROXY), // mode 151 NULL, // pac_url 152 "www.google.com:99", // single_uri 153 }, 154 155 // Expected result. 156 false, // auto_detect 157 GURL(), // pac_url 158 net::ProxyRulesExpectation::Single( // proxy_rules 159 "www.google.com:99", // single 160 "<local>"), // bypass rules 161 }, 162 163 { // 6 164 TEST_DESC("Tolerate a scheme"), 165 166 true, // is_valid 167 168 { // Input. 169 MK_MODE(SINGLE_PROXY), // mode 170 NULL, // pac_url 171 "http://www.google.com:99", // single_uri 172 }, 173 174 // Expected result. 175 false, // auto_detect 176 GURL(), // pac_url 177 net::ProxyRulesExpectation::Single( // proxy_rules 178 "www.google.com:99", // single proxy 179 "<local>"), // bypass rules 180 }, 181 182 { // 7 183 TEST_DESC("Per-scheme proxy rules"), 184 185 true, // is_valid 186 187 { // Input. 188 MK_MODE(PROXY_PER_SCHEME), // mode 189 NULL, // pac_url 190 NULL, // single_uri 191 "www.google.com:80", // http_uri 192 "www.foo.com:110", // https_uri 193 "ftp.foo.com:121", // ftp_uri 194 "socks.com:888", // socks_uri 195 }, 196 197 // Expected result. 198 false, // auto_detect 199 GURL(), // pac_url 200 net::ProxyRulesExpectation::PerSchemeWithSocks( // proxy_rules 201 "www.google.com:80", // http 202 "https://www.foo.com:110", // https 203 "ftp.foo.com:121", // ftp 204 "socks5://socks.com:888", // fallback proxy 205 "<local>"), // bypass rules 206 }, 207 208 { // 8 209 TEST_DESC("Bypass rules"), 210 211 true, // is_valid 212 213 { // Input. 214 MK_MODE(SINGLE_PROXY), // mode 215 NULL, // pac_url 216 "www.google.com", // single_uri 217 NULL, NULL, NULL, NULL, // per-proto 218 "*.google.com, *foo.com:99, 1.2.3.4:22, 127.0.0.1/8", // bypass_rules 219 }, 220 221 // Expected result. 222 false, // auto_detect 223 GURL(), // pac_url 224 net::ProxyRulesExpectation::Single( // proxy_rules 225 "www.google.com:80", // single proxy 226 // bypass_rules 227 "*.google.com,*foo.com:99,1.2.3.4:22,127.0.0.1/8,<local>"), 228 }, 229}; // tests 230 231template<typename TESTBASE> 232class ProxyConfigServiceImplTestBase : public TESTBASE { 233 protected: 234 ProxyConfigServiceImplTestBase() 235 : ui_thread_(BrowserThread::UI, &loop_), 236 io_thread_(BrowserThread::IO, &loop_) {} 237 238 virtual void Init(TestingPrefServiceSimple* pref_service) { 239 ASSERT_TRUE(pref_service); 240 DBusThreadManager::Initialize(); 241 PrefProxyConfigTrackerImpl::RegisterPrefs(pref_service->registry()); 242 ProxyConfigServiceImpl::RegisterPrefs(pref_service->registry()); 243 proxy_config_service_.reset(new ChromeProxyConfigService(NULL)); 244 config_service_impl_.reset(new ProxyConfigServiceImpl(pref_service)); 245 config_service_impl_->SetChromeProxyConfigService( 246 proxy_config_service_.get()); 247 // SetChromeProxyConfigService triggers update of initial prefs proxy 248 // config by tracker to chrome proxy config service, so flush all pending 249 // tasks so that tests start fresh. 250 loop_.RunUntilIdle(); 251 } 252 253 virtual void TearDown() { 254 config_service_impl_->DetachFromPrefService(); 255 loop_.RunUntilIdle(); 256 config_service_impl_.reset(); 257 proxy_config_service_.reset(); 258 DBusThreadManager::Shutdown(); 259 } 260 261 void SetAutomaticProxy( 262 ProxyConfigServiceImpl::ProxyConfig::Mode mode, 263 const char* pac_url, 264 ProxyConfigServiceImpl::ProxyConfig* config, 265 ProxyConfigServiceImpl::ProxyConfig::AutomaticProxy* automatic_proxy) { 266 config->mode = mode; 267 config->state = ProxyPrefs::CONFIG_SYSTEM; 268 if (pac_url) 269 automatic_proxy->pac_url = GURL(pac_url); 270 } 271 272 void SetManualProxy( 273 ProxyConfigServiceImpl::ProxyConfig::Mode mode, 274 const char* server_uri, 275 net::ProxyServer::Scheme scheme, 276 ProxyConfigServiceImpl::ProxyConfig* config, 277 ProxyConfigServiceImpl::ProxyConfig::ManualProxy* manual_proxy) { 278 if (!server_uri) 279 return; 280 config->mode = mode; 281 config->state = ProxyPrefs::CONFIG_SYSTEM; 282 manual_proxy->server = net::ProxyServer::FromURI(server_uri, scheme); 283 } 284 285 void InitConfigWithTestInput( 286 const Input& input, ProxyConfigServiceImpl::ProxyConfig* test_config) { 287 switch (input.mode) { 288 case MK_MODE(DIRECT): 289 case MK_MODE(AUTO_DETECT): 290 case MK_MODE(PAC_SCRIPT): 291 SetAutomaticProxy(input.mode, input.pac_url, test_config, 292 &test_config->automatic_proxy); 293 return; 294 case MK_MODE(SINGLE_PROXY): 295 SetManualProxy(input.mode, input.single_uri, MK_SCHM(HTTP), 296 test_config, &test_config->single_proxy); 297 break; 298 case MK_MODE(PROXY_PER_SCHEME): 299 SetManualProxy(input.mode, input.http_uri, MK_SCHM(HTTP), 300 test_config, &test_config->http_proxy); 301 SetManualProxy(input.mode, input.https_uri, MK_SCHM(HTTPS), 302 test_config, &test_config->https_proxy); 303 SetManualProxy(input.mode, input.ftp_uri, MK_SCHM(HTTP), 304 test_config, &test_config->ftp_proxy); 305 SetManualProxy(input.mode, input.socks_uri, MK_SCHM(SOCKS5), 306 test_config, &test_config->socks_proxy); 307 break; 308 } 309 if (input.bypass_rules) 310 test_config->bypass_rules.ParseFromString(input.bypass_rules); 311 } 312 313 // Synchronously gets the latest proxy config. 314 net::ProxyConfigService::ConfigAvailability SyncGetLatestProxyConfig( 315 net::ProxyConfig* config) { 316 *config = net::ProxyConfig(); 317 // Let message loop process all messages. 318 loop_.RunUntilIdle(); 319 // Calls ChromeProIOGetProxyConfig (which is called from 320 // ProxyConfigService::GetLatestProxyConfig), running on faked IO thread. 321 return proxy_config_service_->GetLatestProxyConfig(config); 322 } 323 324 MessageLoop loop_; 325 scoped_ptr<ChromeProxyConfigService> proxy_config_service_; 326 scoped_ptr<ProxyConfigServiceImpl> config_service_impl_; 327 328 private: 329 // Default stub state has ethernet as the active connected network and 330 // PROFILE_SHARED as profile type, which this unittest expects. 331 ScopedStubCrosEnabler stub_cros_enabler_; 332 content::TestBrowserThread ui_thread_; 333 content::TestBrowserThread io_thread_; 334}; 335 336class ProxyConfigServiceImplTest 337 : public ProxyConfigServiceImplTestBase<testing::Test> { 338 protected: 339 virtual void SetUp() { 340 Init(&pref_service_); 341 } 342 343 TestingPrefServiceSimple pref_service_; 344}; 345 346TEST_F(ProxyConfigServiceImplTest, NetworkProxy) { 347 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { 348 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "] %s", i, 349 tests[i].description.c_str())); 350 351 ProxyConfigServiceImpl::ProxyConfig test_config; 352 InitConfigWithTestInput(tests[i].input, &test_config); 353 config_service_impl_->SetTesting(&test_config); 354 355 net::ProxyConfig config; 356 EXPECT_EQ(MK_AVAIL(VALID), SyncGetLatestProxyConfig(&config)); 357 358 EXPECT_EQ(tests[i].auto_detect, config.auto_detect()); 359 EXPECT_EQ(tests[i].pac_url, config.pac_url()); 360 EXPECT_TRUE(tests[i].proxy_rules.Matches(config.proxy_rules())); 361 } 362} 363 364TEST_F(ProxyConfigServiceImplTest, ModifyFromUI) { 365 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) { 366 SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "] %s", i, 367 tests[i].description.c_str())); 368 369 // Init with direct. 370 ProxyConfigServiceImpl::ProxyConfig test_config; 371 SetAutomaticProxy(MK_MODE(DIRECT), NULL, &test_config, 372 &test_config.automatic_proxy); 373 config_service_impl_->SetTesting(&test_config); 374 375 // Set config to tests[i].input via UI. 376 net::ProxyBypassRules bypass_rules; 377 const Input& input = tests[i].input; 378 switch (input.mode) { 379 case MK_MODE(DIRECT) : 380 config_service_impl_->UISetProxyConfigToDirect(); 381 break; 382 case MK_MODE(AUTO_DETECT) : 383 config_service_impl_->UISetProxyConfigToAutoDetect(); 384 break; 385 case MK_MODE(PAC_SCRIPT) : 386 config_service_impl_->UISetProxyConfigToPACScript(GURL(input.pac_url)); 387 break; 388 case MK_MODE(SINGLE_PROXY) : 389 config_service_impl_->UISetProxyConfigToSingleProxy( 390 net::ProxyServer::FromURI(input.single_uri, MK_SCHM(HTTP))); 391 if (input.bypass_rules) { 392 bypass_rules.ParseFromString(input.bypass_rules); 393 config_service_impl_->UISetProxyConfigBypassRules(bypass_rules); 394 } 395 break; 396 case MK_MODE(PROXY_PER_SCHEME) : 397 if (input.http_uri) { 398 config_service_impl_->UISetProxyConfigToProxyPerScheme("http", 399 net::ProxyServer::FromURI(input.http_uri, MK_SCHM(HTTP))); 400 } 401 if (input.https_uri) { 402 config_service_impl_->UISetProxyConfigToProxyPerScheme("https", 403 net::ProxyServer::FromURI(input.https_uri, MK_SCHM(HTTPS))); 404 } 405 if (input.ftp_uri) { 406 config_service_impl_->UISetProxyConfigToProxyPerScheme("ftp", 407 net::ProxyServer::FromURI(input.ftp_uri, MK_SCHM(HTTP))); 408 } 409 if (input.socks_uri) { 410 config_service_impl_->UISetProxyConfigToProxyPerScheme("socks", 411 net::ProxyServer::FromURI(input.socks_uri, MK_SCHM(SOCKS5))); 412 } 413 if (input.bypass_rules) { 414 bypass_rules.ParseFromString(input.bypass_rules); 415 config_service_impl_->UISetProxyConfigBypassRules(bypass_rules); 416 } 417 break; 418 } 419 420 // Retrieve config from IO thread. 421 net::ProxyConfig io_config; 422 EXPECT_EQ(MK_AVAIL(VALID), SyncGetLatestProxyConfig(&io_config)); 423 EXPECT_EQ(tests[i].auto_detect, io_config.auto_detect()); 424 EXPECT_EQ(tests[i].pac_url, io_config.pac_url()); 425 EXPECT_TRUE(tests[i].proxy_rules.Matches(io_config.proxy_rules())); 426 427 // Retrieve config from UI thread. 428 ProxyConfigServiceImpl::ProxyConfig ui_config; 429 config_service_impl_->UIGetProxyConfig(&ui_config); 430 EXPECT_EQ(input.mode, ui_config.mode); 431 if (tests[i].is_valid) { 432 if (input.pac_url) 433 EXPECT_EQ(GURL(input.pac_url), ui_config.automatic_proxy.pac_url); 434 const net::ProxyRulesExpectation& proxy_rules = tests[i].proxy_rules; 435 if (input.single_uri) 436 EXPECT_EQ(proxy_rules.single_proxy, 437 ui_config.single_proxy.server.ToURI()); 438 if (input.http_uri) 439 EXPECT_EQ(proxy_rules.proxy_for_http, 440 ui_config.http_proxy.server.ToURI()); 441 if (input.https_uri) 442 EXPECT_EQ(proxy_rules.proxy_for_https, 443 ui_config.https_proxy.server.ToURI()); 444 if (input.ftp_uri) 445 EXPECT_EQ(proxy_rules.proxy_for_ftp, 446 ui_config.ftp_proxy.server.ToURI()); 447 if (input.socks_uri) { 448 EXPECT_EQ(proxy_rules.fallback_proxy, 449 ui_config.socks_proxy.server.ToURI()); 450 } 451 if (input.bypass_rules) 452 EXPECT_TRUE(bypass_rules.Equals(ui_config.bypass_rules)); 453 } 454 } 455} 456 457TEST_F(ProxyConfigServiceImplTest, DynamicPrefsOverride) { 458 // Groupings of 3 test inputs to use for managed, recommended and network 459 // proxies respectively. Only valid and non-direct test inputs are used. 460 const size_t proxies[][3] = { 461 { 1, 2, 4, }, 462 { 1, 4, 2, }, 463 { 4, 2, 1, }, 464 { 2, 1, 4, }, 465 { 2, 4, 5, }, 466 { 2, 5, 4, }, 467 { 5, 4, 2, }, 468 { 4, 2, 5, }, 469 { 4, 5, 6, }, 470 { 4, 6, 5, }, 471 { 6, 5, 4, }, 472 { 5, 4, 6, }, 473 { 5, 6, 7, }, 474 { 5, 7, 6, }, 475 { 7, 6, 5, }, 476 { 6, 5, 7, }, 477 { 6, 7, 8, }, 478 { 6, 8, 7, }, 479 { 8, 7, 6, }, 480 { 7, 6, 8, }, 481 }; 482 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(proxies); ++i) { 483 const TestParams& managed_params = tests[proxies[i][0]]; 484 const TestParams& recommended_params = tests[proxies[i][1]]; 485 const TestParams& network_params = tests[proxies[i][2]]; 486 487 SCOPED_TRACE(base::StringPrintf( 488 "Test[%" PRIuS "] managed=[%s], recommended=[%s], network=[%s]", i, 489 managed_params.description.c_str(), 490 recommended_params.description.c_str(), 491 network_params.description.c_str())); 492 493 ProxyConfigServiceImpl::ProxyConfig managed_config; 494 InitConfigWithTestInput(managed_params.input, &managed_config); 495 ProxyConfigServiceImpl::ProxyConfig recommended_config; 496 InitConfigWithTestInput(recommended_params.input, &recommended_config); 497 ProxyConfigServiceImpl::ProxyConfig network_config; 498 InitConfigWithTestInput(network_params.input, &network_config); 499 500 // Managed proxy pref should take effect over recommended proxy and 501 // non-existent network proxy. 502 config_service_impl_->SetTesting(NULL); 503 pref_service_.SetManagedPref(prefs::kProxy, 504 managed_config.ToPrefProxyConfig()); 505 pref_service_.SetRecommendedPref(prefs::kProxy, 506 recommended_config.ToPrefProxyConfig()); 507 net::ProxyConfig actual_config; 508 EXPECT_EQ(MK_AVAIL(VALID), SyncGetLatestProxyConfig(&actual_config)); 509 EXPECT_EQ(managed_params.auto_detect, actual_config.auto_detect()); 510 EXPECT_EQ(managed_params.pac_url, actual_config.pac_url()); 511 EXPECT_TRUE(managed_params.proxy_rules.Matches( 512 actual_config.proxy_rules())); 513 514 // Recommended proxy pref should take effect when managed proxy pref is 515 // removed. 516 pref_service_.RemoveManagedPref(prefs::kProxy); 517 EXPECT_EQ(MK_AVAIL(VALID), SyncGetLatestProxyConfig(&actual_config)); 518 EXPECT_EQ(recommended_params.auto_detect, actual_config.auto_detect()); 519 EXPECT_EQ(recommended_params.pac_url, actual_config.pac_url()); 520 EXPECT_TRUE(recommended_params.proxy_rules.Matches( 521 actual_config.proxy_rules())); 522 523 // Network proxy should take take effect over recommended proxy pref. 524 config_service_impl_->SetTesting(&network_config); 525 EXPECT_EQ(MK_AVAIL(VALID), SyncGetLatestProxyConfig(&actual_config)); 526 EXPECT_EQ(network_params.auto_detect, actual_config.auto_detect()); 527 EXPECT_EQ(network_params.pac_url, actual_config.pac_url()); 528 EXPECT_TRUE(network_params.proxy_rules.Matches( 529 actual_config.proxy_rules())); 530 531 // Managed proxy pref should take effect over network proxy. 532 pref_service_.SetManagedPref(prefs::kProxy, 533 managed_config.ToPrefProxyConfig()); 534 EXPECT_EQ(MK_AVAIL(VALID), SyncGetLatestProxyConfig(&actual_config)); 535 EXPECT_EQ(managed_params.auto_detect, actual_config.auto_detect()); 536 EXPECT_EQ(managed_params.pac_url, actual_config.pac_url()); 537 EXPECT_TRUE(managed_params.proxy_rules.Matches( 538 actual_config.proxy_rules())); 539 540 // Network proxy should take effect over recommended proxy pref when managed 541 // proxy pref is removed. 542 pref_service_.RemoveManagedPref(prefs::kProxy); 543 EXPECT_EQ(MK_AVAIL(VALID), SyncGetLatestProxyConfig(&actual_config)); 544 EXPECT_EQ(network_params.auto_detect, actual_config.auto_detect()); 545 EXPECT_EQ(network_params.pac_url, actual_config.pac_url()); 546 EXPECT_TRUE(network_params.proxy_rules.Matches( 547 actual_config.proxy_rules())); 548 549 // Removing recommended proxy pref should have no effect on network proxy. 550 pref_service_.RemoveRecommendedPref(prefs::kProxy); 551 EXPECT_EQ(MK_AVAIL(VALID), SyncGetLatestProxyConfig(&actual_config)); 552 EXPECT_EQ(network_params.auto_detect, actual_config.auto_detect()); 553 EXPECT_EQ(network_params.pac_url, actual_config.pac_url()); 554 EXPECT_TRUE(network_params.proxy_rules.Matches( 555 actual_config.proxy_rules())); 556 } 557} 558 559} // namespace 560 561} // namespace chromeos 562