// Copyright 2017 The Chromium OS Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include <brillo/http/http_proxy.h> #include <string> #include <vector> #include <base/bind.h> #include <brillo/http/http_transport.h> #include <chromeos/dbus/service_constants.h> #include <dbus/mock_bus.h> #include <dbus/mock_object_proxy.h> #include <gtest/gtest.h> using ::testing::_; using ::testing::ElementsAre; using ::testing::Invoke; using ::testing::Return; namespace { constexpr char kTestUrl[] = "http://www.example.com/test"; } // namespace namespace brillo { namespace http { class HttpProxyTest : public testing::Test { public: void ResolveProxyHandlerAsync(dbus::MethodCall* method_call, int timeout_msec, dbus::ObjectProxy::ResponseCallback callback) { if (null_dbus_response_) { callback.Run(nullptr); return; } callback.Run(CreateDBusResponse(method_call).get()); } dbus::Response* ResolveProxyHandler(dbus::MethodCall* method_call, int timeout_msec) { if (null_dbus_response_) { return nullptr; } // The mock wraps this back into a std::unique_ptr in the function calling // us. return CreateDBusResponse(method_call).release(); } MOCK_METHOD2(GetProxiesCallback, void(bool, const std::vector<std::string>&)); protected: HttpProxyTest() { dbus::Bus::Options options; options.bus_type = dbus::Bus::SYSTEM; bus_ = new dbus::MockBus(options); object_proxy_ = new dbus::MockObjectProxy( bus_.get(), chromeos::kNetworkProxyServiceName, dbus::ObjectPath(chromeos::kNetworkProxyServicePath)); EXPECT_CALL(*bus_, GetObjectProxy(chromeos::kNetworkProxyServiceName, dbus::ObjectPath( chromeos::kNetworkProxyServicePath))) .WillOnce(Return(object_proxy_.get())); } std::unique_ptr<dbus::Response> CreateDBusResponse( dbus::MethodCall* method_call) { EXPECT_EQ(method_call->GetInterface(), chromeos::kNetworkProxyServiceInterface); EXPECT_EQ(method_call->GetMember(), chromeos::kNetworkProxyServiceResolveProxyMethod); method_call->SetSerial(1); // Needs to be non-zero or it fails. std::unique_ptr<dbus::Response> response = dbus::Response::FromMethodCall(method_call); dbus::MessageWriter writer(response.get()); writer.AppendString(proxy_info_); if (invalid_dbus_response_) { return response; } writer.AppendString(proxy_err_); return response; } scoped_refptr<dbus::MockBus> bus_; scoped_refptr<dbus::MockObjectProxy> object_proxy_; std::string proxy_info_; std::string proxy_err_; bool null_dbus_response_ = false; bool invalid_dbus_response_ = false; private: DISALLOW_COPY_AND_ASSIGN(HttpProxyTest); }; TEST_F(HttpProxyTest, DBusNullResponseFails) { std::vector<std::string> proxies; null_dbus_response_ = true; EXPECT_CALL(*object_proxy_, MockCallMethodAndBlock(_, _)) .WillOnce(Invoke(this, &HttpProxyTest::ResolveProxyHandler)); EXPECT_FALSE(GetChromeProxyServers(bus_, kTestUrl, &proxies)); } TEST_F(HttpProxyTest, DBusInvalidResponseFails) { std::vector<std::string> proxies; invalid_dbus_response_ = true; EXPECT_CALL(*object_proxy_, MockCallMethodAndBlock(_, _)) .WillOnce(Invoke(this, &HttpProxyTest::ResolveProxyHandler)); EXPECT_FALSE(GetChromeProxyServers(bus_, kTestUrl, &proxies)); } TEST_F(HttpProxyTest, NoProxies) { std::vector<std::string> proxies; EXPECT_CALL(*object_proxy_, MockCallMethodAndBlock(_, _)) .WillOnce(Invoke(this, &HttpProxyTest::ResolveProxyHandler)); EXPECT_TRUE(GetChromeProxyServers(bus_, kTestUrl, &proxies)); EXPECT_THAT(proxies, ElementsAre(kDirectProxy)); } TEST_F(HttpProxyTest, MultipleProxiesWithoutDirect) { proxy_info_ = "proxy example.com; socks5 foo.com;"; std::vector<std::string> proxies; EXPECT_CALL(*object_proxy_, MockCallMethodAndBlock(_, _)) .WillOnce(Invoke(this, &HttpProxyTest::ResolveProxyHandler)); EXPECT_TRUE(GetChromeProxyServers(bus_, kTestUrl, &proxies)); EXPECT_THAT(proxies, ElementsAre("http://example.com", "socks5://foo.com", kDirectProxy)); } TEST_F(HttpProxyTest, MultipleProxiesWithDirect) { proxy_info_ = "socks foo.com; Https example.com ; badproxy example2.com ; " "socks5 test.com ; proxy foobar.com; DIRECT "; std::vector<std::string> proxies; EXPECT_CALL(*object_proxy_, MockCallMethodAndBlock(_, _)) .WillOnce(Invoke(this, &HttpProxyTest::ResolveProxyHandler)); EXPECT_TRUE(GetChromeProxyServers(bus_, kTestUrl, &proxies)); EXPECT_THAT(proxies, ElementsAre("socks4://foo.com", "https://example.com", "socks5://test.com", "http://foobar.com", kDirectProxy)); } TEST_F(HttpProxyTest, DBusNullResponseFailsAsync) { null_dbus_response_ = true; EXPECT_CALL(*object_proxy_, CallMethod(_, _, _)) .WillOnce(Invoke(this, &HttpProxyTest::ResolveProxyHandlerAsync)); EXPECT_CALL(*this, GetProxiesCallback(false, _)); GetChromeProxyServersAsync( bus_, kTestUrl, base::Bind(&HttpProxyTest::GetProxiesCallback, base::Unretained(this))); } TEST_F(HttpProxyTest, DBusInvalidResponseFailsAsync) { invalid_dbus_response_ = true; EXPECT_CALL(*object_proxy_, CallMethod(_, _, _)) .WillOnce(Invoke(this, &HttpProxyTest::ResolveProxyHandlerAsync)); EXPECT_CALL(*this, GetProxiesCallback(false, _)); GetChromeProxyServersAsync( bus_, kTestUrl, base::Bind(&HttpProxyTest::GetProxiesCallback, base::Unretained(this))); } // We don't need to test all the proxy cases with async because that will be // using the same internal parsing code. TEST_F(HttpProxyTest, MultipleProxiesWithDirectAsync) { proxy_info_ = "socks foo.com; Https example.com ; badproxy example2.com ; " "socks5 test.com ; proxy foobar.com; DIRECT "; std::vector<std::string> expected = { "socks4://foo.com", "https://example.com", "socks5://test.com", "http://foobar.com", kDirectProxy}; EXPECT_CALL(*object_proxy_, CallMethod(_, _, _)) .WillOnce(Invoke(this, &HttpProxyTest::ResolveProxyHandlerAsync)); EXPECT_CALL(*this, GetProxiesCallback(true, expected)); GetChromeProxyServersAsync( bus_, kTestUrl, base::Bind(&HttpProxyTest::GetProxiesCallback, base::Unretained(this))); } } // namespace http } // namespace brillo