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/net/connection_tester.h" 6 7 #include "base/prefs/testing_pref_service.h" 8 #include "content/public/test/test_browser_thread.h" 9 #include "net/cert/mock_cert_verifier.h" 10 #include "net/cookies/cookie_monster.h" 11 #include "net/dns/mock_host_resolver.h" 12 #include "net/ftp/ftp_network_layer.h" 13 #include "net/http/http_auth_handler_factory.h" 14 #include "net/http/http_network_layer.h" 15 #include "net/http/http_network_session.h" 16 #include "net/http/http_server_properties_impl.h" 17 #include "net/http/transport_security_state.h" 18 #include "net/proxy/proxy_config_service_fixed.h" 19 #include "net/proxy/proxy_service.h" 20 #include "net/ssl/ssl_config_service_defaults.h" 21 #include "net/test/spawned_test_server/spawned_test_server.h" 22 #include "net/url_request/url_request_context.h" 23 #include "testing/gtest/include/gtest/gtest.h" 24 #include "testing/platform_test.h" 25 26 using content::BrowserThread; 27 28 namespace { 29 30 // This is a testing delegate which simply counts how many times each of 31 // the delegate's methods were invoked. 32 class ConnectionTesterDelegate : public ConnectionTester::Delegate { 33 public: 34 ConnectionTesterDelegate() 35 : start_connection_test_suite_count_(0), 36 start_connection_test_experiment_count_(0), 37 completed_connection_test_experiment_count_(0), 38 completed_connection_test_suite_count_(0) { 39 } 40 41 virtual void OnStartConnectionTestSuite() OVERRIDE { 42 start_connection_test_suite_count_++; 43 } 44 45 virtual void OnStartConnectionTestExperiment( 46 const ConnectionTester::Experiment& experiment) OVERRIDE { 47 start_connection_test_experiment_count_++; 48 } 49 50 virtual void OnCompletedConnectionTestExperiment( 51 const ConnectionTester::Experiment& experiment, 52 int result) OVERRIDE { 53 completed_connection_test_experiment_count_++; 54 } 55 56 virtual void OnCompletedConnectionTestSuite() OVERRIDE { 57 completed_connection_test_suite_count_++; 58 base::MessageLoop::current()->Quit(); 59 } 60 61 int start_connection_test_suite_count() const { 62 return start_connection_test_suite_count_; 63 } 64 65 int start_connection_test_experiment_count() const { 66 return start_connection_test_experiment_count_; 67 } 68 69 int completed_connection_test_experiment_count() const { 70 return completed_connection_test_experiment_count_; 71 } 72 73 int completed_connection_test_suite_count() const { 74 return completed_connection_test_suite_count_; 75 } 76 77 private: 78 int start_connection_test_suite_count_; 79 int start_connection_test_experiment_count_; 80 int completed_connection_test_experiment_count_; 81 int completed_connection_test_suite_count_; 82 }; 83 84 // The test fixture is responsible for: 85 // - Making sure each test has an IO loop running 86 // - Catching any host resolve requests and mapping them to localhost 87 // (so the test doesn't use any external network dependencies). 88 class ConnectionTesterTest : public PlatformTest { 89 public: 90 ConnectionTesterTest() 91 : message_loop_(base::MessageLoop::TYPE_IO), 92 io_thread_(BrowserThread::IO, &message_loop_), 93 test_server_(net::SpawnedTestServer::TYPE_HTTP, 94 net::SpawnedTestServer::kLocalhost, 95 // Nothing is read in this directory. 96 base::FilePath(FILE_PATH_LITERAL("chrome"))), 97 proxy_script_fetcher_context_(new net::URLRequestContext) { 98 InitializeRequestContext(); 99 } 100 101 protected: 102 // Destroy last the MessageLoop last to give a chance for objects like 103 // ObserverListThreadSave to shut down properly. For example, 104 // SSLClientAuthCache calls RemoveObserver when destroyed, but if the 105 // MessageLoop is already destroyed, then the RemoveObserver will be a 106 // no-op, and the ObserverList will contain invalid entries. 107 base::MessageLoop message_loop_; 108 content::TestBrowserThread io_thread_; 109 net::SpawnedTestServer test_server_; 110 ConnectionTesterDelegate test_delegate_; 111 net::MockHostResolver host_resolver_; 112 scoped_ptr<net::CertVerifier> cert_verifier_; 113 scoped_ptr<net::TransportSecurityState> transport_security_state_; 114 scoped_ptr<net::ProxyService> proxy_service_; 115 scoped_refptr<net::SSLConfigService> ssl_config_service_; 116 scoped_ptr<net::HttpTransactionFactory> http_transaction_factory_; 117 net::HttpAuthHandlerRegistryFactory http_auth_handler_factory_; 118 net::HttpServerPropertiesImpl http_server_properties_impl_; 119 scoped_ptr<net::URLRequestContext> proxy_script_fetcher_context_; 120 121 private: 122 void InitializeRequestContext() { 123 proxy_script_fetcher_context_->set_host_resolver(&host_resolver_); 124 cert_verifier_.reset(new net::MockCertVerifier); 125 transport_security_state_.reset(new net::TransportSecurityState); 126 proxy_script_fetcher_context_->set_cert_verifier(cert_verifier_.get()); 127 proxy_script_fetcher_context_->set_transport_security_state( 128 transport_security_state_.get()); 129 proxy_script_fetcher_context_->set_http_auth_handler_factory( 130 &http_auth_handler_factory_); 131 proxy_service_.reset(net::ProxyService::CreateDirect()); 132 proxy_script_fetcher_context_->set_proxy_service(proxy_service_.get()); 133 ssl_config_service_ = new net::SSLConfigServiceDefaults; 134 net::HttpNetworkSession::Params session_params; 135 session_params.host_resolver = &host_resolver_; 136 session_params.cert_verifier = cert_verifier_.get(); 137 session_params.transport_security_state = transport_security_state_.get(); 138 session_params.http_auth_handler_factory = &http_auth_handler_factory_; 139 session_params.ssl_config_service = ssl_config_service_.get(); 140 session_params.proxy_service = proxy_service_.get(); 141 session_params.http_server_properties = 142 http_server_properties_impl_.GetWeakPtr(); 143 scoped_refptr<net::HttpNetworkSession> network_session( 144 new net::HttpNetworkSession(session_params)); 145 http_transaction_factory_.reset( 146 new net::HttpNetworkLayer(network_session.get())); 147 proxy_script_fetcher_context_->set_http_transaction_factory( 148 http_transaction_factory_.get()); 149 // In-memory cookie store. 150 proxy_script_fetcher_context_->set_cookie_store( 151 new net::CookieMonster(NULL, NULL)); 152 } 153 }; 154 155 TEST_F(ConnectionTesterTest, RunAllTests) { 156 ASSERT_TRUE(test_server_.Start()); 157 158 ConnectionTester tester(&test_delegate_, 159 proxy_script_fetcher_context_.get(), 160 NULL); 161 162 // Start the test suite on URL "echoall". 163 // TODO(eroman): Is this URL right? 164 tester.RunAllTests(test_server_.GetURL("echoall")); 165 166 // Wait for all the tests to complete. 167 base::MessageLoop::current()->Run(); 168 169 const int kNumExperiments = 170 ConnectionTester::PROXY_EXPERIMENT_COUNT * 171 ConnectionTester::HOST_RESOLVER_EXPERIMENT_COUNT; 172 173 EXPECT_EQ(1, test_delegate_.start_connection_test_suite_count()); 174 EXPECT_EQ(kNumExperiments, 175 test_delegate_.start_connection_test_experiment_count()); 176 EXPECT_EQ(kNumExperiments, 177 test_delegate_.completed_connection_test_experiment_count()); 178 EXPECT_EQ(1, test_delegate_.completed_connection_test_suite_count()); 179 } 180 181 TEST_F(ConnectionTesterTest, DeleteWhileInProgress) { 182 ASSERT_TRUE(test_server_.Start()); 183 184 scoped_ptr<ConnectionTester> tester( 185 new ConnectionTester(&test_delegate_, 186 proxy_script_fetcher_context_.get(), 187 NULL)); 188 189 // Start the test suite on URL "echoall". 190 // TODO(eroman): Is this URL right? 191 tester->RunAllTests(test_server_.GetURL("echoall")); 192 193 // Don't run the message loop at all. Otherwise the experiment's request may 194 // complete and post a task to run the next experiment before we quit the 195 // message loop. 196 197 EXPECT_EQ(1, test_delegate_.start_connection_test_suite_count()); 198 EXPECT_EQ(1, test_delegate_.start_connection_test_experiment_count()); 199 EXPECT_EQ(0, test_delegate_.completed_connection_test_experiment_count()); 200 EXPECT_EQ(0, test_delegate_.completed_connection_test_suite_count()); 201 202 // Delete the ConnectionTester while it is in progress. 203 tester.reset(); 204 205 // Drain the tasks on the message loop. 206 // 207 // Note that we cannot simply stop the message loop, since that will delete 208 // any pending tasks instead of running them. This causes a problem with 209 // net::ClientSocketPoolBaseHelper, since the "Group" holds a pointer 210 // |backup_task| that it will try to deref during the destructor, but 211 // depending on the order that pending tasks were deleted in, it might 212 // already be invalid! See http://crbug.com/43291. 213 base::MessageLoop::current()->PostTask(FROM_HERE, 214 base::MessageLoop::QuitClosure()); 215 base::MessageLoop::current()->Run(); 216 } 217 218 } // namespace 219