Home | History | Annotate | Download | only in proxy
      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/perftimer.h"
      6 #include "net/base/mock_host_resolver.h"
      7 #include "net/proxy/proxy_resolver_js_bindings.h"
      8 #include "net/proxy/proxy_resolver_v8.h"
      9 #include "net/url_request/url_request_unittest.h"
     10 #include "testing/gtest/include/gtest/gtest.h"
     11 
     12 #if defined(OS_WIN)
     13 #include "net/proxy/proxy_resolver_winhttp.h"
     14 #elif defined(OS_MACOSX)
     15 #include "net/proxy/proxy_resolver_mac.h"
     16 #endif
     17 
     18 // This class holds the URL to use for resolving, and the expected result.
     19 // We track the expected result in order to make sure the performance
     20 // test is actually resolving URLs properly, otherwise the perf numbers
     21 // are meaningless :-)
     22 struct PacQuery {
     23   const char* query_url;
     24   const char* expected_result;
     25 };
     26 
     27 // Entry listing which PAC scripts to load, and which URLs to try resolving.
     28 // |queries| should be terminated by {NULL, NULL}. A sentinel is used
     29 // rather than a length, to simplify using initializer lists.
     30 struct PacPerfTest {
     31   const char* pac_name;
     32   PacQuery queries[100];
     33 
     34   // Returns the actual number of entries in |queries| (assumes NULL sentinel).
     35   int NumQueries() const;
     36 };
     37 
     38 // List of performance tests.
     39 static PacPerfTest kPerfTests[] = {
     40   // This test uses an ad-blocker PAC script. This script is very heavily
     41   // regular expression oriented, and has no dependencies on the current
     42   // IP address, or DNS resolving of hosts.
     43   { "no-ads.pac",
     44     { // queries:
     45       {"http://www.google.com", "DIRECT"},
     46       {"http://www.imdb.com/photos/cmsicons/x", "PROXY 0.0.0.0:3421"},
     47       {"http://www.imdb.com/x", "DIRECT"},
     48       {"http://www.staples.com/", "DIRECT"},
     49       {"http://www.staples.com/pixeltracker/x", "PROXY 0.0.0.0:3421"},
     50       {"http://www.staples.com/pixel/x", "DIRECT"},
     51       {"http://www.foobar.com", "DIRECT"},
     52       {"http://www.foobarbaz.com/x/y/z", "DIRECT"},
     53       {"http://www.testurl1.com/index.html", "DIRECT"},
     54       {"http://www.testurl2.com", "DIRECT"},
     55       {"https://www.sample/pirate/arrrrrr", "DIRECT"},
     56       {NULL, NULL}
     57     },
     58   },
     59 };
     60 
     61 int PacPerfTest::NumQueries() const {
     62   for (size_t i = 0; i < arraysize(queries); ++i) {
     63     if (queries[i].query_url == NULL)
     64       return i;
     65   }
     66   NOTREACHED();  // Bad definition.
     67   return 0;
     68 }
     69 
     70 // The number of URLs to resolve when testing a PAC script.
     71 const int kNumIterations = 500;
     72 
     73 // Helper class to run through all the performance tests using the specified
     74 // proxy resolver implementation.
     75 class PacPerfSuiteRunner {
     76  public:
     77   // |resolver_name| is the label used when logging the results.
     78   PacPerfSuiteRunner(net::ProxyResolver* resolver,
     79                      const std::string& resolver_name)
     80       : resolver_(resolver), resolver_name_(resolver_name) {
     81   }
     82 
     83   void RunAllTests() {
     84     for (size_t i = 0; i < arraysize(kPerfTests); ++i) {
     85       const PacPerfTest& test_data = kPerfTests[i];
     86       RunTest(test_data.pac_name,
     87               test_data.queries,
     88               test_data.NumQueries());
     89     }
     90   }
     91 
     92  private:
     93   void RunTest(const std::string& script_name,
     94                const PacQuery* queries,
     95                int queries_len) {
     96     if (!resolver_->expects_pac_bytes()) {
     97       InitHttpServer();
     98       GURL pac_url =
     99           server_->TestServerPage(std::string("files/") + script_name);
    100       int rv = resolver_->SetPacScriptByUrl(pac_url, NULL);
    101       EXPECT_EQ(net::OK, rv);
    102     } else {
    103       LoadPacScriptIntoResolver(script_name);
    104     }
    105 
    106     // Do a query to warm things up. In the case of internal-fetch proxy
    107     // resolvers, the first resolve will be slow since it has to download
    108     // the PAC script.
    109     {
    110       net::ProxyInfo proxy_info;
    111       int result = resolver_->GetProxyForURL(
    112           GURL("http://www.warmup.com"), &proxy_info, NULL, NULL, NULL);
    113       ASSERT_EQ(net::OK, result);
    114     }
    115 
    116     // Start the perf timer.
    117     std::string perf_test_name = resolver_name_ + "_" + script_name;
    118     PerfTimeLogger timer(perf_test_name.c_str());
    119 
    120     for (int i = 0; i < kNumIterations; ++i) {
    121       // Round-robin between URLs to resolve.
    122       const PacQuery& query = queries[i % queries_len];
    123 
    124       // Resolve.
    125       net::ProxyInfo proxy_info;
    126       int result = resolver_->GetProxyForURL(GURL(query.query_url),
    127                                              &proxy_info, NULL, NULL, NULL);
    128 
    129       // Check that the result was correct. Note that ToPacString() and
    130       // ASSERT_EQ() are fast, so they won't skew the results.
    131       ASSERT_EQ(net::OK, result);
    132       ASSERT_EQ(query.expected_result, proxy_info.ToPacString());
    133     }
    134 
    135     // Print how long the test ran for.
    136     timer.Done();
    137   }
    138 
    139   // Lazily startup an HTTP server (to serve the PAC script).
    140   void InitHttpServer() {
    141     DCHECK(!resolver_->expects_pac_bytes());
    142     if (!server_) {
    143       server_ = HTTPTestServer::CreateServer(
    144           L"net/data/proxy_resolver_perftest", NULL);
    145     }
    146     ASSERT_TRUE(server_.get() != NULL);
    147   }
    148 
    149   // Read the PAC script from disk and initialize the proxy resolver with it.
    150   void LoadPacScriptIntoResolver(const std::string& script_name) {
    151     FilePath path;
    152     PathService::Get(base::DIR_SOURCE_ROOT, &path);
    153     path = path.AppendASCII("net");
    154     path = path.AppendASCII("data");
    155     path = path.AppendASCII("proxy_resolver_perftest");
    156     path = path.AppendASCII(script_name);
    157 
    158     // Try to read the file from disk.
    159     std::string file_contents;
    160     bool ok = file_util::ReadFileToString(path, &file_contents);
    161 
    162     // If we can't load the file from disk, something is misconfigured.
    163     LOG_IF(ERROR, !ok) << "Failed to read file: " << path.value();
    164     ASSERT_TRUE(ok);
    165 
    166     // Load the PAC script into the ProxyResolver.
    167     int rv = resolver_->SetPacScriptByData(file_contents, NULL);
    168     EXPECT_EQ(net::OK, rv);
    169   }
    170 
    171   net::ProxyResolver* resolver_;
    172   std::string resolver_name_;
    173   scoped_refptr<HTTPTestServer> server_;
    174 };
    175 
    176 #if defined(OS_WIN)
    177 TEST(ProxyResolverPerfTest, ProxyResolverWinHttp) {
    178   net::ProxyResolverWinHttp resolver;
    179   PacPerfSuiteRunner runner(&resolver, "ProxyResolverWinHttp");
    180   runner.RunAllTests();
    181 }
    182 #elif defined(OS_MACOSX)
    183 TEST(ProxyResolverPerfTest, ProxyResolverMac) {
    184   net::ProxyResolverMac resolver;
    185   PacPerfSuiteRunner runner(&resolver, "ProxyResolverMac");
    186   runner.RunAllTests();
    187 }
    188 #endif
    189 
    190 TEST(ProxyResolverPerfTest, ProxyResolverV8) {
    191   net::ProxyResolverJSBindings* js_bindings =
    192       net::ProxyResolverJSBindings::CreateDefault(
    193           new net::MockHostResolver, NULL);
    194 
    195   net::ProxyResolverV8 resolver(js_bindings);
    196   PacPerfSuiteRunner runner(&resolver, "ProxyResolverV8");
    197   runner.RunAllTests();
    198 }
    199