1//
2// Copyright (C) 2011 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "update_engine/chrome_browser_proxy_resolver.h"
18
19#include <deque>
20#include <string>
21#include <vector>
22
23#include <gmock/gmock.h>
24#include <gtest/gtest.h>
25
26#include <base/macros.h>
27#include <brillo/errors/error.h>
28
29#include "network_proxy/dbus-proxies.h"
30#include "network_proxy/dbus-proxy-mocks.h"
31#include "update_engine/dbus_test_utils.h"
32
33using ::testing::DoAll;
34using ::testing::SaveArg;
35using ::testing::StrEq;
36using ::testing::_;
37using org::chromium::NetworkProxyServiceInterfaceProxyMock;
38using std::deque;
39using std::string;
40using std::vector;
41
42namespace chromeos_update_engine {
43
44namespace {
45
46// Callback for ProxyResolver::GetProxiesForUrl() that copies |src| to |dest|.
47void CopyProxies(deque<string>* dest, const deque<string>& src) {
48  *dest = src;
49}
50
51}  // namespace
52
53class ChromeBrowserProxyResolverTest : public ::testing::Test {
54 public:
55  ChromeBrowserProxyResolverTest() = default;
56  ~ChromeBrowserProxyResolverTest() override = default;
57
58 protected:
59  // Adds a GoogleMock expectation for a call to |dbus_proxy_|'s
60  // ResolveProxyAsync method to resolve |url|.
61  void AddResolveProxyExpectation(const std::string& url) {
62    EXPECT_CALL(dbus_proxy_, ResolveProxyAsync(StrEq(url), _, _, _))
63        .WillOnce(DoAll(SaveArg<1>(&success_callback_),
64                        SaveArg<2>(&error_callback_)));
65  }
66
67  NetworkProxyServiceInterfaceProxyMock dbus_proxy_;
68  ChromeBrowserProxyResolver resolver_{&dbus_proxy_};
69
70  // Callbacks that were passed to |dbus_proxy_|'s ResolveProxyAsync method.
71  base::Callback<void(const std::string&, const std::string&)>
72      success_callback_;
73  base::Callback<void(brillo::Error*)> error_callback_;
74
75 private:
76  DISALLOW_COPY_AND_ASSIGN(ChromeBrowserProxyResolverTest);
77};
78
79TEST_F(ChromeBrowserProxyResolverTest, Parse) {
80  // Test ideas from
81  // http://src.chromium.org/svn/trunk/src/net/proxy/proxy_list_unittest.cc
82  vector<string> inputs = {
83      "PROXY foopy:10",
84      " DIRECT", // leading space.
85      "PROXY foopy1 ; proxy foopy2;\t DIRECT",
86      "proxy foopy1 ; SOCKS foopy2",
87      "DIRECT ; proxy foopy1 ; DIRECT ; SOCKS5 foopy2;DIRECT ",
88      "DIRECT ; proxy foopy1:80; DIRECT ; DIRECT",
89      "PROXY-foopy:10",
90      "PROXY",
91      "PROXY foopy1 ; JUNK ; JUNK ; SOCKS5 foopy2 ; ;",
92      "HTTP foopy1; SOCKS5 foopy2",
93  };
94  vector<deque<string>> outputs = {
95      {"http://foopy:10", kNoProxy},
96      {kNoProxy},
97      {"http://foopy1", "http://foopy2", kNoProxy},
98      {"http://foopy1", "socks4://foopy2", kNoProxy},
99      {kNoProxy, "http://foopy1", kNoProxy, "socks5://foopy2", kNoProxy},
100      {kNoProxy, "http://foopy1:80", kNoProxy, kNoProxy},
101      {kNoProxy},
102      {kNoProxy},
103      {"http://foopy1", "socks5://foopy2", kNoProxy},
104      {"socks5://foopy2", kNoProxy},
105  };
106  ASSERT_EQ(inputs.size(), outputs.size());
107
108  for (size_t i = 0; i < inputs.size(); i++) {
109    deque<string> results =
110        ChromeBrowserProxyResolver::ParseProxyString(inputs[i]);
111    deque<string>& expected = outputs[i];
112    EXPECT_EQ(results.size(), expected.size()) << "i = " << i;
113    if (expected.size() != results.size())
114      continue;
115    for (size_t j = 0; j < expected.size(); j++) {
116      EXPECT_EQ(expected[j], results[j]) << "i = " << i;
117    }
118  }
119}
120
121TEST_F(ChromeBrowserProxyResolverTest, Success) {
122  const char kUrl[] = "http://example.com/blah";
123  const char kProxyConfig[] = "SOCKS5 192.168.52.83:5555;DIRECT";
124  AddResolveProxyExpectation(kUrl);
125  deque<string> proxies;
126  resolver_.GetProxiesForUrl(kUrl, base::Bind(&CopyProxies, &proxies));
127
128  // Run the D-Bus success callback and verify that the proxies are passed to
129  // the supplied function.
130  ASSERT_FALSE(success_callback_.is_null());
131  success_callback_.Run(kProxyConfig, string());
132  ASSERT_EQ(2u, proxies.size());
133  EXPECT_EQ("socks5://192.168.52.83:5555", proxies[0]);
134  EXPECT_EQ(kNoProxy, proxies[1]);
135}
136
137TEST_F(ChromeBrowserProxyResolverTest, Failure) {
138  const char kUrl[] = "http://example.com/blah";
139  AddResolveProxyExpectation(kUrl);
140  deque<string> proxies;
141  resolver_.GetProxiesForUrl(kUrl, base::Bind(&CopyProxies, &proxies));
142
143  // Run the D-Bus error callback and verify that the supplied function is
144  // instructed to use a direct connection.
145  ASSERT_FALSE(error_callback_.is_null());
146  brillo::ErrorPtr error = brillo::Error::Create(FROM_HERE, "", "", "");
147  error_callback_.Run(error.get());
148  ASSERT_EQ(1u, proxies.size());
149  EXPECT_EQ(kNoProxy, proxies[0]);
150}
151
152TEST_F(ChromeBrowserProxyResolverTest, CancelCallback) {
153  const char kUrl[] = "http://example.com/blah";
154  AddResolveProxyExpectation(kUrl);
155  int called = 0;
156  auto callback = base::Bind(
157      [](int* called, const deque<string>& proxies) { (*called)++; }, &called);
158  ProxyRequestId request = resolver_.GetProxiesForUrl(kUrl, callback);
159
160  // Cancel the request and then run the D-Bus success callback. The original
161  // callback shouldn't be run.
162  EXPECT_TRUE(resolver_.CancelProxyRequest(request));
163  ASSERT_FALSE(success_callback_.is_null());
164  success_callback_.Run("DIRECT", string());
165  EXPECT_EQ(0, called);
166}
167
168TEST_F(ChromeBrowserProxyResolverTest, CancelCallbackTwice) {
169  const char kUrl[] = "http://example.com/blah";
170  AddResolveProxyExpectation(kUrl);
171  deque<string> proxies;
172  ProxyRequestId request =
173      resolver_.GetProxiesForUrl(kUrl, base::Bind(&CopyProxies, &proxies));
174
175  // Cancel the same request twice. The second call should fail.
176  EXPECT_TRUE(resolver_.CancelProxyRequest(request));
177  EXPECT_FALSE(resolver_.CancelProxyRequest(request));
178}
179
180}  // namespace chromeos_update_engine
181