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