Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 "base/bind.h" | |
| 6 #include "base/synchronization/lock.h" | |
| 7 #include "base/threading/thread.h" | |
| 8 #include "net/proxy/proxy_config.h" | |
| 9 #include "net/proxy/proxy_config_service_android.h" | |
| 10 #include "net/proxy/proxy_info.h" | |
| 11 #include "testing/gtest/include/gtest/gtest.h" | |
| 12 | |
| 13 #include <map> | |
| 14 #include <string> | |
| 15 | |
| 16 namespace net { | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 typedef std::map<std::string, std::string> StringMap; | |
| 21 | |
| 22 class TestDelegate : public ProxyConfigServiceAndroid::Delegate { | |
| 23 public: | |
| 24 TestDelegate(); | |
| 25 | |
| 26 // ProxyConfigServiceAndroid::Delegate: | |
| 27 virtual void Start(ProxyConfigServiceAndroid* service) OVERRIDE; | |
| 28 virtual void Stop() OVERRIDE; | |
| 29 virtual std::string GetProperty(const std::string& property) OVERRIDE; | |
| 30 | |
| 31 // For testing: | |
| 32 void SetProperties(const StringMap& properties); | |
| 33 | |
| 34 private: | |
| 35 base::Lock lock_; | |
|
Ryan Sleevi
2012/04/24 18:20:04
See previous comments about locks and double check
Philippe
2012/05/09 11:48:39
We simplified significantly ProxyConfigServiceAndr
| |
| 36 StringMap properties_; | |
| 37 ProxyConfigServiceAndroid* service_; | |
| 38 }; | |
| 39 | |
| 40 TestDelegate::TestDelegate() | |
| 41 : service_(NULL) { | |
| 42 } | |
|
Ryan Sleevi
2012/04/24 18:20:04
nit: One line
TestDelegate::TestDelegate() : serv
Philippe
2012/05/09 11:48:39
Done.
| |
| 43 | |
| 44 void TestDelegate::Start(ProxyConfigServiceAndroid* service) { | |
| 45 service_ = service; | |
| 46 } | |
| 47 | |
| 48 void TestDelegate::Stop() { | |
|
Ryan Sleevi
2012/04/24 18:20:04
nit: one line
Philippe
2012/05/09 11:48:39
Done.
| |
| 49 } | |
| 50 | |
| 51 std::string TestDelegate::GetProperty(const std::string& property) { | |
| 52 base::AutoLock lock(lock_); | |
| 53 StringMap::iterator it = properties_.find(property); | |
| 54 if (it == properties_.end()) | |
| 55 return ""; | |
| 56 return it->second; | |
| 57 } | |
| 58 | |
| 59 void TestDelegate::SetProperties(const StringMap& properties) { | |
| 60 // Called from UI thread | |
| 61 base::AutoLock lock(lock_); | |
| 62 properties_ = properties; | |
| 63 if (service_) { | |
| 64 // Should not deadlock. Should schedule a task on the IO thread. | |
| 65 service_->ProxySettingsChanged(); | |
| 66 } | |
| 67 } | |
| 68 | |
| 69 class TestObserver : public ProxyConfigService::Observer { | |
| 70 public: | |
| 71 // Construct this on the UI thread. | |
|
Ryan Sleevi
2012/04/24 18:20:04
See previous comments about "UI thread" references
Philippe
2012/05/09 11:48:39
We don't mention network nor UI anymore.
| |
| 72 TestObserver(); | |
| 73 | |
| 74 // ProxyConfigService::Observer: | |
| 75 virtual void OnProxyConfigChanged( | |
| 76 const ProxyConfig& config, | |
| 77 ProxyConfigService::ConfigAvailability availability) OVERRIDE; | |
| 78 | |
| 79 // Called on UI thread. | |
| 80 ProxyConfigService::ConfigAvailability availability(); | |
| 81 ProxyConfig& config(); | |
| 82 | |
| 83 private: | |
| 84 void UpdateConfig(const ProxyConfig& config, | |
| 85 ProxyConfigService::ConfigAvailability availability); | |
| 86 | |
| 87 // Accessed from UI thread. | |
| 88 MessageLoop *ui_loop_; | |
| 89 ProxyConfig config_; | |
| 90 ProxyConfigService::ConfigAvailability availability_; | |
| 91 }; | |
| 92 | |
| 93 TestObserver::TestObserver() | |
| 94 : ui_loop_(MessageLoop::current()) { | |
| 95 } | |
| 96 | |
| 97 void TestObserver::OnProxyConfigChanged( | |
| 98 const ProxyConfig& config, | |
| 99 ProxyConfigService::ConfigAvailability availability) { | |
| 100 // Called from IO thread. | |
| 101 ui_loop_->PostTask( | |
| 102 FROM_HERE, | |
| 103 base::Bind(&TestObserver::UpdateConfig, | |
| 104 base::Unretained(this), config, availability)); | |
| 105 } | |
| 106 | |
| 107 void TestObserver::UpdateConfig( | |
| 108 const ProxyConfig& config, | |
| 109 ProxyConfigService::ConfigAvailability availability) { | |
| 110 DCHECK(MessageLoop::current() == ui_loop_); | |
| 111 config_ = config; | |
| 112 availability_ = availability; | |
| 113 ui_loop_->Quit(); | |
| 114 } | |
| 115 | |
| 116 ProxyConfigService::ConfigAvailability TestObserver::availability() { | |
| 117 DCHECK(MessageLoop::current() == ui_loop_); | |
| 118 return availability_; | |
| 119 } | |
| 120 | |
| 121 ProxyConfig& TestObserver::config() { | |
| 122 DCHECK(MessageLoop::current() == ui_loop_); | |
| 123 return config_; | |
| 124 } | |
| 125 | |
| 126 class TestIOThread : public base::Thread { | |
| 127 public: | |
| 128 TestIOThread(ProxyConfigServiceAndroid* service, | |
| 129 ProxyConfigService::Observer* observer); | |
| 130 // Thread | |
| 131 virtual void Init() OVERRIDE; | |
| 132 virtual void CleanUp() OVERRIDE; | |
| 133 | |
| 134 private: | |
| 135 scoped_ptr<ProxyConfigServiceAndroid> service_; | |
| 136 ProxyConfigService::Observer* observer_; | |
| 137 }; | |
| 138 | |
| 139 TestIOThread::TestIOThread( | |
| 140 ProxyConfigServiceAndroid* service, | |
| 141 ProxyConfigService::Observer* observer) | |
| 142 : base::Thread("io_thread"), | |
| 143 service_(service), | |
| 144 observer_(observer) { | |
| 145 } | |
| 146 | |
| 147 void TestIOThread::Init() { | |
| 148 service_->AddObserver(observer_); | |
| 149 } | |
| 150 | |
| 151 void TestIOThread::CleanUp() { | |
| 152 service_->RemoveObserver(observer_); | |
| 153 service_.reset(); | |
| 154 } | |
| 155 | |
| 156 TEST(ProxyConfigServiceAndroidTest, TestChangePropertiesNotification) { | |
| 157 TestDelegate* delegate = new TestDelegate; | |
| 158 ProxyConfigServiceAndroid *service = | |
| 159 new ProxyConfigServiceAndroid(delegate); // service now owns delegate. | |
| 160 TestObserver observer; | |
| 161 TestIOThread io_thread(service, &observer); // io_thread owns service | |
| 162 io_thread.Start(); | |
| 163 | |
| 164 // Set up a non-empty configuration | |
| 165 StringMap properties; | |
| 166 properties["http.proxyHost"] = "localhost"; | |
| 167 delegate->SetProperties(properties); | |
| 168 MessageLoop::current()->Run(); | |
| 169 EXPECT_EQ(ProxyConfigService::CONFIG_VALID, observer.availability()); | |
| 170 EXPECT_FALSE(observer.config().proxy_rules().empty()); | |
| 171 | |
| 172 // Set up an empty configuration | |
| 173 delegate->SetProperties(StringMap()); | |
| 174 MessageLoop::current()->Run(); | |
| 175 EXPECT_EQ(ProxyConfigService::CONFIG_VALID, observer.availability()); | |
| 176 EXPECT_TRUE(observer.config().proxy_rules().empty()); | |
| 177 | |
| 178 io_thread.Stop(); | |
| 179 } | |
| 180 | |
| 181 class ProxyConfigServiceAndroidMappingTest : public testing::Test { | |
| 182 protected: | |
| 183 ProxyConfigServiceAndroidMappingTest(); | |
| 184 | |
| 185 // testing::Test | |
| 186 virtual void SetUp() OVERRIDE; | |
| 187 | |
| 188 void TestMapping(const std::string& url, const std::string& expected); | |
| 189 | |
| 190 TestDelegate* delegate_; | |
| 191 scoped_ptr<ProxyConfigServiceAndroid> service_; | |
| 192 StringMap configuration_; | |
| 193 }; | |
| 194 | |
| 195 ProxyConfigServiceAndroidMappingTest::ProxyConfigServiceAndroidMappingTest() | |
| 196 : delegate_(new TestDelegate), | |
| 197 service_(new ProxyConfigServiceAndroid(delegate_)) { | |
| 198 // Note that service_ owns delegate_, and that we're just testing the mappings | |
| 199 // here, so we don't need to set up an IO thread explicitly. | |
| 200 } | |
| 201 | |
| 202 void ProxyConfigServiceAndroidMappingTest::SetUp() { | |
| 203 configuration_.clear(); | |
| 204 } | |
| 205 | |
| 206 static std::string ToString(ProxyInfo& proxy_info) { | |
|
Ryan Sleevi
2012/04/24 18:20:04
nit: Use ProxyInfo::ToPacString() instead?
Philippe
2012/05/09 11:48:39
The code using ToString() is generated from a Pyth
| |
| 207 BoundNetLog net_log; | |
| 208 std::string result; | |
| 209 while (!proxy_info.is_empty()) { | |
| 210 if (!result.empty()) | |
| 211 result += ";"; | |
| 212 if (!proxy_info.is_direct()) | |
| 213 result += proxy_info.proxy_server().host_port_pair().ToString(); | |
| 214 proxy_info.Fallback(net_log); | |
| 215 } | |
| 216 return result; | |
| 217 } | |
| 218 | |
| 219 void ProxyConfigServiceAndroidMappingTest::TestMapping( | |
| 220 const std::string& url, | |
| 221 const std::string& expected) { | |
| 222 ProxyConfig config; | |
| 223 EXPECT_EQ(ProxyConfigService::CONFIG_VALID, | |
| 224 service_->GetLatestProxyConfig(&config)); | |
| 225 ProxyInfo proxy_info; | |
| 226 config.proxy_rules().Apply(GURL(url), &proxy_info); | |
| 227 EXPECT_EQ(expected, ToString(proxy_info)); | |
| 228 } | |
| 229 | |
| 230 // !! The following test cases are automatically generated from | |
| 231 // !! net/android/tools/proxy_test_cases.py. | |
| 232 // !! Please edit that file instead of editing the test cases below and | |
| 233 // !! update also the corresponding Java unit tests in | |
| 234 // !! AndroidProxySelectorTest.java | |
| 235 | |
| 236 TEST_F(ProxyConfigServiceAndroidMappingTest, NoProxy) { | |
| 237 // Test direct mapping when no proxy defined. | |
| 238 delegate_->SetProperties(configuration_); | |
| 239 TestMapping("ftp://example.com/", ""); | |
| 240 TestMapping("http://example.com/", ""); | |
| 241 TestMapping("https://example.com/", ""); | |
| 242 } | |
| 243 | |
| 244 TEST_F(ProxyConfigServiceAndroidMappingTest, HttpProxyHostAndPort) { | |
| 245 // Test http.proxyHost and http.proxyPort works. | |
| 246 configuration_["http.proxyHost"] = "httpproxy.com"; | |
| 247 configuration_["http.proxyPort"] = "8080"; | |
| 248 delegate_->SetProperties(configuration_); | |
| 249 TestMapping("ftp://example.com/", ""); | |
| 250 TestMapping("http://example.com/", "httpproxy.com:8080"); | |
| 251 TestMapping("https://example.com/", ""); | |
| 252 } | |
| 253 | |
| 254 TEST_F(ProxyConfigServiceAndroidMappingTest, HttpProxyHostOnly) { | |
| 255 // We should get the default port (80) for proxied hosts. | |
| 256 configuration_["http.proxyHost"] = "httpproxy.com"; | |
| 257 delegate_->SetProperties(configuration_); | |
| 258 TestMapping("ftp://example.com/", ""); | |
| 259 TestMapping("http://example.com/", "httpproxy.com:80"); | |
| 260 TestMapping("https://example.com/", ""); | |
| 261 } | |
| 262 | |
| 263 TEST_F(ProxyConfigServiceAndroidMappingTest, HttpProxyPortOnly) { | |
| 264 // http.proxyPort only should not result in any hosts being proxied. | |
| 265 configuration_["http.proxyPort"] = "8080"; | |
| 266 delegate_->SetProperties(configuration_); | |
| 267 TestMapping("ftp://example.com/", ""); | |
| 268 TestMapping("http://example.com/", ""); | |
| 269 TestMapping("https://example.com/", ""); | |
| 270 } | |
| 271 | |
| 272 TEST_F(ProxyConfigServiceAndroidMappingTest, HttpNonProxyHosts1) { | |
| 273 // Test that HTTP non proxy hosts are mapped correctly | |
| 274 configuration_["http.nonProxyHosts"] = "slashdot.org"; | |
| 275 configuration_["http.proxyHost"] = "httpproxy.com"; | |
| 276 configuration_["http.proxyPort"] = "8080"; | |
| 277 delegate_->SetProperties(configuration_); | |
| 278 TestMapping("http://example.com/", "httpproxy.com:8080"); | |
| 279 TestMapping("http://slashdot.org/", ""); | |
| 280 } | |
| 281 | |
| 282 TEST_F(ProxyConfigServiceAndroidMappingTest, HttpNonProxyHosts2) { | |
| 283 // Test that | pattern works. | |
| 284 configuration_["http.nonProxyHosts"] = "slashdot.org|freecode.net"; | |
| 285 configuration_["http.proxyHost"] = "httpproxy.com"; | |
| 286 configuration_["http.proxyPort"] = "8080"; | |
| 287 delegate_->SetProperties(configuration_); | |
| 288 TestMapping("http://example.com/", "httpproxy.com:8080"); | |
| 289 TestMapping("http://freecode.net/", ""); | |
| 290 TestMapping("http://slashdot.org/", ""); | |
| 291 } | |
| 292 | |
| 293 TEST_F(ProxyConfigServiceAndroidMappingTest, HttpNonProxyHosts3) { | |
| 294 // Test that * pattern works. | |
| 295 configuration_["http.nonProxyHosts"] = "*example.com"; | |
| 296 configuration_["http.proxyHost"] = "httpproxy.com"; | |
| 297 configuration_["http.proxyPort"] = "8080"; | |
| 298 delegate_->SetProperties(configuration_); | |
| 299 TestMapping("http://example.com/", ""); | |
| 300 TestMapping("http://slashdot.org/", "httpproxy.com:8080"); | |
| 301 TestMapping("http://www.example.com/", ""); | |
| 302 } | |
| 303 | |
| 304 TEST_F(ProxyConfigServiceAndroidMappingTest, FtpNonProxyHosts) { | |
| 305 // Test that FTP non proxy hosts are mapped correctly | |
| 306 configuration_["ftp.nonProxyHosts"] = "slashdot.org"; | |
| 307 configuration_["ftp.proxyHost"] = "httpproxy.com"; | |
| 308 configuration_["ftp.proxyPort"] = "8080"; | |
| 309 delegate_->SetProperties(configuration_); | |
| 310 TestMapping("ftp://example.com/", "httpproxy.com:8080"); | |
| 311 TestMapping("http://example.com/", ""); | |
| 312 } | |
| 313 | |
| 314 TEST_F(ProxyConfigServiceAndroidMappingTest, FtpProxyHostAndPort) { | |
| 315 // Test ftp.proxyHost and ftp.proxyPort works. | |
| 316 configuration_["ftp.proxyHost"] = "httpproxy.com"; | |
| 317 configuration_["ftp.proxyPort"] = "8080"; | |
| 318 delegate_->SetProperties(configuration_); | |
| 319 TestMapping("ftp://example.com/", "httpproxy.com:8080"); | |
| 320 TestMapping("http://example.com/", ""); | |
| 321 TestMapping("https://example.com/", ""); | |
| 322 } | |
| 323 | |
| 324 TEST_F(ProxyConfigServiceAndroidMappingTest, FtpProxyHostOnly) { | |
| 325 // Test ftp.proxyHost and default port. | |
| 326 configuration_["ftp.proxyHost"] = "httpproxy.com"; | |
| 327 delegate_->SetProperties(configuration_); | |
| 328 TestMapping("ftp://example.com/", "httpproxy.com:80"); | |
| 329 TestMapping("http://example.com/", ""); | |
| 330 TestMapping("https://example.com/", ""); | |
| 331 } | |
| 332 | |
| 333 TEST_F(ProxyConfigServiceAndroidMappingTest, HttpsProxyHostAndPort) { | |
| 334 // Test https.proxyHost and https.proxyPort works. | |
| 335 configuration_["https.proxyHost"] = "httpproxy.com"; | |
| 336 configuration_["https.proxyPort"] = "8080"; | |
| 337 delegate_->SetProperties(configuration_); | |
| 338 TestMapping("ftp://example.com/", ""); | |
| 339 TestMapping("http://example.com/", ""); | |
| 340 TestMapping("https://example.com/", "httpproxy.com:8080"); | |
| 341 } | |
| 342 | |
| 343 TEST_F(ProxyConfigServiceAndroidMappingTest, HttpsProxyHostOnly) { | |
| 344 // Test https.proxyHost and default port. | |
| 345 configuration_["https.proxyHost"] = "httpproxy.com"; | |
| 346 delegate_->SetProperties(configuration_); | |
| 347 TestMapping("ftp://example.com/", ""); | |
| 348 TestMapping("http://example.com/", ""); | |
| 349 TestMapping("https://example.com/", "httpproxy.com:443"); | |
| 350 } | |
| 351 | |
| 352 TEST_F(ProxyConfigServiceAndroidMappingTest, DefaultProxyExplictPort) { | |
| 353 // Default http proxy is used if a scheme-specific one is not found. | |
| 354 configuration_["ftp.proxyHost"] = "httpproxy.com"; | |
| 355 configuration_["ftp.proxyPort"] = "8080"; | |
| 356 configuration_["proxyHost"] = "defaultproxy.com"; | |
| 357 configuration_["proxyPort"] = "8080"; | |
| 358 delegate_->SetProperties(configuration_); | |
| 359 TestMapping("ftp://example.com/", "httpproxy.com:8080"); | |
| 360 TestMapping("http://example.com/", "defaultproxy.com:8080"); | |
| 361 TestMapping("https://example.com/", "defaultproxy.com:8080"); | |
| 362 } | |
| 363 | |
| 364 TEST_F(ProxyConfigServiceAndroidMappingTest, DefaultProxyDefaultPort) { | |
| 365 // Check that the default proxy port is as expected. | |
| 366 configuration_["proxyHost"] = "defaultproxy.com"; | |
| 367 delegate_->SetProperties(configuration_); | |
| 368 TestMapping("http://example.com/", "defaultproxy.com:80"); | |
| 369 TestMapping("https://example.com/", "defaultproxy.com:443"); | |
| 370 } | |
| 371 | |
| 372 TEST_F(ProxyConfigServiceAndroidMappingTest, FallbackToSocks) { | |
| 373 // SOCKS proxy is used if scheme-specific one is not found. | |
| 374 configuration_["http.proxyHost"] = "defaultproxy.com"; | |
| 375 configuration_["socksProxyHost"] = "socksproxy.com"; | |
| 376 delegate_->SetProperties(configuration_); | |
| 377 TestMapping("ftp://example.com", "socksproxy.com:1080"); | |
| 378 TestMapping("http://example.com/", "defaultproxy.com:80"); | |
| 379 TestMapping("https://example.com/", "socksproxy.com:1080"); | |
| 380 } | |
| 381 | |
| 382 TEST_F(ProxyConfigServiceAndroidMappingTest, SocksExplicitPort) { | |
| 383 // SOCKS proxy port is used if specified | |
| 384 configuration_["socksProxyHost"] = "socksproxy.com"; | |
| 385 configuration_["socksProxyPort"] = "9000"; | |
| 386 delegate_->SetProperties(configuration_); | |
| 387 TestMapping("http://example.com/", "socksproxy.com:9000"); | |
| 388 } | |
| 389 | |
| 390 TEST_F(ProxyConfigServiceAndroidMappingTest, HttpProxySupercedesSocks) { | |
| 391 // SOCKS proxy is ignored if default HTTP proxy defined. | |
| 392 configuration_["proxyHost"] = "defaultproxy.com"; | |
| 393 configuration_["socksProxyHost"] = "socksproxy.com"; | |
| 394 configuration_["socksProxyPort"] = "9000"; | |
| 395 delegate_->SetProperties(configuration_); | |
| 396 TestMapping("http://example.com/", "defaultproxy.com:80"); | |
| 397 } | |
| 398 | |
| 399 } // namespace | |
| 400 | |
| 401 } // namespace net | |
| OLD | NEW |