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
NumQueries() const67 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.
PacPerfSuiteRunner(net::ProxyResolver * resolver,const std::string & resolver_name)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
RunAllTests()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:
RunTest(const std::string & script_name,const PacQuery * queries,int queries_len)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.
LoadPacScriptIntoResolver(const std::string & script_name)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)
TEST(ProxyResolverPerfTest,ProxyResolverWinHttp)180 TEST(ProxyResolverPerfTest, ProxyResolverWinHttp) {
181 net::ProxyResolverWinHttp resolver;
182 PacPerfSuiteRunner runner(&resolver, "ProxyResolverWinHttp");
183 runner.RunAllTests();
184 }
185 #elif defined(OS_MACOSX)
TEST(ProxyResolverPerfTest,ProxyResolverMac)186 TEST(ProxyResolverPerfTest, ProxyResolverMac) {
187 net::ProxyResolverMac resolver;
188 PacPerfSuiteRunner runner(&resolver, "ProxyResolverMac");
189 runner.RunAllTests();
190 }
191 #endif
192
TEST(ProxyResolverPerfTest,ProxyResolverV8)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