Home | History | Annotate | Download | only in update_engine
      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