diff options
author | hamaji@chromium.org <hamaji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-06 12:11:05 +0000 |
---|---|---|
committer | hamaji@chromium.org <hamaji@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-06 12:11:05 +0000 |
commit | a692c6f3a59e711bc38fc72fce3c938deec64da0 (patch) | |
tree | 0583e80059992b55252390a7891e1651ba1c2ab3 /chrome/browser/net | |
parent | 4bd778d6cd4e108a38caeda9b283f01691fe7ecf (diff) | |
download | chromium_src-a692c6f3a59e711bc38fc72fce3c938deec64da0.zip chromium_src-a692c6f3a59e711bc38fc72fce3c938deec64da0.tar.gz chromium_src-a692c6f3a59e711bc38fc72fce3c938deec64da0.tar.bz2 |
Reverting r22591. It seems to be making purify fail.
r22590: http://build.chromium.org/buildbot/waterfall/builders/XP%20Unit%20(purify)/builds/5026
r22591: http://build.chromium.org/buildbot/waterfall/builders/XP%20Unit%20(purify)/builds/5030
TEST=none
BUG=none
TBR=eroman
Review URL: http://codereview.chromium.org/165048
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@22603 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/net')
-rw-r--r-- | chrome/browser/net/resolve_proxy_msg_helper_unittest.cc | 408 |
1 files changed, 278 insertions, 130 deletions
diff --git a/chrome/browser/net/resolve_proxy_msg_helper_unittest.cc b/chrome/browser/net/resolve_proxy_msg_helper_unittest.cc index b9974ca..ef016d3 100644 --- a/chrome/browser/net/resolve_proxy_msg_helper_unittest.cc +++ b/chrome/browser/net/resolve_proxy_msg_helper_unittest.cc @@ -6,12 +6,13 @@ #include "base/waitable_event.h" #include "net/base/net_errors.h" -#include "net/proxy/mock_proxy_resolver.h" #include "net/proxy/proxy_config_service.h" +#include "net/proxy/proxy_resolver.h" +#include "net/proxy/single_threaded_proxy_resolver.h" #include "testing/gtest/include/gtest/gtest.h" // This ProxyConfigService always returns "http://pac" as the PAC url to use. -class MockProxyConfigService : public net::ProxyConfigService { +class MockProxyConfigService: public net::ProxyConfigService { public: virtual int GetProxyConfig(net::ProxyConfig* results) { results->pac_url = GURL("http://pac"); @@ -19,45 +20,232 @@ class MockProxyConfigService : public net::ProxyConfigService { } }; -class MyDelegate : public ResolveProxyMsgHelper::Delegate { +// This PAC resolver always returns the hostname of the query URL as the +// proxy to use. The Block() method will make GetProxyForURL() hang until +// Unblock() is called. +class SyncMockProxyResolver : public net::ProxyResolver { public: - struct PendingResult { - PendingResult(IPC::Message* msg, - int error_code, - const std::string& proxy_list) - : msg(msg), error_code(error_code), proxy_list(proxy_list) { - } - - IPC::Message* msg; - int error_code; - std::string proxy_list; - }; - - // ResolveProxyMsgHelper::Delegate implementation: + SyncMockProxyResolver() : ProxyResolver(false /*expects_pac_bytes*/), + event_(false, false), + is_blocked_(false) { + } + + virtual int GetProxyForURL(const GURL& query_url, + net::ProxyInfo* results, + net::CompletionCallback* callback, + RequestHandle* request) { + if (is_blocked_) + event_.Wait(); + results->UseNamedProxy(query_url.host()); + return net::OK; + } + + virtual void CancelRequest(RequestHandle request) { + NOTREACHED(); + } + + virtual int SetPacScript(const GURL& /*pac_url*/, + const std::string& /*bytes*/, + net::CompletionCallback* /*callback*/) { + return net::OK; + } + + void Block() { + is_blocked_ = true; + event_.Reset(); + } + + void Unblock() { + is_blocked_ = false; + event_.Signal(); + } + + private: + base::WaitableEvent event_; + bool is_blocked_; +}; + +class MockProxyResolver : public net::SingleThreadedProxyResolver { + public: + MockProxyResolver() + : net::SingleThreadedProxyResolver(new SyncMockProxyResolver) { + x = reinterpret_cast<SyncMockProxyResolver*>(resolver()); + } + + // TODO(eroman): cleanup. + SyncMockProxyResolver* x; +}; + +// This struct holds the values that were passed to +// Delegate::OnResolveProxyCompleted(). The caller should use WaitUntilDone() +// to block until the result has been populated. +struct ResultFuture { + public: + ResultFuture() + : reply_msg(NULL), + error_code(0), + started_(false, false), + completed_(false, false) { + } + + // Wait until the request has completed. In other words we have invoked: + // ResolveProxyMsgHelper::Delegate::OnResolveProxyCompleted. + void WaitUntilDone() { + completed_.Wait(); + } + + // Wait until the request has been sent to ResolveProxyMsgHelper. + void WaitUntilStarted() { + started_.Wait(); + } + + bool TimedWaitUntilDone(const base::TimeDelta& max_time) { + return completed_.TimedWait(max_time); + } + + // These fields are only valid after returning from WaitUntilDone(). + IPC::Message* reply_msg; + int error_code; + std::string proxy_list; + + private: + friend class AsyncRequestRunner; + base::WaitableEvent started_; + base::WaitableEvent completed_; +}; + +// This class lives on the io thread. It starts async requests using the +// class under test (ResolveProxyMsgHelper), and signals the result future on +// completion. +class AsyncRequestRunner : public ResolveProxyMsgHelper::Delegate { + public: + AsyncRequestRunner(net::ProxyService* proxy_service) { + resolve_proxy_msg_helper_.reset( + new ResolveProxyMsgHelper(this, proxy_service)); + } + + void Start(ResultFuture* future, const GURL& url, IPC::Message* reply_msg) { + futures_.push_back(future); + resolve_proxy_msg_helper_->Start(url, reply_msg); + + // Notify of request start. + future->started_.Signal(); + } + virtual void OnResolveProxyCompleted(IPC::Message* reply_msg, int error_code, const std::string& proxy_list) { - DCHECK(!pending_result_.get()); - pending_result_.reset(new PendingResult(reply_msg, error_code, proxy_list)); + // Update the result future for this request (top of queue), and signal it. + ResultFuture* future = futures_.front(); + futures_.pop_front(); + + future->reply_msg = reply_msg; + future->error_code = error_code; + future->proxy_list = proxy_list; + + // Notify of request completion. + future->completed_.Signal(); + } + + private: + std::deque<ResultFuture*> futures_; + scoped_ptr<ResolveProxyMsgHelper> resolve_proxy_msg_helper_; +}; + +// Helper class to start async requests on an io thread, and return a +// result future. The caller then uses ResultFuture::WaitUntilDone() to +// get at the results. It "bridges" the originating thread with the helper +// io thread. +class RunnerBridge { + public: + RunnerBridge() : io_thread_("io_thread"), done_(false, false) { + // Start an io thread where we will run the async requests. + base::Thread::Options options; + options.message_loop_type = MessageLoop::TYPE_IO; + io_thread_.StartWithOptions(options); + + // Construct the state that lives on io thread. + io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &RunnerBridge::DoConstruct)); + done_.Wait(); } - const PendingResult* pending_result() const { return pending_result_.get(); } + // Start an async request on the io thread. + ResultFuture* Start(const GURL& url, IPC::Message* reply_msg) { + ResultFuture* future = new ResultFuture(); - void clear_pending_result() { - pending_result_.reset(); + io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + async_runner_, &AsyncRequestRunner::Start, future, url, reply_msg)); + + return future; + } + + void DestroyAsyncRunner() { + io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &RunnerBridge::DoDestroyAsyncRunner)); + done_.Wait(); + } + + ~RunnerBridge() { + io_thread_.message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &RunnerBridge::DoDestroy)); + done_.Wait(); + } + + MockProxyResolver* proxy_resolver() { + return proxy_resolver_; + } + + // Called from io thread. + void DoConstruct() { + proxy_resolver_ = new MockProxyResolver(); + proxy_service_ = new net::ProxyService(new MockProxyConfigService(), + proxy_resolver_); + async_runner_ = new AsyncRequestRunner(proxy_service_); + done_.Signal(); + } + + // Called from io thread. + void DoDestroy() { + delete async_runner_; + delete proxy_service_; + done_.Signal(); + } + + // Called from io thread. + void DoDestroyAsyncRunner() { + delete async_runner_; + async_runner_ = NULL; + done_.Signal(); } private: - scoped_ptr<PendingResult> pending_result_; + base::Thread io_thread_; + base::WaitableEvent done_; + + net::ProxyService* proxy_service_; + MockProxyResolver* proxy_resolver_; // Owned by proxy_service_. + + AsyncRequestRunner* async_runner_; }; +// Avoid the need to have an AddRef / Release +template<> +void RunnableMethodTraits<RunnerBridge>::RetainCallee(RunnerBridge*) {} +template<> +void RunnableMethodTraits<RunnerBridge>::ReleaseCallee(RunnerBridge*) {} + +template<> +void RunnableMethodTraits<AsyncRequestRunner>::RetainCallee( + AsyncRequestRunner*) {} +template<> +void RunnableMethodTraits<AsyncRequestRunner>::ReleaseCallee( + AsyncRequestRunner*) {} + + // Issue three sequential requests -- each should succeed. TEST(ResolveProxyMsgHelperTest, Sequential) { - net::MockAsyncProxyResolver* resolver = new net::MockAsyncProxyResolver; - net::ProxyService service(new MockProxyConfigService, resolver); - - MyDelegate delegate; - ResolveProxyMsgHelper helper(&delegate, &service); + RunnerBridge runner; GURL url1("http://www.google1.com/"); GURL url2("http://www.google2.com/"); @@ -70,56 +258,33 @@ TEST(ResolveProxyMsgHelperTest, Sequential) { // Execute each request sequentially (so there are never 2 requests // outstanding at the same time). - helper.Start(url1, msg1.get()); - - // Finish ProxyService's initialization. - resolver->pending_set_pac_script_request()->CompleteNow(net::OK); + scoped_ptr<ResultFuture> result1(runner.Start(url1, msg1.get())); + result1->WaitUntilDone(); - ASSERT_EQ(1u, resolver->pending_requests().size()); - EXPECT_EQ(url1, resolver->pending_requests()[0]->url()); - resolver->pending_requests()[0]->results()->UseNamedProxy("result1:80"); - resolver->pending_requests()[0]->CompleteNow(net::OK); + scoped_ptr<ResultFuture> result2(runner.Start(url2, msg2.get())); + result2->WaitUntilDone(); - // Check result. - EXPECT_EQ(msg1.get(), delegate.pending_result()->msg); - EXPECT_EQ(net::OK, delegate.pending_result()->error_code); - EXPECT_EQ("PROXY result1:80", delegate.pending_result()->proxy_list); - delegate.clear_pending_result(); + scoped_ptr<ResultFuture> result3(runner.Start(url3, msg3.get())); + result3->WaitUntilDone(); - helper.Start(url2, msg2.get()); + // Check that each request gave the expected result. - ASSERT_EQ(1u, resolver->pending_requests().size()); - EXPECT_EQ(url2, resolver->pending_requests()[0]->url()); - resolver->pending_requests()[0]->results()->UseNamedProxy("result2:80"); - resolver->pending_requests()[0]->CompleteNow(net::OK); + EXPECT_EQ(msg1.get(), result1->reply_msg); + EXPECT_EQ(net::OK, result1->error_code); + EXPECT_EQ("PROXY www.google1.com:80", result1->proxy_list); - // Check result. - EXPECT_EQ(msg2.get(), delegate.pending_result()->msg); - EXPECT_EQ(net::OK, delegate.pending_result()->error_code); - EXPECT_EQ("PROXY result2:80", delegate.pending_result()->proxy_list); - delegate.clear_pending_result(); + EXPECT_EQ(msg2.get(), result2->reply_msg); + EXPECT_EQ(net::OK, result2->error_code); + EXPECT_EQ("PROXY www.google2.com:80", result2->proxy_list); - helper.Start(url3, msg3.get()); - - ASSERT_EQ(1u, resolver->pending_requests().size()); - EXPECT_EQ(url3, resolver->pending_requests()[0]->url()); - resolver->pending_requests()[0]->results()->UseNamedProxy("result3:80"); - resolver->pending_requests()[0]->CompleteNow(net::OK); - - // Check result. - EXPECT_EQ(msg3.get(), delegate.pending_result()->msg); - EXPECT_EQ(net::OK, delegate.pending_result()->error_code); - EXPECT_EQ("PROXY result3:80", delegate.pending_result()->proxy_list); - delegate.clear_pending_result(); + EXPECT_EQ(msg3.get(), result3->reply_msg); + EXPECT_EQ(net::OK, result3->error_code); + EXPECT_EQ("PROXY www.google3.com:80", result3->proxy_list); } // Issue a request while one is already in progress -- should be queued. TEST(ResolveProxyMsgHelperTest, QueueRequests) { - net::MockAsyncProxyResolver* resolver = new net::MockAsyncProxyResolver; - net::ProxyService service(new MockProxyConfigService, resolver); - - MyDelegate delegate; - ResolveProxyMsgHelper helper(&delegate, &service); + RunnerBridge runner; GURL url1("http://www.google1.com/"); GURL url2("http://www.google2.com/"); @@ -129,64 +294,44 @@ TEST(ResolveProxyMsgHelperTest, QueueRequests) { scoped_ptr<IPC::Message> msg2(new IPC::Message()); scoped_ptr<IPC::Message> msg3(new IPC::Message()); - // Start three requests. Since the proxy resolver is async, all the - // requests will be pending. - - helper.Start(url1, msg1.get()); - - // Finish ProxyService's initialization. - resolver->pending_set_pac_script_request()->CompleteNow(net::OK); + // Make the proxy resolver hang on the next request. + runner.proxy_resolver()->x->Block(); - helper.Start(url2, msg2.get()); - helper.Start(url3, msg3.get()); + // Start three requests. Since the proxy resolver is hung, the second two + // will be pending. - // ResolveProxyHelper only keeps 1 request outstanding in ProxyService - // at a time. - ASSERT_EQ(1u, resolver->pending_requests().size()); - EXPECT_EQ(url1, resolver->pending_requests()[0]->url()); + scoped_ptr<ResultFuture> result1(runner.Start(url1, msg1.get())); + scoped_ptr<ResultFuture> result2(runner.Start(url2, msg2.get())); + scoped_ptr<ResultFuture> result3(runner.Start(url3, msg3.get())); - resolver->pending_requests()[0]->results()->UseNamedProxy("result1:80"); - resolver->pending_requests()[0]->CompleteNow(net::OK); + // Wait for the final request to have been scheduled. Otherwise we may rush + // to calling Unblock() without actually having blocked anything. + result3->WaitUntilStarted(); - // Check result. - EXPECT_EQ(msg1.get(), delegate.pending_result()->msg); - EXPECT_EQ(net::OK, delegate.pending_result()->error_code); - EXPECT_EQ("PROXY result1:80", delegate.pending_result()->proxy_list); - delegate.clear_pending_result(); + // Unblock the proxy service so requests 1-3 can complete. + runner.proxy_resolver()->x->Unblock(); - ASSERT_EQ(1u, resolver->pending_requests().size()); - EXPECT_EQ(url2, resolver->pending_requests()[0]->url()); + // Wait for all the requests to finish (they run in FIFO order). + result3->WaitUntilDone(); - resolver->pending_requests()[0]->results()->UseNamedProxy("result2:80"); - resolver->pending_requests()[0]->CompleteNow(net::OK); + // Check that each call invoked the callback with the right parameters. - // Check result. - EXPECT_EQ(msg2.get(), delegate.pending_result()->msg); - EXPECT_EQ(net::OK, delegate.pending_result()->error_code); - EXPECT_EQ("PROXY result2:80", delegate.pending_result()->proxy_list); - delegate.clear_pending_result(); + EXPECT_EQ(msg1.get(), result1->reply_msg); + EXPECT_EQ(net::OK, result1->error_code); + EXPECT_EQ("PROXY www.google1.com:80", result1->proxy_list); - ASSERT_EQ(1u, resolver->pending_requests().size()); - EXPECT_EQ(url3, resolver->pending_requests()[0]->url()); + EXPECT_EQ(msg2.get(), result2->reply_msg); + EXPECT_EQ(net::OK, result2->error_code); + EXPECT_EQ("PROXY www.google2.com:80", result2->proxy_list); - resolver->pending_requests()[0]->results()->UseNamedProxy("result3:80"); - resolver->pending_requests()[0]->CompleteNow(net::OK); - - // Check result. - EXPECT_EQ(msg3.get(), delegate.pending_result()->msg); - EXPECT_EQ(net::OK, delegate.pending_result()->error_code); - EXPECT_EQ("PROXY result3:80", delegate.pending_result()->proxy_list); - delegate.clear_pending_result(); + EXPECT_EQ(msg3.get(), result3->reply_msg); + EXPECT_EQ(net::OK, result3->error_code); + EXPECT_EQ("PROXY www.google3.com:80", result3->proxy_list); } // Delete the helper while a request is in progress, and others are pending. TEST(ResolveProxyMsgHelperTest, CancelPendingRequests) { - net::MockAsyncProxyResolver* resolver = new net::MockAsyncProxyResolver; - net::ProxyService service(new MockProxyConfigService, resolver); - - MyDelegate delegate; - scoped_ptr<ResolveProxyMsgHelper> helper( - new ResolveProxyMsgHelper(&delegate, &service)); + RunnerBridge runner; GURL url1("http://www.google1.com/"); GURL url2("http://www.google2.com/"); @@ -198,32 +343,35 @@ TEST(ResolveProxyMsgHelperTest, CancelPendingRequests) { IPC::Message* msg2 = new IPC::Message(); IPC::Message* msg3 = new IPC::Message(); - // Start three requests. Since the proxy resolver is async, all the - // requests will be pending. + // Make the next request block. + runner.proxy_resolver()->x->Block(); - helper->Start(url1, msg1); + // Start three requests; since the first one blocked, the other two should + // be pending. - // Finish ProxyService's initialization. - resolver->pending_set_pac_script_request()->CompleteNow(net::OK); + scoped_ptr<ResultFuture> result1(runner.Start(url1, msg1)); + scoped_ptr<ResultFuture> result2(runner.Start(url2, msg2)); + scoped_ptr<ResultFuture> result3(runner.Start(url3, msg3)); - helper->Start(url2, msg2); - helper->Start(url3, msg3); - - // ResolveProxyHelper only keeps 1 request outstanding in ProxyService - // at a time. - ASSERT_EQ(1u, resolver->pending_requests().size()); - EXPECT_EQ(url1, resolver->pending_requests()[0]->url()); + result3->WaitUntilStarted(); // Delete the underlying ResolveProxyMsgHelper -- this should cancel all // the requests which are outstanding. - helper.reset(); - - // The pending requests sent to the proxy resolver should have been cancelled. + runner.DestroyAsyncRunner(); - EXPECT_EQ(0u, resolver->pending_requests().size()); + // Unblocking the proxy resolver means the three requests can complete -- + // however they should not try to notify the delegate since we have already + // deleted the helper. + runner.proxy_resolver()->x->Unblock(); - EXPECT_EQ(NULL, delegate.pending_result()); + // Check that none of the requests were sent to the delegate. + EXPECT_FALSE( + result1->TimedWaitUntilDone(base::TimeDelta::FromMilliseconds(2))); + EXPECT_FALSE( + result2->TimedWaitUntilDone(base::TimeDelta::FromMilliseconds(2))); + EXPECT_FALSE( + result3->TimedWaitUntilDone(base::TimeDelta::FromMilliseconds(2))); // It should also be the case that msg1, msg2, msg3 were deleted by the - // cancellation. (Else will show up as a leak in Purify/Valgrind). + // cancellation. (Else will show up as a leak in Purify). } |