Chromium Code Reviews| Index: net/proxy/proxy_config_service_android_unittest.cc |
| diff --git a/net/proxy/proxy_config_service_android_unittest.cc b/net/proxy/proxy_config_service_android_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..17383e4c20858e8761da8ef6b208be2acdaa71ef |
| --- /dev/null |
| +++ b/net/proxy/proxy_config_service_android_unittest.cc |
| @@ -0,0 +1,401 @@ |
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "base/bind.h" |
| +#include "base/synchronization/lock.h" |
| +#include "base/threading/thread.h" |
| +#include "net/proxy/proxy_config.h" |
| +#include "net/proxy/proxy_config_service_android.h" |
| +#include "net/proxy/proxy_info.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +#include <map> |
| +#include <string> |
| + |
| +namespace net { |
| + |
| +namespace { |
| + |
| +typedef std::map<std::string, std::string> StringMap; |
| + |
| +class TestDelegate : public ProxyConfigServiceAndroid::Delegate { |
| + public: |
| + TestDelegate(); |
| + |
| + // ProxyConfigServiceAndroid::Delegate: |
| + virtual void Start(ProxyConfigServiceAndroid* service) OVERRIDE; |
| + virtual void Stop() OVERRIDE; |
| + virtual std::string GetProperty(const std::string& property) OVERRIDE; |
| + |
| + // For testing: |
| + void SetProperties(const StringMap& properties); |
| + |
| + private: |
| + 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
|
| + StringMap properties_; |
| + ProxyConfigServiceAndroid* service_; |
| +}; |
| + |
| +TestDelegate::TestDelegate() |
| + : service_(NULL) { |
| +} |
|
Ryan Sleevi
2012/04/24 18:20:04
nit: One line
TestDelegate::TestDelegate() : serv
Philippe
2012/05/09 11:48:39
Done.
|
| + |
| +void TestDelegate::Start(ProxyConfigServiceAndroid* service) { |
| + service_ = service; |
| +} |
| + |
| +void TestDelegate::Stop() { |
|
Ryan Sleevi
2012/04/24 18:20:04
nit: one line
Philippe
2012/05/09 11:48:39
Done.
|
| +} |
| + |
| +std::string TestDelegate::GetProperty(const std::string& property) { |
| + base::AutoLock lock(lock_); |
| + StringMap::iterator it = properties_.find(property); |
| + if (it == properties_.end()) |
| + return ""; |
| + return it->second; |
| +} |
| + |
| +void TestDelegate::SetProperties(const StringMap& properties) { |
| + // Called from UI thread |
| + base::AutoLock lock(lock_); |
| + properties_ = properties; |
| + if (service_) { |
| + // Should not deadlock. Should schedule a task on the IO thread. |
| + service_->ProxySettingsChanged(); |
| + } |
| +} |
| + |
| +class TestObserver : public ProxyConfigService::Observer { |
| + public: |
| + // 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.
|
| + TestObserver(); |
| + |
| + // ProxyConfigService::Observer: |
| + virtual void OnProxyConfigChanged( |
| + const ProxyConfig& config, |
| + ProxyConfigService::ConfigAvailability availability) OVERRIDE; |
| + |
| + // Called on UI thread. |
| + ProxyConfigService::ConfigAvailability availability(); |
| + ProxyConfig& config(); |
| + |
| + private: |
| + void UpdateConfig(const ProxyConfig& config, |
| + ProxyConfigService::ConfigAvailability availability); |
| + |
| + // Accessed from UI thread. |
| + MessageLoop *ui_loop_; |
| + ProxyConfig config_; |
| + ProxyConfigService::ConfigAvailability availability_; |
| +}; |
| + |
| +TestObserver::TestObserver() |
| + : ui_loop_(MessageLoop::current()) { |
| +} |
| + |
| +void TestObserver::OnProxyConfigChanged( |
| + const ProxyConfig& config, |
| + ProxyConfigService::ConfigAvailability availability) { |
| + // Called from IO thread. |
| + ui_loop_->PostTask( |
| + FROM_HERE, |
| + base::Bind(&TestObserver::UpdateConfig, |
| + base::Unretained(this), config, availability)); |
| +} |
| + |
| +void TestObserver::UpdateConfig( |
| + const ProxyConfig& config, |
| + ProxyConfigService::ConfigAvailability availability) { |
| + DCHECK(MessageLoop::current() == ui_loop_); |
| + config_ = config; |
| + availability_ = availability; |
| + ui_loop_->Quit(); |
| +} |
| + |
| +ProxyConfigService::ConfigAvailability TestObserver::availability() { |
| + DCHECK(MessageLoop::current() == ui_loop_); |
| + return availability_; |
| +} |
| + |
| +ProxyConfig& TestObserver::config() { |
| + DCHECK(MessageLoop::current() == ui_loop_); |
| + return config_; |
| +} |
| + |
| +class TestIOThread : public base::Thread { |
| + public: |
| + TestIOThread(ProxyConfigServiceAndroid* service, |
| + ProxyConfigService::Observer* observer); |
| + // Thread |
| + virtual void Init() OVERRIDE; |
| + virtual void CleanUp() OVERRIDE; |
| + |
| + private: |
| + scoped_ptr<ProxyConfigServiceAndroid> service_; |
| + ProxyConfigService::Observer* observer_; |
| +}; |
| + |
| +TestIOThread::TestIOThread( |
| + ProxyConfigServiceAndroid* service, |
| + ProxyConfigService::Observer* observer) |
| + : base::Thread("io_thread"), |
| + service_(service), |
| + observer_(observer) { |
| +} |
| + |
| +void TestIOThread::Init() { |
| + service_->AddObserver(observer_); |
| +} |
| + |
| +void TestIOThread::CleanUp() { |
| + service_->RemoveObserver(observer_); |
| + service_.reset(); |
| +} |
| + |
| +TEST(ProxyConfigServiceAndroidTest, TestChangePropertiesNotification) { |
| + TestDelegate* delegate = new TestDelegate; |
| + ProxyConfigServiceAndroid *service = |
| + new ProxyConfigServiceAndroid(delegate); // service now owns delegate. |
| + TestObserver observer; |
| + TestIOThread io_thread(service, &observer); // io_thread owns service |
| + io_thread.Start(); |
| + |
| + // Set up a non-empty configuration |
| + StringMap properties; |
| + properties["http.proxyHost"] = "localhost"; |
| + delegate->SetProperties(properties); |
| + MessageLoop::current()->Run(); |
| + EXPECT_EQ(ProxyConfigService::CONFIG_VALID, observer.availability()); |
| + EXPECT_FALSE(observer.config().proxy_rules().empty()); |
| + |
| + // Set up an empty configuration |
| + delegate->SetProperties(StringMap()); |
| + MessageLoop::current()->Run(); |
| + EXPECT_EQ(ProxyConfigService::CONFIG_VALID, observer.availability()); |
| + EXPECT_TRUE(observer.config().proxy_rules().empty()); |
| + |
| + io_thread.Stop(); |
| +} |
| + |
| +class ProxyConfigServiceAndroidMappingTest : public testing::Test { |
| + protected: |
| + ProxyConfigServiceAndroidMappingTest(); |
| + |
| + // testing::Test |
| + virtual void SetUp() OVERRIDE; |
| + |
| + void TestMapping(const std::string& url, const std::string& expected); |
| + |
| + TestDelegate* delegate_; |
| + scoped_ptr<ProxyConfigServiceAndroid> service_; |
| + StringMap configuration_; |
| +}; |
| + |
| +ProxyConfigServiceAndroidMappingTest::ProxyConfigServiceAndroidMappingTest() |
| + : delegate_(new TestDelegate), |
| + service_(new ProxyConfigServiceAndroid(delegate_)) { |
| + // Note that service_ owns delegate_, and that we're just testing the mappings |
| + // here, so we don't need to set up an IO thread explicitly. |
| +} |
| + |
| +void ProxyConfigServiceAndroidMappingTest::SetUp() { |
| + configuration_.clear(); |
| +} |
| + |
| +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
|
| + BoundNetLog net_log; |
| + std::string result; |
| + while (!proxy_info.is_empty()) { |
| + if (!result.empty()) |
| + result += ";"; |
| + if (!proxy_info.is_direct()) |
| + result += proxy_info.proxy_server().host_port_pair().ToString(); |
| + proxy_info.Fallback(net_log); |
| + } |
| + return result; |
| +} |
| + |
| +void ProxyConfigServiceAndroidMappingTest::TestMapping( |
| + const std::string& url, |
| + const std::string& expected) { |
| + ProxyConfig config; |
| + EXPECT_EQ(ProxyConfigService::CONFIG_VALID, |
| + service_->GetLatestProxyConfig(&config)); |
| + ProxyInfo proxy_info; |
| + config.proxy_rules().Apply(GURL(url), &proxy_info); |
| + EXPECT_EQ(expected, ToString(proxy_info)); |
| +} |
| + |
| +// !! The following test cases are automatically generated from |
| +// !! net/android/tools/proxy_test_cases.py. |
| +// !! Please edit that file instead of editing the test cases below and |
| +// !! update also the corresponding Java unit tests in |
| +// !! AndroidProxySelectorTest.java |
| + |
| +TEST_F(ProxyConfigServiceAndroidMappingTest, NoProxy) { |
| + // Test direct mapping when no proxy defined. |
| + delegate_->SetProperties(configuration_); |
| + TestMapping("ftp://example.com/", ""); |
| + TestMapping("http://example.com/", ""); |
| + TestMapping("https://example.com/", ""); |
| +} |
| + |
| +TEST_F(ProxyConfigServiceAndroidMappingTest, HttpProxyHostAndPort) { |
| + // Test http.proxyHost and http.proxyPort works. |
| + configuration_["http.proxyHost"] = "httpproxy.com"; |
| + configuration_["http.proxyPort"] = "8080"; |
| + delegate_->SetProperties(configuration_); |
| + TestMapping("ftp://example.com/", ""); |
| + TestMapping("http://example.com/", "httpproxy.com:8080"); |
| + TestMapping("https://example.com/", ""); |
| +} |
| + |
| +TEST_F(ProxyConfigServiceAndroidMappingTest, HttpProxyHostOnly) { |
| + // We should get the default port (80) for proxied hosts. |
| + configuration_["http.proxyHost"] = "httpproxy.com"; |
| + delegate_->SetProperties(configuration_); |
| + TestMapping("ftp://example.com/", ""); |
| + TestMapping("http://example.com/", "httpproxy.com:80"); |
| + TestMapping("https://example.com/", ""); |
| +} |
| + |
| +TEST_F(ProxyConfigServiceAndroidMappingTest, HttpProxyPortOnly) { |
| + // http.proxyPort only should not result in any hosts being proxied. |
| + configuration_["http.proxyPort"] = "8080"; |
| + delegate_->SetProperties(configuration_); |
| + TestMapping("ftp://example.com/", ""); |
| + TestMapping("http://example.com/", ""); |
| + TestMapping("https://example.com/", ""); |
| +} |
| + |
| +TEST_F(ProxyConfigServiceAndroidMappingTest, HttpNonProxyHosts1) { |
| + // Test that HTTP non proxy hosts are mapped correctly |
| + configuration_["http.nonProxyHosts"] = "slashdot.org"; |
| + configuration_["http.proxyHost"] = "httpproxy.com"; |
| + configuration_["http.proxyPort"] = "8080"; |
| + delegate_->SetProperties(configuration_); |
| + TestMapping("http://example.com/", "httpproxy.com:8080"); |
| + TestMapping("http://slashdot.org/", ""); |
| +} |
| + |
| +TEST_F(ProxyConfigServiceAndroidMappingTest, HttpNonProxyHosts2) { |
| + // Test that | pattern works. |
| + configuration_["http.nonProxyHosts"] = "slashdot.org|freecode.net"; |
| + configuration_["http.proxyHost"] = "httpproxy.com"; |
| + configuration_["http.proxyPort"] = "8080"; |
| + delegate_->SetProperties(configuration_); |
| + TestMapping("http://example.com/", "httpproxy.com:8080"); |
| + TestMapping("http://freecode.net/", ""); |
| + TestMapping("http://slashdot.org/", ""); |
| +} |
| + |
| +TEST_F(ProxyConfigServiceAndroidMappingTest, HttpNonProxyHosts3) { |
| + // Test that * pattern works. |
| + configuration_["http.nonProxyHosts"] = "*example.com"; |
| + configuration_["http.proxyHost"] = "httpproxy.com"; |
| + configuration_["http.proxyPort"] = "8080"; |
| + delegate_->SetProperties(configuration_); |
| + TestMapping("http://example.com/", ""); |
| + TestMapping("http://slashdot.org/", "httpproxy.com:8080"); |
| + TestMapping("http://www.example.com/", ""); |
| +} |
| + |
| +TEST_F(ProxyConfigServiceAndroidMappingTest, FtpNonProxyHosts) { |
| + // Test that FTP non proxy hosts are mapped correctly |
| + configuration_["ftp.nonProxyHosts"] = "slashdot.org"; |
| + configuration_["ftp.proxyHost"] = "httpproxy.com"; |
| + configuration_["ftp.proxyPort"] = "8080"; |
| + delegate_->SetProperties(configuration_); |
| + TestMapping("ftp://example.com/", "httpproxy.com:8080"); |
| + TestMapping("http://example.com/", ""); |
| +} |
| + |
| +TEST_F(ProxyConfigServiceAndroidMappingTest, FtpProxyHostAndPort) { |
| + // Test ftp.proxyHost and ftp.proxyPort works. |
| + configuration_["ftp.proxyHost"] = "httpproxy.com"; |
| + configuration_["ftp.proxyPort"] = "8080"; |
| + delegate_->SetProperties(configuration_); |
| + TestMapping("ftp://example.com/", "httpproxy.com:8080"); |
| + TestMapping("http://example.com/", ""); |
| + TestMapping("https://example.com/", ""); |
| +} |
| + |
| +TEST_F(ProxyConfigServiceAndroidMappingTest, FtpProxyHostOnly) { |
| + // Test ftp.proxyHost and default port. |
| + configuration_["ftp.proxyHost"] = "httpproxy.com"; |
| + delegate_->SetProperties(configuration_); |
| + TestMapping("ftp://example.com/", "httpproxy.com:80"); |
| + TestMapping("http://example.com/", ""); |
| + TestMapping("https://example.com/", ""); |
| +} |
| + |
| +TEST_F(ProxyConfigServiceAndroidMappingTest, HttpsProxyHostAndPort) { |
| + // Test https.proxyHost and https.proxyPort works. |
| + configuration_["https.proxyHost"] = "httpproxy.com"; |
| + configuration_["https.proxyPort"] = "8080"; |
| + delegate_->SetProperties(configuration_); |
| + TestMapping("ftp://example.com/", ""); |
| + TestMapping("http://example.com/", ""); |
| + TestMapping("https://example.com/", "httpproxy.com:8080"); |
| +} |
| + |
| +TEST_F(ProxyConfigServiceAndroidMappingTest, HttpsProxyHostOnly) { |
| + // Test https.proxyHost and default port. |
| + configuration_["https.proxyHost"] = "httpproxy.com"; |
| + delegate_->SetProperties(configuration_); |
| + TestMapping("ftp://example.com/", ""); |
| + TestMapping("http://example.com/", ""); |
| + TestMapping("https://example.com/", "httpproxy.com:443"); |
| +} |
| + |
| +TEST_F(ProxyConfigServiceAndroidMappingTest, DefaultProxyExplictPort) { |
| + // Default http proxy is used if a scheme-specific one is not found. |
| + configuration_["ftp.proxyHost"] = "httpproxy.com"; |
| + configuration_["ftp.proxyPort"] = "8080"; |
| + configuration_["proxyHost"] = "defaultproxy.com"; |
| + configuration_["proxyPort"] = "8080"; |
| + delegate_->SetProperties(configuration_); |
| + TestMapping("ftp://example.com/", "httpproxy.com:8080"); |
| + TestMapping("http://example.com/", "defaultproxy.com:8080"); |
| + TestMapping("https://example.com/", "defaultproxy.com:8080"); |
| +} |
| + |
| +TEST_F(ProxyConfigServiceAndroidMappingTest, DefaultProxyDefaultPort) { |
| + // Check that the default proxy port is as expected. |
| + configuration_["proxyHost"] = "defaultproxy.com"; |
| + delegate_->SetProperties(configuration_); |
| + TestMapping("http://example.com/", "defaultproxy.com:80"); |
| + TestMapping("https://example.com/", "defaultproxy.com:443"); |
| +} |
| + |
| +TEST_F(ProxyConfigServiceAndroidMappingTest, FallbackToSocks) { |
| + // SOCKS proxy is used if scheme-specific one is not found. |
| + configuration_["http.proxyHost"] = "defaultproxy.com"; |
| + configuration_["socksProxyHost"] = "socksproxy.com"; |
| + delegate_->SetProperties(configuration_); |
| + TestMapping("ftp://example.com", "socksproxy.com:1080"); |
| + TestMapping("http://example.com/", "defaultproxy.com:80"); |
| + TestMapping("https://example.com/", "socksproxy.com:1080"); |
| +} |
| + |
| +TEST_F(ProxyConfigServiceAndroidMappingTest, SocksExplicitPort) { |
| + // SOCKS proxy port is used if specified |
| + configuration_["socksProxyHost"] = "socksproxy.com"; |
| + configuration_["socksProxyPort"] = "9000"; |
| + delegate_->SetProperties(configuration_); |
| + TestMapping("http://example.com/", "socksproxy.com:9000"); |
| +} |
| + |
| +TEST_F(ProxyConfigServiceAndroidMappingTest, HttpProxySupercedesSocks) { |
| + // SOCKS proxy is ignored if default HTTP proxy defined. |
| + configuration_["proxyHost"] = "defaultproxy.com"; |
| + configuration_["socksProxyHost"] = "socksproxy.com"; |
| + configuration_["socksProxyPort"] = "9000"; |
| + delegate_->SetProperties(configuration_); |
| + TestMapping("http://example.com/", "defaultproxy.com:80"); |
| +} |
| + |
| +} // namespace |
| + |
| +} // namespace net |