|  | // | 
|  | // Copyright (C) 2011 The Android Open Source Project | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  | // | 
|  |  | 
|  | #include "update_engine/chrome_browser_proxy_resolver.h" | 
|  |  | 
|  | #include <deque> | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include <gmock/gmock.h> | 
|  | #include <gtest/gtest.h> | 
|  |  | 
|  | #include <base/macros.h> | 
|  | #include <brillo/errors/error.h> | 
|  |  | 
|  | #include "network_proxy/dbus-proxies.h" | 
|  | #include "network_proxy/dbus-proxy-mocks.h" | 
|  | #include "update_engine/dbus_test_utils.h" | 
|  |  | 
|  | using ::testing::DoAll; | 
|  | using ::testing::SaveArg; | 
|  | using ::testing::StrEq; | 
|  | using ::testing::_; | 
|  | using org::chromium::NetworkProxyServiceInterfaceProxyMock; | 
|  | using std::deque; | 
|  | using std::string; | 
|  | using std::vector; | 
|  |  | 
|  | namespace chromeos_update_engine { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Callback for ProxyResolver::GetProxiesForUrl() that copies |src| to |dest|. | 
|  | void CopyProxies(deque<string>* dest, const deque<string>& src) { | 
|  | *dest = src; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | class ChromeBrowserProxyResolverTest : public ::testing::Test { | 
|  | public: | 
|  | ChromeBrowserProxyResolverTest() = default; | 
|  | ~ChromeBrowserProxyResolverTest() override = default; | 
|  |  | 
|  | protected: | 
|  | // Adds a GoogleMock expectation for a call to |dbus_proxy_|'s | 
|  | // ResolveProxyAsync method to resolve |url|. | 
|  | void AddResolveProxyExpectation(const std::string& url) { | 
|  | EXPECT_CALL(dbus_proxy_, ResolveProxyAsync(StrEq(url), _, _, _)) | 
|  | .WillOnce(DoAll(SaveArg<1>(&success_callback_), | 
|  | SaveArg<2>(&error_callback_))); | 
|  | } | 
|  |  | 
|  | NetworkProxyServiceInterfaceProxyMock dbus_proxy_; | 
|  | ChromeBrowserProxyResolver resolver_{&dbus_proxy_}; | 
|  |  | 
|  | // Callbacks that were passed to |dbus_proxy_|'s ResolveProxyAsync method. | 
|  | base::Callback<void(const std::string&, const std::string&)> | 
|  | success_callback_; | 
|  | base::Callback<void(brillo::Error*)> error_callback_; | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(ChromeBrowserProxyResolverTest); | 
|  | }; | 
|  |  | 
|  | TEST_F(ChromeBrowserProxyResolverTest, Parse) { | 
|  | // Test ideas from | 
|  | // http://src.chromium.org/svn/trunk/src/net/proxy/proxy_list_unittest.cc | 
|  | vector<string> inputs = { | 
|  | "PROXY foopy:10", | 
|  | " DIRECT", // leading space. | 
|  | "PROXY foopy1 ; proxy foopy2;\t DIRECT", | 
|  | "proxy foopy1 ; SOCKS foopy2", | 
|  | "DIRECT ; proxy foopy1 ; DIRECT ; SOCKS5 foopy2;DIRECT ", | 
|  | "DIRECT ; proxy foopy1:80; DIRECT ; DIRECT", | 
|  | "PROXY-foopy:10", | 
|  | "PROXY", | 
|  | "PROXY foopy1 ; JUNK ; JUNK ; SOCKS5 foopy2 ; ;", | 
|  | "HTTP foopy1; SOCKS5 foopy2", | 
|  | }; | 
|  | vector<deque<string>> outputs = { | 
|  | {"http://foopy:10", kNoProxy}, | 
|  | {kNoProxy}, | 
|  | {"http://foopy1", "http://foopy2", kNoProxy}, | 
|  | {"http://foopy1", "socks4://foopy2", kNoProxy}, | 
|  | {kNoProxy, "http://foopy1", kNoProxy, "socks5://foopy2", kNoProxy}, | 
|  | {kNoProxy, "http://foopy1:80", kNoProxy, kNoProxy}, | 
|  | {kNoProxy}, | 
|  | {kNoProxy}, | 
|  | {"http://foopy1", "socks5://foopy2", kNoProxy}, | 
|  | {"socks5://foopy2", kNoProxy}, | 
|  | }; | 
|  | ASSERT_EQ(inputs.size(), outputs.size()); | 
|  |  | 
|  | for (size_t i = 0; i < inputs.size(); i++) { | 
|  | deque<string> results = | 
|  | ChromeBrowserProxyResolver::ParseProxyString(inputs[i]); | 
|  | deque<string>& expected = outputs[i]; | 
|  | EXPECT_EQ(results.size(), expected.size()) << "i = " << i; | 
|  | if (expected.size() != results.size()) | 
|  | continue; | 
|  | for (size_t j = 0; j < expected.size(); j++) { | 
|  | EXPECT_EQ(expected[j], results[j]) << "i = " << i; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(ChromeBrowserProxyResolverTest, Success) { | 
|  | const char kUrl[] = "http://example.com/blah"; | 
|  | const char kProxyConfig[] = "SOCKS5 192.168.52.83:5555;DIRECT"; | 
|  | AddResolveProxyExpectation(kUrl); | 
|  | deque<string> proxies; | 
|  | resolver_.GetProxiesForUrl(kUrl, base::Bind(&CopyProxies, &proxies)); | 
|  |  | 
|  | // Run the D-Bus success callback and verify that the proxies are passed to | 
|  | // the supplied function. | 
|  | ASSERT_FALSE(success_callback_.is_null()); | 
|  | success_callback_.Run(kProxyConfig, string()); | 
|  | ASSERT_EQ(2u, proxies.size()); | 
|  | EXPECT_EQ("socks5://192.168.52.83:5555", proxies[0]); | 
|  | EXPECT_EQ(kNoProxy, proxies[1]); | 
|  | } | 
|  |  | 
|  | TEST_F(ChromeBrowserProxyResolverTest, Failure) { | 
|  | const char kUrl[] = "http://example.com/blah"; | 
|  | AddResolveProxyExpectation(kUrl); | 
|  | deque<string> proxies; | 
|  | resolver_.GetProxiesForUrl(kUrl, base::Bind(&CopyProxies, &proxies)); | 
|  |  | 
|  | // Run the D-Bus error callback and verify that the supplied function is | 
|  | // instructed to use a direct connection. | 
|  | ASSERT_FALSE(error_callback_.is_null()); | 
|  | brillo::ErrorPtr error = brillo::Error::Create(FROM_HERE, "", "", ""); | 
|  | error_callback_.Run(error.get()); | 
|  | ASSERT_EQ(1u, proxies.size()); | 
|  | EXPECT_EQ(kNoProxy, proxies[0]); | 
|  | } | 
|  |  | 
|  | TEST_F(ChromeBrowserProxyResolverTest, CancelCallback) { | 
|  | const char kUrl[] = "http://example.com/blah"; | 
|  | AddResolveProxyExpectation(kUrl); | 
|  | int called = 0; | 
|  | auto callback = base::Bind( | 
|  | [](int* called, const deque<string>& proxies) { (*called)++; }, &called); | 
|  | ProxyRequestId request = resolver_.GetProxiesForUrl(kUrl, callback); | 
|  |  | 
|  | // Cancel the request and then run the D-Bus success callback. The original | 
|  | // callback shouldn't be run. | 
|  | EXPECT_TRUE(resolver_.CancelProxyRequest(request)); | 
|  | ASSERT_FALSE(success_callback_.is_null()); | 
|  | success_callback_.Run("DIRECT", string()); | 
|  | EXPECT_EQ(0, called); | 
|  | } | 
|  |  | 
|  | TEST_F(ChromeBrowserProxyResolverTest, CancelCallbackTwice) { | 
|  | const char kUrl[] = "http://example.com/blah"; | 
|  | AddResolveProxyExpectation(kUrl); | 
|  | deque<string> proxies; | 
|  | ProxyRequestId request = | 
|  | resolver_.GetProxiesForUrl(kUrl, base::Bind(&CopyProxies, &proxies)); | 
|  |  | 
|  | // Cancel the same request twice. The second call should fail. | 
|  | EXPECT_TRUE(resolver_.CancelProxyRequest(request)); | 
|  | EXPECT_FALSE(resolver_.CancelProxyRequest(request)); | 
|  | } | 
|  |  | 
|  | }  // namespace chromeos_update_engine |