blob: 55caca5b806e6e0beb74e3853bd22e9e28631247 [file] [log] [blame]
// Copyright 2018 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 "bluetooth/newblued/agent_manager_interface_handler.h"
#include <memory>
#include <string>
#include <utility>
#include <base/memory/ref_counted.h>
#include <brillo/dbus/dbus_object.h>
#include <brillo/dbus/exported_property_set.h>
#include <brillo/dbus/mock_exported_object_manager.h>
#include <chromeos/dbus/service_constants.h>
#include <dbus/exported_object.h>
#include <dbus/mock_bus.h>
#include <dbus/mock_exported_object.h>
#include <dbus/mock_object_proxy.h>
#include <dbus/object_path.h>
#include <gtest/gtest.h>
#include "bluetooth/common/exported_object_manager_wrapper.h"
using ::testing::_;
using ::testing::DoAll;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SaveArgPointee;
ACTION_TEMPLATE(MovePointee,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_1_VALUE_PARAMS(pointer)) {
*pointer = std::move(*(::std::get<k>(args)));
}
namespace bluetooth {
namespace {
constexpr char kTestAgentPath[] = "/some/agent";
constexpr char kTestSender[] = ":1.1";
constexpr char kTestDeviceAddress[] = "11:22:33:44:55:66";
constexpr char kTestCapability[] = "some capability";
constexpr int kTestSerial = 123;
constexpr int kTestPasskey = 123456;
void SaveResponse(std::unique_ptr<dbus::Response>* saved_response,
std::unique_ptr<dbus::Response> response) {
*saved_response = std::move(response);
}
// Matcher to compare method call by its interface and member name, ignoring
// the message payload.
MATCHER_P(MethodCallEq, expected_method_call, "") {
return (arg->GetInterface() == (expected_method_call)->GetInterface() &&
arg->GetMember() == (expected_method_call)->GetMember());
}
} // namespace
class AgentManagerInterfaceHandlerTest : public ::testing::Test {
public:
void SetUp() override {
bus_ = new dbus::MockBus(dbus::Bus::Options());
auto exported_object_manager =
std::make_unique<brillo::dbus_utils::MockExportedObjectManager>(
bus_, dbus::ObjectPath("/"));
exported_object_manager_wrapper_ =
std::make_unique<ExportedObjectManagerWrapper>(
bus_, std::move(exported_object_manager));
agent_manager_interface_handler_ =
std::make_unique<AgentManagerInterfaceHandler>(
bus_, exported_object_manager_wrapper_.get());
exported_agent_manager_object_ = SetupExportedAgentManagerObject();
}
protected:
void ExpectAgentManagerMethodsExported(
dbus::ExportedObject::MethodCallCallback* register_agent_method_handler,
dbus::ExportedObject::MethodCallCallback* unregister_agent_method_handler,
dbus::ExportedObject::MethodCallCallback*
request_default_agent_method_handler) {
// Catch the standard dbus property handler
EXPECT_CALL(*exported_agent_manager_object_,
ExportMethodAndBlock(dbus::kDBusPropertiesInterface, _, _))
.WillRepeatedly(DoAll(SaveArg<2>(request_default_agent_method_handler),
Return(true)));
EXPECT_CALL(*exported_agent_manager_object_,
ExportMethodAndBlock(
bluetooth_agent_manager::kBluetoothAgentManagerInterface,
bluetooth_agent_manager::kRegisterAgent, _))
.WillOnce(
DoAll(SaveArg<2>(register_agent_method_handler), Return(true)));
EXPECT_CALL(*exported_agent_manager_object_,
ExportMethodAndBlock(
bluetooth_agent_manager::kBluetoothAgentManagerInterface,
bluetooth_agent_manager::kUnregisterAgent, _))
.WillOnce(
DoAll(SaveArg<2>(unregister_agent_method_handler), Return(true)));
EXPECT_CALL(*exported_agent_manager_object_,
ExportMethodAndBlock(
bluetooth_agent_manager::kBluetoothAgentManagerInterface,
bluetooth_agent_manager::kRequestDefaultAgent, _))
.WillOnce(DoAll(SaveArg<2>(request_default_agent_method_handler),
Return(true)));
}
scoped_refptr<dbus::MockExportedObject> SetupExportedAgentManagerObject() {
dbus::ObjectPath agent_manager_path(
bluetooth_agent_manager::kBluetoothAgentManagerServicePath);
scoped_refptr<dbus::MockExportedObject> exported_agent_manager_object =
new dbus::MockExportedObject(bus_.get(), agent_manager_path);
EXPECT_CALL(*bus_, GetExportedObject(agent_manager_path))
.WillRepeatedly(Return(exported_agent_manager_object.get()));
return exported_agent_manager_object;
}
void RegisterAgent(
dbus::ExportedObject::MethodCallCallback register_agent_method_handler) {
dbus::MethodCall register_agent_method_call(
bluetooth_agent_manager::kBluetoothAgentManagerInterface,
bluetooth_agent_manager::kRegisterAgent);
register_agent_method_call.SetPath(dbus::ObjectPath(
bluetooth_agent_manager::kBluetoothAgentManagerServicePath));
register_agent_method_call.SetSender(kTestSender);
register_agent_method_call.SetSerial(kTestSerial);
dbus::MessageWriter register_agent_writer(&register_agent_method_call);
register_agent_writer.AppendObjectPath(dbus::ObjectPath(kTestAgentPath));
register_agent_writer.AppendString(kTestCapability);
std::unique_ptr<dbus::Response> register_agent_response;
register_agent_method_handler.Run(
&register_agent_method_call,
base::Bind(&SaveResponse, &register_agent_response));
EXPECT_EQ("", register_agent_response->GetErrorName());
}
void SetDefaultAgent(dbus::ExportedObject::MethodCallCallback
request_default_agent_method_handler) {
dbus::MethodCall request_default_agent_method_call(
bluetooth_agent_manager::kBluetoothAgentManagerInterface,
bluetooth_agent_manager::kRequestDefaultAgent);
request_default_agent_method_call.SetPath(dbus::ObjectPath(
bluetooth_agent_manager::kBluetoothAgentManagerServicePath));
request_default_agent_method_call.SetSender(kTestSender);
request_default_agent_method_call.SetSerial(kTestSerial);
dbus::MessageWriter request_default_agent_writer(
&request_default_agent_method_call);
request_default_agent_writer.AppendObjectPath(
dbus::ObjectPath(kTestAgentPath));
std::unique_ptr<dbus::Response> request_default_agent_response;
request_default_agent_method_handler.Run(
&request_default_agent_method_call,
base::Bind(&SaveResponse, &request_default_agent_response));
EXPECT_EQ("", request_default_agent_response->GetErrorName());
}
scoped_refptr<dbus::MockBus> bus_;
// A raw pointer of this is kept by exported_object_manager_wrapper_, so
// declare this first to make sure it's destructed later.
scoped_refptr<dbus::MockExportedObject> exported_agent_manager_object_;
std::unique_ptr<ExportedObjectManagerWrapper>
exported_object_manager_wrapper_;
std::unique_ptr<AgentManagerInterfaceHandler>
agent_manager_interface_handler_;
};
TEST_F(AgentManagerInterfaceHandlerTest, DisplayPasskey) {
dbus::ExportedObject::MethodCallCallback register_agent_method_handler;
dbus::ExportedObject::MethodCallCallback unregister_agent_method_handler;
dbus::ExportedObject::MethodCallCallback request_default_agent_method_handler;
ExpectAgentManagerMethodsExported(&register_agent_method_handler,
&unregister_agent_method_handler,
&request_default_agent_method_handler);
agent_manager_interface_handler_->Init();
scoped_refptr<dbus::MockObjectProxy> agent_object_proxy =
new dbus::MockObjectProxy(
bus_.get(), bluetooth_agent_manager::kBluetoothAgentManagerInterface,
dbus::ObjectPath(kTestAgentPath));
// Before any client registers as an agent, DisplayPasskey won't call any
// agent.
EXPECT_CALL(*agent_object_proxy, DoCallMethod(_, _, _)).Times(0);
agent_manager_interface_handler_->DisplayPasskey(kTestDeviceAddress,
kTestPasskey);
RegisterAgent(register_agent_method_handler);
// A client has registered as an agent but has not requested to become the
// default agent. So DisplayPasskey should still not call any agent.
EXPECT_CALL(*agent_object_proxy, DoCallMethod(_, _, _)).Times(0);
agent_manager_interface_handler_->DisplayPasskey(kTestDeviceAddress,
kTestPasskey);
SetDefaultAgent(request_default_agent_method_handler);
// Now that a client has requested to become the default agent, check that
// DisplayPasskey correctly handles this based on the current default agent.
EXPECT_CALL(*bus_,
GetObjectProxy(kTestSender, dbus::ObjectPath(kTestAgentPath)))
.WillOnce(Return(agent_object_proxy.get()));
dbus::MethodCall expected_method_call(
bluetooth_agent::kBluetoothAgentInterface,
bluetooth_agent::kDisplayPasskey);
EXPECT_CALL(*agent_object_proxy,
DoCallMethod(MethodCallEq(&expected_method_call), _, _))
.Times(1);
agent_manager_interface_handler_->DisplayPasskey(kTestDeviceAddress,
kTestPasskey);
// Test org.bluez.AgentManager1.UnregisterAgent.
dbus::MethodCall unregister_agent_method_call(
bluetooth_agent_manager::kBluetoothAgentManagerInterface,
bluetooth_agent_manager::kUnregisterAgent);
unregister_agent_method_call.SetPath(dbus::ObjectPath(
bluetooth_agent_manager::kBluetoothAgentManagerServicePath));
unregister_agent_method_call.SetSender(kTestSender);
unregister_agent_method_call.SetSerial(kTestSerial);
dbus::MessageWriter unregister_agent_writer(&unregister_agent_method_call);
unregister_agent_writer.AppendObjectPath(dbus::ObjectPath(kTestAgentPath));
std::unique_ptr<dbus::Response> unregister_agent_response;
register_agent_method_handler.Run(
&unregister_agent_method_call,
base::Bind(&SaveResponse, &unregister_agent_response));
EXPECT_EQ("", unregister_agent_response->GetErrorName());
// After the client unregisters from an agent, DisplayPasskey won't call any
// agent.
EXPECT_CALL(*agent_object_proxy, DoCallMethod(_, _, _)).Times(0);
agent_manager_interface_handler_->DisplayPasskey(kTestDeviceAddress,
kTestPasskey);
}
TEST_F(AgentManagerInterfaceHandlerTest, RequestAuthorization) {
dbus::ExportedObject::MethodCallCallback register_agent_method_handler;
dbus::ExportedObject::MethodCallCallback unregister_agent_method_handler;
dbus::ExportedObject::MethodCallCallback request_default_agent_method_handler;
ExpectAgentManagerMethodsExported(&register_agent_method_handler,
&unregister_agent_method_handler,
&request_default_agent_method_handler);
agent_manager_interface_handler_->Init();
scoped_refptr<dbus::MockObjectProxy> agent_object_proxy =
new dbus::MockObjectProxy(
bus_.get(), bluetooth_agent_manager::kBluetoothAgentManagerInterface,
dbus::ObjectPath(kTestAgentPath));
// Before any client registers as an agent, RequestAuthorization won't call
// any agent.
EXPECT_CALL(*agent_object_proxy, DoCallMethodWithErrorCallback(_, _, _, _))
.Times(0);
agent_manager_interface_handler_->RequestAuthorization(kTestDeviceAddress);
RegisterAgent(register_agent_method_handler);
// A client has registered as an agent but has not requested to become the
// default agent. So RequestAuthorization should still not call any agent.
EXPECT_CALL(*agent_object_proxy, DoCallMethodWithErrorCallback(_, _, _, _))
.Times(0);
agent_manager_interface_handler_->RequestAuthorization(kTestDeviceAddress);
SetDefaultAgent(request_default_agent_method_handler);
// Now that a client has requested to become the default agent, check that
// RequestAuthorization correctly handles this based on the current default
// agent.
dbus::ObjectProxy::ResponseCallback callback;
dbus::ObjectProxy::ErrorCallback error_callback;
EXPECT_CALL(*bus_,
GetObjectProxy(kTestSender, dbus::ObjectPath(kTestAgentPath)))
.WillOnce(Return(agent_object_proxy.get()));
dbus::MethodCall expected_method_call(
bluetooth_agent::kBluetoothAgentInterface,
bluetooth_agent::kRequestAuthorization);
EXPECT_CALL(*agent_object_proxy,
DoCallMethodWithErrorCallback(MethodCallEq(&expected_method_call),
_, _, _))
.Times(1)
.WillOnce(
DoAll(MovePointee<2>(&callback), MovePointee<3>(&error_callback)));
// TODO(yudiliu): verify the two callbacks once they are implemented.
agent_manager_interface_handler_->RequestAuthorization(kTestDeviceAddress);
}
} // namespace bluetooth