// 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