Index: chrome/browser/net/resolve_proxy_msg_helper_unittest.cc |
=================================================================== |
--- chrome/browser/net/resolve_proxy_msg_helper_unittest.cc (revision 22580) |
+++ chrome/browser/net/resolve_proxy_msg_helper_unittest.cc (working copy) |
@@ -6,13 +6,12 @@ |
#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"); |
@@ -20,233 +19,46 @@ |
} |
}; |
-// 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 { |
+class MyDelegate : public ResolveProxyMsgHelper::Delegate { |
public: |
- SyncMockProxyResolver() : ProxyResolver(false /*expects_pac_bytes*/), |
- event_(false, false), |
- is_blocked_(false) { |
- } |
+ struct PendingResult { |
+ PendingResult(IPC::Message* msg, |
+ int error_code, |
+ const std::string& proxy_list) |
+ : msg(msg), error_code(error_code), proxy_list(proxy_list) { |
+ } |
- 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; |
- } |
+ IPC::Message* msg; |
+ int error_code; |
+ std::string proxy_list; |
+ }; |
- 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(); |
- } |
- |
+ // ResolveProxyMsgHelper::Delegate implementation: |
virtual void OnResolveProxyCompleted(IPC::Message* reply_msg, |
int error_code, |
const std::string& 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(); |
+ DCHECK(!pending_result_.get()); |
+ pending_result_.reset(new PendingResult(reply_msg, error_code, proxy_list)); |
} |
- private: |
- std::deque<ResultFuture*> futures_; |
- scoped_ptr<ResolveProxyMsgHelper> resolve_proxy_msg_helper_; |
-}; |
+ const PendingResult* pending_result() const { return pending_result_.get(); } |
-// 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(); |
+ void clear_pending_result() { |
+ pending_result_.reset(); |
} |
- // Start an async request on the io thread. |
- ResultFuture* Start(const GURL& url, IPC::Message* reply_msg) { |
- ResultFuture* future = new ResultFuture(); |
- |
- 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: |
- base::Thread io_thread_; |
- base::WaitableEvent done_; |
- |
- net::ProxyService* proxy_service_; |
- MockProxyResolver* proxy_resolver_; // Owned by proxy_service_. |
- |
- AsyncRequestRunner* async_runner_; |
+ scoped_ptr<PendingResult> pending_result_; |
}; |
-// 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) { |
- RunnerBridge runner; |
+ net::MockAsyncProxyResolver* resolver = new net::MockAsyncProxyResolver; |
+ net::ProxyService service(new MockProxyConfigService, resolver); |
+ MyDelegate delegate; |
+ ResolveProxyMsgHelper helper(&delegate, &service); |
+ |
GURL url1("http://www.google1.com/"); |
GURL url2("http://www.google2.com/"); |
GURL url3("http://www.google3.com/"); |
@@ -258,34 +70,57 @@ |
// Execute each request sequentially (so there are never 2 requests |
// outstanding at the same time). |
- scoped_ptr<ResultFuture> result1(runner.Start(url1, msg1.get())); |
- result1->WaitUntilDone(); |
+ helper.Start(url1, msg1.get()); |
- scoped_ptr<ResultFuture> result2(runner.Start(url2, msg2.get())); |
- result2->WaitUntilDone(); |
+ // Finish ProxyService's initialization. |
+ resolver->pending_set_pac_script_request()->CompleteNow(net::OK); |
- scoped_ptr<ResultFuture> result3(runner.Start(url3, msg3.get())); |
- result3->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); |
- // Check that each request gave the expected result. |
+ // 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(); |
- EXPECT_EQ(msg1.get(), result1->reply_msg); |
- EXPECT_EQ(net::OK, result1->error_code); |
- EXPECT_EQ("PROXY www.google1.com:80", result1->proxy_list); |
+ helper.Start(url2, msg2.get()); |
- EXPECT_EQ(msg2.get(), result2->reply_msg); |
- EXPECT_EQ(net::OK, result2->error_code); |
- EXPECT_EQ("PROXY www.google2.com:80", result2->proxy_list); |
+ 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(msg3.get(), result3->reply_msg); |
- EXPECT_EQ(net::OK, result3->error_code); |
- EXPECT_EQ("PROXY www.google3.com:80", result3->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(); |
+ |
+ 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(); |
} |
// Issue a request while one is already in progress -- should be queued. |
TEST(ResolveProxyMsgHelperTest, QueueRequests) { |
- RunnerBridge runner; |
+ net::MockAsyncProxyResolver* resolver = new net::MockAsyncProxyResolver; |
+ net::ProxyService service(new MockProxyConfigService, resolver); |
+ MyDelegate delegate; |
+ ResolveProxyMsgHelper helper(&delegate, &service); |
+ |
GURL url1("http://www.google1.com/"); |
GURL url2("http://www.google2.com/"); |
GURL url3("http://www.google3.com/"); |
@@ -294,45 +129,65 @@ |
scoped_ptr<IPC::Message> msg2(new IPC::Message()); |
scoped_ptr<IPC::Message> msg3(new IPC::Message()); |
- // Make the proxy resolver hang on the next request. |
- runner.proxy_resolver()->x->Block(); |
+ // Start three requests. Since the proxy resolver is async, all the |
+ // requests will be pending. |
- // Start three requests. Since the proxy resolver is hung, the second two |
- // will be pending. |
+ helper.Start(url1, msg1.get()); |
- 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())); |
+ // Finish ProxyService's initialization. |
+ resolver->pending_set_pac_script_request()->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(); |
+ helper.Start(url2, msg2.get()); |
+ helper.Start(url3, msg3.get()); |
- // Unblock the proxy service so requests 1-3 can complete. |
- runner.proxy_resolver()->x->Unblock(); |
+ // 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()); |
- // Wait for all the requests to finish (they run in FIFO order). |
- result3->WaitUntilDone(); |
+ resolver->pending_requests()[0]->results()->UseNamedProxy("result1:80"); |
+ resolver->pending_requests()[0]->CompleteNow(net::OK); |
- // Check that each call invoked the callback with the right parameters. |
+ // 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(); |
- 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(url2, 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("result2:80"); |
+ resolver->pending_requests()[0]->CompleteNow(net::OK); |
- EXPECT_EQ(msg3.get(), result3->reply_msg); |
- EXPECT_EQ(net::OK, result3->error_code); |
- EXPECT_EQ("PROXY www.google3.com:80", result3->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(); |
+ |
+ 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(); |
} |
// Delete the helper while a request is in progress, and others are pending. |
TEST(ResolveProxyMsgHelperTest, CancelPendingRequests) { |
- RunnerBridge runner; |
+ net::MockAsyncProxyResolver* resolver = new net::MockAsyncProxyResolver; |
+ net::ProxyService service(new MockProxyConfigService, resolver); |
+ MyDelegate delegate; |
+ scoped_ptr<ResolveProxyMsgHelper> helper( |
+ new ResolveProxyMsgHelper(&delegate, &service)); |
+ |
GURL url1("http://www.google1.com/"); |
GURL url2("http://www.google2.com/"); |
GURL url3("http://www.google3.com/"); |
@@ -343,35 +198,32 @@ |
IPC::Message* msg2 = new IPC::Message(); |
IPC::Message* msg3 = new IPC::Message(); |
- // Make the next request block. |
- runner.proxy_resolver()->x->Block(); |
+ // Start three requests. Since the proxy resolver is async, all the |
+ // requests will be pending. |
- // Start three requests; since the first one blocked, the other two should |
- // be pending. |
+ helper->Start(url1, msg1); |
- scoped_ptr<ResultFuture> result1(runner.Start(url1, msg1)); |
- scoped_ptr<ResultFuture> result2(runner.Start(url2, msg2)); |
- scoped_ptr<ResultFuture> result3(runner.Start(url3, msg3)); |
+ // Finish ProxyService's initialization. |
+ resolver->pending_set_pac_script_request()->CompleteNow(net::OK); |
- result3->WaitUntilStarted(); |
+ 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()); |
+ |
// Delete the underlying ResolveProxyMsgHelper -- this should cancel all |
// the requests which are outstanding. |
- runner.DestroyAsyncRunner(); |
+ helper.reset(); |
- // 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(); |
+ // The pending requests sent to the proxy resolver should have been cancelled. |
- // 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))); |
+ EXPECT_EQ(0u, resolver->pending_requests().size()); |
+ EXPECT_EQ(NULL, delegate.pending_result()); |
+ |
// It should also be the case that msg1, msg2, msg3 were deleted by the |
- // cancellation. (Else will show up as a leak in Purify). |
+ // cancellation. (Else will show up as a leak in Purify/Valgrind). |
} |