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 <gtest/gtest.h> 24 25 #include <base/bind.h> 26 #include <brillo/make_unique_ptr.h> 27 #include <brillo/message_loops/fake_message_loop.h> 28 29 #include "libcros/dbus-proxies.h" 30 #include "libcros/dbus-proxy-mocks.h" 31 #include "update_engine/dbus_test_utils.h" 32 33 using ::testing::Return; 34 using ::testing::StrEq; 35 using ::testing::_; 36 using brillo::MessageLoop; 37 using org::chromium::LibCrosServiceInterfaceProxyMock; 38 using org::chromium::UpdateEngineLibcrosProxyResolvedInterfaceProxyMock; 39 using std::deque; 40 using std::string; 41 using std::vector; 42 43 namespace chromeos_update_engine { 44 45 class ChromeBrowserProxyResolverTest : public ::testing::Test { 46 protected: 47 ChromeBrowserProxyResolverTest() 48 : service_interface_mock_(new LibCrosServiceInterfaceProxyMock()), 49 ue_proxy_resolved_interface_mock_( 50 new UpdateEngineLibcrosProxyResolvedInterfaceProxyMock()), 51 libcros_proxy_( 52 brillo::make_unique_ptr(service_interface_mock_), 53 brillo::make_unique_ptr(ue_proxy_resolved_interface_mock_)) {} 54 55 void SetUp() override { 56 loop_.SetAsCurrent(); 57 // The ProxyResolved signal should be subscribed to. 58 MOCK_SIGNAL_HANDLER_EXPECT_SIGNAL_HANDLER( 59 ue_proxy_resolved_signal_, 60 *ue_proxy_resolved_interface_mock_, 61 ProxyResolved); 62 63 EXPECT_TRUE(resolver_.Init()); 64 // Run the loop once to dispatch the successfully registered signal handler. 65 EXPECT_TRUE(loop_.RunOnce(false)); 66 } 67 68 void TearDown() override { 69 EXPECT_FALSE(loop_.PendingTasks()); 70 } 71 72 // Send the signal to the callback passed during registration of the 73 // ProxyResolved. 74 void SendReplySignal(const string& source_url, 75 const string& proxy_info, 76 const string& error_message); 77 78 void RunTest(bool chrome_replies, bool chrome_alive); 79 80 brillo::FakeMessageLoop loop_{nullptr}; 81 82 // Local pointers to the mocks. The instances are owned by the 83 // |libcros_proxy_|. 84 LibCrosServiceInterfaceProxyMock* service_interface_mock_; 85 UpdateEngineLibcrosProxyResolvedInterfaceProxyMock* 86 ue_proxy_resolved_interface_mock_; 87 88 // The registered signal handler for the signal 89 // UpdateEngineLibcrosProxyResolvedInterface.ProxyResolved. 90 chromeos_update_engine::dbus_test_utils::MockSignalHandler< 91 void(const string&, const string&, const string&)> 92 ue_proxy_resolved_signal_; 93 94 LibCrosProxy libcros_proxy_; 95 ChromeBrowserProxyResolver resolver_{&libcros_proxy_}; 96 }; 97 98 99 void ChromeBrowserProxyResolverTest::SendReplySignal( 100 const string& source_url, 101 const string& proxy_info, 102 const string& error_message) { 103 ASSERT_TRUE(ue_proxy_resolved_signal_.IsHandlerRegistered()); 104 ue_proxy_resolved_signal_.signal_callback().Run( 105 source_url, proxy_info, error_message); 106 } 107 108 namespace { 109 void CheckResponseResolved(const deque<string>& proxies) { 110 EXPECT_EQ(2U, proxies.size()); 111 EXPECT_EQ("socks5://192.168.52.83:5555", proxies[0]); 112 EXPECT_EQ(kNoProxy, proxies[1]); 113 MessageLoop::current()->BreakLoop(); 114 } 115 116 void CheckResponseNoReply(const deque<string>& proxies) { 117 EXPECT_EQ(1U, proxies.size()); 118 EXPECT_EQ(kNoProxy, proxies[0]); 119 MessageLoop::current()->BreakLoop(); 120 } 121 } // namespace 122 123 // chrome_replies should be set to whether or not we fake a reply from 124 // chrome. If there's no reply, the resolver should time out. 125 // If chrome_alive is false, assume that sending to chrome fails. 126 void ChromeBrowserProxyResolverTest::RunTest(bool chrome_replies, 127 bool chrome_alive) { 128 char kUrl[] = "http://example.com/blah"; 129 char kProxyConfig[] = "SOCKS5 192.168.52.83:5555;DIRECT"; 130 131 EXPECT_CALL(*service_interface_mock_, 132 ResolveNetworkProxy(StrEq(kUrl), 133 StrEq(kLibCrosProxyResolveSignalInterface), 134 StrEq(kLibCrosProxyResolveName), 135 _, 136 _)) 137 .WillOnce(Return(chrome_alive)); 138 139 ProxiesResolvedFn get_proxies_response = base::Bind(&CheckResponseNoReply); 140 if (chrome_replies) { 141 get_proxies_response = base::Bind(&CheckResponseResolved); 142 MessageLoop::current()->PostDelayedTask( 143 FROM_HERE, 144 base::Bind(&ChromeBrowserProxyResolverTest::SendReplySignal, 145 base::Unretained(this), 146 kUrl, 147 kProxyConfig, 148 ""), 149 base::TimeDelta::FromSeconds(1)); 150 } 151 152 EXPECT_NE(kProxyRequestIdNull, 153 resolver_.GetProxiesForUrl(kUrl, get_proxies_response)); 154 MessageLoop::current()->Run(); 155 } 156 157 158 TEST_F(ChromeBrowserProxyResolverTest, ParseTest) { 159 // Test ideas from 160 // http://src.chromium.org/svn/trunk/src/net/proxy/proxy_list_unittest.cc 161 vector<string> inputs = { 162 "PROXY foopy:10", 163 " DIRECT", // leading space. 164 "PROXY foopy1 ; proxy foopy2;\t DIRECT", 165 "proxy foopy1 ; SOCKS foopy2", 166 "DIRECT ; proxy foopy1 ; DIRECT ; SOCKS5 foopy2;DIRECT ", 167 "DIRECT ; proxy foopy1:80; DIRECT ; DIRECT", 168 "PROXY-foopy:10", 169 "PROXY", 170 "PROXY foopy1 ; JUNK ; JUNK ; SOCKS5 foopy2 ; ;", 171 "HTTP foopy1; SOCKS5 foopy2"}; 172 vector<deque<string>> outputs = { 173 {"http://foopy:10", kNoProxy}, 174 {kNoProxy}, 175 {"http://foopy1", "http://foopy2", kNoProxy}, 176 {"http://foopy1", "socks4://foopy2", kNoProxy}, 177 {kNoProxy, "http://foopy1", kNoProxy, "socks5://foopy2", kNoProxy}, 178 {kNoProxy, "http://foopy1:80", kNoProxy, kNoProxy}, 179 {kNoProxy}, 180 {kNoProxy}, 181 {"http://foopy1", "socks5://foopy2", kNoProxy}, 182 {"socks5://foopy2", kNoProxy}}; 183 ASSERT_EQ(inputs.size(), outputs.size()); 184 185 for (size_t i = 0; i < inputs.size(); i++) { 186 deque<string> results = 187 ChromeBrowserProxyResolver::ParseProxyString(inputs[i]); 188 deque<string>& expected = outputs[i]; 189 EXPECT_EQ(results.size(), expected.size()) << "i = " << i; 190 if (expected.size() != results.size()) 191 continue; 192 for (size_t j = 0; j < expected.size(); j++) { 193 EXPECT_EQ(expected[j], results[j]) << "i = " << i; 194 } 195 } 196 } 197 198 TEST_F(ChromeBrowserProxyResolverTest, SuccessTest) { 199 RunTest(true, true); 200 } 201 202 TEST_F(ChromeBrowserProxyResolverTest, NoReplyTest) { 203 RunTest(false, true); 204 } 205 206 TEST_F(ChromeBrowserProxyResolverTest, NoChromeTest) { 207 RunTest(false, false); 208 } 209 210 TEST_F(ChromeBrowserProxyResolverTest, CancelCallbackTest) { 211 int called = 0; 212 auto callback = base::Bind( 213 [](int* called, const deque<string>& proxies) { (*called)++; }, &called); 214 215 EXPECT_CALL(*service_interface_mock_, ResolveNetworkProxy(_, _, _, _, _)) 216 .Times(4) 217 .WillRepeatedly(Return(true)); 218 219 EXPECT_NE(kProxyRequestIdNull, 220 resolver_.GetProxiesForUrl("http://urlA", callback)); 221 ProxyRequestId req_b = resolver_.GetProxiesForUrl("http://urlB", callback); 222 // Note that we add twice the same url. 223 ProxyRequestId req_c = resolver_.GetProxiesForUrl("http://urlC", callback); 224 EXPECT_NE(kProxyRequestIdNull, 225 resolver_.GetProxiesForUrl("http://urlC", callback)); 226 227 EXPECT_EQ(0, called); 228 EXPECT_TRUE(resolver_.CancelProxyRequest(req_b)); 229 EXPECT_TRUE(resolver_.CancelProxyRequest(req_c)); 230 // Canceling the same request twice should fail even if there's another 231 // request for the same URL. 232 EXPECT_FALSE(resolver_.CancelProxyRequest(req_c)); 233 234 loop_.Run(); 235 EXPECT_EQ(2, called); 236 } 237 238 } // namespace chromeos_update_engine 239