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