blob: 635d22c2fb23e99a3a662cc16183163d278c74f9 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/bluetooth/floss/bluetooth_socket_floss.h"
#include <memory>
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_socket.h"
#include "device/bluetooth/bluetooth_socket_thread.h"
#include "device/bluetooth/floss/bluetooth_adapter_floss.h"
#include "device/bluetooth/floss/fake_floss_adapter_client.h"
#include "device/bluetooth/floss/fake_floss_manager_client.h"
#include "device/bluetooth/floss/fake_floss_socket_manager.h"
#include "device/bluetooth/floss/floss_dbus_client.h"
#include "device/bluetooth/floss/floss_dbus_manager.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
using ::device::BluetoothAdapter;
} // namespace
namespace floss {
class BluetoothSocketFlossTest : public testing::Test {
public:
void SetUp() override {
std::unique_ptr<floss::FlossDBusManagerSetter> dbus_setter =
floss::FlossDBusManager::GetSetterForTesting();
auto fake_floss_manager_client = std::make_unique<FakeFlossManagerClient>();
fake_floss_manager_client_ = fake_floss_manager_client.get();
dbus_setter->SetFlossManagerClient(std::move(fake_floss_manager_client));
InitializeAndEnableAdapter();
}
void TearDown() override {
adapter_ = nullptr;
device::BluetoothSocketThread::CleanupForTesting();
}
void InitializeAndEnableAdapter() {
adapter_ = BluetoothAdapterFloss::CreateAdapter();
fake_floss_manager_client_->SetDefaultEnabled(true);
base::RunLoop run_loop;
adapter_->Initialize(run_loop.QuitClosure());
run_loop.Run();
ASSERT_TRUE(adapter_);
ASSERT_TRUE(adapter_->IsInitialized());
ASSERT_TRUE(adapter_->IsPowered());
ASSERT_TRUE(adapter_.get() != nullptr);
fake_floss_manager_client_->NotifyObservers(
base::BindLambdaForTesting([](FlossManagerClient::Observer* observer) {
observer->AdapterEnabledChanged(/*adapter=*/0, /*enabled=*/true);
}));
base::RunLoop().RunUntilIdle();
// Get the socket thread.
device::BluetoothSocketThread::Get();
}
void AcceptSuccessCallback(base::OnceClosure exitloop,
const device::BluetoothDevice* device,
scoped_refptr<device::BluetoothSocket> socket) {
success_callback_count_++;
last_socket_ = std::move(socket);
std::move(exitloop).Run();
}
void ConnectToServiceSuccessCallback(
base::OnceClosure exitloop,
scoped_refptr<device::BluetoothSocket> socket) {
success_callback_count_++;
last_socket_ = std::move(socket);
std::move(exitloop).Run();
}
void CreateServiceSuccessCallback(
base::OnceClosure exitloop,
scoped_refptr<device::BluetoothSocket> socket) {
success_callback_count_++;
last_socket_ = std::move(socket);
std::move(exitloop).Run();
}
void DisconnectSuccessCallback(base::OnceClosure exitloop) {
std::move(exitloop).Run();
}
void ErrorCallback(base::OnceClosure exitloop, const std::string& message) {
LOG(ERROR) << "ErrorCallback: " << message;
error_callback_count_++;
last_message_ = message;
std::move(exitloop).Run();
}
void ImmediateSuccessCallback() { success_callback_count_++; }
void SendSuccessCallback(base::OnceClosure exitloop, int bytes_sent) {
++success_callback_count_;
last_bytes_sent_ = bytes_sent;
std::move(exitloop).Run();
}
// Clear counters for test.
void ClearCounters() {
last_bytes_sent_ = 0;
last_bytes_received_ = 0;
success_callback_count_ = 0;
error_callback_count_ = 0;
last_socket_ = nullptr;
}
void DisconnectSocket(device::BluetoothSocket* socket) {
base::RunLoop run_loop;
socket->Disconnect(base::BindOnce(
&BluetoothSocketFlossTest::DisconnectSuccessCallback,
weak_ptr_factory_.GetWeakPtr(), run_loop.QuitWhenIdleClosure()));
run_loop.Run();
}
FakeFlossSocketManager* GetFakeFlossSocketManager() {
return static_cast<FakeFlossSocketManager*>(
FlossDBusManager::Get()->GetSocketManager());
}
base::test::TaskEnvironment task_environment_;
scoped_refptr<BluetoothAdapter> adapter_;
std::string last_message_;
int last_bytes_sent_ = 0;
int last_bytes_received_ = 0;
int success_callback_count_ = 0;
int error_callback_count_ = 0;
scoped_refptr<device::BluetoothSocket> last_socket_;
// Holds pointer to FakeFloss*Client's so that we can manipulate the fake
// within tests.
raw_ptr<FakeFlossManagerClient> fake_floss_manager_client_;
base::WeakPtrFactory<BluetoothSocketFlossTest> weak_ptr_factory_{this};
};
TEST_F(BluetoothSocketFlossTest, Connect) {
device::BluetoothDevice* device =
adapter_->GetDevice(FakeFlossAdapterClient::kBondedAddress1);
ASSERT_TRUE(device != nullptr);
// First establish a connection.
{
base::RunLoop run_loop;
device->ConnectToService(
device::BluetoothUUID(FakeFlossSocketManager::kRfcommUuid),
base::BindOnce(
&BluetoothSocketFlossTest::ConnectToServiceSuccessCallback,
weak_ptr_factory_.GetWeakPtr(), run_loop.QuitWhenIdleClosure()),
base::BindOnce(&BluetoothSocketFlossTest::ErrorCallback,
weak_ptr_factory_.GetWeakPtr(),
run_loop.QuitWhenIdleClosure()));
run_loop.Run();
}
EXPECT_EQ(1, success_callback_count_);
EXPECT_EQ(0, error_callback_count_);
EXPECT_TRUE(last_socket_.get() != nullptr);
// Take ownership of socket.
scoped_refptr<device::BluetoothSocket> socket = std::move(last_socket_);
ClearCounters();
auto write_buffer = base::MakeRefCounted<net::StringIOBuffer>("test");
{
base::RunLoop run_loop;
socket->Send(write_buffer.get(), write_buffer->size(),
base::BindOnce(&BluetoothSocketFlossTest::SendSuccessCallback,
weak_ptr_factory_.GetWeakPtr(),
run_loop.QuitWhenIdleClosure()),
base::BindOnce(&BluetoothSocketFlossTest::ErrorCallback,
weak_ptr_factory_.GetWeakPtr(),
run_loop.QuitWhenIdleClosure()));
run_loop.Run();
}
EXPECT_EQ(1, success_callback_count_);
EXPECT_EQ(0, error_callback_count_);
EXPECT_EQ(last_bytes_sent_, write_buffer->size());
ClearCounters();
// Clean up the socket
DisconnectSocket(socket.get());
socket = nullptr;
}
// TODO (crbug.com/1412530) Test is failing on ASan bots
TEST_F(BluetoothSocketFlossTest, Listen) {
// Get socket id for next returned socket.
FlossSocketManager::SocketId id = GetFakeFlossSocketManager()->GetNextId();
// First create the service.
{
base::RunLoop run_loop;
adapter_->CreateRfcommService(
device::BluetoothUUID(FakeFlossSocketManager::kRfcommUuid),
BluetoothAdapter::ServiceOptions(),
base::BindOnce(&BluetoothSocketFlossTest::CreateServiceSuccessCallback,
weak_ptr_factory_.GetWeakPtr(),
run_loop.QuitWhenIdleClosure()),
base::BindOnce(&BluetoothSocketFlossTest::ErrorCallback,
weak_ptr_factory_.GetWeakPtr(),
run_loop.QuitWhenIdleClosure()));
run_loop.Run();
}
EXPECT_EQ(1, success_callback_count_);
EXPECT_EQ(0, error_callback_count_);
EXPECT_TRUE(last_socket_.get() != nullptr);
// Take ownership of server socket.
scoped_refptr<device::BluetoothSocket> server_socket =
std::move(last_socket_);
ClearCounters();
// Mark the socket as ready. This should trigger an accept.
GetFakeFlossSocketManager()->SendSocketReady(
id, device::BluetoothUUID(FakeFlossSocketManager::kRfcommUuid),
FlossDBusClient::BtifStatus::kSuccess);
// Simulate incoming connection. This queues one up to be accepted later.
FlossDeviceId device = {.address = FakeFlossAdapterClient::kBondedAddress1,
.name = "Foobar"};
GetFakeFlossSocketManager()->SendIncomingConnection(
id, device, device::BluetoothUUID(FakeFlossSocketManager::kRfcommUuid));
// Accept a connection and verify there is something there.
{
base::RunLoop run_loop;
server_socket->Accept(
base::BindOnce(&BluetoothSocketFlossTest::AcceptSuccessCallback,
weak_ptr_factory_.GetWeakPtr(),
run_loop.QuitWhenIdleClosure()),
base::BindOnce(&BluetoothSocketFlossTest::ErrorCallback,
weak_ptr_factory_.GetWeakPtr(),
run_loop.QuitWhenIdleClosure()));
run_loop.Run();
}
EXPECT_EQ(1, success_callback_count_);
EXPECT_EQ(0, error_callback_count_);
EXPECT_TRUE(last_socket_.get() != nullptr);
// Take ownership of the client socket and close it.
scoped_refptr<device::BluetoothSocket> client_socket =
std::move(last_socket_);
ClearCounters();
DisconnectSocket(client_socket.get());
client_socket = nullptr;
ClearCounters();
// Accept a connection when there's nothing there and then receives connection
// failed.
{
base::RunLoop run_loop;
server_socket->Accept(
base::BindOnce(&BluetoothSocketFlossTest::AcceptSuccessCallback,
weak_ptr_factory_.GetWeakPtr(),
run_loop.QuitWhenIdleClosure()),
base::BindOnce(&BluetoothSocketFlossTest::ErrorCallback,
weak_ptr_factory_.GetWeakPtr(),
run_loop.QuitWhenIdleClosure()));
run_loop.RunUntilIdle();
// No sockets found to accept.
EXPECT_EQ(0, success_callback_count_);
EXPECT_EQ(0, error_callback_count_);
GetFakeFlossSocketManager()->SendSocketReady(
id, device::BluetoothUUID(FakeFlossSocketManager::kRfcommUuid),
FlossDBusClient::BtifStatus::kFail);
EXPECT_EQ(1, error_callback_count_);
EXPECT_EQ(0, success_callback_count_);
EXPECT_TRUE(last_socket_.get() == nullptr);
ClearCounters();
}
// Accept a connection when there's nothing there and then send connection.
{
// First runloop will push the accept callbacks into socket.
// Second runloop will actually trigger when incoming connection occurs.
base::RunLoop outer_loop;
base::RunLoop inner_loop;
server_socket->Accept(
base::BindOnce(&BluetoothSocketFlossTest::AcceptSuccessCallback,
weak_ptr_factory_.GetWeakPtr(),
inner_loop.QuitWhenIdleClosure()),
base::BindOnce(&BluetoothSocketFlossTest::ErrorCallback,
weak_ptr_factory_.GetWeakPtr(),
inner_loop.QuitWhenIdleClosure()));
outer_loop.RunUntilIdle();
// No sockets found to accept.
EXPECT_EQ(0, success_callback_count_);
EXPECT_EQ(0, error_callback_count_);
EXPECT_TRUE(last_socket_.get() == nullptr);
GetFakeFlossSocketManager()->SendIncomingConnection(
id, device, device::BluetoothUUID(FakeFlossSocketManager::kRfcommUuid));
inner_loop.Run();
EXPECT_EQ(0, error_callback_count_);
EXPECT_EQ(1, success_callback_count_);
EXPECT_TRUE(last_socket_.get() != nullptr);
// Disconnect last connecting socket
client_socket = std::move(last_socket_);
DisconnectSocket(client_socket.get());
client_socket = nullptr;
last_socket_ = nullptr;
}
// Try to accept twice and make sure the second one fails.
ClearCounters();
{
base::RunLoop run_loop;
server_socket->Accept(
base::BindOnce(&BluetoothSocketFlossTest::AcceptSuccessCallback,
weak_ptr_factory_.GetWeakPtr(),
run_loop.QuitWhenIdleClosure()),
base::BindOnce(&BluetoothSocketFlossTest::ErrorCallback,
weak_ptr_factory_.GetWeakPtr(),
run_loop.QuitWhenIdleClosure()));
run_loop.RunUntilIdle();
// No change after first one
EXPECT_EQ(0, error_callback_count_);
server_socket->Accept(
base::BindOnce(&BluetoothSocketFlossTest::AcceptSuccessCallback,
weak_ptr_factory_.GetWeakPtr(),
run_loop.QuitWhenIdleClosure()),
base::BindOnce(&BluetoothSocketFlossTest::ErrorCallback,
weak_ptr_factory_.GetWeakPtr(),
run_loop.QuitWhenIdleClosure()));
run_loop.RunUntilIdle();
// Second one should fail
EXPECT_EQ(1, error_callback_count_);
ClearCounters();
}
// Clean up server socket at end.
DisconnectSocket(server_socket.get());
}
} // namespace floss