blob: 51d49394c9be9850f4316c8745b7f21e38c71332 [file] [log] [blame]
// Copyright 2022 The Chromium 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 "device/bluetooth/floss/exported_callback_manager.h"
#include <utility>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "dbus/bus.h"
#include "dbus/message.h"
#include "dbus/mock_bus.h"
#include "dbus/mock_exported_object.h"
#include "dbus/mock_object_proxy.h"
#include "dbus/object_path.h"
#include "device/bluetooth/floss/floss_dbus_client.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace floss {
namespace {
const char kExportedCallbackPath[] = "/org/chromium/some/callback";
const char kTestSender[] = ":0.1";
const int kTestSerial = 1;
class ISomeCallback {
public:
virtual ~ISomeCallback() = default;
virtual base::WeakPtr<ISomeCallback> GetWeakPtr() = 0;
virtual void OnSomethingHappened(std::string name,
uint32_t number,
bool status) = 0;
virtual void SomeMethod() = 0;
};
class SomeCallback : public ISomeCallback {
public:
base::WeakPtr<ISomeCallback> GetWeakPtr() override {
return weak_ptr_factory_.GetWeakPtr();
}
void OnSomethingHappened(std::string name,
uint32_t number,
bool status) override {
last_something_happened = {name, number, status};
}
void SomeMethod() override { some_method_called = true; }
// For test inspections.
absl::optional<std::tuple<std::string, uint32_t, bool>>
last_something_happened;
bool some_method_called = false;
private:
base::WeakPtrFactory<SomeCallback> weak_ptr_factory_{this};
};
} // namespace
class ExportedCallbackManagerTest : public testing::Test {
public:
ExportedCallbackManagerTest() = default;
void SetUp() override {
bus_ = base::MakeRefCounted<dbus::MockBus>(dbus::Bus::Options());
}
protected:
void TestSomethingHappenedWrongParameters(
dbus::ExportedObject::MethodCallCallback method_handler,
SomeCallback& some_callback) {
dbus::MethodCall method_call("some.interface", "OnSomethingHappened");
method_call.SetPath(dbus::ObjectPath(kExportedCallbackPath));
method_call.SetSender(kTestSender);
method_call.SetSerial(kTestSerial);
dbus::MessageWriter writer(&method_call);
writer.AppendString("foo");
std::unique_ptr<dbus::Response> saved_response;
method_handler.Run(&method_call,
base::BindOnce(
[](std::unique_ptr<dbus::Response>* saved_response,
std::unique_ptr<dbus::Response> response) {
*saved_response = std::move(response);
},
&saved_response));
ASSERT_TRUE(!!saved_response);
EXPECT_EQ(FlossDBusClient::kErrorInvalidParameters,
saved_response->GetErrorName());
}
void TestSomethingHappenedRightParameters(
dbus::ExportedObject::MethodCallCallback method_handler,
SomeCallback& some_callback) {
dbus::MethodCall method_call("some.interface", "OnSomethingHappened");
method_call.SetPath(dbus::ObjectPath(kExportedCallbackPath));
method_call.SetSender(kTestSender);
method_call.SetSerial(kTestSerial);
dbus::MessageWriter writer(&method_call);
writer.AppendString("foo");
writer.AppendUint32(10);
writer.AppendBool(true);
std::unique_ptr<dbus::Response> saved_response;
method_handler.Run(&method_call,
base::BindOnce(
[](std::unique_ptr<dbus::Response>* saved_response,
std::unique_ptr<dbus::Response> response) {
*saved_response = std::move(response);
},
&saved_response));
ASSERT_TRUE(!!saved_response);
EXPECT_EQ("", saved_response->GetErrorName());
EXPECT_EQ(std::make_tuple("foo", 10, true),
some_callback.last_something_happened);
}
void TestSomeMethod(dbus::ExportedObject::MethodCallCallback method_handler,
SomeCallback& some_callback) {
dbus::MethodCall method_call("some.interface", "SomeMethod");
method_call.SetPath(dbus::ObjectPath(kExportedCallbackPath));
method_call.SetSender(kTestSender);
method_call.SetSerial(kTestSerial);
dbus::MessageWriter writer(&method_call);
std::unique_ptr<dbus::Response> saved_response;
method_handler.Run(&method_call,
base::BindOnce(
[](std::unique_ptr<dbus::Response>* saved_response,
std::unique_ptr<dbus::Response> response) {
*saved_response = std::move(response);
},
&saved_response));
ASSERT_TRUE(!!saved_response);
EXPECT_EQ("", saved_response->GetErrorName());
ASSERT_TRUE(some_callback.some_method_called);
}
void TestCallbackDoesNotExist(
dbus::ExportedObject::MethodCallCallback method_handler) {
dbus::MethodCall method_call("some.interface", "SomeMethod");
method_call.SetPath(dbus::ObjectPath(kExportedCallbackPath));
method_call.SetSender(kTestSender);
method_call.SetSerial(kTestSerial);
dbus::MessageWriter writer(&method_call);
std::unique_ptr<dbus::Response> saved_response;
method_handler.Run(&method_call,
base::BindOnce(
[](std::unique_ptr<dbus::Response>* saved_response,
std::unique_ptr<dbus::Response> response) {
*saved_response = std::move(response);
},
&saved_response));
ASSERT_TRUE(!!saved_response);
EXPECT_EQ(FlossDBusClient::kErrorDoesNotExist,
saved_response->GetErrorName());
}
scoped_refptr<dbus::MockBus> bus_;
base::WeakPtrFactory<ExportedCallbackManagerTest> weak_ptr_factory_{this};
};
TEST_F(ExportedCallbackManagerTest, TestMethodHandler) {
ExportedCallbackManager<ISomeCallback> manager("org.example.interface");
manager.Init(bus_);
manager.AddMethod("OnSomethingHappened", &ISomeCallback::OnSomethingHappened);
manager.AddMethod("SomeMethod", &ISomeCallback::SomeMethod);
scoped_refptr<::dbus::MockExportedObject> exported_callback =
base::MakeRefCounted<::dbus::MockExportedObject>(
bus_.get(), dbus::ObjectPath(kExportedCallbackPath));
dbus::ExportedObject::MethodCallCallback method_handler_something_happened;
EXPECT_CALL(*exported_callback.get(),
ExportMethod("org.example.interface", "OnSomethingHappened",
testing::_, testing::_))
.WillOnce(testing::SaveArg<2>(&method_handler_something_happened));
dbus::ExportedObject::MethodCallCallback method_handler_some_method;
EXPECT_CALL(*exported_callback.get(),
ExportMethod("org.example.interface", "SomeMethod", testing::_,
testing::_))
.WillOnce(testing::SaveArg<2>(&method_handler_some_method));
auto some_callback = std::make_unique<SomeCallback>();
EXPECT_CALL(*bus_.get(),
GetExportedObject(dbus::ObjectPath(kExportedCallbackPath)))
.WillRepeatedly(testing::Return(exported_callback.get()));
manager.ExportCallback(dbus::ObjectPath(kExportedCallbackPath),
some_callback->GetWeakPtr());
ASSERT_TRUE(!!method_handler_something_happened);
ASSERT_TRUE(!!method_handler_some_method);
TestSomethingHappenedWrongParameters(method_handler_something_happened,
*some_callback);
TestSomethingHappenedRightParameters(method_handler_something_happened,
*some_callback);
TestSomeMethod(method_handler_some_method, *some_callback);
some_callback.reset();
TestCallbackDoesNotExist(method_handler_some_method);
}
} // namespace floss