| // Copyright 2025 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/bluetooth_socket_android.h" |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <limits> |
| |
| #include "base/memory/scoped_refptr.h" |
| #include "base/run_loop.h" |
| #include "base/test/bind.h" |
| #include "base/test/task_environment.h" |
| #include "bluetooth_socket_thread.h" |
| #include "device/bluetooth/bluetooth_device_android.h" |
| #include "device/bluetooth/bluetooth_socket.h" |
| #include "device/bluetooth/test/bluetooth_test_android.h" |
| #include "device/bluetooth/test/test_bluetooth_adapter_observer.h" |
| #include "net/base/io_buffer.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace device { |
| |
| namespace { |
| |
| std::vector<uint8_t> GenerateMessage() { |
| constexpr size_t kMessageSize = 8192; |
| std::vector<uint8_t> message(kMessageSize); |
| |
| for (size_t i = 0; i < kMessageSize; ++i) { |
| uint16_t value = i % 512; |
| value = value < 256 ? value : 512 - value; |
| message[i] = value; |
| } |
| |
| return message; |
| } |
| |
| } // namespace |
| |
| class BluetoothSocketAndroidTest |
| : public BluetoothTestAndroid, |
| public testing::WithParamInterface< |
| base::RepeatingCallback<void(BluetoothSocketAndroidTest*)>> { |
| public: |
| // BluetoothTestAndroid overrides |
| void SetUp() override; |
| void TearDown() override; |
| |
| void Connect(); |
| void ConnectInsecurely(); |
| |
| protected: |
| void ConnectSocket(); |
| void DisconnectSocket(); |
| |
| raw_ptr<BluetoothDeviceAndroid> device_; |
| scoped_refptr<BluetoothSocket> socket_; |
| |
| std::string last_error_message_; |
| }; |
| |
| void BluetoothSocketAndroidTest::SetUp() { |
| BluetoothTestAndroid::SetUp(); |
| |
| InitWithFakeAdapter(); |
| |
| device_ = static_cast<BluetoothDeviceAndroid*>( |
| adapter_->GetDevice(SimulatePairedClassicDevice(1))); |
| } |
| |
| void BluetoothSocketAndroidTest::TearDown() { |
| if (socket_) { |
| DisconnectSocket(); |
| } |
| |
| BluetoothTestAndroid::TearDown(); |
| } |
| |
| void BluetoothSocketAndroidTest::Connect() { |
| base::RunLoop run_loop; |
| device_->ConnectToService( |
| BluetoothUUID(kTestUUIDSerial), |
| base::BindLambdaForTesting([&](scoped_refptr<BluetoothSocket> socket) { |
| socket_ = std::move(socket); |
| run_loop.Quit(); |
| }), |
| base::BindLambdaForTesting([&](const std::string& error_message) { |
| last_error_message_ = error_message; |
| run_loop.Quit(); |
| })); |
| run_loop.Run(); |
| } |
| |
| void BluetoothSocketAndroidTest::ConnectInsecurely() { |
| base::RunLoop run_loop; |
| device_->ConnectToServiceInsecurely( |
| BluetoothUUID(kTestUUIDSerial), |
| base::BindLambdaForTesting([&](scoped_refptr<BluetoothSocket> socket) { |
| socket_ = std::move(socket); |
| run_loop.Quit(); |
| }), |
| base::BindLambdaForTesting([&](const std::string& error_message) { |
| last_error_message_ = error_message; |
| run_loop.Quit(); |
| })); |
| run_loop.Run(); |
| } |
| |
| void BluetoothSocketAndroidTest::ConnectSocket() { |
| GetParam().Run(this); |
| } |
| |
| void BluetoothSocketAndroidTest::DisconnectSocket() { |
| base::RunLoop run_loop; |
| socket_->Disconnect(base::BindLambdaForTesting([&] { |
| socket_.reset(); |
| run_loop.Quit(); |
| })); |
| run_loop.Run(); |
| |
| EXPECT_FALSE(socket_); |
| } |
| |
| TEST_P(BluetoothSocketAndroidTest, Connect) { |
| ConnectSocket(); |
| |
| EXPECT_TRUE(socket_); |
| EXPECT_EQ(last_error_message_, std::string()); |
| } |
| |
| TEST_P(BluetoothSocketAndroidTest, ConnectFailed) { |
| const std::string kErrorMessage = "Test error"; |
| FailNextServiceConnection(device_, kErrorMessage); |
| |
| ConnectSocket(); |
| |
| EXPECT_FALSE(socket_); |
| EXPECT_EQ(last_error_message_, kErrorMessage); |
| } |
| |
| TEST_P(BluetoothSocketAndroidTest, DisconnectFailed) { |
| ConnectSocket(); |
| |
| FailNextOperation(socket_.get(), "Test error"); |
| |
| DisconnectSocket(); |
| } |
| |
| TEST_P(BluetoothSocketAndroidTest, Receive) { |
| ConnectSocket(); |
| |
| std::vector<uint8_t> message = GenerateMessage(); |
| SetReceivedBytes(socket_.get(), message); |
| |
| std::vector<uint8_t> received_message; |
| received_message.reserve(message.size()); |
| constexpr size_t kBufferSize = 2000; |
| for (size_t i = 0; i < message.size() / kBufferSize; i++) { |
| base::RunLoop run_loop; |
| socket_->Receive( |
| kBufferSize, |
| base::BindLambdaForTesting([&](int bytes_received, |
| scoped_refptr<net::IOBuffer> buffer) { |
| ASSERT_EQ(static_cast<size_t>(bytes_received), kBufferSize); |
| received_message.insert(received_message.end(), |
| buffer->span().begin(), buffer->span().end()); |
| run_loop.Quit(); |
| }), |
| base::BindLambdaForTesting( |
| [&](device::BluetoothSocket::ErrorReason reason, |
| const std::string& error_message) { |
| last_error_message_ = error_message; |
| run_loop.Quit(); |
| })); |
| run_loop.Run(); |
| } |
| |
| size_t remainder = message.size() % kBufferSize; |
| base::RunLoop run_loop; |
| socket_->Receive( |
| kBufferSize, |
| base::BindLambdaForTesting([&](int bytes_received, |
| scoped_refptr<net::IOBuffer> buffer) { |
| ASSERT_EQ(static_cast<size_t>(bytes_received), remainder); |
| received_message.insert(received_message.end(), buffer->span().begin(), |
| buffer->span().begin() + remainder); |
| run_loop.Quit(); |
| }), |
| base::BindLambdaForTesting( |
| [&](device::BluetoothSocket::ErrorReason reason, |
| const std::string& error_message) { |
| last_error_message_ = error_message; |
| run_loop.Quit(); |
| })); |
| run_loop.Run(); |
| |
| EXPECT_EQ(message, received_message); |
| EXPECT_EQ(last_error_message_, std::string()); |
| } |
| |
| TEST_P(BluetoothSocketAndroidTest, ReceiveFailed) { |
| ConnectSocket(); |
| |
| const std::string kErrorMessage = "Test error"; |
| FailNextOperation(socket_.get(), kErrorMessage); |
| |
| constexpr size_t kBufferSize = 2000; |
| base::RunLoop run_loop; |
| socket_->Receive( |
| kBufferSize, |
| base::BindLambdaForTesting( |
| [&](int bytes_received, scoped_refptr<net::IOBuffer> buffer) { |
| ADD_FAILURE(); |
| run_loop.Quit(); |
| }), |
| base::BindLambdaForTesting([&](BluetoothSocket::ErrorReason reason, |
| const std::string& error_message) { |
| EXPECT_EQ(reason, BluetoothSocket::ErrorReason::kSystemError); |
| last_error_message_ = error_message; |
| run_loop.Quit(); |
| })); |
| run_loop.Run(); |
| |
| EXPECT_EQ(last_error_message_, kErrorMessage); |
| } |
| |
| TEST_P(BluetoothSocketAndroidTest, ReceiveAfterDisconnect) { |
| ConnectSocket(); |
| scoped_refptr<BluetoothSocket> socket = socket_; |
| DisconnectSocket(); |
| |
| constexpr size_t kBufferSize = 2000; |
| base::RunLoop run_loop; |
| socket->Receive( |
| kBufferSize, |
| base::BindLambdaForTesting( |
| [&](int bytes_received, scoped_refptr<net::IOBuffer> buffer) { |
| ADD_FAILURE(); |
| run_loop.Quit(); |
| }), |
| base::BindLambdaForTesting([&](BluetoothSocket::ErrorReason reason, |
| const std::string& error_message) { |
| EXPECT_EQ(reason, BluetoothSocket::ErrorReason::kDisconnected); |
| run_loop.Quit(); |
| })); |
| run_loop.Run(); |
| } |
| |
| TEST_P(BluetoothSocketAndroidTest, Send) { |
| ConnectSocket(); |
| |
| std::vector<uint8_t> message = GenerateMessage(); |
| |
| scoped_refptr<net::IOBuffer> buffer = |
| base::MakeRefCounted<net::VectorIOBuffer>(message); |
| constexpr size_t kBufferSize = 2000; |
| |
| base::RunLoop run_loop; |
| socket_->Send( |
| buffer, kBufferSize, base::BindLambdaForTesting([&](int bytes_sent) { |
| EXPECT_EQ(static_cast<size_t>(bytes_sent), kBufferSize); |
| run_loop.Quit(); |
| }), |
| base::BindLambdaForTesting([&](const std::string& error_message) { |
| last_error_message_ = error_message; |
| run_loop.Quit(); |
| })); |
| run_loop.Run(); |
| |
| std::vector<uint8_t> sent_message = GetSentBytes(socket_.get()); |
| message.resize(kBufferSize); |
| EXPECT_EQ(message, sent_message); |
| EXPECT_EQ(last_error_message_, std::string()); |
| } |
| |
| TEST_P(BluetoothSocketAndroidTest, SendFailed) { |
| ConnectSocket(); |
| |
| std::vector<uint8_t> message = GenerateMessage(); |
| |
| scoped_refptr<net::IOBuffer> buffer = |
| base::MakeRefCounted<net::VectorIOBuffer>(message); |
| constexpr size_t kBufferSize = 2000; |
| |
| std::string error_message = "Test error"; |
| FailNextOperation(socket_.get(), error_message); |
| |
| base::RunLoop run_loop; |
| socket_->Send( |
| buffer, kBufferSize, base::BindLambdaForTesting([&](int bytes_sent) { |
| ADD_FAILURE(); |
| run_loop.Quit(); |
| }), |
| base::BindLambdaForTesting([&](const std::string& error_message) { |
| last_error_message_ = error_message; |
| run_loop.Quit(); |
| })); |
| run_loop.Run(); |
| |
| EXPECT_EQ(last_error_message_, error_message); |
| } |
| |
| TEST_P(BluetoothSocketAndroidTest, SendAfterDisconnect) { |
| ConnectSocket(); |
| scoped_refptr<BluetoothSocket> socket = socket_; |
| DisconnectSocket(); |
| |
| std::vector<uint8_t> message = GenerateMessage(); |
| |
| scoped_refptr<net::IOBuffer> buffer = |
| base::MakeRefCounted<net::VectorIOBuffer>(message); |
| constexpr size_t kBufferSize = 2000; |
| |
| base::RunLoop run_loop; |
| socket->Send( |
| buffer, kBufferSize, base::BindLambdaForTesting([&](int bytes_sent) { |
| ADD_FAILURE(); |
| run_loop.Quit(); |
| }), |
| base::BindLambdaForTesting([&](const std::string& error_message) { |
| last_error_message_ = error_message; |
| run_loop.Quit(); |
| })); |
| run_loop.Run(); |
| |
| EXPECT_NE(last_error_message_, std::string()); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| BluetoothSocketAndroidTests, |
| BluetoothSocketAndroidTest, |
| testing::Values( |
| base::BindRepeating(&BluetoothSocketAndroidTest::Connect), |
| base::BindRepeating(&BluetoothSocketAndroidTest::ConnectInsecurely))); |
| |
| } // namespace device |