Index: net/proxy/dhcp_proxy_script_adapter_fetcher_win_unittest.cc |
diff --git a/net/proxy/dhcp_proxy_script_adapter_fetcher_win_unittest.cc b/net/proxy/dhcp_proxy_script_adapter_fetcher_win_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b4b05f9f3a255941eb95f49a98ff2bf81e796861 |
--- /dev/null |
+++ b/net/proxy/dhcp_proxy_script_adapter_fetcher_win_unittest.cc |
@@ -0,0 +1,300 @@ |
+// Copyright (c) 2011 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 "net/proxy/dhcp_proxy_script_adapter_fetcher_win.h" |
+ |
+#include "base/perftimer.h" |
+#include "base/synchronization/waitable_event.h" |
+#include "base/timer.h" |
+#include "net/base/net_errors.h" |
+#include "net/base/test_completion_callback.h" |
+#include "net/proxy/mock_proxy_script_fetcher.h" |
+#include "net/proxy/proxy_script_fetcher_impl.h" |
+#include "net/test/test_server.h" |
+#include "net/url_request/url_request_test_util.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace net { |
+ |
+namespace { |
+ |
+const char* const kPacUrl = "http://pacserver/script.pac"; |
+ |
+// In net/proxy/dhcp_proxy_script_fetcher_win_unittest.cc there are a few |
+// tests that exercise DhcpProxyScriptAdapterFetcher end-to-end along with |
+// DhcpProxyScriptFetcherWin, i.e. it tests the end-to-end usage of Win32 |
+// APIs and the network. In this file we test only by stubbing out |
+// functionality. |
+ |
+// Version of DhcpProxyScriptAdapterFetcher that mocks out dependencies |
+// to allow unit testing. |
+class MockDhcpProxyScriptAdapterFetcher |
+ : public DhcpProxyScriptAdapterFetcher { |
+ public: |
+ explicit MockDhcpProxyScriptAdapterFetcher(URLRequestContext* context) |
+ : DhcpProxyScriptAdapterFetcher(context), |
+ dhcp_delay_ms_(1), |
+ timeout_ms_(100), |
+ configured_url_(kPacUrl), |
+ fetcher_delay_ms_(1), |
+ fetcher_result_(OK), |
+ pac_script_("bingo") { |
+ } |
+ |
+ void Cancel() { |
+ DhcpProxyScriptAdapterFetcher::Cancel(); |
+ fetcher_ = NULL; |
+ } |
+ |
+ virtual ProxyScriptFetcher* ImplCreateScriptFetcher() OVERRIDE { |
+ // We don't maintain ownership of the fetcher, it is transferred to |
+ // the caller. |
+ fetcher_ = new MockProxyScriptFetcher(); |
+ if (fetcher_delay_ms_ != -1) { |
+ fetcher_timer_.Start( |
+ base::TimeDelta::FromMilliseconds(fetcher_delay_ms_), |
+ this, &MockDhcpProxyScriptAdapterFetcher::OnFetcherTimer); |
+ } |
+ return fetcher_; |
+ } |
+ |
+ class DelayingWorkerThread : public WorkerThread { |
+ public: |
+ explicit DelayingWorkerThread( |
+ const base::WeakPtr<DhcpProxyScriptAdapterFetcher>& owner) |
+ : WorkerThread(owner), |
+ test_finished_event_(true, false) { |
+ } |
+ |
+ std::string ImplGetPacURLFromDhcp( |
+ const std::string& adapter_name) OVERRIDE { |
+ PerfTimer timer; |
+ test_finished_event_.TimedWait(dhcp_delay_); |
+ return configured_url_; |
+ } |
+ |
+ base::WaitableEvent test_finished_event_; |
+ TimeDelta dhcp_delay_; |
+ std::string configured_url_; |
+ }; |
+ |
+ virtual WorkerThread* ImplCreateWorkerThread( |
+ const base::WeakPtr<DhcpProxyScriptAdapterFetcher>& owner) OVERRIDE { |
+ worker_thread_ = new DelayingWorkerThread(owner); |
+ worker_thread_->dhcp_delay_ = TimeDelta::FromMilliseconds(dhcp_delay_ms_); |
+ worker_thread_->configured_url_ = configured_url_; |
+ return worker_thread_; |
+ } |
+ |
+ // Use a shorter timeout so tests can finish more quickly. |
+ virtual base::TimeDelta ImplGetTimeout() const OVERRIDE { |
+ return base::TimeDelta::FromMilliseconds(timeout_ms_); |
+ } |
+ |
+ void OnFetcherTimer() { |
+ // Note that there is an assumption by this mock implementation that |
+ // DhcpProxyScriptAdapterFetcher::Fetch will call ImplCreateScriptFetcher |
+ // and call Fetch on the fetcher before the message loop is re-entered. |
+ // This holds true today, but if you hit this DCHECK the problem can |
+ // possibly be resolved by having a separate subclass of |
+ // MockProxyScriptFetcher that adds the delay internally (instead of |
+ // the simple approach currently used in ImplCreateScriptFetcher above). |
+ DCHECK(fetcher_ && fetcher_->has_pending_request()); |
+ fetcher_->NotifyFetchCompletion(fetcher_result_, pac_script_); |
+ fetcher_ = NULL; |
+ } |
+ |
+ bool IsWaitingForFetcher() const { |
+ return state_ == STATE_WAIT_URL; |
+ } |
+ |
+ bool WasCancelled() const { |
+ return state_ == STATE_CANCEL; |
+ } |
+ |
+ void FinishTest() { |
+ DCHECK(worker_thread_); |
+ worker_thread_->test_finished_event_.Signal(); |
+ } |
+ |
+ int dhcp_delay_ms_; |
+ int timeout_ms_; |
+ std::string configured_url_; |
+ int fetcher_delay_ms_; |
+ int fetcher_result_; |
+ std::string pac_script_; |
+ MockProxyScriptFetcher* fetcher_; |
+ base::OneShotTimer<MockDhcpProxyScriptAdapterFetcher> fetcher_timer_; |
+ scoped_refptr<DelayingWorkerThread> worker_thread_; |
+}; |
+ |
+class FetcherClient { |
+ public: |
+ FetcherClient() |
+ : url_request_context_(new TestURLRequestContext()), |
+ fetcher_( |
+ new MockDhcpProxyScriptAdapterFetcher(url_request_context_.get())) { |
+ } |
+ |
+ void WaitForResult(int expected_error) { |
+ EXPECT_EQ(expected_error, callback_.WaitForResult()); |
+ } |
+ |
+ void RunTest() { |
+ fetcher_->Fetch("adapter name", &callback_); |
+ } |
+ |
+ void FinishTestAllowCleanup() { |
+ fetcher_->FinishTest(); |
+ MessageLoop::current()->RunAllPending(); |
+ } |
+ |
+ TestCompletionCallback callback_; |
+ scoped_refptr<URLRequestContext> url_request_context_; |
+ scoped_ptr<MockDhcpProxyScriptAdapterFetcher> fetcher_; |
+ string16 pac_text_; |
+}; |
+ |
+TEST(DhcpProxyScriptAdapterFetcher, NormalCaseURLNotInDhcp) { |
+ FetcherClient client; |
+ client.fetcher_->configured_url_ = ""; |
+ client.RunTest(); |
+ client.WaitForResult(ERR_PAC_NOT_IN_DHCP); |
+ ASSERT_TRUE(client.fetcher_->DidFinish()); |
+ EXPECT_EQ(ERR_PAC_NOT_IN_DHCP, client.fetcher_->GetResult()); |
+ EXPECT_EQ(string16(L""), client.fetcher_->GetPacScript()); |
+} |
+ |
+TEST(DhcpProxyScriptAdapterFetcher, NormalCaseURLInDhcp) { |
+ FetcherClient client; |
+ client.RunTest(); |
+ client.WaitForResult(OK); |
+ ASSERT_TRUE(client.fetcher_->DidFinish()); |
+ EXPECT_EQ(OK, client.fetcher_->GetResult()); |
+ EXPECT_EQ(string16(L"bingo"), client.fetcher_->GetPacScript()); |
+ EXPECT_EQ(GURL(kPacUrl), client.fetcher_->GetPacURL()); |
+} |
+ |
+TEST(DhcpProxyScriptAdapterFetcher, TimeoutDuringDhcp) { |
+ // Does a Fetch() with a long enough delay on accessing DHCP that the |
+ // fetcher should time out. This is to test a case manual testing found, |
+ // where under certain circumstances (e.g. adapter enabled for DHCP and |
+ // needs to retrieve its configuration from DHCP, but no DHCP server |
+ // present on the network) accessing DHCP can take on the order of tens |
+ // of seconds. |
+ FetcherClient client; |
+ client.fetcher_->dhcp_delay_ms_ = 20 * 1000; |
+ client.fetcher_->timeout_ms_ = 25; |
+ |
+ PerfTimer timer; |
+ client.RunTest(); |
+ client.WaitForResult(ERR_TIMED_OUT); |
+ |
+ // The timeout should occur within about 25 ms, way before the 20s set as |
+ // the API delay above. |
+ ASSERT_GT(base::TimeDelta::FromMilliseconds(35), timer.Elapsed()); |
+ ASSERT_TRUE(client.fetcher_->DidFinish()); |
+ EXPECT_EQ(ERR_TIMED_OUT, client.fetcher_->GetResult()); |
+ EXPECT_EQ(string16(L""), client.fetcher_->GetPacScript()); |
+ EXPECT_EQ(GURL(), client.fetcher_->GetPacURL()); |
+ client.FinishTestAllowCleanup(); |
+} |
+ |
+TEST(DhcpProxyScriptAdapterFetcher, CancelWhileDhcp) { |
+ FetcherClient client; |
+ client.fetcher_->dhcp_delay_ms_ = 10; |
+ client.RunTest(); |
+ client.fetcher_->Cancel(); |
+ MessageLoop::current()->RunAllPending(); |
+ ASSERT_FALSE(client.fetcher_->DidFinish()); |
+ ASSERT_TRUE(client.fetcher_->WasCancelled()); |
+ EXPECT_EQ(ERR_ABORTED, client.fetcher_->GetResult()); |
+ EXPECT_EQ(string16(L""), client.fetcher_->GetPacScript()); |
+ EXPECT_EQ(GURL(), client.fetcher_->GetPacURL()); |
+ client.FinishTestAllowCleanup(); |
+} |
+ |
+TEST(DhcpProxyScriptAdapterFetcher, CancelWhileFetcher) { |
+ FetcherClient client; |
+ // This causes the mock fetcher not to pretend the |
+ // fetcher finishes after a timeout. |
+ client.fetcher_->fetcher_delay_ms_ = -1; |
+ client.RunTest(); |
+ int max_loops = 4; |
+ while (!client.fetcher_->IsWaitingForFetcher() && max_loops--) { |
+ base::PlatformThread::Sleep(10); |
+ MessageLoop::current()->RunAllPending(); |
+ } |
+ client.fetcher_->Cancel(); |
+ MessageLoop::current()->RunAllPending(); |
+ ASSERT_FALSE(client.fetcher_->DidFinish()); |
+ ASSERT_TRUE(client.fetcher_->WasCancelled()); |
+ EXPECT_EQ(ERR_ABORTED, client.fetcher_->GetResult()); |
+ EXPECT_EQ(string16(L""), client.fetcher_->GetPacScript()); |
+ // GetPacURL() still returns the URL fetched in this case. |
+ EXPECT_EQ(GURL(kPacUrl), client.fetcher_->GetPacURL()); |
+ client.FinishTestAllowCleanup(); |
+} |
+ |
+TEST(DhcpProxyScriptAdapterFetcher, CancelAtCompletion) { |
+ FetcherClient client; |
+ client.RunTest(); |
+ client.WaitForResult(OK); |
+ client.fetcher_->Cancel(); |
+ // Canceling after you're done should have no effect, so these |
+ // are identical expectations to the NormalCaseURLInDhcp test. |
+ ASSERT_TRUE(client.fetcher_->DidFinish()); |
+ EXPECT_EQ(OK, client.fetcher_->GetResult()); |
+ EXPECT_EQ(string16(L"bingo"), client.fetcher_->GetPacScript()); |
+ EXPECT_EQ(GURL(kPacUrl), client.fetcher_->GetPacURL()); |
+ client.FinishTestAllowCleanup(); |
+} |
+ |
+// Does a real fetch on a mock DHCP configuration. |
+class MockDhcpRealFetchProxyScriptAdapterFetcher |
+ : public MockDhcpProxyScriptAdapterFetcher { |
+ public: |
+ explicit MockDhcpRealFetchProxyScriptAdapterFetcher( |
+ URLRequestContext* context) |
+ : MockDhcpProxyScriptAdapterFetcher(context), |
+ url_request_context_(context) { |
+ } |
+ |
+ // Returns a real proxy script fetcher. |
+ ProxyScriptFetcher* ImplCreateScriptFetcher() OVERRIDE { |
+ ProxyScriptFetcher* fetcher = |
+ new ProxyScriptFetcherImpl(url_request_context_); |
+ return fetcher; |
+ } |
+ |
+ URLRequestContext* url_request_context_; |
+}; |
+ |
+TEST(DhcpProxyScriptAdapterFetcher, MockDhcpRealFetch) { |
+ TestServer test_server( |
+ TestServer::TYPE_HTTP, |
+ FilePath(FILE_PATH_LITERAL("net/data/proxy_script_fetcher_unittest"))); |
+ ASSERT_TRUE(test_server.Start()); |
+ |
+ GURL configured_url = test_server.GetURL("files/downloadable.pac"); |
+ |
+ FetcherClient client; |
+ scoped_refptr<URLRequestContext> url_request_context( |
+ new TestURLRequestContext()); |
+ client.fetcher_.reset( |
+ new MockDhcpRealFetchProxyScriptAdapterFetcher( |
+ url_request_context.get())); |
+ client.fetcher_->configured_url_ = configured_url.spec(); |
+ client.RunTest(); |
+ client.WaitForResult(OK); |
+ ASSERT_TRUE(client.fetcher_->DidFinish()); |
+ EXPECT_EQ(OK, client.fetcher_->GetResult()); |
+ EXPECT_EQ(string16(L"-downloadable.pac-\n"), client.fetcher_->GetPacScript()); |
+ EXPECT_EQ(configured_url, |
+ client.fetcher_->GetPacURL()); |
+} |
+ |
+} // namespace |
+ |
+} // namespace net |