1bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant// Use of this source code is governed by a BSD-style license that can be
3f5256e16dfc425c1d466f6308d4026d529ce9e0bHoward Hinnant// found in the LICENSE file.
4bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
5b64f8b07c104c6cc986570ac8ee0ed16a9f23976Howard Hinnant#include "net/proxy/proxy_resolver_v8_tracing.h"
6b64f8b07c104c6cc986570ac8ee0ed16a9f23976Howard Hinnant
7bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "base/files/file_util.h"
8bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "base/message_loop/message_loop.h"
9bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "base/path_service.h"
10bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "base/stl_util.h"
11bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "base/strings/string_util.h"
12bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "base/strings/stringprintf.h"
13bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "base/strings/utf_string_conversions.h"
14bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "base/synchronization/waitable_event.h"
15bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "base/threading/platform_thread.h"
16bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "base/values.h"
17bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "net/base/net_errors.h"
18bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "net/base/net_log.h"
19bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "net/base/net_log_unittest.h"
20bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "net/base/test_completion_callback.h"
21bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "net/dns/host_cache.h"
22bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "net/dns/mock_host_resolver.h"
23bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "net/proxy/proxy_info.h"
24bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "net/proxy/proxy_resolver_error_observer.h"
25bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "testing/gtest/include/gtest/gtest.h"
26bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant#include "url/gurl.h"
27bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
28bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantnamespace net {
29bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant
30bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnantnamespace {
31ac6de546bd30d11eba9b1be40f7dc21cda6fa029Howard Hinnant
32ac6de546bd30d11eba9b1be40f7dc21cda6fa029Howard Hinnantclass ProxyResolverV8TracingTest : public testing::Test {
33ac6de546bd30d11eba9b1be40f7dc21cda6fa029Howard Hinnant public:
34ac6de546bd30d11eba9b1be40f7dc21cda6fa029Howard Hinnant  virtual void TearDown() OVERRIDE {
35ac6de546bd30d11eba9b1be40f7dc21cda6fa029Howard Hinnant    // Drain any pending messages, which may be left over from cancellation.
36ac6de546bd30d11eba9b1be40f7dc21cda6fa029Howard Hinnant    // This way they get reliably run as part of the current test, rather than
37ac6de546bd30d11eba9b1be40f7dc21cda6fa029Howard Hinnant    // spilling into the next test's execution.
38ac6de546bd30d11eba9b1be40f7dc21cda6fa029Howard Hinnant    base::MessageLoop::current()->RunUntilIdle();
39ac6de546bd30d11eba9b1be40f7dc21cda6fa029Howard Hinnant  }
40ac6de546bd30d11eba9b1be40f7dc21cda6fa029Howard Hinnant};
41ac6de546bd30d11eba9b1be40f7dc21cda6fa029Howard Hinnant
42ac6de546bd30d11eba9b1be40f7dc21cda6fa029Howard Hinnantscoped_refptr<ProxyResolverScriptData> LoadScriptData(const char* filename) {
43ac6de546bd30d11eba9b1be40f7dc21cda6fa029Howard Hinnant  base::FilePath path;
44ac6de546bd30d11eba9b1be40f7dc21cda6fa029Howard Hinnant  PathService::Get(base::DIR_SOURCE_ROOT, &path);
45bc8d3f97eb5c958007f2713238472e0c1c8fe02Howard Hinnant  path = path.AppendASCII("net");
46  path = path.AppendASCII("data");
47  path = path.AppendASCII("proxy_resolver_v8_tracing_unittest");
48  path = path.AppendASCII(filename);
49
50  // Try to read the file from disk.
51  std::string file_contents;
52  bool ok = base::ReadFileToString(path, &file_contents);
53
54  // If we can't load the file from disk, something is misconfigured.
55  EXPECT_TRUE(ok) << "Failed to read file: " << path.value();
56
57  // Load the PAC script into the ProxyResolver.
58  return ProxyResolverScriptData::FromUTF8(file_contents);
59}
60
61void InitResolver(ProxyResolverV8Tracing* resolver, const char* filename) {
62  TestCompletionCallback callback;
63  int rv =
64      resolver->SetPacScript(LoadScriptData(filename), callback.callback());
65  EXPECT_EQ(ERR_IO_PENDING, rv);
66  EXPECT_EQ(OK, callback.WaitForResult());
67}
68
69class MockErrorObserver : public ProxyResolverErrorObserver {
70 public:
71  MockErrorObserver() : event_(true, false) {}
72
73  virtual void OnPACScriptError(int line_number,
74                                const base::string16& error) OVERRIDE {
75    {
76      base::AutoLock l(lock_);
77      output += base::StringPrintf("Error: line %d: %s\n", line_number,
78                                   base::UTF16ToASCII(error).c_str());
79    }
80    event_.Signal();
81  }
82
83  std::string GetOutput() {
84    base::AutoLock l(lock_);
85    return output;
86  }
87
88  void WaitForOutput() {
89    event_.Wait();
90  }
91
92 private:
93  base::Lock lock_;
94  std::string output;
95
96  base::WaitableEvent event_;
97};
98
99TEST_F(ProxyResolverV8TracingTest, Simple) {
100  CapturingNetLog log;
101  CapturingBoundNetLog request_log;
102  MockCachingHostResolver host_resolver;
103  MockErrorObserver* error_observer = new MockErrorObserver;
104  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
105
106  InitResolver(&resolver, "simple.js");
107
108  TestCompletionCallback callback;
109  ProxyInfo proxy_info;
110
111  int rv = resolver.GetProxyForURL(
112      GURL("http://foo/"), &proxy_info, callback.callback(),
113      NULL, request_log.bound());
114
115  EXPECT_EQ(ERR_IO_PENDING, rv);
116  EXPECT_EQ(OK, callback.WaitForResult());
117
118  EXPECT_EQ("foo:99", proxy_info.proxy_server().ToURI());
119
120  EXPECT_EQ(0u, host_resolver.num_resolve());
121
122  // There were no errors.
123  EXPECT_EQ("", error_observer->GetOutput());
124
125  // Check the NetLogs -- nothing was logged.
126  EXPECT_EQ(0u, log.GetSize());
127  EXPECT_EQ(0u, request_log.GetSize());
128}
129
130TEST_F(ProxyResolverV8TracingTest, JavascriptError) {
131  CapturingNetLog log;
132  CapturingBoundNetLog request_log;
133  MockCachingHostResolver host_resolver;
134  MockErrorObserver* error_observer = new MockErrorObserver;
135  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
136
137  InitResolver(&resolver, "error.js");
138
139  TestCompletionCallback callback;
140  ProxyInfo proxy_info;
141
142  int rv = resolver.GetProxyForURL(
143      GURL("http://throw-an-error/"), &proxy_info, callback.callback(), NULL,
144      request_log.bound());
145
146  EXPECT_EQ(ERR_IO_PENDING, rv);
147  EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult());
148
149  EXPECT_EQ(0u, host_resolver.num_resolve());
150
151  EXPECT_EQ("Error: line 5: Uncaught TypeError: Cannot read property 'split' "
152            "of null\n", error_observer->GetOutput());
153
154  // Check the NetLogs -- there was 1 alert and 1 javascript error, and they
155  // were output to both the global log, and per-request log.
156  CapturingNetLog::CapturedEntryList entries_list[2];
157  log.GetEntries(&entries_list[0]);
158  request_log.GetEntries(&entries_list[1]);
159
160  for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
161    const CapturingNetLog::CapturedEntryList& entries = entries_list[list_i];
162    EXPECT_EQ(2u, entries.size());
163    EXPECT_TRUE(
164        LogContainsEvent(entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
165                         NetLog::PHASE_NONE));
166    EXPECT_TRUE(
167        LogContainsEvent(entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_ERROR,
168                         NetLog::PHASE_NONE));
169
170    EXPECT_EQ("{\"message\":\"Prepare to DIE!\"}", entries[0].GetParamsJson());
171    EXPECT_EQ("{\"line_number\":5,\"message\":\"Uncaught TypeError: Cannot "
172              "read property 'split' of null\"}", entries[1].GetParamsJson());
173  }
174}
175
176TEST_F(ProxyResolverV8TracingTest, TooManyAlerts) {
177  CapturingNetLog log;
178  CapturingBoundNetLog request_log;
179  MockCachingHostResolver host_resolver;
180  MockErrorObserver* error_observer = new MockErrorObserver;
181  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
182
183  InitResolver(&resolver, "too_many_alerts.js");
184
185  TestCompletionCallback callback;
186  ProxyInfo proxy_info;
187
188  int rv = resolver.GetProxyForURL(
189      GURL("http://foo/"),
190      &proxy_info,
191      callback.callback(),
192      NULL,
193      request_log.bound());
194
195  EXPECT_EQ(ERR_IO_PENDING, rv);
196  EXPECT_EQ(OK, callback.WaitForResult());
197
198  // Iteration1 does a DNS resolve
199  // Iteration2 exceeds the alert buffer
200  // Iteration3 runs in blocking mode and completes
201  EXPECT_EQ("foo:3", proxy_info.proxy_server().ToURI());
202
203  EXPECT_EQ(1u, host_resolver.num_resolve());
204
205  // No errors.
206  EXPECT_EQ("", error_observer->GetOutput());
207
208  // Check the NetLogs -- the script generated 50 alerts, which were mirrored
209  // to both the global and per-request logs.
210  CapturingNetLog::CapturedEntryList entries_list[2];
211  log.GetEntries(&entries_list[0]);
212  request_log.GetEntries(&entries_list[1]);
213
214  for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
215    const CapturingNetLog::CapturedEntryList& entries = entries_list[list_i];
216    EXPECT_EQ(50u, entries.size());
217    for (size_t i = 0; i < entries.size(); ++i) {
218      ASSERT_TRUE(
219          LogContainsEvent(entries, i, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
220                           NetLog::PHASE_NONE));
221    }
222  }
223}
224
225// Verify that buffered alerts cannot grow unboundedly, even when the message is
226// empty string.
227TEST_F(ProxyResolverV8TracingTest, TooManyEmptyAlerts) {
228  CapturingNetLog log;
229  CapturingBoundNetLog request_log;
230  MockCachingHostResolver host_resolver;
231  MockErrorObserver* error_observer = new MockErrorObserver;
232  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
233
234  InitResolver(&resolver, "too_many_empty_alerts.js");
235
236  TestCompletionCallback callback;
237  ProxyInfo proxy_info;
238
239  int rv = resolver.GetProxyForURL(
240      GURL("http://foo/"),
241      &proxy_info,
242      callback.callback(),
243      NULL,
244      request_log.bound());
245
246  EXPECT_EQ(ERR_IO_PENDING, rv);
247  EXPECT_EQ(OK, callback.WaitForResult());
248
249  EXPECT_EQ("foo:3", proxy_info.proxy_server().ToURI());
250
251  EXPECT_EQ(1u, host_resolver.num_resolve());
252
253  // No errors.
254  EXPECT_EQ("", error_observer->GetOutput());
255
256  // Check the NetLogs -- the script generated 50 alerts, which were mirrored
257  // to both the global and per-request logs.
258  CapturingNetLog::CapturedEntryList entries_list[2];
259  log.GetEntries(&entries_list[0]);
260  request_log.GetEntries(&entries_list[1]);
261
262  for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
263    const CapturingNetLog::CapturedEntryList& entries = entries_list[list_i];
264    EXPECT_EQ(1000u, entries.size());
265    for (size_t i = 0; i < entries.size(); ++i) {
266      ASSERT_TRUE(
267          LogContainsEvent(entries, i, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
268                           NetLog::PHASE_NONE));
269    }
270  }
271}
272
273// This test runs a PAC script that issues a sequence of DNS resolves. The test
274// verifies the final result, and that the underlying DNS resolver received
275// the correct set of queries.
276TEST_F(ProxyResolverV8TracingTest, Dns) {
277  CapturingNetLog log;
278  CapturingBoundNetLog request_log;
279  MockCachingHostResolver host_resolver;
280  MockErrorObserver* error_observer = new MockErrorObserver;
281  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
282
283  host_resolver.rules()->AddRuleForAddressFamily(
284      "host1", ADDRESS_FAMILY_IPV4, "166.155.144.44");
285  host_resolver.rules()
286      ->AddIPLiteralRule("host1", "::1,192.168.1.1", std::string());
287  host_resolver.rules()->AddSimulatedFailure("host2");
288  host_resolver.rules()->AddRule("host3", "166.155.144.33");
289  host_resolver.rules()->AddRule("host5", "166.155.144.55");
290  host_resolver.rules()->AddSimulatedFailure("host6");
291  host_resolver.rules()->AddRuleForAddressFamily(
292      "*", ADDRESS_FAMILY_IPV4, "122.133.144.155");
293  host_resolver.rules()->AddRule("*", "133.122.100.200");
294
295  InitResolver(&resolver, "dns.js");
296
297  TestCompletionCallback callback;
298  ProxyInfo proxy_info;
299
300  int rv = resolver.GetProxyForURL(
301      GURL("http://foo/"),
302      &proxy_info,
303      callback.callback(),
304      NULL,
305      request_log.bound());
306
307  EXPECT_EQ(ERR_IO_PENDING, rv);
308  EXPECT_EQ(OK, callback.WaitForResult());
309
310  // The test does 13 DNS resolution, however only 7 of them are unique.
311  EXPECT_EQ(7u, host_resolver.num_resolve());
312
313  const char* kExpectedResult =
314    "122.133.144.155-"  // myIpAddress()
315    "null-"  // dnsResolve('')
316    "__1_192.168.1.1-"  // dnsResolveEx('host1')
317    "null-"  // dnsResolve('host2')
318    "166.155.144.33-"  // dnsResolve('host3')
319    "122.133.144.155-"  // myIpAddress()
320    "166.155.144.33-"  // dnsResolve('host3')
321    "__1_192.168.1.1-"  // dnsResolveEx('host1')
322    "122.133.144.155-"  // myIpAddress()
323    "null-"  // dnsResolve('host2')
324    "-"  // dnsResolveEx('host6')
325    "133.122.100.200-"  // myIpAddressEx()
326    "166.155.144.44"  // dnsResolve('host1')
327    ":99";
328
329  EXPECT_EQ(kExpectedResult, proxy_info.proxy_server().ToURI());
330
331  // No errors.
332  EXPECT_EQ("", error_observer->GetOutput());
333
334  // Check the NetLogs -- the script generated 1 alert, mirrored to both
335  // the per-request and global logs.
336  CapturingNetLog::CapturedEntryList entries_list[2];
337  log.GetEntries(&entries_list[0]);
338  request_log.GetEntries(&entries_list[1]);
339
340  for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
341    const CapturingNetLog::CapturedEntryList& entries = entries_list[list_i];
342    EXPECT_EQ(1u, entries.size());
343    EXPECT_TRUE(
344        LogContainsEvent(entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
345                         NetLog::PHASE_NONE));
346    EXPECT_EQ("{\"message\":\"iteration: 7\"}", entries[0].GetParamsJson());
347  }
348}
349
350// This test runs a PAC script that does "myIpAddress()" followed by
351// "dnsResolve()". This requires 2 restarts. However once the HostResolver's
352// cache is warmed, subsequent calls should take 0 restarts.
353TEST_F(ProxyResolverV8TracingTest, DnsChecksCache) {
354  CapturingNetLog log;
355  CapturingBoundNetLog request_log;
356  MockCachingHostResolver host_resolver;
357  MockErrorObserver* error_observer = new MockErrorObserver;
358  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
359
360  host_resolver.rules()->AddRule("foopy", "166.155.144.11");
361  host_resolver.rules()->AddRule("*", "122.133.144.155");
362
363  InitResolver(&resolver, "simple_dns.js");
364
365  TestCompletionCallback callback1;
366  TestCompletionCallback callback2;
367  ProxyInfo proxy_info;
368
369  int rv = resolver.GetProxyForURL(
370      GURL("http://foopy/req1"),
371      &proxy_info,
372      callback1.callback(),
373      NULL,
374      request_log.bound());
375
376  EXPECT_EQ(ERR_IO_PENDING, rv);
377  EXPECT_EQ(OK, callback1.WaitForResult());
378
379  // The test does 2 DNS resolutions.
380  EXPECT_EQ(2u, host_resolver.num_resolve());
381
382  // The first request took 2 restarts, hence on g_iteration=3.
383  EXPECT_EQ("166.155.144.11:3", proxy_info.proxy_server().ToURI());
384
385  rv = resolver.GetProxyForURL(
386      GURL("http://foopy/req2"),
387      &proxy_info,
388      callback2.callback(),
389      NULL,
390      request_log.bound());
391
392  EXPECT_EQ(ERR_IO_PENDING, rv);
393  EXPECT_EQ(OK, callback2.WaitForResult());
394
395  EXPECT_EQ(4u, host_resolver.num_resolve());
396
397  // This time no restarts were required, so g_iteration incremented by 1.
398  EXPECT_EQ("166.155.144.11:4", proxy_info.proxy_server().ToURI());
399
400  // No errors.
401  EXPECT_EQ("", error_observer->GetOutput());
402
403  EXPECT_EQ(0u, log.GetSize());
404  EXPECT_EQ(0u, request_log.GetSize());
405}
406
407// This test runs a weird PAC script that was designed to defeat the DNS tracing
408// optimization. The proxy resolver should detect the inconsistency and
409// fall-back to synchronous mode execution.
410TEST_F(ProxyResolverV8TracingTest, FallBackToSynchronous1) {
411  CapturingNetLog log;
412  CapturingBoundNetLog request_log;
413  MockCachingHostResolver host_resolver;
414  MockErrorObserver* error_observer = new MockErrorObserver;
415  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
416
417  host_resolver.rules()->AddRule("host1", "166.155.144.11");
418  host_resolver.rules()->AddRule("crazy4", "133.199.111.4");
419  host_resolver.rules()->AddRule("*", "122.133.144.155");
420
421  InitResolver(&resolver, "global_sideffects1.js");
422
423  TestCompletionCallback callback;
424  ProxyInfo proxy_info;
425
426  int rv = resolver.GetProxyForURL(
427      GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
428      request_log.bound());
429  EXPECT_EQ(ERR_IO_PENDING, rv);
430  EXPECT_EQ(OK, callback.WaitForResult());
431
432  // The script itself only does 2 DNS resolves per execution, however it
433  // constructs the hostname using a global counter which changes on each
434  // invocation.
435  EXPECT_EQ(3u, host_resolver.num_resolve());
436
437  EXPECT_EQ("166.155.144.11-133.199.111.4:100",
438            proxy_info.proxy_server().ToURI());
439
440  // No errors.
441  EXPECT_EQ("", error_observer->GetOutput());
442
443  // Check the NetLogs -- the script generated 1 alert, mirrored to both
444  // the per-request and global logs.
445  CapturingNetLog::CapturedEntryList entries_list[2];
446  log.GetEntries(&entries_list[0]);
447  request_log.GetEntries(&entries_list[1]);
448
449  for (size_t list_i = 0; list_i < arraysize(entries_list); list_i++) {
450    const CapturingNetLog::CapturedEntryList& entries = entries_list[list_i];
451    EXPECT_EQ(1u, entries.size());
452    EXPECT_TRUE(
453        LogContainsEvent(entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
454                         NetLog::PHASE_NONE));
455    EXPECT_EQ("{\"message\":\"iteration: 4\"}", entries[0].GetParamsJson());
456  }
457}
458
459// This test runs a weird PAC script that was designed to defeat the DNS tracing
460// optimization. The proxy resolver should detect the inconsistency and
461// fall-back to synchronous mode execution.
462TEST_F(ProxyResolverV8TracingTest, FallBackToSynchronous2) {
463  CapturingNetLog log;
464  CapturingBoundNetLog request_log;
465  MockCachingHostResolver host_resolver;
466  MockErrorObserver* error_observer = new MockErrorObserver;
467  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
468
469  host_resolver.rules()->AddRule("host1", "166.155.144.11");
470  host_resolver.rules()->AddRule("host2", "166.155.144.22");
471  host_resolver.rules()->AddRule("host3", "166.155.144.33");
472  host_resolver.rules()->AddRule("host4", "166.155.144.44");
473  host_resolver.rules()->AddRule("*", "122.133.144.155");
474
475  InitResolver(&resolver, "global_sideffects2.js");
476
477  TestCompletionCallback callback;
478  ProxyInfo proxy_info;
479
480  int rv = resolver.GetProxyForURL(
481      GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
482      request_log.bound());
483  EXPECT_EQ(ERR_IO_PENDING, rv);
484  EXPECT_EQ(OK, callback.WaitForResult());
485
486  EXPECT_EQ(3u, host_resolver.num_resolve());
487
488  EXPECT_EQ("166.155.144.44:100", proxy_info.proxy_server().ToURI());
489
490  // No errors.
491  EXPECT_EQ("", error_observer->GetOutput());
492
493  // Check the NetLogs -- nothing was logged.
494  EXPECT_EQ(0u, log.GetSize());
495  EXPECT_EQ(0u, request_log.GetSize());
496}
497
498// This test runs a weird PAC script that yields a never ending sequence
499// of DNS resolves when restarting. Running it will hit the maximum
500// DNS resolves per request limit (20) after which every DNS resolve will
501// fail.
502TEST_F(ProxyResolverV8TracingTest, InfiniteDNSSequence) {
503  CapturingNetLog log;
504  CapturingBoundNetLog request_log;
505  MockCachingHostResolver host_resolver;
506  MockErrorObserver* error_observer = new MockErrorObserver;
507  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
508
509  host_resolver.rules()->AddRule("host*", "166.155.144.11");
510  host_resolver.rules()->AddRule("*", "122.133.144.155");
511
512  InitResolver(&resolver, "global_sideffects3.js");
513
514  TestCompletionCallback callback;
515  ProxyInfo proxy_info;
516
517  int rv = resolver.GetProxyForURL(
518      GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
519      request_log.bound());
520  EXPECT_EQ(ERR_IO_PENDING, rv);
521  EXPECT_EQ(OK, callback.WaitForResult());
522
523  EXPECT_EQ(20u, host_resolver.num_resolve());
524
525  EXPECT_EQ(
526      "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
527      "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
528      "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
529      "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
530      "166.155.144.11-166.155.144.11-166.155.144.11-166.155.144.11-"
531      "null:21", proxy_info.proxy_server().ToURI());
532
533  // No errors.
534  EXPECT_EQ("", error_observer->GetOutput());
535
536  // Check the NetLogs -- 1 alert was logged.
537  EXPECT_EQ(1u, log.GetSize());
538  EXPECT_EQ(1u, request_log.GetSize());
539}
540
541// This test runs a weird PAC script that yields a never ending sequence
542// of DNS resolves when restarting. Running it will hit the maximum
543// DNS resolves per request limit (20) after which every DNS resolve will
544// fail.
545TEST_F(ProxyResolverV8TracingTest, InfiniteDNSSequence2) {
546  CapturingNetLog log;
547  CapturingBoundNetLog request_log;
548  MockCachingHostResolver host_resolver;
549  MockErrorObserver* error_observer = new MockErrorObserver;
550  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
551
552  host_resolver.rules()->AddRule("host*", "166.155.144.11");
553  host_resolver.rules()->AddRule("*", "122.133.144.155");
554
555  InitResolver(&resolver, "global_sideffects4.js");
556
557  TestCompletionCallback callback;
558  ProxyInfo proxy_info;
559
560  int rv = resolver.GetProxyForURL(
561      GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
562      request_log.bound());
563  EXPECT_EQ(ERR_IO_PENDING, rv);
564  EXPECT_EQ(OK, callback.WaitForResult());
565
566  EXPECT_EQ(20u, host_resolver.num_resolve());
567
568  EXPECT_EQ("null21:34", proxy_info.proxy_server().ToURI());
569
570  // No errors.
571  EXPECT_EQ("", error_observer->GetOutput());
572
573  // Check the NetLogs -- 1 alert was logged.
574  EXPECT_EQ(1u, log.GetSize());
575  EXPECT_EQ(1u, request_log.GetSize());
576}
577
578void DnsDuringInitHelper(bool synchronous_host_resolver) {
579  CapturingNetLog log;
580  CapturingBoundNetLog request_log;
581  MockCachingHostResolver host_resolver;
582  host_resolver.set_synchronous_mode(synchronous_host_resolver);
583  MockErrorObserver* error_observer = new MockErrorObserver;
584  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
585
586  host_resolver.rules()->AddRule("host1", "91.13.12.1");
587  host_resolver.rules()->AddRule("host2", "91.13.12.2");
588
589  InitResolver(&resolver, "dns_during_init.js");
590
591  // Initialization did 2 dnsResolves.
592  EXPECT_EQ(2u, host_resolver.num_resolve());
593
594  host_resolver.rules()->ClearRules();
595  host_resolver.GetHostCache()->clear();
596
597  host_resolver.rules()->AddRule("host1", "145.88.13.3");
598  host_resolver.rules()->AddRule("host2", "137.89.8.45");
599
600  TestCompletionCallback callback;
601  ProxyInfo proxy_info;
602
603  int rv = resolver.GetProxyForURL(
604      GURL("http://foo/"), &proxy_info, callback.callback(), NULL,
605      request_log.bound());
606  EXPECT_EQ(ERR_IO_PENDING, rv);
607  EXPECT_EQ(OK, callback.WaitForResult());
608
609  // Fetched host1 and host2 again, since the ones done during initialization
610  // should not have been cached.
611  EXPECT_EQ(4u, host_resolver.num_resolve());
612
613  EXPECT_EQ("91.13.12.1-91.13.12.2-145.88.13.3-137.89.8.45:99",
614            proxy_info.proxy_server().ToURI());
615
616  // Check the NetLogs -- the script generated 2 alerts during initialization.
617  EXPECT_EQ(0u, request_log.GetSize());
618  CapturingNetLog::CapturedEntryList entries;
619  log.GetEntries(&entries);
620
621  ASSERT_EQ(2u, entries.size());
622  EXPECT_TRUE(
623      LogContainsEvent(entries, 0, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
624                       NetLog::PHASE_NONE));
625  EXPECT_TRUE(
626      LogContainsEvent(entries, 1, NetLog::TYPE_PAC_JAVASCRIPT_ALERT,
627                       NetLog::PHASE_NONE));
628
629  EXPECT_EQ("{\"message\":\"Watsup\"}", entries[0].GetParamsJson());
630  EXPECT_EQ("{\"message\":\"Watsup2\"}", entries[1].GetParamsJson());
631}
632
633// Tests a PAC script which does DNS resolves during initialization.
634TEST_F(ProxyResolverV8TracingTest, DnsDuringInit) {
635  // Test with both both a host resolver that always completes asynchronously,
636  // and then again with one that completes synchronously.
637  DnsDuringInitHelper(false);
638  DnsDuringInitHelper(true);
639}
640
641void CrashCallback(int) {
642  // Be extra sure that if the callback ever gets invoked, the test will fail.
643  CHECK(false);
644}
645
646// Start some requests, cancel them all, and then destroy the resolver.
647// Note the execution order for this test can vary. Since multiple
648// threads are involved, the cancellation may be received a different
649// times.
650TEST_F(ProxyResolverV8TracingTest, CancelAll) {
651  MockCachingHostResolver host_resolver;
652  MockErrorObserver* error_observer = new MockErrorObserver;
653  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
654
655  host_resolver.rules()->AddSimulatedFailure("*");
656
657  InitResolver(&resolver, "dns.js");
658
659  const size_t kNumRequests = 5;
660  ProxyInfo proxy_info[kNumRequests];
661  ProxyResolver::RequestHandle request[kNumRequests];
662
663  for (size_t i = 0; i < kNumRequests; ++i) {
664    int rv = resolver.GetProxyForURL(
665        GURL("http://foo/"), &proxy_info[i],
666        base::Bind(&CrashCallback), &request[i], BoundNetLog());
667    EXPECT_EQ(ERR_IO_PENDING, rv);
668  }
669
670  for (size_t i = 0; i < kNumRequests; ++i) {
671    resolver.CancelRequest(request[i]);
672  }
673}
674
675// Note the execution order for this test can vary. Since multiple
676// threads are involved, the cancellation may be received a different
677// times.
678TEST_F(ProxyResolverV8TracingTest, CancelSome) {
679  MockCachingHostResolver host_resolver;
680  MockErrorObserver* error_observer = new MockErrorObserver;
681  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
682
683  host_resolver.rules()->AddSimulatedFailure("*");
684
685  InitResolver(&resolver, "dns.js");
686
687  ProxyInfo proxy_info1;
688  ProxyInfo proxy_info2;
689  ProxyResolver::RequestHandle request1;
690  ProxyResolver::RequestHandle request2;
691  TestCompletionCallback callback;
692
693  int rv = resolver.GetProxyForURL(
694      GURL("http://foo/"), &proxy_info1,
695      base::Bind(&CrashCallback), &request1, BoundNetLog());
696  EXPECT_EQ(ERR_IO_PENDING, rv);
697
698  rv = resolver.GetProxyForURL(
699      GURL("http://foo/"), &proxy_info2,
700      callback.callback(), &request2, BoundNetLog());
701  EXPECT_EQ(ERR_IO_PENDING, rv);
702
703  resolver.CancelRequest(request1);
704
705  EXPECT_EQ(OK, callback.WaitForResult());
706}
707
708// Cancel a request after it has finished running on the worker thread, and has
709// posted a task the completion task back to origin thread.
710TEST_F(ProxyResolverV8TracingTest, CancelWhilePendingCompletionTask) {
711  MockCachingHostResolver host_resolver;
712  MockErrorObserver* error_observer = new MockErrorObserver;
713  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
714
715  host_resolver.rules()->AddSimulatedFailure("*");
716
717  InitResolver(&resolver, "error.js");
718
719  ProxyInfo proxy_info1;
720  ProxyInfo proxy_info2;
721  ProxyInfo proxy_info3;
722  ProxyResolver::RequestHandle request1;
723  ProxyResolver::RequestHandle request2;
724  ProxyResolver::RequestHandle request3;
725  TestCompletionCallback callback;
726
727  int rv = resolver.GetProxyForURL(
728      GURL("http://foo/"), &proxy_info1,
729      base::Bind(&CrashCallback), &request1, BoundNetLog());
730  EXPECT_EQ(ERR_IO_PENDING, rv);
731
732  rv = resolver.GetProxyForURL(
733      GURL("http://throw-an-error/"), &proxy_info2,
734      callback.callback(), &request2, BoundNetLog());
735  EXPECT_EQ(ERR_IO_PENDING, rv);
736
737  // Wait until the first request has finished running on the worker thread.
738  // (The second request will output an error).
739  error_observer->WaitForOutput();
740
741  // Cancel the first request, while it has a pending completion task on
742  // the origin thread.
743  resolver.CancelRequest(request1);
744
745  EXPECT_EQ(ERR_PAC_SCRIPT_FAILED, callback.WaitForResult());
746
747  // Start another request, to make sure it is able to complete.
748  rv = resolver.GetProxyForURL(
749      GURL("http://i-have-no-idea-what-im-doing/"), &proxy_info3,
750      callback.callback(), &request3, BoundNetLog());
751  EXPECT_EQ(ERR_IO_PENDING, rv);
752
753  EXPECT_EQ(OK, callback.WaitForResult());
754
755  EXPECT_EQ("i-approve-this-message:42",
756            proxy_info3.proxy_server().ToURI());
757}
758
759// This implementation of HostResolver allows blocking until a resolve request
760// has been received. The resolve requests it receives will never be completed.
761class BlockableHostResolver : public HostResolver {
762 public:
763  BlockableHostResolver()
764      : num_cancelled_requests_(0), waiting_for_resolve_(false) {}
765
766  virtual int Resolve(const RequestInfo& info,
767                      RequestPriority priority,
768                      AddressList* addresses,
769                      const CompletionCallback& callback,
770                      RequestHandle* out_req,
771                      const BoundNetLog& net_log) OVERRIDE {
772    EXPECT_FALSE(callback.is_null());
773    EXPECT_TRUE(out_req);
774
775    if (!action_.is_null())
776      action_.Run();
777
778    // Indicate to the caller that a request was received.
779    EXPECT_TRUE(waiting_for_resolve_);
780    base::MessageLoop::current()->Quit();
781
782    // This line is intentionally after action_.Run(), since one of the
783    // tests does a cancellation inside of Resolve(), and it is more
784    // interesting if *out_req hasn't been written yet at that point.
785    *out_req = reinterpret_cast<RequestHandle*>(1);  // Magic value.
786
787    // Return ERR_IO_PENDING as this request will NEVER be completed.
788    // Expectation is for the caller to later cancel the request.
789    return ERR_IO_PENDING;
790  }
791
792  virtual int ResolveFromCache(const RequestInfo& info,
793                               AddressList* addresses,
794                               const BoundNetLog& net_log) OVERRIDE {
795    NOTREACHED();
796    return ERR_DNS_CACHE_MISS;
797  }
798
799  virtual void CancelRequest(RequestHandle req) OVERRIDE {
800    EXPECT_EQ(reinterpret_cast<RequestHandle*>(1), req);
801    num_cancelled_requests_++;
802  }
803
804  void SetAction(const base::Callback<void(void)>& action) {
805    action_ = action;
806  }
807
808  // Waits until Resolve() has been called.
809  void WaitUntilRequestIsReceived() {
810    waiting_for_resolve_ = true;
811    base::MessageLoop::current()->Run();
812    DCHECK(waiting_for_resolve_);
813    waiting_for_resolve_ = false;
814  }
815
816  int num_cancelled_requests() const {
817    return num_cancelled_requests_;
818  }
819
820 private:
821  int num_cancelled_requests_;
822  bool waiting_for_resolve_;
823  base::Callback<void(void)> action_;
824};
825
826// This cancellation test exercises a more predictable cancellation codepath --
827// when the request has an outstanding DNS request in flight.
828TEST_F(ProxyResolverV8TracingTest, CancelWhileOutstandingNonBlockingDns) {
829  BlockableHostResolver host_resolver;
830  MockErrorObserver* error_observer = new MockErrorObserver;
831  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
832
833  InitResolver(&resolver, "dns.js");
834
835  ProxyInfo proxy_info1;
836  ProxyInfo proxy_info2;
837  ProxyResolver::RequestHandle request1;
838  ProxyResolver::RequestHandle request2;
839
840  int rv = resolver.GetProxyForURL(
841      GURL("http://foo/req1"), &proxy_info1,
842      base::Bind(&CrashCallback), &request1, BoundNetLog());
843
844  EXPECT_EQ(ERR_IO_PENDING, rv);
845
846  host_resolver.WaitUntilRequestIsReceived();
847
848  rv = resolver.GetProxyForURL(
849      GURL("http://foo/req2"), &proxy_info2,
850      base::Bind(&CrashCallback), &request2, BoundNetLog());
851
852  EXPECT_EQ(ERR_IO_PENDING, rv);
853
854  host_resolver.WaitUntilRequestIsReceived();
855
856  resolver.CancelRequest(request1);
857  resolver.CancelRequest(request2);
858
859  EXPECT_EQ(2, host_resolver.num_cancelled_requests());
860
861  // After leaving this scope, the ProxyResolver is destroyed.
862  // This should not cause any problems, as the outstanding work
863  // should have been cancelled.
864}
865
866void CancelRequestAndPause(ProxyResolverV8Tracing* resolver,
867                           ProxyResolver::RequestHandle request) {
868  resolver->CancelRequest(request);
869
870  // Sleep for a little bit. This makes it more likely for the worker
871  // thread to have returned from its call, and serves as a regression
872  // test for http://crbug.com/173373.
873  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(30));
874}
875
876// In non-blocking mode, the worker thread actually does block for
877// a short time to see if the result is in the DNS cache. Test
878// cancellation while the worker thread is waiting on this event.
879TEST_F(ProxyResolverV8TracingTest, CancelWhileBlockedInNonBlockingDns) {
880  BlockableHostResolver host_resolver;
881  MockErrorObserver* error_observer = new MockErrorObserver;
882  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
883
884  InitResolver(&resolver, "dns.js");
885
886  ProxyInfo proxy_info;
887  ProxyResolver::RequestHandle request;
888
889  int rv = resolver.GetProxyForURL(
890      GURL("http://foo/"), &proxy_info,
891      base::Bind(&CrashCallback), &request, BoundNetLog());
892
893  EXPECT_EQ(ERR_IO_PENDING, rv);
894
895  host_resolver.SetAction(
896      base::Bind(CancelRequestAndPause, &resolver, request));
897
898  host_resolver.WaitUntilRequestIsReceived();
899
900  // At this point the host resolver ran Resolve(), and should have cancelled
901  // the request.
902
903  EXPECT_EQ(1, host_resolver.num_cancelled_requests());
904}
905
906// Cancel the request while there is a pending DNS request, however before
907// the request is sent to the host resolver.
908TEST_F(ProxyResolverV8TracingTest, CancelWhileBlockedInNonBlockingDns2) {
909  MockCachingHostResolver host_resolver;
910  MockErrorObserver* error_observer = new MockErrorObserver;
911  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
912
913  InitResolver(&resolver, "dns.js");
914
915  ProxyInfo proxy_info;
916  ProxyResolver::RequestHandle request;
917
918  int rv = resolver.GetProxyForURL(
919      GURL("http://foo/"), &proxy_info,
920      base::Bind(&CrashCallback), &request, BoundNetLog());
921
922  EXPECT_EQ(ERR_IO_PENDING, rv);
923
924  // Wait a bit, so the DNS task has hopefully been posted. The test will
925  // work whatever the delay is here, but it is most useful if the delay
926  // is large enough to allow a task to be posted back.
927  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
928  resolver.CancelRequest(request);
929
930  EXPECT_EQ(0u, host_resolver.num_resolve());
931}
932
933TEST_F(ProxyResolverV8TracingTest, CancelSetPacWhileOutstandingBlockingDns) {
934  BlockableHostResolver host_resolver;
935  MockErrorObserver* error_observer = new MockErrorObserver;
936
937  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, NULL);
938
939  int rv =
940      resolver.SetPacScript(LoadScriptData("dns_during_init.js"),
941      base::Bind(&CrashCallback));
942  EXPECT_EQ(ERR_IO_PENDING, rv);
943
944  host_resolver.WaitUntilRequestIsReceived();
945
946  resolver.CancelSetPacScript();
947  EXPECT_EQ(1, host_resolver.num_cancelled_requests());
948}
949
950// This tests that the execution of a PAC script is terminated when the DNS
951// dependencies are missing. If the test fails, then it will hang.
952TEST_F(ProxyResolverV8TracingTest, Terminate) {
953  CapturingNetLog log;
954  CapturingBoundNetLog request_log;
955  MockCachingHostResolver host_resolver;
956  MockErrorObserver* error_observer = new MockErrorObserver;
957  ProxyResolverV8Tracing resolver(&host_resolver, error_observer, &log);
958
959  host_resolver.rules()->AddRule("host1", "182.111.0.222");
960  host_resolver.rules()->AddRule("host2", "111.33.44.55");
961
962  InitResolver(&resolver, "terminate.js");
963
964  TestCompletionCallback callback;
965  ProxyInfo proxy_info;
966
967  int rv = resolver.GetProxyForURL(
968      GURL("http://foopy/req1"),
969      &proxy_info,
970      callback.callback(),
971      NULL,
972      request_log.bound());
973
974  EXPECT_EQ(ERR_IO_PENDING, rv);
975  EXPECT_EQ(OK, callback.WaitForResult());
976
977  // The test does 2 DNS resolutions.
978  EXPECT_EQ(2u, host_resolver.num_resolve());
979
980  EXPECT_EQ("foopy:3", proxy_info.proxy_server().ToURI());
981
982  // No errors.
983  EXPECT_EQ("", error_observer->GetOutput());
984
985  EXPECT_EQ(0u, log.GetSize());
986  EXPECT_EQ(0u, request_log.GetSize());
987}
988
989// Tests that multiple instances of ProxyResolverV8Tracing can coexist and run
990// correctly at the same time. This is relevant because at the moment (time
991// this test was written) each ProxyResolverV8Tracing creates its own thread to
992// run V8 on, however each thread is operating on the same v8::Isolate.
993TEST_F(ProxyResolverV8TracingTest, MultipleResolvers) {
994  // ------------------------
995  // Setup resolver0
996  // ------------------------
997  MockHostResolver host_resolver0;
998  host_resolver0.rules()->AddRuleForAddressFamily(
999      "host1", ADDRESS_FAMILY_IPV4, "166.155.144.44");
1000  host_resolver0.rules()
1001      ->AddIPLiteralRule("host1", "::1,192.168.1.1", std::string());
1002  host_resolver0.rules()->AddSimulatedFailure("host2");
1003  host_resolver0.rules()->AddRule("host3", "166.155.144.33");
1004  host_resolver0.rules()->AddRule("host5", "166.155.144.55");
1005  host_resolver0.rules()->AddSimulatedFailure("host6");
1006  host_resolver0.rules()->AddRuleForAddressFamily(
1007      "*", ADDRESS_FAMILY_IPV4, "122.133.144.155");
1008  host_resolver0.rules()->AddRule("*", "133.122.100.200");
1009  ProxyResolverV8Tracing resolver0(
1010      &host_resolver0, new MockErrorObserver, NULL);
1011  InitResolver(&resolver0, "dns.js");
1012
1013  // ------------------------
1014  // Setup resolver1
1015  // ------------------------
1016  ProxyResolverV8Tracing resolver1(
1017      &host_resolver0, new MockErrorObserver, NULL);
1018  InitResolver(&resolver1, "dns.js");
1019
1020  // ------------------------
1021  // Setup resolver2
1022  // ------------------------
1023  ProxyResolverV8Tracing resolver2(
1024      &host_resolver0, new MockErrorObserver, NULL);
1025  InitResolver(&resolver2, "simple.js");
1026
1027  // ------------------------
1028  // Setup resolver3
1029  // ------------------------
1030  MockHostResolver host_resolver3;
1031  host_resolver3.rules()->AddRule("foo", "166.155.144.33");
1032  ProxyResolverV8Tracing resolver3(
1033      &host_resolver3, new MockErrorObserver, NULL);
1034  InitResolver(&resolver3, "simple_dns.js");
1035
1036  // ------------------------
1037  // Queue up work for each resolver (which will be running in parallel).
1038  // ------------------------
1039
1040  ProxyResolverV8Tracing* resolver[] = {
1041    &resolver0, &resolver1, &resolver2, &resolver3,
1042  };
1043
1044  const size_t kNumResolvers = arraysize(resolver);
1045  const size_t kNumIterations = 20;
1046  const size_t kNumResults = kNumResolvers * kNumIterations;
1047  TestCompletionCallback callback[kNumResults];
1048  ProxyInfo proxy_info[kNumResults];
1049
1050  for (size_t i = 0; i < kNumResults; ++i) {
1051    size_t resolver_i = i % kNumResolvers;
1052    int rv = resolver[resolver_i]->GetProxyForURL(
1053        GURL("http://foo/"), &proxy_info[i], callback[i].callback(), NULL,
1054        BoundNetLog());
1055    EXPECT_EQ(ERR_IO_PENDING, rv);
1056  }
1057
1058  // ------------------------
1059  // Verify all of the results.
1060  // ------------------------
1061
1062  const char* kExpectedForDnsJs =
1063    "122.133.144.155-"  // myIpAddress()
1064    "null-"  // dnsResolve('')
1065    "__1_192.168.1.1-"  // dnsResolveEx('host1')
1066    "null-"  // dnsResolve('host2')
1067    "166.155.144.33-"  // dnsResolve('host3')
1068    "122.133.144.155-"  // myIpAddress()
1069    "166.155.144.33-"  // dnsResolve('host3')
1070    "__1_192.168.1.1-"  // dnsResolveEx('host1')
1071    "122.133.144.155-"  // myIpAddress()
1072    "null-"  // dnsResolve('host2')
1073    "-"  // dnsResolveEx('host6')
1074    "133.122.100.200-"  // myIpAddressEx()
1075    "166.155.144.44"  // dnsResolve('host1')
1076    ":99";
1077
1078  for (size_t i = 0; i < kNumResults; ++i) {
1079    size_t resolver_i = i % kNumResolvers;
1080    EXPECT_EQ(OK, callback[i].WaitForResult());
1081
1082    std::string proxy_uri = proxy_info[i].proxy_server().ToURI();
1083
1084    if (resolver_i == 0 || resolver_i == 1) {
1085      EXPECT_EQ(kExpectedForDnsJs, proxy_uri);
1086    } else if (resolver_i == 2) {
1087      EXPECT_EQ("foo:99", proxy_uri);
1088    } else if (resolver_i == 3) {
1089      EXPECT_EQ("166.155.144.33:",
1090                proxy_uri.substr(0, proxy_uri.find(':') + 1));
1091    } else {
1092      NOTREACHED();
1093    }
1094  }
1095}
1096
1097}  // namespace
1098
1099}  // namespace net
1100