Home | History | Annotate | Download | only in proxy
      1 // Copyright (c) 2012 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/compiler_specific.h"
      7 #include "base/files/file_util.h"
      8 #include "base/path_service.h"
      9 #include "base/strings/string_util.h"
     10 #include "base/test/perf_time_logger.h"
     11 #include "net/base/net_errors.h"
     12 #include "net/dns/mock_host_resolver.h"
     13 #include "net/proxy/proxy_info.h"
     14 #include "net/proxy/proxy_resolver_v8.h"
     15 #include "net/test/spawned_test_server/spawned_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_(
     89             net::SpawnedTestServer::TYPE_HTTP,
     90             net::SpawnedTestServer::kLocalhost,
     91             base::FilePath(
     92                 FILE_PATH_LITERAL("net/data/proxy_resolver_perftest"))) {
     93   }
     94 
     95   void RunAllTests() {
     96     ASSERT_TRUE(test_server_.Start());
     97     for (size_t i = 0; i < arraysize(kPerfTests); ++i) {
     98       const PacPerfTest& test_data = kPerfTests[i];
     99       RunTest(test_data.pac_name,
    100               test_data.queries,
    101               test_data.NumQueries());
    102     }
    103   }
    104 
    105  private:
    106   void RunTest(const std::string& script_name,
    107                const PacQuery* queries,
    108                int queries_len) {
    109     if (!resolver_->expects_pac_bytes()) {
    110       GURL pac_url =
    111           test_server_.GetURL(std::string("files/") + script_name);
    112       int rv = resolver_->SetPacScript(
    113           net::ProxyResolverScriptData::FromURL(pac_url),
    114           net::CompletionCallback());
    115       EXPECT_EQ(net::OK, rv);
    116     } else {
    117       LoadPacScriptIntoResolver(script_name);
    118     }
    119 
    120     // Do a query to warm things up. In the case of internal-fetch proxy
    121     // resolvers, the first resolve will be slow since it has to download
    122     // the PAC script.
    123     {
    124       net::ProxyInfo proxy_info;
    125       int result = resolver_->GetProxyForURL(
    126           GURL("http://www.warmup.com"), &proxy_info, net::CompletionCallback(),
    127           NULL, net::BoundNetLog());
    128       ASSERT_EQ(net::OK, result);
    129     }
    130 
    131     // Start the perf timer.
    132     std::string perf_test_name = resolver_name_ + "_" + script_name;
    133     base::PerfTimeLogger timer(perf_test_name.c_str());
    134 
    135     for (int i = 0; i < kNumIterations; ++i) {
    136       // Round-robin between URLs to resolve.
    137       const PacQuery& query = queries[i % queries_len];
    138 
    139       // Resolve.
    140       net::ProxyInfo proxy_info;
    141       int result = resolver_->GetProxyForURL(
    142           GURL(query.query_url), &proxy_info, net::CompletionCallback(), NULL,
    143           net::BoundNetLog());
    144 
    145       // Check that the result was correct. Note that ToPacString() and
    146       // ASSERT_EQ() are fast, so they won't skew the results.
    147       ASSERT_EQ(net::OK, result);
    148       ASSERT_EQ(query.expected_result, proxy_info.ToPacString());
    149     }
    150 
    151     // Print how long the test ran for.
    152     timer.Done();
    153   }
    154 
    155   // Read the PAC script from disk and initialize the proxy resolver with it.
    156   void LoadPacScriptIntoResolver(const std::string& script_name) {
    157     base::FilePath path;
    158     PathService::Get(base::DIR_SOURCE_ROOT, &path);
    159     path = path.AppendASCII("net");
    160     path = path.AppendASCII("data");
    161     path = path.AppendASCII("proxy_resolver_perftest");
    162     path = path.AppendASCII(script_name);
    163 
    164     // Try to read the file from disk.
    165     std::string file_contents;
    166     bool ok = base::ReadFileToString(path, &file_contents);
    167 
    168     // If we can't load the file from disk, something is misconfigured.
    169     LOG_IF(ERROR, !ok) << "Failed to read file: " << path.value();
    170     ASSERT_TRUE(ok);
    171 
    172     // Load the PAC script into the ProxyResolver.
    173     int rv = resolver_->SetPacScript(
    174         net::ProxyResolverScriptData::FromUTF8(file_contents),
    175         net::CompletionCallback());
    176     EXPECT_EQ(net::OK, rv);
    177   }
    178 
    179   net::ProxyResolver* resolver_;
    180   std::string resolver_name_;
    181   net::SpawnedTestServer test_server_;
    182 };
    183 
    184 #if defined(OS_WIN)
    185 TEST(ProxyResolverPerfTest, ProxyResolverWinHttp) {
    186   net::ProxyResolverWinHttp resolver;
    187   PacPerfSuiteRunner runner(&resolver, "ProxyResolverWinHttp");
    188   runner.RunAllTests();
    189 }
    190 #elif defined(OS_MACOSX)
    191 TEST(ProxyResolverPerfTest, ProxyResolverMac) {
    192   net::ProxyResolverMac resolver;
    193   PacPerfSuiteRunner runner(&resolver, "ProxyResolverMac");
    194   runner.RunAllTests();
    195 }
    196 #endif
    197 
    198 class MockJSBindings : public net::ProxyResolverV8::JSBindings {
    199  public:
    200   MockJSBindings() {}
    201 
    202   virtual void Alert(const base::string16& message) OVERRIDE {
    203     CHECK(false);
    204   }
    205 
    206   virtual bool ResolveDns(const std::string& host,
    207                           ResolveDnsOperation op,
    208                           std::string* output,
    209                           bool* terminate) OVERRIDE {
    210     CHECK(false);
    211     return false;
    212   }
    213 
    214   virtual void OnError(int line_number,
    215                        const base::string16& message) OVERRIDE {
    216     CHECK(false);
    217   }
    218 };
    219 
    220 TEST(ProxyResolverPerfTest, ProxyResolverV8) {
    221   net::ProxyResolverV8::EnsureIsolateCreated();
    222 
    223   MockJSBindings js_bindings;
    224   net::ProxyResolverV8 resolver;
    225   resolver.set_js_bindings(&js_bindings);
    226   PacPerfSuiteRunner runner(&resolver, "ProxyResolverV8");
    227   runner.RunAllTests();
    228 }
    229