OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2009 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 "base/waitable_event.h" |
| 6 #include "googleurl/src/gurl.h" |
| 7 #include "net/base/net_errors.h" |
| 8 #include "net/base/test_completion_callback.h" |
| 9 #include "net/proxy/proxy_info.h" |
| 10 #include "net/proxy/single_threaded_proxy_resolver.h" |
| 11 #include "testing/gtest/include/gtest/gtest.h" |
| 12 |
| 13 namespace net { |
| 14 namespace { |
| 15 |
| 16 // A synchronous mock ProxyResolver implementation, which can be used in |
| 17 // conjunction with SingleThreadedProxyResolver. |
| 18 // - returns a single-item proxy list with the query's host. |
| 19 class MockProxyResolver : public ProxyResolver { |
| 20 public: |
| 21 MockProxyResolver() |
| 22 : ProxyResolver(true /*expects_pac_bytes*/), |
| 23 wrong_loop_(MessageLoop::current()), |
| 24 request_count_(0), |
| 25 resolve_latency_ms_(0) {} |
| 26 |
| 27 // ProxyResolver implementation: |
| 28 virtual int GetProxyForURL(const GURL& query_url, |
| 29 ProxyInfo* results, |
| 30 CompletionCallback* callback, |
| 31 RequestHandle* request) { |
| 32 if (resolve_latency_ms_) |
| 33 PlatformThread::Sleep(resolve_latency_ms_); |
| 34 |
| 35 CheckIsOnWorkerThread(); |
| 36 |
| 37 EXPECT_EQ(NULL, callback); |
| 38 EXPECT_EQ(NULL, request); |
| 39 |
| 40 results->UseNamedProxy(query_url.host()); |
| 41 |
| 42 // Return a success code which represents the request's order. |
| 43 return request_count_++; |
| 44 } |
| 45 |
| 46 virtual void CancelRequest(RequestHandle request) { |
| 47 NOTREACHED(); |
| 48 } |
| 49 |
| 50 virtual void SetPacScriptByDataInternal(const std::string& bytes) { |
| 51 CheckIsOnWorkerThread(); |
| 52 last_pac_bytes_ = bytes; |
| 53 } |
| 54 |
| 55 const std::string& last_pac_bytes() const { return last_pac_bytes_; } |
| 56 |
| 57 void SetResolveLatency(int latency_ms) { |
| 58 resolve_latency_ms_ = latency_ms; |
| 59 } |
| 60 |
| 61 private: |
| 62 void CheckIsOnWorkerThread() { |
| 63 // We should be running on the worker thread -- while we don't know the |
| 64 // message loop of SingleThreadedProxyResolver's worker thread, we do |
| 65 // know that it is going to be distinct from the loop running the |
| 66 // test, so at least make sure it isn't the main loop. |
| 67 EXPECT_NE(MessageLoop::current(), wrong_loop_); |
| 68 } |
| 69 |
| 70 MessageLoop* wrong_loop_; |
| 71 int request_count_; |
| 72 std::string last_pac_bytes_; |
| 73 int resolve_latency_ms_; |
| 74 }; |
| 75 |
| 76 |
| 77 // A mock synchronous ProxyResolver which can be set to block upon reaching |
| 78 // GetProxyForURL(). |
| 79 class BlockableProxyResolver : public MockProxyResolver { |
| 80 public: |
| 81 BlockableProxyResolver() |
| 82 : should_block_(false), |
| 83 unblocked_(true, true), |
| 84 blocked_(true, false) { |
| 85 } |
| 86 |
| 87 void Block() { |
| 88 should_block_ = true; |
| 89 unblocked_.Reset(); |
| 90 } |
| 91 |
| 92 void Unblock() { |
| 93 should_block_ = false; |
| 94 blocked_.Reset(); |
| 95 unblocked_.Signal(); |
| 96 } |
| 97 |
| 98 void WaitUntilBlocked() { |
| 99 blocked_.Wait(); |
| 100 } |
| 101 |
| 102 virtual int GetProxyForURL(const GURL& query_url, |
| 103 ProxyInfo* results, |
| 104 CompletionCallback* callback, |
| 105 RequestHandle* request) { |
| 106 if (should_block_) { |
| 107 blocked_.Signal(); |
| 108 unblocked_.Wait(); |
| 109 } |
| 110 |
| 111 return MockProxyResolver::GetProxyForURL( |
| 112 query_url, results, callback, request); |
| 113 } |
| 114 |
| 115 private: |
| 116 bool should_block_; |
| 117 base::WaitableEvent unblocked_; |
| 118 base::WaitableEvent blocked_; |
| 119 }; |
| 120 |
| 121 TEST(SingleThreadedProxyResolverTest, Basic) { |
| 122 MockProxyResolver* mock = new MockProxyResolver; |
| 123 scoped_ptr<SingleThreadedProxyResolver> resolver( |
| 124 new SingleThreadedProxyResolver(mock)); |
| 125 |
| 126 int rv; |
| 127 |
| 128 EXPECT_TRUE(resolver->expects_pac_bytes()); |
| 129 |
| 130 // Call SetPacScriptByData() -- we will make sure it reaches the sync resolver |
| 131 // later on. |
| 132 resolver->SetPacScriptByData("pac script bytes"); |
| 133 |
| 134 // Start request 0. |
| 135 TestCompletionCallback callback0; |
| 136 ProxyInfo results0; |
| 137 rv = resolver->GetProxyForURL( |
| 138 GURL("http://request0"), &results0, &callback0, NULL); |
| 139 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 140 |
| 141 // Wait for request 0 to finish. |
| 142 rv = callback0.WaitForResult(); |
| 143 EXPECT_EQ(0, rv); |
| 144 EXPECT_EQ("PROXY request0:80", results0.ToPacString()); |
| 145 |
| 146 // Verify that the data from SetPacScriptByData() reached the resolver. |
| 147 // (Since we waited for the first request to complete, we are guaranteed |
| 148 // that the earlier post completed). |
| 149 EXPECT_EQ("pac script bytes", mock->last_pac_bytes()); |
| 150 |
| 151 // Start 3 more requests (request1 to request3). |
| 152 |
| 153 TestCompletionCallback callback1; |
| 154 ProxyInfo results1; |
| 155 rv = resolver->GetProxyForURL( |
| 156 GURL("http://request1"), &results1, &callback1, NULL); |
| 157 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 158 |
| 159 TestCompletionCallback callback2; |
| 160 ProxyInfo results2; |
| 161 rv = resolver->GetProxyForURL( |
| 162 GURL("http://request2"), &results2, &callback2, NULL); |
| 163 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 164 |
| 165 TestCompletionCallback callback3; |
| 166 ProxyInfo results3; |
| 167 rv = resolver->GetProxyForURL( |
| 168 GURL("http://request3"), &results3, &callback3, NULL); |
| 169 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 170 |
| 171 // Wait for the requests to finish (they must finish in the order they were |
| 172 // started, which is what we check for from their magic return value) |
| 173 |
| 174 rv = callback1.WaitForResult(); |
| 175 EXPECT_EQ(1, rv); |
| 176 EXPECT_EQ("PROXY request1:80", results1.ToPacString()); |
| 177 |
| 178 rv = callback2.WaitForResult(); |
| 179 EXPECT_EQ(2, rv); |
| 180 EXPECT_EQ("PROXY request2:80", results2.ToPacString()); |
| 181 |
| 182 rv = callback3.WaitForResult(); |
| 183 EXPECT_EQ(3, rv); |
| 184 EXPECT_EQ("PROXY request3:80", results3.ToPacString()); |
| 185 } |
| 186 |
| 187 // Cancel a request which is in progress, and then cancel a request which |
| 188 // is pending. |
| 189 TEST(SingleThreadedProxyResolverTest, CancelRequest) { |
| 190 BlockableProxyResolver* mock = new BlockableProxyResolver; |
| 191 scoped_ptr<SingleThreadedProxyResolver> resolver( |
| 192 new SingleThreadedProxyResolver(mock)); |
| 193 |
| 194 int rv; |
| 195 |
| 196 // Block the proxy resolver, so no request can complete. |
| 197 mock->Block(); |
| 198 |
| 199 // Start request 0. |
| 200 ProxyResolver::RequestHandle request0; |
| 201 TestCompletionCallback callback0; |
| 202 ProxyInfo results0; |
| 203 rv = resolver->GetProxyForURL( |
| 204 GURL("http://request0"), &results0, &callback0, &request0); |
| 205 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 206 |
| 207 // Wait until requests 0 reaches the worker thread. |
| 208 mock->WaitUntilBlocked(); |
| 209 |
| 210 // Start 3 more requests (request1 : request3). |
| 211 |
| 212 TestCompletionCallback callback1; |
| 213 ProxyInfo results1; |
| 214 rv = resolver->GetProxyForURL( |
| 215 GURL("http://request1"), &results1, &callback1, NULL); |
| 216 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 217 |
| 218 ProxyResolver::RequestHandle request2; |
| 219 TestCompletionCallback callback2; |
| 220 ProxyInfo results2; |
| 221 rv = resolver->GetProxyForURL( |
| 222 GURL("http://request2"), &results2, &callback2, &request2); |
| 223 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 224 |
| 225 TestCompletionCallback callback3; |
| 226 ProxyInfo results3; |
| 227 rv = resolver->GetProxyForURL( |
| 228 GURL("http://request3"), &results3, &callback3, NULL); |
| 229 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 230 |
| 231 // Cancel request0 (inprogress) and request2 (pending). |
| 232 resolver->CancelRequest(request0); |
| 233 resolver->CancelRequest(request2); |
| 234 |
| 235 // Unblock the worker thread so the requests can continue running. |
| 236 mock->Unblock(); |
| 237 |
| 238 // Wait for requests 1 and 3 to finish. |
| 239 |
| 240 rv = callback1.WaitForResult(); |
| 241 EXPECT_EQ(1, rv); |
| 242 EXPECT_EQ("PROXY request1:80", results1.ToPacString()); |
| 243 |
| 244 rv = callback3.WaitForResult(); |
| 245 // Note that since request2 was cancelled before reaching the resolver, |
| 246 // the request count is 2 and not 3 here. |
| 247 EXPECT_EQ(2, rv); |
| 248 EXPECT_EQ("PROXY request3:80", results3.ToPacString()); |
| 249 |
| 250 // Requests 0 and 2 which were cancelled, hence their completion callbacks |
| 251 // were never summoned. |
| 252 EXPECT_FALSE(callback0.have_result()); |
| 253 EXPECT_FALSE(callback2.have_result()); |
| 254 } |
| 255 |
| 256 // Test that deleting SingleThreadedProxyResolver while requests are |
| 257 // outstanding cancels them (and doesn't leak anything). |
| 258 TEST(SingleThreadedProxyResolverTest, CancelRequestByDeleting) { |
| 259 BlockableProxyResolver* mock = new BlockableProxyResolver; |
| 260 scoped_ptr<SingleThreadedProxyResolver> resolver( |
| 261 new SingleThreadedProxyResolver(mock)); |
| 262 |
| 263 int rv; |
| 264 |
| 265 // Block the proxy resolver, so no request can complete. |
| 266 mock->Block(); |
| 267 |
| 268 // Start 3 requests. |
| 269 |
| 270 TestCompletionCallback callback0; |
| 271 ProxyInfo results0; |
| 272 rv = resolver->GetProxyForURL( |
| 273 GURL("http://request0"), &results0, &callback0, NULL); |
| 274 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 275 |
| 276 TestCompletionCallback callback1; |
| 277 ProxyInfo results1; |
| 278 rv = resolver->GetProxyForURL( |
| 279 GURL("http://request1"), &results1, &callback1, NULL); |
| 280 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 281 |
| 282 TestCompletionCallback callback2; |
| 283 ProxyInfo results2; |
| 284 rv = resolver->GetProxyForURL( |
| 285 GURL("http://request2"), &results2, &callback2, NULL); |
| 286 EXPECT_EQ(ERR_IO_PENDING, rv); |
| 287 |
| 288 // Wait until request 0 reaches the worker thread. |
| 289 mock->WaitUntilBlocked(); |
| 290 |
| 291 // Add some latency, to improve the chance that when |
| 292 // SingleThreadedProxyResolver is deleted below we are still running inside |
| 293 // of the worker thread. The test will pass regardless, so this race doesn't |
| 294 // cause flakiness. However the destruction during execution is a more |
| 295 // interesting case to test. |
| 296 mock->SetResolveLatency(100); |
| 297 |
| 298 // Unblock the worker thread and delete the underlying |
| 299 // SingleThreadedProxyResolver immediately. |
| 300 mock->Unblock(); |
| 301 resolver.reset(); |
| 302 |
| 303 // Give any posted tasks a chance to run (in case there is badness). |
| 304 MessageLoop::current()->RunAllPending(); |
| 305 |
| 306 // Check that none of the outstanding requests were completed. |
| 307 EXPECT_FALSE(callback0.have_result()); |
| 308 EXPECT_FALSE(callback1.have_result()); |
| 309 EXPECT_FALSE(callback2.have_result()); |
| 310 } |
| 311 |
| 312 } // namespace |
| 313 } // namespace net |
OLD | NEW |