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