blob: 84ccf2449ee819d1d9758785bf78f25e1c4ee993 [file] [log] [blame]
// Copyright 2014 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 <string>
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/string_piece.h"
#include "device/serial/data_receiver.h"
#include "device/serial/data_sender.h"
#include "device/serial/data_stream.mojom.h"
#include "device/serial/serial.mojom.h"
#include "device/serial/serial_connection.h"
#include "device/serial/serial_service_impl.h"
#include "device/serial/test_serial_io_handler.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/mojo/src/mojo/public/cpp/bindings/error_handler.h"
#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_ptr.h"
#include "third_party/mojo/src/mojo/public/cpp/bindings/interface_request.h"
namespace device {
namespace {
class FakeSerialDeviceEnumerator : public SerialDeviceEnumerator {
mojo::Array<serial::DeviceInfoPtr> GetDevices() override {
mojo::Array<serial::DeviceInfoPtr> devices(1);
devices[0] = serial::DeviceInfo::New();
devices[0]->path = "device";
return devices.Pass();
}
};
} // namespace
class SerialConnectionTest : public testing::Test, public mojo::ErrorHandler {
public:
enum Event {
EVENT_NONE,
EVENT_GOT_INFO,
EVENT_SET_OPTIONS,
EVENT_GOT_CONTROL_SIGNALS,
EVENT_SET_CONTROL_SIGNALS,
EVENT_FLUSHED,
EVENT_DATA_AT_IO_HANDLER,
EVENT_DATA_SENT,
EVENT_SEND_ERROR,
EVENT_DATA_RECEIVED,
EVENT_RECEIVE_ERROR,
EVENT_CANCEL_COMPLETE,
EVENT_ERROR,
};
static const uint32_t kBufferSize;
SerialConnectionTest()
: connected_(false),
success_(false),
bytes_sent_(0),
send_error_(serial::SEND_ERROR_NONE),
receive_error_(serial::RECEIVE_ERROR_NONE),
expected_event_(EVENT_NONE) {}
void SetUp() override {
message_loop_.reset(new base::MessageLoop);
mojo::InterfacePtr<serial::SerialService> service;
mojo::BindToProxy(
new SerialServiceImpl(
new SerialConnectionFactory(
base::Bind(&SerialConnectionTest::CreateIoHandler,
base::Unretained(this)),
base::MessageLoopProxy::current()),
scoped_ptr<SerialDeviceEnumerator>(new FakeSerialDeviceEnumerator)),
&service);
service.set_error_handler(this);
mojo::InterfacePtr<serial::DataSink> sink;
mojo::InterfacePtr<serial::DataSource> source;
mojo::InterfacePtr<serial::DataSourceClient> source_client;
mojo::InterfaceRequest<serial::DataSourceClient> source_client_request =
mojo::GetProxy(&source_client);
service->Connect("device", serial::ConnectionOptions::New(),
mojo::GetProxy(&connection_), mojo::GetProxy(&sink),
mojo::GetProxy(&source), source_client.Pass());
sender_.reset(new DataSender(sink.Pass(), kBufferSize,
serial::SEND_ERROR_DISCONNECTED));
receiver_ =
new DataReceiver(source.Pass(), source_client_request.Pass(),
kBufferSize, serial::RECEIVE_ERROR_DISCONNECTED);
connection_.set_error_handler(this);
connection_->GetInfo(
base::Bind(&SerialConnectionTest::StoreInfo, base::Unretained(this)));
WaitForEvent(EVENT_GOT_INFO);
ASSERT_TRUE(io_handler_.get());
}
void StoreInfo(serial::ConnectionInfoPtr options) {
info_ = options.Pass();
EventReceived(EVENT_GOT_INFO);
}
void StoreControlSignals(serial::DeviceControlSignalsPtr signals) {
signals_ = signals.Pass();
EventReceived(EVENT_GOT_CONTROL_SIGNALS);
}
void StoreSuccess(Event event_to_report, bool success) {
success_ = success;
EventReceived(event_to_report);
}
void Send(const base::StringPiece& data) {
ASSERT_TRUE(sender_->Send(
data,
base::Bind(&SerialConnectionTest::OnDataSent, base::Unretained(this)),
base::Bind(&SerialConnectionTest::OnSendError,
base::Unretained(this))));
}
void Receive() {
ASSERT_TRUE(
receiver_->Receive(base::Bind(&SerialConnectionTest::OnDataReceived,
base::Unretained(this)),
base::Bind(&SerialConnectionTest::OnReceiveError,
base::Unretained(this))));
}
void WaitForEvent(Event event) {
expected_event_ = event;
base::RunLoop run_loop;
stop_run_loop_ = run_loop.QuitClosure();
run_loop.Run();
}
void EventReceived(Event event) {
if (event != expected_event_)
return;
expected_event_ = EVENT_NONE;
ASSERT_TRUE(message_loop_);
ASSERT_TRUE(!stop_run_loop_.is_null());
message_loop_->PostTask(FROM_HERE, stop_run_loop_);
}
scoped_refptr<SerialIoHandler> CreateIoHandler() {
io_handler_ = new TestSerialIoHandler;
return io_handler_;
}
void OnDataSent(uint32_t bytes_sent) {
bytes_sent_ += bytes_sent;
send_error_ = serial::SEND_ERROR_NONE;
EventReceived(EVENT_DATA_SENT);
}
void OnSendError(uint32_t bytes_sent, int32_t error) {
bytes_sent_ += bytes_sent;
send_error_ = static_cast<serial::SendError>(error);
EventReceived(EVENT_SEND_ERROR);
}
void OnDataReceived(scoped_ptr<ReadOnlyBuffer> buffer) {
data_received_ += std::string(buffer->GetData(), buffer->GetSize());
buffer->Done(buffer->GetSize());
receive_error_ = serial::RECEIVE_ERROR_NONE;
EventReceived(EVENT_DATA_RECEIVED);
}
void OnReceiveError(int32_t error) {
receive_error_ = static_cast<serial::ReceiveError>(error);
EventReceived(EVENT_RECEIVE_ERROR);
}
void OnConnectionError() override {
EventReceived(EVENT_ERROR);
FAIL() << "Connection error";
}
mojo::Array<serial::DeviceInfoPtr> devices_;
serial::ConnectionInfoPtr info_;
serial::DeviceControlSignalsPtr signals_;
bool connected_;
bool success_;
int bytes_sent_;
serial::SendError send_error_;
serial::ReceiveError receive_error_;
std::string data_received_;
Event expected_event_;
scoped_ptr<base::MessageLoop> message_loop_;
base::Closure stop_run_loop_;
mojo::InterfacePtr<serial::Connection> connection_;
scoped_ptr<DataSender> sender_;
scoped_refptr<DataReceiver> receiver_;
scoped_refptr<TestSerialIoHandler> io_handler_;
private:
DISALLOW_COPY_AND_ASSIGN(SerialConnectionTest);
};
const uint32_t SerialConnectionTest::kBufferSize = 10;
TEST_F(SerialConnectionTest, GetInfo) {
// |info_| is filled in during SetUp().
ASSERT_TRUE(info_);
EXPECT_EQ(9600u, info_->bitrate);
EXPECT_EQ(serial::DATA_BITS_EIGHT, info_->data_bits);
EXPECT_EQ(serial::PARITY_BIT_NO, info_->parity_bit);
EXPECT_EQ(serial::STOP_BITS_ONE, info_->stop_bits);
EXPECT_FALSE(info_->cts_flow_control);
}
TEST_F(SerialConnectionTest, SetOptions) {
serial::ConnectionOptionsPtr options(serial::ConnectionOptions::New());
options->bitrate = 12345;
options->data_bits = serial::DATA_BITS_SEVEN;
options->has_cts_flow_control = true;
options->cts_flow_control = true;
connection_->SetOptions(options.Pass(),
base::Bind(&SerialConnectionTest::StoreSuccess,
base::Unretained(this),
EVENT_SET_OPTIONS));
WaitForEvent(EVENT_SET_OPTIONS);
ASSERT_TRUE(success_);
serial::ConnectionInfo* info = io_handler_->connection_info();
EXPECT_EQ(12345u, info->bitrate);
EXPECT_EQ(serial::DATA_BITS_SEVEN, info->data_bits);
EXPECT_EQ(serial::PARITY_BIT_NO, info->parity_bit);
EXPECT_EQ(serial::STOP_BITS_ONE, info->stop_bits);
EXPECT_TRUE(info->cts_flow_control);
}
TEST_F(SerialConnectionTest, GetControlSignals) {
connection_->GetControlSignals(base::Bind(
&SerialConnectionTest::StoreControlSignals, base::Unretained(this)));
serial::DeviceControlSignals* signals = io_handler_->device_control_signals();
signals->dcd = true;
signals->dsr = true;
WaitForEvent(EVENT_GOT_CONTROL_SIGNALS);
ASSERT_TRUE(signals_);
EXPECT_TRUE(signals_->dcd);
EXPECT_FALSE(signals_->cts);
EXPECT_FALSE(signals_->ri);
EXPECT_TRUE(signals_->dsr);
}
TEST_F(SerialConnectionTest, SetControlSignals) {
serial::HostControlSignalsPtr signals(serial::HostControlSignals::New());
signals->has_dtr = true;
signals->dtr = true;
signals->has_rts = true;
signals->rts = true;
connection_->SetControlSignals(signals.Pass(),
base::Bind(&SerialConnectionTest::StoreSuccess,
base::Unretained(this),
EVENT_SET_CONTROL_SIGNALS));
WaitForEvent(EVENT_SET_CONTROL_SIGNALS);
ASSERT_TRUE(success_);
EXPECT_TRUE(io_handler_->dtr());
EXPECT_TRUE(io_handler_->rts());
}
TEST_F(SerialConnectionTest, Flush) {
ASSERT_EQ(0, io_handler_->flushes());
connection_->Flush(base::Bind(&SerialConnectionTest::StoreSuccess,
base::Unretained(this),
EVENT_FLUSHED));
WaitForEvent(EVENT_FLUSHED);
ASSERT_TRUE(success_);
EXPECT_EQ(1, io_handler_->flushes());
}
TEST_F(SerialConnectionTest, DisconnectWithSend) {
connection_.reset();
io_handler_->set_send_callback(base::Bind(base::DoNothing));
ASSERT_NO_FATAL_FAILURE(Send("data"));
WaitForEvent(EVENT_SEND_ERROR);
EXPECT_EQ(serial::SEND_ERROR_DISCONNECTED, send_error_);
EXPECT_EQ(0, bytes_sent_);
EXPECT_TRUE(io_handler_->HasOneRef());
}
TEST_F(SerialConnectionTest, DisconnectWithReceive) {
connection_.reset();
ASSERT_NO_FATAL_FAILURE(Receive());
WaitForEvent(EVENT_RECEIVE_ERROR);
EXPECT_EQ(serial::RECEIVE_ERROR_DISCONNECTED, receive_error_);
EXPECT_EQ("", data_received_);
EXPECT_TRUE(io_handler_->HasOneRef());
}
TEST_F(SerialConnectionTest, Echo) {
ASSERT_NO_FATAL_FAILURE(Send("data"));
WaitForEvent(EVENT_DATA_SENT);
EXPECT_EQ(serial::SEND_ERROR_NONE, send_error_);
EXPECT_EQ(4, bytes_sent_);
ASSERT_NO_FATAL_FAILURE(Receive());
WaitForEvent(EVENT_DATA_RECEIVED);
EXPECT_EQ("data", data_received_);
EXPECT_EQ(serial::RECEIVE_ERROR_NONE, receive_error_);
}
TEST_F(SerialConnectionTest, Cancel) {
// To test that cancels are correctly passed to the IoHandler, we need a send
// to be in progress because otherwise, the DataSinkReceiver would handle the
// cancel internally.
io_handler_->set_send_callback(
base::Bind(&SerialConnectionTest::EventReceived,
base::Unretained(this),
EVENT_DATA_AT_IO_HANDLER));
ASSERT_NO_FATAL_FAILURE(Send("something else"));
WaitForEvent(EVENT_DATA_AT_IO_HANDLER);
EXPECT_EQ(0, bytes_sent_);
ASSERT_TRUE(sender_->Cancel(serial::SEND_ERROR_TIMEOUT,
base::Bind(&SerialConnectionTest::EventReceived,
base::Unretained(this),
EVENT_CANCEL_COMPLETE)));
WaitForEvent(EVENT_CANCEL_COMPLETE);
EXPECT_EQ(serial::SEND_ERROR_TIMEOUT, send_error_);
ASSERT_NO_FATAL_FAILURE(Send("data"));
WaitForEvent(EVENT_DATA_SENT);
EXPECT_EQ(serial::SEND_ERROR_NONE, send_error_);
EXPECT_EQ(4, bytes_sent_);
ASSERT_NO_FATAL_FAILURE(Receive());
WaitForEvent(EVENT_DATA_RECEIVED);
EXPECT_EQ("data", data_received_);
EXPECT_EQ(serial::RECEIVE_ERROR_NONE, receive_error_);
}
} // namespace device