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