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:
ChromeBrowserProxyResolverTest()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 
SetUp()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 
TearDown()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  private:
81   brillo::FakeMessageLoop loop_{nullptr};
82 
83   // Local pointers to the mocks. The instances are owned by the
84   // |libcros_proxy_|.
85   LibCrosServiceInterfaceProxyMock* service_interface_mock_;
86   UpdateEngineLibcrosProxyResolvedInterfaceProxyMock*
87       ue_proxy_resolved_interface_mock_;
88 
89   // The registered signal handler for the signal
90   // UpdateEngineLibcrosProxyResolvedInterface.ProxyResolved.
91   chromeos_update_engine::dbus_test_utils::MockSignalHandler<
92       void(const string&, const string&, const string&)>
93       ue_proxy_resolved_signal_;
94 
95   LibCrosProxy libcros_proxy_;
96   ChromeBrowserProxyResolver resolver_{&libcros_proxy_};
97 };
98 
99 
SendReplySignal(const string & source_url,const string & proxy_info,const string & error_message)100 void ChromeBrowserProxyResolverTest::SendReplySignal(
101     const string& source_url,
102     const string& proxy_info,
103     const string& error_message) {
104   ASSERT_TRUE(ue_proxy_resolved_signal_.IsHandlerRegistered());
105   ue_proxy_resolved_signal_.signal_callback().Run(
106       source_url, proxy_info, error_message);
107 }
108 
109 namespace {
CheckResponseResolved(const deque<string> & proxies,void *)110 void CheckResponseResolved(const deque<string>& proxies,
111                            void* /* pirv_data */) {
112   EXPECT_EQ(2U, proxies.size());
113   EXPECT_EQ("socks5://192.168.52.83:5555", proxies[0]);
114   EXPECT_EQ(kNoProxy, proxies[1]);
115   MessageLoop::current()->BreakLoop();
116 }
117 
CheckResponseNoReply(const deque<string> & proxies,void *)118 void CheckResponseNoReply(const deque<string>& proxies, void* /* pirv_data */) {
119   EXPECT_EQ(1U, proxies.size());
120   EXPECT_EQ(kNoProxy, proxies[0]);
121   MessageLoop::current()->BreakLoop();
122 }
123 }  // namespace
124 
125 // chrome_replies should be set to whether or not we fake a reply from
126 // chrome. If there's no reply, the resolver should time out.
127 // If chrome_alive is false, assume that sending to chrome fails.
RunTest(bool chrome_replies,bool chrome_alive)128 void ChromeBrowserProxyResolverTest::RunTest(bool chrome_replies,
129                                              bool chrome_alive) {
130   char kUrl[] = "http://example.com/blah";
131   char kProxyConfig[] = "SOCKS5 192.168.52.83:5555;DIRECT";
132 
133   EXPECT_CALL(*service_interface_mock_,
134               ResolveNetworkProxy(StrEq(kUrl),
135                                   StrEq(kLibCrosProxyResolveSignalInterface),
136                                   StrEq(kLibCrosProxyResolveName),
137                                   _,
138                                   _))
139       .WillOnce(Return(chrome_alive));
140 
141   ProxiesResolvedFn get_proxies_response = &CheckResponseNoReply;
142   if (chrome_replies) {
143     get_proxies_response = &CheckResponseResolved;
144     MessageLoop::current()->PostDelayedTask(
145         FROM_HERE,
146         base::Bind(&ChromeBrowserProxyResolverTest::SendReplySignal,
147                    base::Unretained(this),
148                    kUrl,
149                    kProxyConfig,
150                    ""),
151         base::TimeDelta::FromSeconds(1));
152   }
153 
154   EXPECT_TRUE(resolver_.GetProxiesForUrl(kUrl, get_proxies_response, nullptr));
155   MessageLoop::current()->Run();
156 }
157 
158 
TEST_F(ChromeBrowserProxyResolverTest,ParseTest)159 TEST_F(ChromeBrowserProxyResolverTest, ParseTest) {
160   // Test ideas from
161   // http://src.chromium.org/svn/trunk/src/net/proxy/proxy_list_unittest.cc
162   vector<string> inputs = {
163       "PROXY foopy:10",
164       " DIRECT",  // leading space.
165       "PROXY foopy1 ; proxy foopy2;\t DIRECT",
166       "proxy foopy1 ; SOCKS foopy2",
167       "DIRECT ; proxy foopy1 ; DIRECT ; SOCKS5 foopy2;DIRECT ",
168       "DIRECT ; proxy foopy1:80; DIRECT ; DIRECT",
169       "PROXY-foopy:10",
170       "PROXY",
171       "PROXY foopy1 ; JUNK ; JUNK ; SOCKS5 foopy2 ; ;",
172       "HTTP foopy1; SOCKS5 foopy2"};
173   vector<deque<string>> outputs = {
174       {"http://foopy:10", kNoProxy},
175       {kNoProxy},
176       {"http://foopy1", "http://foopy2", kNoProxy},
177       {"http://foopy1", "socks4://foopy2", kNoProxy},
178       {kNoProxy, "http://foopy1", kNoProxy, "socks5://foopy2", kNoProxy},
179       {kNoProxy, "http://foopy1:80", kNoProxy, kNoProxy},
180       {kNoProxy},
181       {kNoProxy},
182       {"http://foopy1", "socks5://foopy2", kNoProxy},
183       {"socks5://foopy2", kNoProxy}};
184   ASSERT_EQ(inputs.size(), outputs.size());
185 
186   for (size_t i = 0; i < inputs.size(); i++) {
187     deque<string> results =
188         ChromeBrowserProxyResolver::ParseProxyString(inputs[i]);
189     deque<string>& expected = outputs[i];
190     EXPECT_EQ(results.size(), expected.size()) << "i = " << i;
191     if (expected.size() != results.size())
192       continue;
193     for (size_t j = 0; j < expected.size(); j++) {
194       EXPECT_EQ(expected[j], results[j]) << "i = " << i;
195     }
196   }
197 }
198 
TEST_F(ChromeBrowserProxyResolverTest,SuccessTest)199 TEST_F(ChromeBrowserProxyResolverTest, SuccessTest) {
200   RunTest(true, true);
201 }
202 
TEST_F(ChromeBrowserProxyResolverTest,NoReplyTest)203 TEST_F(ChromeBrowserProxyResolverTest, NoReplyTest) {
204   RunTest(false, true);
205 }
206 
TEST_F(ChromeBrowserProxyResolverTest,NoChromeTest)207 TEST_F(ChromeBrowserProxyResolverTest, NoChromeTest) {
208   RunTest(false, false);
209 }
210 
211 }  // namespace chromeos_update_engine
212