| 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).
|
| }
|
|
|