blob: 924ff53e8cfc493015f490053b9c10c8f709909a [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/common/dbus_client.h"
#include <memory>
#include <utility>
#include <base/bind.h>
#include <base/message_loop/message_loop.h>
#include <base/run_loop.h>
#include <base/strings/stringprintf.h>
#include <dbus/message.h>
#include <dbus/mock_bus.h>
#include <gtest/gtest.h>
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::Return;
using ::testing::SaveArg;
namespace bluetooth {
namespace {
constexpr char kTestClientAddress[] = ":1.2";
constexpr char kTestInterfaceName[] = "org.example.Interface";
constexpr char kTestMethodName[] = "SomeMethod";
constexpr char kDBusSystemObjectPath[] = "/org/freedesktop/DBus";
constexpr char kDBusSystemObjectInterface[] = "org.freedesktop.DBus";
constexpr char kDBusSystemObjectAddress[] = "org.freedesktop.DBus";
constexpr char kNameOwnerChangedMember[] = "NameOwnerChanged";
} // namespace
class DBusClientTest : public ::testing::Test {
public:
void SetUp() override {
bus_ = new dbus::MockBus(dbus::Bus::Options());
EXPECT_CALL(*bus_, GetOriginTaskRunner())
.WillRepeatedly(Return(message_loop_.task_runner().get()));
EXPECT_CALL(*bus_, AssertOnDBusThread()).Times(AnyNumber());
}
// Will be called when client becomes available. Keeps track the count this
// happens so we can verify it's called.
void OnClientUnavailable() { client_unavailable_callback_count_++; }
protected:
base::MessageLoop message_loop_;
scoped_refptr<dbus::MockBus> bus_;
int client_unavailable_callback_count_ = 0;
};
TEST_F(DBusClientTest, WatchClientUnavailable) {
auto dbus_client = std::make_unique<DBusClient>(bus_, kTestClientAddress);
DBusHandleMessageFunction handle_message;
EXPECT_CALL(*bus_, AddFilterFunction(_, dbus_client.get()))
.WillOnce(SaveArg<0>(&handle_message));
std::string match_rule = base::StringPrintf(
"type='signal',interface='%s',member='%s',path='%s',sender='%s',"
"arg0='%s'",
kDBusSystemObjectInterface, kNameOwnerChangedMember,
kDBusSystemObjectPath, kDBusSystemObjectAddress, kTestClientAddress);
EXPECT_CALL(*bus_, AddMatch(match_rule, _)).Times(1);
dbus_client->WatchClientUnavailable(
base::Bind(&DBusClientTest::OnClientUnavailable, base::Unretained(this)));
// Other signals shouldn't trigger dbus_client unavailable callback.
dbus::Signal signal_other(kTestInterfaceName, kTestMethodName);
handle_message(nullptr, signal_other.raw_message(), dbus_client.get());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(0, client_unavailable_callback_count_);
// NameOwnerChanged signal with the right parameters should trigger client
// unavailable callback.
dbus::Signal signal_name_owner_changed(kDBusSystemObjectInterface,
kNameOwnerChangedMember);
signal_name_owner_changed.SetPath(dbus::ObjectPath(kDBusSystemObjectPath));
signal_name_owner_changed.SetSender(kDBusSystemObjectAddress);
dbus::MessageWriter writer(&signal_name_owner_changed);
writer.AppendString(kTestClientAddress); // 1st arg = address
writer.AppendString(kTestClientAddress); // 2nd arg = old owner
writer.AppendString(""); // 3rd arg = new owner
handle_message(nullptr, signal_name_owner_changed.raw_message(),
dbus_client.get());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1, client_unavailable_callback_count_);
EXPECT_CALL(*bus_, RemoveMatch(match_rule, _)).Times(1);
EXPECT_CALL(*bus_, RemoveFilterFunction(_, dbus_client.get()))
.WillOnce(SaveArg<0>(&handle_message));
dbus_client.reset();
}
} // namespace bluetooth