| Index: net/proxy/single_threaded_proxy_resolver_unittest.cc
|
| ===================================================================
|
| --- net/proxy/single_threaded_proxy_resolver_unittest.cc (revision 51914)
|
| +++ net/proxy/single_threaded_proxy_resolver_unittest.cc (working copy)
|
| @@ -1,476 +0,0 @@
|
| -// 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 "base/string_util.h"
|
| -#include "base/waitable_event.h"
|
| -#include "googleurl/src/gurl.h"
|
| -#include "net/base/net_log.h"
|
| -#include "net/base/net_log_unittest.h"
|
| -#include "net/base/net_errors.h"
|
| -#include "net/base/test_completion_callback.h"
|
| -#include "net/proxy/proxy_info.h"
|
| -#include "net/proxy/single_threaded_proxy_resolver.h"
|
| -#include "testing/gtest/include/gtest/gtest.h"
|
| -
|
| -namespace net {
|
| -namespace {
|
| -
|
| -// A synchronous mock ProxyResolver implementation, which can be used in
|
| -// conjunction with SingleThreadedProxyResolver.
|
| -// - returns a single-item proxy list with the query's host.
|
| -class MockProxyResolver : public ProxyResolver {
|
| - public:
|
| - MockProxyResolver()
|
| - : ProxyResolver(true /*expects_pac_bytes*/),
|
| - wrong_loop_(MessageLoop::current()),
|
| - request_count_(0),
|
| - purge_count_(0),
|
| - resolve_latency_ms_(0) {}
|
| -
|
| - // ProxyResolver implementation:
|
| - virtual int GetProxyForURL(const GURL& query_url,
|
| - ProxyInfo* results,
|
| - CompletionCallback* callback,
|
| - RequestHandle* request,
|
| - const BoundNetLog& net_log) {
|
| - if (resolve_latency_ms_)
|
| - PlatformThread::Sleep(resolve_latency_ms_);
|
| -
|
| - CheckIsOnWorkerThread();
|
| -
|
| - EXPECT_TRUE(callback == NULL);
|
| - EXPECT_TRUE(request == NULL);
|
| -
|
| - // Write something into |net_log| (doesn't really have any meaning.)
|
| - net_log.BeginEvent(NetLog::TYPE_PROXY_RESOLVER_V8_DNS_RESOLVE, NULL);
|
| -
|
| - results->UseNamedProxy(query_url.host());
|
| -
|
| - // Return a success code which represents the request's order.
|
| - return request_count_++;
|
| - }
|
| -
|
| - virtual void CancelRequest(RequestHandle request) {
|
| - NOTREACHED();
|
| - }
|
| -
|
| - virtual int SetPacScript(const GURL& pac_url,
|
| - const string16& text,
|
| - CompletionCallback* callback) {
|
| - CheckIsOnWorkerThread();
|
| - last_pac_script_ = text;
|
| - return OK;
|
| - }
|
| -
|
| - virtual void PurgeMemory() {
|
| - CheckIsOnWorkerThread();
|
| - ++purge_count_;
|
| - }
|
| -
|
| - int purge_count() const { return purge_count_; }
|
| -
|
| - const string16& last_pac_script() const { return last_pac_script_; }
|
| -
|
| - void SetResolveLatency(int latency_ms) {
|
| - resolve_latency_ms_ = latency_ms;
|
| - }
|
| -
|
| - private:
|
| - void CheckIsOnWorkerThread() {
|
| - // We should be running on the worker thread -- while we don't know the
|
| - // message loop of SingleThreadedProxyResolver's worker thread, we do
|
| - // know that it is going to be distinct from the loop running the
|
| - // test, so at least make sure it isn't the main loop.
|
| - EXPECT_NE(MessageLoop::current(), wrong_loop_);
|
| - }
|
| -
|
| - MessageLoop* wrong_loop_;
|
| - int request_count_;
|
| - int purge_count_;
|
| - string16 last_pac_script_;
|
| - int resolve_latency_ms_;
|
| -};
|
| -
|
| -
|
| -// A mock synchronous ProxyResolver which can be set to block upon reaching
|
| -// GetProxyForURL().
|
| -// TODO(eroman): WaitUntilBlocked() *must* be called before calling Unblock(),
|
| -// otherwise there will be a race on |should_block_| since it is
|
| -// read without any synchronization.
|
| -class BlockableProxyResolver : public MockProxyResolver {
|
| - public:
|
| - BlockableProxyResolver()
|
| - : should_block_(false),
|
| - unblocked_(true, true),
|
| - blocked_(true, false) {
|
| - }
|
| -
|
| - void Block() {
|
| - should_block_ = true;
|
| - unblocked_.Reset();
|
| - }
|
| -
|
| - void Unblock() {
|
| - should_block_ = false;
|
| - blocked_.Reset();
|
| - unblocked_.Signal();
|
| - }
|
| -
|
| - void WaitUntilBlocked() {
|
| - blocked_.Wait();
|
| - }
|
| -
|
| - virtual int GetProxyForURL(const GURL& query_url,
|
| - ProxyInfo* results,
|
| - CompletionCallback* callback,
|
| - RequestHandle* request,
|
| - const BoundNetLog& net_log) {
|
| - if (should_block_) {
|
| - blocked_.Signal();
|
| - unblocked_.Wait();
|
| - }
|
| -
|
| - return MockProxyResolver::GetProxyForURL(
|
| - query_url, results, callback, request, net_log);
|
| - }
|
| -
|
| - private:
|
| - bool should_block_;
|
| - base::WaitableEvent unblocked_;
|
| - base::WaitableEvent blocked_;
|
| -};
|
| -
|
| -TEST(SingleThreadedProxyResolverTest, Basic) {
|
| - MockProxyResolver* mock = new MockProxyResolver;
|
| - SingleThreadedProxyResolver resolver(mock);
|
| -
|
| - int rv;
|
| -
|
| - EXPECT_TRUE(resolver.expects_pac_bytes());
|
| -
|
| - // Call SetPacScriptByData() -- verify that it reaches the synchronous
|
| - // resolver.
|
| - TestCompletionCallback set_script_callback;
|
| - rv = resolver.SetPacScriptByData(ASCIIToUTF16("pac script bytes"),
|
| - &set_script_callback);
|
| - EXPECT_EQ(ERR_IO_PENDING, rv);
|
| - EXPECT_EQ(OK, set_script_callback.WaitForResult());
|
| - EXPECT_EQ(ASCIIToUTF16("pac script bytes"), mock->last_pac_script());
|
| -
|
| - // Start request 0.
|
| - TestCompletionCallback callback0;
|
| - CapturingBoundNetLog log0(CapturingNetLog::kUnbounded);
|
| - ProxyInfo results0;
|
| - rv = resolver.GetProxyForURL(
|
| - GURL("http://request0"), &results0, &callback0, NULL, log0.bound());
|
| - EXPECT_EQ(ERR_IO_PENDING, rv);
|
| -
|
| - // Wait for request 0 to finish.
|
| - rv = callback0.WaitForResult();
|
| - EXPECT_EQ(0, rv);
|
| - EXPECT_EQ("PROXY request0:80", results0.ToPacString());
|
| -
|
| - // The mock proxy resolver should have written 1 log entry. And
|
| - // on completion, this should have been copied into |log0|.
|
| - EXPECT_EQ(1u, log0.entries().size());
|
| -
|
| - // Start 3 more requests (request1 to request3).
|
| -
|
| - TestCompletionCallback callback1;
|
| - ProxyInfo results1;
|
| - rv = resolver.GetProxyForURL(
|
| - GURL("http://request1"), &results1, &callback1, NULL, BoundNetLog());
|
| - EXPECT_EQ(ERR_IO_PENDING, rv);
|
| -
|
| - TestCompletionCallback callback2;
|
| - ProxyInfo results2;
|
| - rv = resolver.GetProxyForURL(
|
| - GURL("http://request2"), &results2, &callback2, NULL, BoundNetLog());
|
| - EXPECT_EQ(ERR_IO_PENDING, rv);
|
| -
|
| - TestCompletionCallback callback3;
|
| - ProxyInfo results3;
|
| - rv = resolver.GetProxyForURL(
|
| - GURL("http://request3"), &results3, &callback3, NULL, BoundNetLog());
|
| - EXPECT_EQ(ERR_IO_PENDING, rv);
|
| -
|
| - // Wait for the requests to finish (they must finish in the order they were
|
| - // started, which is what we check for from their magic return value)
|
| -
|
| - rv = callback1.WaitForResult();
|
| - EXPECT_EQ(1, rv);
|
| - EXPECT_EQ("PROXY request1:80", results1.ToPacString());
|
| -
|
| - rv = callback2.WaitForResult();
|
| - EXPECT_EQ(2, rv);
|
| - EXPECT_EQ("PROXY request2:80", results2.ToPacString());
|
| -
|
| - rv = callback3.WaitForResult();
|
| - EXPECT_EQ(3, rv);
|
| - EXPECT_EQ("PROXY request3:80", results3.ToPacString());
|
| -
|
| - // Ensure that PurgeMemory() reaches the wrapped resolver and happens on the
|
| - // right thread.
|
| - EXPECT_EQ(0, mock->purge_count());
|
| - resolver.PurgeMemory();
|
| - // There is no way to get a callback directly when PurgeMemory() completes, so
|
| - // we queue up a dummy request after the PurgeMemory() call and wait until it
|
| - // finishes to ensure PurgeMemory() has had a chance to run.
|
| - TestCompletionCallback dummy_callback;
|
| - rv = resolver.SetPacScriptByData(ASCIIToUTF16("dummy"), &dummy_callback);
|
| - EXPECT_EQ(OK, dummy_callback.WaitForResult());
|
| - EXPECT_EQ(1, mock->purge_count());
|
| -}
|
| -
|
| -// Tests that the NetLog is updated to include the time the request was waiting
|
| -// to be scheduled to a thread.
|
| -TEST(SingleThreadedProxyResolverTest, UpdatesNetLogWithThreadWait) {
|
| - BlockableProxyResolver* mock = new BlockableProxyResolver;
|
| - SingleThreadedProxyResolver resolver(mock);
|
| -
|
| - int rv;
|
| -
|
| - // Block the proxy resolver, so no request can complete.
|
| - mock->Block();
|
| -
|
| - // Start request 0.
|
| - ProxyResolver::RequestHandle request0;
|
| - TestCompletionCallback callback0;
|
| - ProxyInfo results0;
|
| - CapturingBoundNetLog log0(CapturingNetLog::kUnbounded);
|
| - rv = resolver.GetProxyForURL(
|
| - GURL("http://request0"), &results0, &callback0, &request0, log0.bound());
|
| - EXPECT_EQ(ERR_IO_PENDING, rv);
|
| -
|
| - // Start 2 more requests (request1 and request2).
|
| -
|
| - TestCompletionCallback callback1;
|
| - ProxyInfo results1;
|
| - CapturingBoundNetLog log1(CapturingNetLog::kUnbounded);
|
| - rv = resolver.GetProxyForURL(
|
| - GURL("http://request1"), &results1, &callback1, NULL, log1.bound());
|
| - EXPECT_EQ(ERR_IO_PENDING, rv);
|
| -
|
| - ProxyResolver::RequestHandle request2;
|
| - TestCompletionCallback callback2;
|
| - ProxyInfo results2;
|
| - CapturingBoundNetLog log2(CapturingNetLog::kUnbounded);
|
| - rv = resolver.GetProxyForURL(
|
| - GURL("http://request2"), &results2, &callback2, &request2, log2.bound());
|
| - EXPECT_EQ(ERR_IO_PENDING, rv);
|
| -
|
| - // Unblock the worker thread so the requests can continue running.
|
| - mock->WaitUntilBlocked();
|
| - mock->Unblock();
|
| -
|
| - // Check that request 0 completed as expected.
|
| - // The NetLog only has 1 entry (that came from the mock proxy resolver.)
|
| - EXPECT_EQ(0, callback0.WaitForResult());
|
| - EXPECT_EQ("PROXY request0:80", results0.ToPacString());
|
| - ASSERT_EQ(1u, log0.entries().size());
|
| -
|
| - // Check that request 1 completed as expected.
|
| - EXPECT_EQ(1, callback1.WaitForResult());
|
| - EXPECT_EQ("PROXY request1:80", results1.ToPacString());
|
| - ASSERT_EQ(3u, log1.entries().size());
|
| - EXPECT_TRUE(LogContainsBeginEvent(
|
| - log1.entries(), 0,
|
| - NetLog::TYPE_WAITING_FOR_SINGLE_PROXY_RESOLVER_THREAD));
|
| - EXPECT_TRUE(LogContainsEndEvent(
|
| - log1.entries(), 1,
|
| - NetLog::TYPE_WAITING_FOR_SINGLE_PROXY_RESOLVER_THREAD));
|
| -
|
| - // Check that request 2 completed as expected.
|
| - EXPECT_EQ(2, callback2.WaitForResult());
|
| - EXPECT_EQ("PROXY request2:80", results2.ToPacString());
|
| - ASSERT_EQ(3u, log2.entries().size());
|
| - EXPECT_TRUE(LogContainsBeginEvent(
|
| - log2.entries(), 0,
|
| - NetLog::TYPE_WAITING_FOR_SINGLE_PROXY_RESOLVER_THREAD));
|
| - EXPECT_TRUE(LogContainsEndEvent(
|
| - log2.entries(), 1,
|
| - NetLog::TYPE_WAITING_FOR_SINGLE_PROXY_RESOLVER_THREAD));
|
| -}
|
| -
|
| -// Cancel a request which is in progress, and then cancel a request which
|
| -// is pending.
|
| -TEST(SingleThreadedProxyResolverTest, CancelRequest) {
|
| - BlockableProxyResolver* mock = new BlockableProxyResolver;
|
| - SingleThreadedProxyResolver resolver(mock);
|
| -
|
| - int rv;
|
| -
|
| - // Block the proxy resolver, so no request can complete.
|
| - mock->Block();
|
| -
|
| - // Start request 0.
|
| - ProxyResolver::RequestHandle request0;
|
| - TestCompletionCallback callback0;
|
| - ProxyInfo results0;
|
| - rv = resolver.GetProxyForURL(
|
| - GURL("http://request0"), &results0, &callback0, &request0, BoundNetLog());
|
| - EXPECT_EQ(ERR_IO_PENDING, rv);
|
| -
|
| - // Wait until requests 0 reaches the worker thread.
|
| - mock->WaitUntilBlocked();
|
| -
|
| - // Start 3 more requests (request1 : request3).
|
| -
|
| - TestCompletionCallback callback1;
|
| - ProxyInfo results1;
|
| - rv = resolver.GetProxyForURL(
|
| - GURL("http://request1"), &results1, &callback1, NULL, BoundNetLog());
|
| - EXPECT_EQ(ERR_IO_PENDING, rv);
|
| -
|
| - ProxyResolver::RequestHandle request2;
|
| - TestCompletionCallback callback2;
|
| - ProxyInfo results2;
|
| - rv = resolver.GetProxyForURL(
|
| - GURL("http://request2"), &results2, &callback2, &request2, BoundNetLog());
|
| - EXPECT_EQ(ERR_IO_PENDING, rv);
|
| -
|
| - TestCompletionCallback callback3;
|
| - ProxyInfo results3;
|
| - rv = resolver.GetProxyForURL(
|
| - GURL("http://request3"), &results3, &callback3, NULL, BoundNetLog());
|
| - EXPECT_EQ(ERR_IO_PENDING, rv);
|
| -
|
| - // Cancel request0 (inprogress) and request2 (pending).
|
| - resolver.CancelRequest(request0);
|
| - resolver.CancelRequest(request2);
|
| -
|
| - // Unblock the worker thread so the requests can continue running.
|
| - mock->Unblock();
|
| -
|
| - // Wait for requests 1 and 3 to finish.
|
| -
|
| - rv = callback1.WaitForResult();
|
| - EXPECT_EQ(1, rv);
|
| - EXPECT_EQ("PROXY request1:80", results1.ToPacString());
|
| -
|
| - rv = callback3.WaitForResult();
|
| - // Note that since request2 was cancelled before reaching the resolver,
|
| - // the request count is 2 and not 3 here.
|
| - EXPECT_EQ(2, rv);
|
| - EXPECT_EQ("PROXY request3:80", results3.ToPacString());
|
| -
|
| - // Requests 0 and 2 which were cancelled, hence their completion callbacks
|
| - // were never summoned.
|
| - EXPECT_FALSE(callback0.have_result());
|
| - EXPECT_FALSE(callback2.have_result());
|
| -}
|
| -
|
| -// Test that deleting SingleThreadedProxyResolver while requests are
|
| -// outstanding cancels them (and doesn't leak anything).
|
| -TEST(SingleThreadedProxyResolverTest, CancelRequestByDeleting) {
|
| - BlockableProxyResolver* mock = new BlockableProxyResolver;
|
| - scoped_ptr<SingleThreadedProxyResolver> resolver(
|
| - new SingleThreadedProxyResolver(mock));
|
| -
|
| - int rv;
|
| -
|
| - // Block the proxy resolver, so no request can complete.
|
| - mock->Block();
|
| -
|
| - // Start 3 requests.
|
| -
|
| - TestCompletionCallback callback0;
|
| - ProxyInfo results0;
|
| - rv = resolver->GetProxyForURL(
|
| - GURL("http://request0"), &results0, &callback0, NULL, BoundNetLog());
|
| - EXPECT_EQ(ERR_IO_PENDING, rv);
|
| -
|
| - TestCompletionCallback callback1;
|
| - ProxyInfo results1;
|
| - rv = resolver->GetProxyForURL(
|
| - GURL("http://request1"), &results1, &callback1, NULL, BoundNetLog());
|
| - EXPECT_EQ(ERR_IO_PENDING, rv);
|
| -
|
| - TestCompletionCallback callback2;
|
| - ProxyInfo results2;
|
| - rv = resolver->GetProxyForURL(
|
| - GURL("http://request2"), &results2, &callback2, NULL, BoundNetLog());
|
| - EXPECT_EQ(ERR_IO_PENDING, rv);
|
| -
|
| - // Wait until request 0 reaches the worker thread.
|
| - mock->WaitUntilBlocked();
|
| -
|
| - // Add some latency, to improve the chance that when
|
| - // SingleThreadedProxyResolver is deleted below we are still running inside
|
| - // of the worker thread. The test will pass regardless, so this race doesn't
|
| - // cause flakiness. However the destruction during execution is a more
|
| - // interesting case to test.
|
| - mock->SetResolveLatency(100);
|
| -
|
| - // Unblock the worker thread and delete the underlying
|
| - // SingleThreadedProxyResolver immediately.
|
| - mock->Unblock();
|
| - resolver.reset();
|
| -
|
| - // Give any posted tasks a chance to run (in case there is badness).
|
| - MessageLoop::current()->RunAllPending();
|
| -
|
| - // Check that none of the outstanding requests were completed.
|
| - EXPECT_FALSE(callback0.have_result());
|
| - EXPECT_FALSE(callback1.have_result());
|
| - EXPECT_FALSE(callback2.have_result());
|
| -}
|
| -
|
| -// Cancel an outstanding call to SetPacScriptByData().
|
| -TEST(SingleThreadedProxyResolverTest, CancelSetPacScript) {
|
| - BlockableProxyResolver* mock = new BlockableProxyResolver;
|
| - SingleThreadedProxyResolver resolver(mock);
|
| -
|
| - int rv;
|
| -
|
| - // Block the proxy resolver, so no request can complete.
|
| - mock->Block();
|
| -
|
| - // Start request 0.
|
| - ProxyResolver::RequestHandle request0;
|
| - TestCompletionCallback callback0;
|
| - ProxyInfo results0;
|
| - rv = resolver.GetProxyForURL(
|
| - GURL("http://request0"), &results0, &callback0, &request0, BoundNetLog());
|
| - EXPECT_EQ(ERR_IO_PENDING, rv);
|
| -
|
| - // Wait until requests 0 reaches the worker thread.
|
| - mock->WaitUntilBlocked();
|
| -
|
| - TestCompletionCallback set_pac_script_callback;
|
| - rv = resolver.SetPacScriptByData(ASCIIToUTF16("data"),
|
| - &set_pac_script_callback);
|
| - EXPECT_EQ(ERR_IO_PENDING, rv);
|
| -
|
| - // Cancel the SetPacScriptByData request (it can't have finished yet,
|
| - // since the single-thread is currently blocked).
|
| - resolver.CancelSetPacScript();
|
| -
|
| - // Start 1 more request.
|
| -
|
| - TestCompletionCallback callback1;
|
| - ProxyInfo results1;
|
| - rv = resolver.GetProxyForURL(
|
| - GURL("http://request1"), &results1, &callback1, NULL, BoundNetLog());
|
| - EXPECT_EQ(ERR_IO_PENDING, rv);
|
| -
|
| - // Unblock the worker thread so the requests can continue running.
|
| - mock->Unblock();
|
| -
|
| - // Wait for requests 0 and 1 to finish.
|
| -
|
| - rv = callback0.WaitForResult();
|
| - EXPECT_EQ(0, rv);
|
| - EXPECT_EQ("PROXY request0:80", results0.ToPacString());
|
| -
|
| - rv = callback1.WaitForResult();
|
| - EXPECT_EQ(1, rv);
|
| - EXPECT_EQ("PROXY request1:80", results1.ToPacString());
|
| -
|
| - // The SetPacScript callback should never have been completed.
|
| - EXPECT_FALSE(set_pac_script_callback.have_result());
|
| -}
|
| -
|
| -} // namespace
|
| -} // namespace net
|
|
|