blob: 00ced1bb81db03c5a9b7d715cce5108e106f75ec [file] [log] [blame]
// Copyright 2020 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/socket.h"
#include <tuple>
#include <vector>
#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/run_loop.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/task_environment.h"
#include "device/bluetooth/bluetooth_socket.h"
#include "device/bluetooth/test/fake_bluetooth_socket.h"
#include "mojo/public/cpp/system/simple_watcher.h"
#include "net/base/io_buffer.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace bluetooth {
class SocketTest : public testing::Test {
public:
SocketTest() = default;
~SocketTest() override = default;
SocketTest(const SocketTest&) = delete;
SocketTest& operator=(const SocketTest&) = delete;
void SetUp() override {
mojo::ScopedDataPipeProducerHandle receive_pipe_producer_handle;
mojo::ScopedDataPipeConsumerHandle receive_pipe_consumer_handle;
ASSERT_EQ(
MOJO_RESULT_OK,
mojo::CreateDataPipe(/*options=*/nullptr, receive_pipe_producer_handle,
receive_pipe_consumer_handle));
mojo::ScopedDataPipeProducerHandle send_pipe_producer_handle;
mojo::ScopedDataPipeConsumerHandle send_pipe_consumer_handle;
ASSERT_EQ(MOJO_RESULT_OK, mojo::CreateDataPipe(/*options=*/nullptr,
send_pipe_producer_handle,
send_pipe_consumer_handle));
receive_stream_ = std::move(receive_pipe_consumer_handle);
send_stream_ = std::move(send_pipe_producer_handle);
fake_bluetooth_socket_ =
base::MakeRefCounted<device::FakeBluetoothSocket>();
socket_ = std::make_unique<Socket>(fake_bluetooth_socket_,
std::move(receive_pipe_producer_handle),
std::move(send_pipe_consumer_handle));
}
void VerifyReceiveAndRead(const std::string& message, bool success) {
EXPECT_FALSE(receive_stream_->QuerySignalsState().never_readable());
// Socket should only have 1 outstanding invocation of
// BluetoothSocket::Receive().
EXPECT_TRUE(fake_bluetooth_socket_->HasReceiveArgs());
auto receive_args = fake_bluetooth_socket_->TakeReceiveArgs();
EXPECT_FALSE(fake_bluetooth_socket_->HasReceiveArgs());
int max_buffer_size = std::get<0>(*receive_args);
EXPECT_GT(max_buffer_size, 0);
// Attempting to read from |receive_stream_| before the BluetoothSocket
// provides received data should signal a MOJO_RESULT_SHOULD_WAIT result.
uint32_t buffer_size = static_cast<uint32_t>(max_buffer_size);
EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT,
receive_stream_->ReadData(nullptr, &buffer_size,
MOJO_READ_DATA_FLAG_NONE));
if (success) {
// Emulate a successful response from the remote device on the other side
// of the BluetoothSocket. |receive_stream_| should then be ready to be
// read from.
auto success_callback = std::move(std::get<1>(*receive_args));
std::move(success_callback)
.Run(
/*num_bytes_received=*/message.size(),
/*io_buffer=*/base::MakeRefCounted<net::StringIOBuffer>(message));
std::vector<char> buffer(max_buffer_size);
EXPECT_EQ(MOJO_RESULT_OK,
receive_stream_->ReadData(buffer.data(), &buffer_size,
MOJO_READ_DATA_FLAG_NONE));
std::string received_string(buffer.data(), buffer_size);
EXPECT_EQ(message, received_string);
} else {
// Emulate an error in the stack. We should not be able to read from
// |receive_stream_|.
auto error_callback = std::move(std::get<2>(*receive_args));
std::move(error_callback)
.Run(device::BluetoothSocket::ErrorReason::kSystemError, "Error");
}
// Socket should only invoke BluetoothSocket::Receive() if it received
// a success callback from the previous invocation.
EXPECT_EQ(success, fake_bluetooth_socket_->HasReceiveArgs());
// |receive_stream_| should only remain readable if Socket received a
// success callback.
EXPECT_EQ(success, !receive_stream_->QuerySignalsState().never_readable());
}
void WriteAndVerifySend(const std::string& message, bool success) {
EXPECT_FALSE(send_stream_->QuerySignalsState().never_writable());
// Verify that Socket has not attempted to invoke BluetoothSocket::Send(),
// because no bytes have been written over |send_stream_| yet.
EXPECT_FALSE(fake_bluetooth_socket_->HasSendArgs());
uint32_t message_size = message.size();
EXPECT_EQ(MOJO_RESULT_OK,
send_stream_->WriteData(message.data(), &message_size,
MOJO_WRITE_DATA_FLAG_NONE));
EXPECT_EQ(message.size(), message_size);
// Allow Socket to be notified that it can now read |send_stream_|.
base::RunLoop().RunUntilIdle();
// Socket should have now attempted to send our |message| to the remote
// device on the other side of the BluetoothSocket.
EXPECT_TRUE(fake_bluetooth_socket_->HasSendArgs());
auto send_args = fake_bluetooth_socket_->TakeSendArgs();
int buffer_size = std::get<1>(*send_args);
EXPECT_EQ(message_size, static_cast<uint32_t>(buffer_size));
char* buffer = std::get<0>(*send_args)->data();
std::string sent_string(buffer, buffer_size);
EXPECT_EQ(message, sent_string);
if (success) {
auto success_callback = std::move(std::get<2>(*send_args));
std::move(success_callback).Run(/*num_bytes_sent=*/message.size());
} else {
auto error_callback = std::move(std::get<3>(*send_args));
std::move(error_callback).Run(/*error_message=*/"Error");
}
// Never expect an outstanding invocation of BluetoothSocket::Send().
EXPECT_FALSE(fake_bluetooth_socket_->HasSendArgs());
// |send_stream_| should only remain writeable if Socket received a success
// callback.
EXPECT_EQ(success, !send_stream_->QuerySignalsState().never_writable());
}
protected:
scoped_refptr<device::FakeBluetoothSocket> fake_bluetooth_socket_;
mojo::ScopedDataPipeConsumerHandle receive_stream_;
mojo::ScopedDataPipeProducerHandle send_stream_;
std::unique_ptr<Socket> socket_;
private:
base::test::SingleThreadTaskEnvironment task_environment;
};
TEST_F(SocketTest, TestOnDestroyCallsClose) {
// When destroyed, |socket_| is expected to tear down its BluetoothSocket.
socket_.reset();
EXPECT_TRUE(fake_bluetooth_socket_->called_disconnect());
}
TEST_F(SocketTest, TestDisconnect) {
socket_->Disconnect(base::DoNothing());
EXPECT_TRUE(fake_bluetooth_socket_->called_disconnect());
}
TEST_F(SocketTest, TestReceive_Success) {
VerifyReceiveAndRead("received_message", /*success=*/true);
}
TEST_F(SocketTest, TestReceive_Error) {
VerifyReceiveAndRead("received_message", /*success=*/false);
}
TEST_F(SocketTest, TestSend_Success) {
WriteAndVerifySend("sent_message", /*success=*/true);
}
TEST_F(SocketTest, TestSend_Error) {
WriteAndVerifySend("sent_message", /*success=*/false);
}
TEST_F(SocketTest, TestReceiveAndSendMultiple) {
VerifyReceiveAndRead("message_1", /*success=*/true);
VerifyReceiveAndRead("message_2", /*success=*/true);
WriteAndVerifySend("message_3", /*success=*/true);
WriteAndVerifySend("message_4", /*success=*/true);
VerifyReceiveAndRead("message_5", /*success=*/true);
WriteAndVerifySend("message_6", /*success=*/true);
}
} // namespace bluetooth