Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(345)

Unified Diff: chrome/browser/net/resolve_proxy_msg_helper_unittest.cc

Issue 14142: Start using the proxy resolve IPC for plugins.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/net/resolve_proxy_msg_helper.cc ('k') | chrome/browser/plugin_process_host.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/net/resolve_proxy_msg_helper_unittest.cc
===================================================================
--- chrome/browser/net/resolve_proxy_msg_helper_unittest.cc (revision 0)
+++ chrome/browser/net/resolve_proxy_msg_helper_unittest.cc (revision 0)
@@ -0,0 +1,349 @@
+// Copyright (c) 2009 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 "chrome/browser/net/resolve_proxy_msg_helper.h"
+
+#include "base/waitable_event.h"
+#include "net/base/net_errors.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 {
+ public:
+ virtual int GetProxyConfig(net::ProxyConfig* results) {
+ results->pac_url = GURL("http://pac");
+ return net::OK;
+ }
+};
+
+// 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 MockProxyResolver : public net::ProxyResolver {
+ public:
+ explicit MockProxyResolver() : event_(false, false), is_blocked_(false) {
+ }
+
+ virtual int GetProxyForURL(const GURL& query_url,
+ const GURL& /*pac_url*/,
+ net::ProxyInfo* results) {
+ if (is_blocked_)
+ event_.Wait();
+ results->UseNamedProxy(query_url.host());
+ return net::OK;
+ }
+
+ void Block() {
+ is_blocked_ = true;
+ event_.Reset();
+ }
+
+ void Unblock() {
+ is_blocked_ = false;
+ event_.Signal();
+ }
+
+ private:
+ base::WaitableEvent event_;
+ bool is_blocked_;
+};
+
+// 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) {
+ // 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_(true, 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();
+ }
+
+ // 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_;
+};
+
+// 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;
+
+ GURL url1("http://www.google1.com/");
+ GURL url2("http://www.google2.com/");
+ GURL url3("http://www.google3.com/");
+
+ scoped_ptr<IPC::Message> msg1(new IPC::Message());
+ scoped_ptr<IPC::Message> msg2(new IPC::Message());
+ scoped_ptr<IPC::Message> msg3(new IPC::Message());
+
+ // 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();
+
+ scoped_ptr<ResultFuture> result2(runner.Start(url2, msg2.get()));
+ result2->WaitUntilDone();
+
+ scoped_ptr<ResultFuture> result3(runner.Start(url3, msg3.get()));
+ result3->WaitUntilDone();
+
+ // Check that each request gave the expected result.
+
+ EXPECT_EQ(msg1.get(), result1->reply_msg);
+ EXPECT_EQ(net::OK, result1->error_code);
+ EXPECT_EQ("PROXY www.google1.com", result1->proxy_list);
+
+ EXPECT_EQ(msg2.get(), result2->reply_msg);
+ EXPECT_EQ(net::OK, result2->error_code);
+ EXPECT_EQ("PROXY www.google2.com", result2->proxy_list);
+
+ EXPECT_EQ(msg3.get(), result3->reply_msg);
+ EXPECT_EQ(net::OK, result3->error_code);
+ EXPECT_EQ("PROXY www.google3.com", result3->proxy_list);
+}
+
+// Issue a request while one is already in progress -- should be queued.
+TEST(ResolveProxyMsgHelperTest, QueueRequests) {
+ RunnerBridge runner;
+
+ GURL url1("http://www.google1.com/");
+ GURL url2("http://www.google2.com/");
+ GURL url3("http://www.google3.com/");
+
+ scoped_ptr<IPC::Message> msg1(new IPC::Message());
+ 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()->Block();
+
+ // Start three requests. Since the proxy resolver is hung, the second two
+ // will be pending.
+
+ 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()));
+
+ // Wait for the final request to have been scheduled. Otherwise we may rush
+ // to calling Unblock() without actually having blocked anything.
+ result3->WaitUntilStarted();
+
+ // Unblock the proxy service so requests 1-3 can complete.
+ runner.proxy_resolver()->Unblock();
+
+ // Wait for all the requests to finish (they run in FIFO order).
+ result3->WaitUntilDone();
+
+ // Check that each call invoked the callback with the right parameters.
+
+ EXPECT_EQ(msg1.get(), result1->reply_msg);
+ EXPECT_EQ(net::OK, result1->error_code);
+ EXPECT_EQ("PROXY www.google1.com", result1->proxy_list);
+
+ EXPECT_EQ(msg2.get(), result2->reply_msg);
+ EXPECT_EQ(net::OK, result2->error_code);
+ EXPECT_EQ("PROXY www.google2.com", result2->proxy_list);
+
+ EXPECT_EQ(msg3.get(), result3->reply_msg);
+ EXPECT_EQ(net::OK, result3->error_code);
+ EXPECT_EQ("PROXY www.google3.com", result3->proxy_list);
+}
+
+// Delete the helper while a request is in progress, and others are pending.
+TEST(ResolveProxyMsgHelperTest, CancelPendingRequests) {
+ RunnerBridge runner;
+
+ GURL url1("http://www.google1.com/");
+ GURL url2("http://www.google2.com/");
+ GURL url3("http://www.google3.com/");
+
+ // NOTE: these are not scoped ptr, since they will be deleted by the
+ // request's cancellation.
+ IPC::Message* msg1 = new IPC::Message();
+ IPC::Message* msg2 = new IPC::Message();
+ IPC::Message* msg3 = new IPC::Message();
+
+ // Make the next request block.
+ runner.proxy_resolver()->Block();
+
+ // Start three requests; since the first one blocked, the other two should
+ // be pending.
+
+ scoped_ptr<ResultFuture> result1(runner.Start(url1, msg1));
+ scoped_ptr<ResultFuture> result2(runner.Start(url2, msg2));
+ scoped_ptr<ResultFuture> result3(runner.Start(url3, msg3));
+
+ result3->WaitUntilStarted();
+
+ // Delete the underlying ResolveProxyMsgHelper -- this should cancel all
+ // the requests which are outstanding.
+ runner.DestroyAsyncRunner();
+
+ // 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()->Unblock();
+
+ // 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).
+}
+
Property changes on: chrome\browser\net\resolve_proxy_msg_helper_unittest.cc
___________________________________________________________________
Added: svn:eol-style
+ LF
« no previous file with comments | « chrome/browser/net/resolve_proxy_msg_helper.cc ('k') | chrome/browser/plugin_process_host.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698