| OLD | NEW |
| (Empty) |
| 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 <utility> | |
| 6 | |
| 7 #include "base/base_paths.h" | |
| 8 #include "base/compiler_specific.h" | |
| 9 #include "base/files/file_util.h" | |
| 10 #include "base/macros.h" | |
| 11 #include "base/message_loop/message_loop.h" | |
| 12 #include "base/path_service.h" | |
| 13 #include "base/strings/string_util.h" | |
| 14 #include "base/test/perf_time_logger.h" | |
| 15 #include "net/base/net_errors.h" | |
| 16 #include "net/dns/mock_host_resolver.h" | |
| 17 #include "net/log/net_log_with_source.h" | |
| 18 #include "net/proxy/proxy_info.h" | |
| 19 #include "net/proxy/proxy_resolver.h" | |
| 20 #include "net/proxy/proxy_resolver_factory.h" | |
| 21 #include "net/proxy/proxy_resolver_v8.h" | |
| 22 #include "net/test/embedded_test_server/embedded_test_server.h" | |
| 23 #include "net/test/gtest_util.h" | |
| 24 #include "testing/gmock/include/gmock/gmock.h" | |
| 25 #include "testing/gtest/include/gtest/gtest.h" | |
| 26 | |
| 27 #if defined(OS_WIN) | |
| 28 #include "net/proxy/proxy_resolver_winhttp.h" | |
| 29 #elif defined(OS_MACOSX) | |
| 30 #include "net/proxy/proxy_resolver_mac.h" | |
| 31 #endif | |
| 32 | |
| 33 using net::test::IsOk; | |
| 34 | |
| 35 namespace net { | |
| 36 | |
| 37 namespace { | |
| 38 | |
| 39 // This class holds the URL to use for resolving, and the expected result. | |
| 40 // We track the expected result in order to make sure the performance | |
| 41 // test is actually resolving URLs properly, otherwise the perf numbers | |
| 42 // are meaningless :-) | |
| 43 struct PacQuery { | |
| 44 const char* query_url; | |
| 45 const char* expected_result; | |
| 46 }; | |
| 47 | |
| 48 // Entry listing which PAC scripts to load, and which URLs to try resolving. | |
| 49 // |queries| should be terminated by {NULL, NULL}. A sentinel is used | |
| 50 // rather than a length, to simplify using initializer lists. | |
| 51 struct PacPerfTest { | |
| 52 const char* pac_name; | |
| 53 PacQuery queries[100]; | |
| 54 | |
| 55 // Returns the actual number of entries in |queries| (assumes NULL sentinel). | |
| 56 int NumQueries() const; | |
| 57 }; | |
| 58 | |
| 59 // List of performance tests. | |
| 60 static PacPerfTest kPerfTests[] = { | |
| 61 // This test uses an ad-blocker PAC script. This script is very heavily | |
| 62 // regular expression oriented, and has no dependencies on the current | |
| 63 // IP address, or DNS resolving of hosts. | |
| 64 { "no-ads.pac", | |
| 65 { // queries: | |
| 66 {"http://www.google.com", "DIRECT"}, | |
| 67 {"http://www.imdb.com/photos/cmsicons/x", "PROXY 0.0.0.0:3421"}, | |
| 68 {"http://www.imdb.com/x", "DIRECT"}, | |
| 69 {"http://www.staples.com/", "DIRECT"}, | |
| 70 {"http://www.staples.com/pixeltracker/x", "PROXY 0.0.0.0:3421"}, | |
| 71 {"http://www.staples.com/pixel/x", "DIRECT"}, | |
| 72 {"http://www.foobar.com", "DIRECT"}, | |
| 73 {"http://www.foobarbaz.com/x/y/z", "DIRECT"}, | |
| 74 {"http://www.testurl1.com/index.html", "DIRECT"}, | |
| 75 {"http://www.testurl2.com", "DIRECT"}, | |
| 76 {"https://www.sample/pirate/arrrrrr", "DIRECT"}, | |
| 77 {NULL, NULL} | |
| 78 }, | |
| 79 }, | |
| 80 }; | |
| 81 | |
| 82 int PacPerfTest::NumQueries() const { | |
| 83 for (size_t i = 0; i < arraysize(queries); ++i) { | |
| 84 if (queries[i].query_url == NULL) | |
| 85 return i; | |
| 86 } | |
| 87 NOTREACHED(); // Bad definition. | |
| 88 return 0; | |
| 89 } | |
| 90 | |
| 91 // The number of URLs to resolve when testing a PAC script. | |
| 92 const int kNumIterations = 500; | |
| 93 | |
| 94 // Helper class to run through all the performance tests using the specified | |
| 95 // proxy resolver implementation. | |
| 96 class PacPerfSuiteRunner { | |
| 97 public: | |
| 98 // |resolver_name| is the label used when logging the results. | |
| 99 PacPerfSuiteRunner(ProxyResolverFactory* factory, | |
| 100 const std::string& resolver_name) | |
| 101 : factory_(factory), resolver_name_(resolver_name) { | |
| 102 test_server_.ServeFilesFromSourceDirectory( | |
| 103 "net/data/proxy_resolver_perftest"); | |
| 104 } | |
| 105 | |
| 106 void RunAllTests() { | |
| 107 ASSERT_TRUE(test_server_.Start()); | |
| 108 for (size_t i = 0; i < arraysize(kPerfTests); ++i) { | |
| 109 const PacPerfTest& test_data = kPerfTests[i]; | |
| 110 RunTest(test_data.pac_name, | |
| 111 test_data.queries, | |
| 112 test_data.NumQueries()); | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 private: | |
| 117 void RunTest(const std::string& script_name, | |
| 118 const PacQuery* queries, | |
| 119 int queries_len) { | |
| 120 std::unique_ptr<ProxyResolver> resolver; | |
| 121 if (!factory_->expects_pac_bytes()) { | |
| 122 GURL pac_url = test_server_.GetURL(std::string("/") + script_name); | |
| 123 int rv = factory_->CreateProxyResolver( | |
| 124 ProxyResolverScriptData::FromURL(pac_url), &resolver, | |
| 125 CompletionCallback(), nullptr); | |
| 126 EXPECT_THAT(rv, IsOk()); | |
| 127 } else { | |
| 128 resolver = LoadPacScriptAndCreateResolver(script_name); | |
| 129 } | |
| 130 ASSERT_TRUE(resolver); | |
| 131 | |
| 132 // Do a query to warm things up. In the case of internal-fetch proxy | |
| 133 // resolvers, the first resolve will be slow since it has to download | |
| 134 // the PAC script. | |
| 135 { | |
| 136 ProxyInfo proxy_info; | |
| 137 int result = resolver->GetProxyForURL(GURL("http://www.warmup.com"), | |
| 138 &proxy_info, CompletionCallback(), | |
| 139 NULL, NetLogWithSource()); | |
| 140 ASSERT_THAT(result, IsOk()); | |
| 141 } | |
| 142 | |
| 143 // Start the perf timer. | |
| 144 std::string perf_test_name = resolver_name_ + "_" + script_name; | |
| 145 base::PerfTimeLogger timer(perf_test_name.c_str()); | |
| 146 | |
| 147 for (int i = 0; i < kNumIterations; ++i) { | |
| 148 // Round-robin between URLs to resolve. | |
| 149 const PacQuery& query = queries[i % queries_len]; | |
| 150 | |
| 151 // Resolve. | |
| 152 ProxyInfo proxy_info; | |
| 153 int result = resolver->GetProxyForURL(GURL(query.query_url), &proxy_info, | |
| 154 CompletionCallback(), NULL, | |
| 155 NetLogWithSource()); | |
| 156 | |
| 157 // Check that the result was correct. Note that ToPacString() and | |
| 158 // ASSERT_EQ() are fast, so they won't skew the results. | |
| 159 ASSERT_THAT(result, IsOk()); | |
| 160 ASSERT_EQ(query.expected_result, proxy_info.ToPacString()); | |
| 161 } | |
| 162 | |
| 163 // Print how long the test ran for. | |
| 164 timer.Done(); | |
| 165 } | |
| 166 | |
| 167 // Read the PAC script from disk and initialize the proxy resolver with it. | |
| 168 std::unique_ptr<ProxyResolver> LoadPacScriptAndCreateResolver( | |
| 169 const std::string& script_name) { | |
| 170 base::FilePath path; | |
| 171 PathService::Get(base::DIR_SOURCE_ROOT, &path); | |
| 172 path = path.AppendASCII("net"); | |
| 173 path = path.AppendASCII("data"); | |
| 174 path = path.AppendASCII("proxy_resolver_perftest"); | |
| 175 path = path.AppendASCII(script_name); | |
| 176 | |
| 177 // Try to read the file from disk. | |
| 178 std::string file_contents; | |
| 179 bool ok = base::ReadFileToString(path, &file_contents); | |
| 180 | |
| 181 // If we can't load the file from disk, something is misconfigured. | |
| 182 LOG_IF(ERROR, !ok) << "Failed to read file: " << path.value(); | |
| 183 if (!ok) | |
| 184 return nullptr; | |
| 185 | |
| 186 // Load the PAC script into the ProxyResolver. | |
| 187 std::unique_ptr<ProxyResolver> resolver; | |
| 188 int rv = factory_->CreateProxyResolver( | |
| 189 ProxyResolverScriptData::FromUTF8(file_contents), &resolver, | |
| 190 CompletionCallback(), nullptr); | |
| 191 EXPECT_THAT(rv, IsOk()); | |
| 192 return resolver; | |
| 193 } | |
| 194 | |
| 195 ProxyResolverFactory* factory_; | |
| 196 std::string resolver_name_; | |
| 197 EmbeddedTestServer test_server_; | |
| 198 }; | |
| 199 | |
| 200 #if defined(OS_WIN) | |
| 201 TEST(ProxyResolverPerfTest, ProxyResolverWinHttp) { | |
| 202 ProxyResolverFactoryWinHttp factory; | |
| 203 PacPerfSuiteRunner runner(&factory, "ProxyResolverWinHttp"); | |
| 204 runner.RunAllTests(); | |
| 205 } | |
| 206 #elif defined(OS_MACOSX) | |
| 207 TEST(ProxyResolverPerfTest, ProxyResolverMac) { | |
| 208 ProxyResolverFactoryMac factory; | |
| 209 PacPerfSuiteRunner runner(&factory, "ProxyResolverMac"); | |
| 210 runner.RunAllTests(); | |
| 211 } | |
| 212 #endif | |
| 213 | |
| 214 class MockJSBindings : public ProxyResolverV8::JSBindings { | |
| 215 public: | |
| 216 MockJSBindings() {} | |
| 217 | |
| 218 void Alert(const base::string16& message) override { CHECK(false); } | |
| 219 | |
| 220 bool ResolveDns(const std::string& host, | |
| 221 ResolveDnsOperation op, | |
| 222 std::string* output, | |
| 223 bool* terminate) override { | |
| 224 CHECK(false); | |
| 225 return false; | |
| 226 } | |
| 227 | |
| 228 void OnError(int line_number, const base::string16& message) override { | |
| 229 CHECK(false); | |
| 230 } | |
| 231 }; | |
| 232 | |
| 233 class ProxyResolverV8Wrapper : public ProxyResolver { | |
| 234 public: | |
| 235 ProxyResolverV8Wrapper(std::unique_ptr<ProxyResolverV8> resolver, | |
| 236 std::unique_ptr<MockJSBindings> bindings) | |
| 237 : resolver_(std::move(resolver)), bindings_(std::move(bindings)) {} | |
| 238 | |
| 239 int GetProxyForURL(const GURL& url, | |
| 240 ProxyInfo* results, | |
| 241 const CompletionCallback& /*callback*/, | |
| 242 std::unique_ptr<Request>* /*request*/, | |
| 243 const NetLogWithSource& net_log) override { | |
| 244 return resolver_->GetProxyForURL(url, results, bindings_.get()); | |
| 245 } | |
| 246 | |
| 247 private: | |
| 248 std::unique_ptr<ProxyResolverV8> resolver_; | |
| 249 std::unique_ptr<MockJSBindings> bindings_; | |
| 250 | |
| 251 DISALLOW_COPY_AND_ASSIGN(ProxyResolverV8Wrapper); | |
| 252 }; | |
| 253 | |
| 254 class ProxyResolverV8Factory : public ProxyResolverFactory { | |
| 255 public: | |
| 256 ProxyResolverV8Factory() : ProxyResolverFactory(true) {} | |
| 257 int CreateProxyResolver( | |
| 258 const scoped_refptr<ProxyResolverScriptData>& pac_script, | |
| 259 std::unique_ptr<ProxyResolver>* resolver, | |
| 260 const net::CompletionCallback& callback, | |
| 261 std::unique_ptr<Request>* request) override { | |
| 262 std::unique_ptr<ProxyResolverV8> v8_resolver; | |
| 263 std::unique_ptr<MockJSBindings> js_bindings_(new MockJSBindings); | |
| 264 int result = | |
| 265 ProxyResolverV8::Create(pac_script, js_bindings_.get(), &v8_resolver); | |
| 266 if (result == OK) { | |
| 267 resolver->reset(new ProxyResolverV8Wrapper(std::move(v8_resolver), | |
| 268 std::move(js_bindings_))); | |
| 269 } | |
| 270 return result; | |
| 271 } | |
| 272 | |
| 273 private: | |
| 274 DISALLOW_COPY_AND_ASSIGN(ProxyResolverV8Factory); | |
| 275 }; | |
| 276 | |
| 277 TEST(ProxyResolverPerfTest, ProxyResolverV8) { | |
| 278 base::MessageLoop message_loop; | |
| 279 ProxyResolverV8Factory factory; | |
| 280 PacPerfSuiteRunner runner(&factory, "ProxyResolverV8"); | |
| 281 runner.RunAllTests(); | |
| 282 } | |
| 283 | |
| 284 } // namespace | |
| 285 | |
| 286 } // namespace net | |
| OLD | NEW |