#include #include #include #include #include #include using android::pdx::BorrowedChannelHandle; using android::pdx::BorrowedHandle; using android::pdx::ClientBase; using android::pdx::ClientChannel; using android::pdx::ClientChannelFactory; using android::pdx::ErrorStatus; using android::pdx::LocalChannelHandle; using android::pdx::LocalHandle; using android::pdx::MockClientChannel; using android::pdx::MockClientChannelFactory; using android::pdx::RemoteChannelHandle; using android::pdx::RemoteHandle; using android::pdx::Status; using android::pdx::Transaction; using android::pdx::rpc::Void; using testing::A; using testing::AnyNumber; using testing::ByMove; using testing::Invoke; using testing::Ne; using testing::Return; using testing::_; namespace { inline void* IntToPtr(intptr_t addr) { return reinterpret_cast(addr); } inline const void* IntToConstPtr(intptr_t addr) { return reinterpret_cast(addr); } struct TestInterface final { // Op codes. enum { kOpAdd = 0, kOpSendFile, kOpGetFile, kOpPushChannel, }; // Methods. PDX_REMOTE_METHOD(Add, kOpAdd, int(int, int)); PDX_REMOTE_METHOD(SendFile, kOpSendFile, void(const LocalHandle& fd)); PDX_REMOTE_METHOD(GetFile, kOpGetFile, LocalHandle(const std::string&, int)); PDX_REMOTE_METHOD(PushChannel, kOpPushChannel, LocalChannelHandle(Void)); PDX_REMOTE_API(API, Add, SendFile, GetFile, PushChannel); }; class SimpleClient : public ClientBase { public: explicit SimpleClient(std::unique_ptr channel) : BASE{std::move(channel)} {} SimpleClient(std::unique_ptr channel_factory, int64_t timeout_ms) : BASE{std::move(channel_factory), timeout_ms} { EnableAutoReconnect(timeout_ms); } using BASE::SendImpulse; using BASE::InvokeRemoteMethod; using BASE::InvokeRemoteMethodInPlace; using BASE::Close; using BASE::IsConnected; using BASE::EnableAutoReconnect; using BASE::DisableAutoReconnect; using BASE::event_fd; using BASE::GetChannel; MOCK_METHOD0(OnConnect, void()); }; class FailingClient : public ClientBase { public: explicit FailingClient(std::unique_ptr channel, int error_code) : BASE{std::move(channel)} { Close(error_code); } }; class ClientChannelTest : public testing::Test { public: ClientChannelTest() : client_{SimpleClient::Create( std::make_unique>())} {} MockClientChannel* mock_channel() { return static_cast(client_->GetChannel()); } std::unique_ptr client_; }; class ClientChannelFactoryTest : public testing::Test { public: ClientChannelFactoryTest() { auto factory = std::make_unique>(); ON_CALL(*factory, Connect(kTimeout)) .WillByDefault(Invoke(this, &ClientChannelFactoryTest::OnConnect)); client_ = SimpleClient::Create(std::move(factory), kTimeout); } MockClientChannel* mock_channel() { return static_cast(client_->GetChannel()); } Status> OnConnect(int64_t /*timeout_ms*/) { if (on_connect_error_) return ErrorStatus(on_connect_error_); std::unique_ptr channel = std::make_unique>(); if (on_connect_callback_) on_connect_callback_(channel.get()); return Status>{std::move(channel)}; } void OnConnectCallback(std::function callback) { on_connect_callback_ = callback; } void SetOnConnectError(int error) { on_connect_error_ = error; } void ResetOnConnectError() { on_connect_error_ = 0; } constexpr static int64_t kTimeout = 123; std::unique_ptr client_; std::function on_connect_callback_; int on_connect_error_{0}; }; constexpr int64_t ClientChannelFactoryTest::kTimeout; class ClientTransactionTest : public ClientChannelTest { public: ClientTransactionTest() : transaction_{*client_} {} Transaction transaction_; }; } // anonymous namespace TEST_F(ClientChannelTest, IsInitialized) { ASSERT_NE(client_.get(), nullptr); EXPECT_TRUE(client_->IsInitialized()); EXPECT_TRUE(client_->IsConnected()); } TEST_F(ClientChannelTest, CloseOnConstruction) { FailingClient failed_client1{std::make_unique(), EACCES}; ASSERT_FALSE(failed_client1.IsInitialized()); EXPECT_EQ(-EACCES, failed_client1.error()); FailingClient failed_client2{std::make_unique(), -EACCES}; ASSERT_FALSE(failed_client2.IsInitialized()); EXPECT_EQ(-EACCES, failed_client2.error()); auto failed_client3 = FailingClient::Create(std::make_unique(), EIO); ASSERT_EQ(failed_client3.get(), nullptr); } TEST_F(ClientChannelTest, IsConnected) { EXPECT_TRUE(client_->IsConnected()); EXPECT_EQ(0, client_->error()); client_->Close(-EINVAL); EXPECT_FALSE(client_->IsConnected()); EXPECT_EQ(-EINVAL, client_->error()); } TEST_F(ClientChannelTest, event_fd) { EXPECT_CALL(*mock_channel(), event_fd()).WillOnce(Return(12)); EXPECT_EQ(12, client_->event_fd()); } TEST_F(ClientChannelTest, SendImpulse) { EXPECT_CALL(*mock_channel(), SendImpulse(123, nullptr, 0)) .WillOnce(Return(Status{})); EXPECT_TRUE(client_->SendImpulse(123)); EXPECT_CALL(*mock_channel(), SendImpulse(17, nullptr, 0)) .WillOnce(Return(ErrorStatus{EIO})); auto status = client_->SendImpulse(17); ASSERT_FALSE(status); EXPECT_EQ(EIO, status.error()); const void* const kTestPtr = IntToConstPtr(1234); EXPECT_CALL(*mock_channel(), SendImpulse(1, kTestPtr, 17)) .WillOnce(Return(Status{})); EXPECT_TRUE(client_->SendImpulse(1, kTestPtr, 17)); } TEST_F(ClientChannelTest, InvokeRemoteMethodNullTransactionState) { EXPECT_CALL(*mock_channel(), AllocateTransactionState()) .WillOnce(Return(nullptr)); EXPECT_CALL(*mock_channel(), SendWithInt(nullptr, TestInterface::kOpAdd, _, _, nullptr, 0)) .WillOnce(Return(9)); EXPECT_CALL(*mock_channel(), FreeTransactionState(nullptr)); EXPECT_TRUE(client_->InvokeRemoteMethod(4, 5)); } TEST_F(ClientChannelTest, InvokeRemoteMethodAddSuccess) { void* const kTransactionState = IntToPtr(123); EXPECT_CALL(*mock_channel(), AllocateTransactionState()) .WillOnce(Return(kTransactionState)); EXPECT_CALL( *mock_channel(), SendWithInt(kTransactionState, TestInterface::kOpAdd, _, _, nullptr, 0)) .WillOnce(Return(3)); EXPECT_CALL(*mock_channel(), FreeTransactionState(kTransactionState)); Status status = client_->InvokeRemoteMethod(1, 2); ASSERT_TRUE(status); EXPECT_EQ(3, status.get()); } TEST_F(ClientChannelTest, InvokeRemoteMethodAddFailure) { void* const kTransactionState = IntToPtr(123); EXPECT_CALL(*mock_channel(), AllocateTransactionState()) .WillOnce(Return(kTransactionState)); EXPECT_CALL( *mock_channel(), SendWithInt(kTransactionState, TestInterface::kOpAdd, _, _, nullptr, 0)) .WillOnce(Return(ErrorStatus{EIO})); EXPECT_CALL(*mock_channel(), FreeTransactionState(kTransactionState)); Status status = client_->InvokeRemoteMethod(1, 2); ASSERT_FALSE(status); EXPECT_EQ(EIO, status.error()); } TEST_F(ClientChannelTest, InvokeRemoteMethodGetFileSuccess) { void* const kTransactionState = IntToPtr(123); int fd = eventfd(0, 0); EXPECT_CALL(*mock_channel(), AllocateTransactionState()) .WillOnce(Return(kTransactionState)); EXPECT_CALL(*mock_channel(), SendWithFileHandle(kTransactionState, TestInterface::kOpGetFile, _, _, nullptr, 0)) .WillOnce(Return(ByMove(LocalHandle{fd}))); EXPECT_CALL(*mock_channel(), FreeTransactionState(kTransactionState)); Status status = client_->InvokeRemoteMethod(); ASSERT_TRUE(status); EXPECT_EQ(fd, status.get().Get()); } TEST_F(ClientChannelTest, InvokeRemoteMethodGetFileFailure) { void* const kTransactionState = IntToPtr(123); EXPECT_CALL(*mock_channel(), AllocateTransactionState()) .WillOnce(Return(kTransactionState)); EXPECT_CALL(*mock_channel(), SendWithFileHandle(kTransactionState, TestInterface::kOpGetFile, _, _, nullptr, 0)) .WillOnce(Return(ByMove(ErrorStatus{EACCES}))); EXPECT_CALL(*mock_channel(), FreeTransactionState(kTransactionState)); Status status = client_->InvokeRemoteMethod("file", 0); ASSERT_FALSE(status); EXPECT_EQ(EACCES, status.error()); } TEST_F(ClientChannelTest, InvokeRemoteMethodPushChannelSuccess) { void* const kTransactionState = IntToPtr(123); const int32_t kHandleValue = 17; EXPECT_CALL(*mock_channel(), AllocateTransactionState()) .WillOnce(Return(kTransactionState)); EXPECT_CALL( *mock_channel(), SendWithChannelHandle(kTransactionState, TestInterface::kOpPushChannel, _, _, nullptr, 0)) .WillOnce(Return(ByMove(LocalChannelHandle{nullptr, kHandleValue}))); EXPECT_CALL(*mock_channel(), FreeTransactionState(kTransactionState)); Status status = client_->InvokeRemoteMethod(); ASSERT_TRUE(status); EXPECT_EQ(kHandleValue, status.get().value()); } TEST_F(ClientChannelTest, InvokeRemoteMethodPushChannelFailure) { void* const kTransactionState = IntToPtr(123); EXPECT_CALL(*mock_channel(), AllocateTransactionState()) .WillOnce(Return(kTransactionState)); EXPECT_CALL( *mock_channel(), SendWithChannelHandle(kTransactionState, TestInterface::kOpPushChannel, _, _, nullptr, 0)) .WillOnce(Return(ByMove(ErrorStatus{EACCES}))); EXPECT_CALL(*mock_channel(), FreeTransactionState(kTransactionState)); Status status = client_->InvokeRemoteMethod(); ASSERT_FALSE(status); EXPECT_EQ(EACCES, status.error()); } TEST_F(ClientChannelTest, InvokeRemoteMethodSendFileSuccess) { void* const kTransactionState = IntToPtr(123); LocalHandle fd{eventfd(0, 0)}; EXPECT_CALL(*mock_channel(), AllocateTransactionState()) .WillOnce(Return(kTransactionState)); EXPECT_CALL(*mock_channel(), PushFileHandle(kTransactionState, A())) .WillOnce(Return(1)); EXPECT_CALL(*mock_channel(), SendWithInt(kTransactionState, TestInterface::kOpSendFile, _, _, nullptr, 0)) .WillOnce(Return(0)); EXPECT_CALL(*mock_channel(), FreeTransactionState(kTransactionState)); EXPECT_TRUE(client_->InvokeRemoteMethod(fd)); } TEST_F(ClientChannelTest, InvokeRemoteMethodSendFileFailure) { void* const kTransactionState = IntToPtr(123); LocalHandle fd{eventfd(0, 0)}; EXPECT_CALL(*mock_channel(), AllocateTransactionState()) .WillOnce(Return(kTransactionState)); EXPECT_CALL(*mock_channel(), PushFileHandle(kTransactionState, A())) .WillOnce(Return(1)); EXPECT_CALL(*mock_channel(), SendWithInt(kTransactionState, TestInterface::kOpSendFile, _, _, nullptr, 0)) .WillOnce(Return(ErrorStatus{EACCES})); EXPECT_CALL(*mock_channel(), FreeTransactionState(kTransactionState)); EXPECT_FALSE(client_->InvokeRemoteMethod(fd)); } TEST_F(ClientChannelFactoryTest, IsInitialized) { ASSERT_NE(client_.get(), nullptr); EXPECT_TRUE(client_->IsInitialized()); EXPECT_TRUE(client_->IsConnected()); } TEST_F(ClientChannelFactoryTest, NotConnectedButInitialized) { auto factory = std::make_unique>(); EXPECT_CALL(*factory, Connect(kTimeout)) .WillOnce(Return(ByMove(ErrorStatus(ESHUTDOWN)))) .WillOnce(Invoke(this, &ClientChannelFactoryTest::OnConnect)); client_ = SimpleClient::Create(std::move(factory), kTimeout); ASSERT_NE(client_.get(), nullptr); EXPECT_TRUE(client_->IsInitialized()); EXPECT_FALSE(client_->IsConnected()); client_->DisableAutoReconnect(); ASSERT_FALSE(client_->SendImpulse(17)); EXPECT_FALSE(client_->IsConnected()); client_->EnableAutoReconnect(kTimeout); EXPECT_CALL(*client_, OnConnect()); OnConnectCallback([](auto* mock) { EXPECT_CALL(*mock, SendImpulse(17, nullptr, 0)) .WillOnce(Return(Status{})); }); ASSERT_TRUE(client_->SendImpulse(17)); EXPECT_TRUE(client_->IsConnected()); } TEST_F(ClientChannelFactoryTest, CheckDisconnect) { EXPECT_CALL(*mock_channel(), SendImpulse(17, nullptr, 0)) .WillOnce(Return(ErrorStatus{ESHUTDOWN})); ASSERT_FALSE(client_->SendImpulse(17)); EXPECT_FALSE(client_->IsConnected()); EXPECT_EQ(-ESHUTDOWN, client_->error()); } TEST_F(ClientChannelFactoryTest, CheckReconnect) { client_->Close(ESHUTDOWN); ASSERT_FALSE(client_->IsConnected()); EXPECT_CALL(*client_, OnConnect()); OnConnectCallback([](auto* mock) { EXPECT_CALL(*mock, SendImpulse(17, nullptr, 0)) .WillOnce(Return(Status{})); }); ASSERT_TRUE(client_->SendImpulse(17)); EXPECT_TRUE(client_->IsConnected()); } TEST_F(ClientChannelFactoryTest, CloseOnConnect) { client_->Close(ESHUTDOWN); EXPECT_CALL(*client_, OnConnect()).WillOnce(Invoke([this] { client_->Close(EIO); })); auto status = client_->SendImpulse(17); ASSERT_FALSE(status); EXPECT_EQ(EIO, status.error()); EXPECT_FALSE(client_->IsConnected()); EXPECT_EQ(-EIO, client_->error()); } TEST_F(ClientChannelFactoryTest, DisableAutoReconnect) { client_->Close(EIO); ASSERT_FALSE(client_->IsConnected()); client_->DisableAutoReconnect(); auto status = client_->SendImpulse(17); ASSERT_FALSE(status); EXPECT_EQ(ESHUTDOWN, status.error()); EXPECT_FALSE(client_->IsConnected()); client_->EnableAutoReconnect(kTimeout); EXPECT_CALL(*client_, OnConnect()); OnConnectCallback([](auto* mock) { EXPECT_CALL(*mock, SendImpulse(17, nullptr, 0)) .WillOnce(Return(Status{})); }); ASSERT_TRUE(client_->SendImpulse(17)); EXPECT_TRUE(client_->IsConnected()); } TEST_F(ClientTransactionTest, SendNoData) { void* const kTransactionState = IntToPtr(123); EXPECT_CALL(*mock_channel(), AllocateTransactionState()) .WillOnce(Return(kTransactionState)); EXPECT_CALL(*mock_channel(), FreeTransactionState(kTransactionState)); EXPECT_CALL(*mock_channel(), SendWithInt(kTransactionState, 1, nullptr, 0, nullptr, 0)) .WillOnce(Return(0)); EXPECT_TRUE(transaction_.Send(1)); EXPECT_CALL(*mock_channel(), SendWithFileHandle(kTransactionState, 2, nullptr, 0, nullptr, 0)) .WillOnce(Return(ByMove(LocalHandle{-1}))); EXPECT_TRUE(transaction_.Send(2)); EXPECT_CALL(*mock_channel(), SendWithChannelHandle(kTransactionState, 3, nullptr, 0, nullptr, 0)) .WillOnce(Return(ByMove(LocalChannelHandle{nullptr, 1}))); EXPECT_TRUE(transaction_.Send(3)); } TEST_F(ClientTransactionTest, SendNoState) { EXPECT_CALL(*mock_channel(), AllocateTransactionState()) .WillOnce(Return(nullptr)); EXPECT_CALL(*mock_channel(), SendWithInt(nullptr, 1, nullptr, 0, nullptr, 0)) .WillOnce(Return(0)); EXPECT_CALL(*mock_channel(), FreeTransactionState(nullptr)); EXPECT_TRUE(transaction_.Send(1)); } TEST_F(ClientTransactionTest, SendBuffers) { const void* const kSendBuffer = IntToConstPtr(123); const size_t kSendSize = 12; void* const kReceiveBuffer = IntToPtr(456); const size_t kReceiveSize = 34; EXPECT_CALL(*mock_channel(), AllocateTransactionState()) .WillOnce(Return(nullptr)); EXPECT_CALL(*mock_channel(), FreeTransactionState(nullptr)); EXPECT_CALL(*mock_channel(), SendWithInt(nullptr, 1, nullptr, 0, nullptr, 0)) .WillOnce(Return(0)); EXPECT_TRUE(transaction_.Send(1, nullptr, 0, nullptr, 0)); EXPECT_CALL(*mock_channel(), SendWithInt(nullptr, 2, Ne(nullptr), 1, nullptr, 0)) .WillOnce(Return(0)); EXPECT_TRUE(transaction_.Send(2, kSendBuffer, kSendSize, nullptr, 0)); EXPECT_CALL(*mock_channel(), SendWithInt(nullptr, 3, nullptr, 0, nullptr, 0)) .WillOnce(Return(0)); EXPECT_TRUE(transaction_.Send(3, kSendBuffer, 0, nullptr, 0)); EXPECT_CALL(*mock_channel(), SendWithInt(nullptr, 4, nullptr, 0, Ne(nullptr), 1)) .WillOnce(Return(0)); EXPECT_TRUE( transaction_.Send(4, nullptr, 0, kReceiveBuffer, kReceiveSize)); EXPECT_CALL(*mock_channel(), SendWithInt(nullptr, 5, nullptr, 0, nullptr, 0)) .WillOnce(Return(0)); EXPECT_TRUE(transaction_.Send(5, nullptr, 0, kReceiveBuffer, 0)); EXPECT_CALL(*mock_channel(), SendWithInt(nullptr, 5, Ne(nullptr), 1, Ne(nullptr), 1)) .WillOnce(Return(0)); EXPECT_TRUE(transaction_.Send(5, kSendBuffer, kSendSize, kReceiveBuffer, kReceiveSize)); } TEST_F(ClientTransactionTest, SendVector) { iovec send[3] = {}; iovec recv[4] = {}; EXPECT_CALL(*mock_channel(), AllocateTransactionState()) .WillOnce(Return(nullptr)); EXPECT_CALL(*mock_channel(), FreeTransactionState(nullptr)); EXPECT_CALL(*mock_channel(), SendWithInt(nullptr, 1, nullptr, 0, nullptr, 0)) .WillOnce(Return(0)); EXPECT_TRUE(transaction_.SendVector(1, nullptr, 0, nullptr, 0)); EXPECT_CALL(*mock_channel(), SendWithInt(nullptr, 2, send, 3, recv, 4)) .WillOnce(Return(0)); EXPECT_TRUE(transaction_.SendVector(2, send, 3, recv, 4)); EXPECT_CALL(*mock_channel(), SendWithInt(nullptr, 3, send, 3, nullptr, 0)) .WillOnce(Return(0)); EXPECT_TRUE(transaction_.SendVector(3, send, nullptr)); EXPECT_CALL(*mock_channel(), SendWithInt(nullptr, 4, nullptr, 0, recv, 4)) .WillOnce(Return(0)); EXPECT_TRUE(transaction_.SendVector(4, nullptr, recv)); EXPECT_CALL(*mock_channel(), SendWithInt(nullptr, 5, send, 3, recv, 4)) .WillOnce(Return(0)); EXPECT_TRUE(transaction_.SendVector(5, send, recv)); } TEST_F(ClientTransactionTest, PushHandle) { void* const kTransactionState = IntToPtr(123); EXPECT_CALL(*mock_channel(), AllocateTransactionState()) .WillOnce(Return(kTransactionState)); EXPECT_CALL(*mock_channel(), FreeTransactionState(kTransactionState)); EXPECT_CALL(*mock_channel(), PushFileHandle(kTransactionState, A())) .WillOnce(Return(1)); EXPECT_EQ(1, transaction_.PushFileHandle(LocalHandle{-1}).get()); EXPECT_CALL(*mock_channel(), PushFileHandle(kTransactionState, A())) .WillOnce(Return(2)); EXPECT_EQ(2, transaction_.PushFileHandle(BorrowedHandle{-1}).get()); EXPECT_EQ(3, transaction_.PushFileHandle(RemoteHandle{3}).get()); EXPECT_CALL( *mock_channel(), PushChannelHandle(kTransactionState, A())) .WillOnce(Return(11)); EXPECT_EQ( 11, transaction_.PushChannelHandle(LocalChannelHandle{nullptr, 1}).get()); EXPECT_CALL( *mock_channel(), PushChannelHandle(kTransactionState, A())) .WillOnce(Return(12)); EXPECT_EQ(12, transaction_.PushChannelHandle(BorrowedChannelHandle{2}).get()); EXPECT_EQ(13, transaction_.PushChannelHandle(RemoteChannelHandle{13}).get()); } TEST_F(ClientTransactionTest, GetHandle) { void* const kTransactionState = IntToPtr(123); EXPECT_CALL(*mock_channel(), AllocateTransactionState()) .WillOnce(Return(kTransactionState)); EXPECT_CALL(*mock_channel(), FreeTransactionState(kTransactionState)); EXPECT_CALL(*mock_channel(), GetFileHandle(kTransactionState, 1, _)) .WillOnce(Return(false)) .WillOnce(Return(true)); LocalHandle file_handle; EXPECT_FALSE(transaction_.GetFileHandle(1, &file_handle)); EXPECT_TRUE(transaction_.GetFileHandle(1, &file_handle)); EXPECT_CALL(*mock_channel(), GetChannelHandle(kTransactionState, 2, _)) .WillOnce(Return(false)) .WillOnce(Return(true)); LocalChannelHandle channel_handle; EXPECT_FALSE(transaction_.GetChannelHandle(2, &channel_handle)); EXPECT_TRUE(transaction_.GetChannelHandle(2, &channel_handle)); }