1// Copyright (c) 2011 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 "content/browser/resolve_proxy_msg_helper.h" 6 7#include "content/browser/browser_thread_impl.h" 8#include "content/common/view_messages.h" 9#include "ipc/ipc_test_sink.h" 10#include "net/base/net_errors.h" 11#include "net/proxy/mock_proxy_resolver.h" 12#include "net/proxy/proxy_config_service.h" 13#include "net/proxy/proxy_service.h" 14#include "testing/gtest/include/gtest/gtest.h" 15 16namespace content { 17 18// This ProxyConfigService always returns "http://pac" as the PAC url to use. 19class MockProxyConfigService : public net::ProxyConfigService { 20 public: 21 virtual void AddObserver(Observer* observer) OVERRIDE {} 22 virtual void RemoveObserver(Observer* observer) OVERRIDE {} 23 virtual ConfigAvailability GetLatestProxyConfig( 24 net::ProxyConfig* results) OVERRIDE { 25 *results = net::ProxyConfig::CreateFromCustomPacURL(GURL("http://pac")); 26 return CONFIG_VALID; 27 } 28}; 29 30class TestResolveProxyMsgHelper : public ResolveProxyMsgHelper { 31 public: 32 TestResolveProxyMsgHelper( 33 net::ProxyService* proxy_service, 34 IPC::Listener* listener) 35 : ResolveProxyMsgHelper(proxy_service), 36 listener_(listener) {} 37 virtual bool Send(IPC::Message* message) OVERRIDE { 38 listener_->OnMessageReceived(*message); 39 delete message; 40 return true; 41 } 42 43 protected: 44 virtual ~TestResolveProxyMsgHelper() {} 45 46 IPC::Listener* listener_; 47}; 48 49class ResolveProxyMsgHelperTest : public testing::Test, public IPC::Listener { 50 public: 51 struct PendingResult { 52 PendingResult(bool result, 53 const std::string& proxy_list) 54 : result(result), proxy_list(proxy_list) { 55 } 56 57 bool result; 58 std::string proxy_list; 59 }; 60 61 ResolveProxyMsgHelperTest() 62 : resolver_(new net::MockAsyncProxyResolver), 63 service_( 64 new net::ProxyService(new MockProxyConfigService, resolver_, NULL)), 65 helper_(new TestResolveProxyMsgHelper(service_.get(), this)), 66 io_thread_(BrowserThread::IO, &message_loop_) { 67 test_sink_.AddFilter(this); 68 } 69 70 protected: 71 const PendingResult* pending_result() const { return pending_result_.get(); } 72 73 void clear_pending_result() { 74 pending_result_.reset(); 75 } 76 77 IPC::Message* GenerateReply() { 78 bool temp_bool; 79 std::string temp_string; 80 ViewHostMsg_ResolveProxy message(GURL(), &temp_bool, &temp_string); 81 return IPC::SyncMessage::GenerateReply(&message); 82 } 83 84 net::MockAsyncProxyResolver* resolver_; 85 scoped_ptr<net::ProxyService> service_; 86 scoped_refptr<ResolveProxyMsgHelper> helper_; 87 scoped_ptr<PendingResult> pending_result_; 88 89 private: 90 virtual bool OnMessageReceived(const IPC::Message& msg) OVERRIDE { 91 TupleTypes<ViewHostMsg_ResolveProxy::ReplyParam>::ValueTuple reply_data; 92 EXPECT_TRUE(ViewHostMsg_ResolveProxy::ReadReplyParam(&msg, &reply_data)); 93 DCHECK(!pending_result_.get()); 94 pending_result_.reset(new PendingResult(reply_data.a, reply_data.b)); 95 test_sink_.ClearMessages(); 96 return true; 97 } 98 99 base::MessageLoopForIO message_loop_; 100 BrowserThreadImpl io_thread_; 101 IPC::TestSink test_sink_; 102}; 103 104// Issue three sequential requests -- each should succeed. 105TEST_F(ResolveProxyMsgHelperTest, Sequential) { 106 GURL url1("http://www.google1.com/"); 107 GURL url2("http://www.google2.com/"); 108 GURL url3("http://www.google3.com/"); 109 110 // Messages are deleted by the sink. 111 IPC::Message* msg1 = GenerateReply(); 112 IPC::Message* msg2 = GenerateReply(); 113 IPC::Message* msg3 = GenerateReply(); 114 115 // Execute each request sequentially (so there are never 2 requests 116 // outstanding at the same time). 117 118 helper_->OnResolveProxy(url1, msg1); 119 120 // Finish ProxyService's initialization. 121 resolver_->pending_set_pac_script_request()->CompleteNow(net::OK); 122 123 ASSERT_EQ(1u, resolver_->pending_requests().size()); 124 EXPECT_EQ(url1, resolver_->pending_requests()[0]->url()); 125 resolver_->pending_requests()[0]->results()->UseNamedProxy("result1:80"); 126 resolver_->pending_requests()[0]->CompleteNow(net::OK); 127 128 // Check result. 129 EXPECT_EQ(true, pending_result()->result); 130 EXPECT_EQ("PROXY result1:80", pending_result()->proxy_list); 131 clear_pending_result(); 132 133 helper_->OnResolveProxy(url2, msg2); 134 135 ASSERT_EQ(1u, resolver_->pending_requests().size()); 136 EXPECT_EQ(url2, resolver_->pending_requests()[0]->url()); 137 resolver_->pending_requests()[0]->results()->UseNamedProxy("result2:80"); 138 resolver_->pending_requests()[0]->CompleteNow(net::OK); 139 140 // Check result. 141 EXPECT_EQ(true, pending_result()->result); 142 EXPECT_EQ("PROXY result2:80", pending_result()->proxy_list); 143 clear_pending_result(); 144 145 helper_->OnResolveProxy(url3, msg3); 146 147 ASSERT_EQ(1u, resolver_->pending_requests().size()); 148 EXPECT_EQ(url3, resolver_->pending_requests()[0]->url()); 149 resolver_->pending_requests()[0]->results()->UseNamedProxy("result3:80"); 150 resolver_->pending_requests()[0]->CompleteNow(net::OK); 151 152 // Check result. 153 EXPECT_EQ(true, pending_result()->result); 154 EXPECT_EQ("PROXY result3:80", pending_result()->proxy_list); 155 clear_pending_result(); 156} 157 158// Issue a request while one is already in progress -- should be queued. 159TEST_F(ResolveProxyMsgHelperTest, QueueRequests) { 160 GURL url1("http://www.google1.com/"); 161 GURL url2("http://www.google2.com/"); 162 GURL url3("http://www.google3.com/"); 163 164 IPC::Message* msg1 = GenerateReply(); 165 IPC::Message* msg2 = GenerateReply(); 166 IPC::Message* msg3 = GenerateReply(); 167 168 // Start three requests. Since the proxy resolver is async, all the 169 // requests will be pending. 170 171 helper_->OnResolveProxy(url1, msg1); 172 173 // Finish ProxyService's initialization. 174 resolver_->pending_set_pac_script_request()->CompleteNow(net::OK); 175 176 helper_->OnResolveProxy(url2, msg2); 177 helper_->OnResolveProxy(url3, msg3); 178 179 // ResolveProxyHelper only keeps 1 request outstanding in ProxyService 180 // at a time. 181 ASSERT_EQ(1u, resolver_->pending_requests().size()); 182 EXPECT_EQ(url1, resolver_->pending_requests()[0]->url()); 183 184 resolver_->pending_requests()[0]->results()->UseNamedProxy("result1:80"); 185 resolver_->pending_requests()[0]->CompleteNow(net::OK); 186 187 // Check result. 188 EXPECT_EQ(true, pending_result()->result); 189 EXPECT_EQ("PROXY result1:80", pending_result()->proxy_list); 190 clear_pending_result(); 191 192 ASSERT_EQ(1u, resolver_->pending_requests().size()); 193 EXPECT_EQ(url2, resolver_->pending_requests()[0]->url()); 194 195 resolver_->pending_requests()[0]->results()->UseNamedProxy("result2:80"); 196 resolver_->pending_requests()[0]->CompleteNow(net::OK); 197 198 // Check result. 199 EXPECT_EQ(true, pending_result()->result); 200 EXPECT_EQ("PROXY result2:80", pending_result()->proxy_list); 201 clear_pending_result(); 202 203 ASSERT_EQ(1u, resolver_->pending_requests().size()); 204 EXPECT_EQ(url3, resolver_->pending_requests()[0]->url()); 205 206 resolver_->pending_requests()[0]->results()->UseNamedProxy("result3:80"); 207 resolver_->pending_requests()[0]->CompleteNow(net::OK); 208 209 // Check result. 210 EXPECT_EQ(true, pending_result()->result); 211 EXPECT_EQ("PROXY result3:80", pending_result()->proxy_list); 212 clear_pending_result(); 213} 214 215// Delete the helper while a request is in progress, and others are pending. 216TEST_F(ResolveProxyMsgHelperTest, CancelPendingRequests) { 217 GURL url1("http://www.google1.com/"); 218 GURL url2("http://www.google2.com/"); 219 GURL url3("http://www.google3.com/"); 220 221 // They will be deleted by the request's cancellation. 222 IPC::Message* msg1 = GenerateReply(); 223 IPC::Message* msg2 = GenerateReply(); 224 IPC::Message* msg3 = GenerateReply(); 225 226 // Start three requests. Since the proxy resolver is async, all the 227 // requests will be pending. 228 229 helper_->OnResolveProxy(url1, msg1); 230 231 // Finish ProxyService's initialization. 232 resolver_->pending_set_pac_script_request()->CompleteNow(net::OK); 233 234 helper_->OnResolveProxy(url2, msg2); 235 helper_->OnResolveProxy(url3, msg3); 236 237 // ResolveProxyHelper only keeps 1 request outstanding in ProxyService 238 // at a time. 239 ASSERT_EQ(1u, resolver_->pending_requests().size()); 240 EXPECT_EQ(url1, resolver_->pending_requests()[0]->url()); 241 242 // Delete the underlying ResolveProxyMsgHelper -- this should cancel all 243 // the requests which are outstanding. 244 helper_ = NULL; 245 246 // The pending requests sent to the proxy resolver should have been cancelled. 247 248 EXPECT_EQ(0u, resolver_->pending_requests().size()); 249 250 EXPECT_TRUE(pending_result() == NULL); 251 252 // It should also be the case that msg1, msg2, msg3 were deleted by the 253 // cancellation. (Else will show up as a leak in Valgrind). 254} 255 256} // namespace content 257