blob: 938d73774e8dc94d92fbcbf7fbcbbaf1d464fc6d [file] [log] [blame]
#include <pdx/service.h>
#include <memory>
#include <string>
#include <gmock/gmock.h>
#include <pdx/mock_service_endpoint.h>
using android::pdx::BorrowedChannelHandle;
using android::pdx::BorrowedHandle;
using android::pdx::Channel;
using android::pdx::ChannelReference;
using android::pdx::ErrorStatus;
using android::pdx::FileReference;
using android::pdx::LocalChannelHandle;
using android::pdx::LocalHandle;
using android::pdx::Message;
using android::pdx::MessageInfo;
using android::pdx::MockEndpoint;
using android::pdx::RemoteChannelHandle;
using android::pdx::RemoteHandle;
using android::pdx::Service;
using android::pdx::Status;
using testing::A;
using testing::ByMove;
using testing::DoAll;
using testing::Invoke;
using testing::Matcher;
using testing::Ref;
using testing::Return;
using testing::SetArgPointee;
using testing::WithArg;
using testing::WithoutArgs;
using testing::_;
namespace {
// Helper functions to construct fake void pointers for tests.
inline void* IntToPtr(intptr_t addr) { return reinterpret_cast<void*>(addr); }
// Helper matchers for working with iovec structures in tests.
// Simple matcher for one element iovec array:
// EXPECT_CALL(mock, method(IoVecMatcher(ptr, size)));
MATCHER_P2(IoVecMatcher, ptr, size, "") {
return arg->iov_base == ptr && arg->iov_len == size;
}
// Matcher for an array of iovecs:
// EXPECT_CALL(mock,
// method(IoVecMatcher(IoVecArray{{ptr1, size1}, {ptr2, size2}})));
using IoVecArray = std::vector<iovec>;
MATCHER_P(IoVecMatcher, iovec_array, "") {
auto local_arg = arg;
for (const iovec& item : iovec_array) {
if (local_arg->iov_base != item.iov_base || local_arg->iov_len != item.iov_len)
return false;
local_arg++;
}
return true;
}
using IoVecData = std::vector<std::string>;
MATCHER_P(IoVecDataMatcher, iovec_data, "") {
auto local_arg = arg;
for (const std::string& item : iovec_data) {
std::string data{reinterpret_cast<const char*>(local_arg->iov_base),
local_arg->iov_len};
if (data != item)
return false;
local_arg++;
}
return true;
}
MATCHER_P(FileHandleMatcher, value, "") { return arg.Get() == value; }
MATCHER_P(ChannelHandleMatcher, value, "") { return arg.value() == value; }
enum : int {
kTestPid = 1,
kTestTid,
kTestCid,
kTestMid,
kTestEuid,
kTestEgid,
kTestOp,
};
class MockService : public Service {
public:
using Service::Service;
MOCK_METHOD1(OnChannelOpen, std::shared_ptr<Channel>(Message& message));
MOCK_METHOD2(OnChannelClose,
void(Message& message, const std::shared_ptr<Channel>& channel));
MOCK_METHOD1(HandleMessage, Status<void>(Message& message));
MOCK_METHOD1(HandleImpulse, void(Message& impulse));
MOCK_METHOD0(OnSysPropChange, void());
MOCK_METHOD1(DumpState, std::string(size_t max_length));
};
class ServiceTest : public testing::Test {
public:
ServiceTest() {
auto endpoint = std::make_unique<testing::StrictMock<MockEndpoint>>();
EXPECT_CALL(*endpoint, SetService(_))
.Times(2)
.WillRepeatedly(Return(Status<void>{}));
service_ = std::make_shared<MockService>("MockSvc", std::move(endpoint));
}
MockEndpoint* endpoint() {
return static_cast<MockEndpoint*>(service_->endpoint());
}
void SetupMessageInfo(MessageInfo* info, int32_t op, bool impulse = false) {
info->pid = kTestPid;
info->tid = kTestTid;
info->cid = kTestCid;
info->mid = impulse ? Message::IMPULSE_MESSAGE_ID : kTestMid;
info->euid = kTestEuid;
info->egid = kTestEgid;
info->op = op;
info->flags = 0;
info->service = service_.get();
info->channel = nullptr;
info->send_len = 0;
info->recv_len = 0;
info->fd_count = 0;
memset(info->impulse, 0, sizeof(info->impulse));
}
void SetupMessageInfoAndDefaultExpectations(MessageInfo* info, int32_t op,
bool impulse = false) {
SetupMessageInfo(info, op, impulse);
EXPECT_CALL(*endpoint(), AllocateMessageState()).WillOnce(Return(kState));
EXPECT_CALL(*endpoint(), FreeMessageState(kState));
}
void ExpectDefaultHandleMessage() {
EXPECT_CALL(*endpoint(), MessageReply(_, -EOPNOTSUPP))
.WillOnce(Return(Status<void>{}));
}
std::shared_ptr<MockService> service_;
void* kState = IntToPtr(123456);
};
class ServiceMessageTest : public ServiceTest {
public:
ServiceMessageTest() {
MessageInfo info;
SetupMessageInfoAndDefaultExpectations(&info, kTestOp);
message_ = std::make_unique<Message>(info);
}
std::unique_ptr<Message> message_;
};
} // anonymous namespace
///////////////////////////////////////////////////////////////////////////////
// Service class tests
///////////////////////////////////////////////////////////////////////////////
TEST_F(ServiceTest, IsInitialized) {
EXPECT_TRUE(service_->IsInitialized());
service_ = std::make_shared<MockService>("MockSvc2", nullptr);
EXPECT_FALSE(service_->IsInitialized());
}
TEST_F(ServiceTest, ConstructMessage) {
MessageInfo info;
SetupMessageInfo(&info, kTestOp);
auto test_channel = std::make_shared<Channel>();
info.channel = test_channel.get();
EXPECT_CALL(*endpoint(), AllocateMessageState()).WillOnce(Return(kState));
Message message{info};
EXPECT_FALSE(message.IsImpulse());
EXPECT_EQ(kTestPid, message.GetProcessId());
EXPECT_EQ(kTestTid, message.GetThreadId());
EXPECT_EQ(kTestCid, message.GetChannelId());
EXPECT_EQ(kTestMid, message.GetMessageId());
EXPECT_EQ((unsigned) kTestEuid, message.GetEffectiveUserId());
EXPECT_EQ((unsigned) kTestEgid, message.GetEffectiveGroupId());
EXPECT_EQ(kTestOp, message.GetOp());
EXPECT_EQ(service_, message.GetService());
EXPECT_EQ(test_channel, message.GetChannel());
EXPECT_FALSE(message.replied());
EXPECT_FALSE(message.IsChannelExpired());
EXPECT_FALSE(message.IsServiceExpired());
EXPECT_EQ(kState, message.GetState());
ExpectDefaultHandleMessage();
EXPECT_CALL(*endpoint(), FreeMessageState(kState));
}
TEST_F(ServiceTest, ConstructImpulseMessage) {
MessageInfo info;
SetupMessageInfo(&info, kTestOp, true);
auto test_channel = std::make_shared<Channel>();
info.channel = test_channel.get();
EXPECT_CALL(*endpoint(), AllocateMessageState()).WillOnce(Return(nullptr));
Message message{info};
EXPECT_TRUE(message.IsImpulse());
EXPECT_EQ(kTestOp, message.GetOp());
EXPECT_EQ(service_, message.GetService());
EXPECT_EQ(test_channel, message.GetChannel());
EXPECT_TRUE(message.replied());
EXPECT_FALSE(message.IsChannelExpired());
EXPECT_FALSE(message.IsServiceExpired());
// DefaultHandleMessage should not be called here.
EXPECT_CALL(*endpoint(), FreeMessageState(nullptr));
}
TEST_F(ServiceTest, HandleMessageChannelOpen) {
MessageInfo info;
SetupMessageInfoAndDefaultExpectations(&info,
android::pdx::opcodes::CHANNEL_OPEN);
Message message{info};
auto channel = std::make_shared<Channel>();
EXPECT_CALL(*service_, OnChannelOpen(Ref(message))).WillOnce(Return(channel));
EXPECT_CALL(*endpoint(), SetChannel(kTestCid, channel.get()))
.WillOnce(Return(Status<void>{}));
EXPECT_CALL(*endpoint(), MessageReply(&message, 0))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(service_->Service::HandleMessage(message));
}
TEST_F(ServiceTest, HandleMessageChannelClose) {
MessageInfo info;
SetupMessageInfoAndDefaultExpectations(&info,
android::pdx::opcodes::CHANNEL_CLOSE);
auto channel = std::make_shared<Channel>();
info.channel = channel.get();
Message message{info};
EXPECT_CALL(*service_, OnChannelClose(Ref(message), channel));
EXPECT_CALL(*endpoint(), SetChannel(kTestCid, nullptr))
.WillOnce(Return(Status<void>{}));
EXPECT_CALL(*endpoint(), MessageReply(&message, 0))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(service_->Service::HandleMessage(message));
}
TEST_F(ServiceTest, HandleMessageOnSysPropChange) {
MessageInfo info;
SetupMessageInfoAndDefaultExpectations(
&info, android::pdx::opcodes::REPORT_SYSPROP_CHANGE);
Message message{info};
EXPECT_CALL(*service_, OnSysPropChange());
EXPECT_CALL(*endpoint(), MessageReply(&message, 0))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(service_->Service::HandleMessage(message));
}
TEST_F(ServiceTest, HandleMessageOnDumpState) {
const size_t kRecvBufSize = 1000;
MessageInfo info;
SetupMessageInfoAndDefaultExpectations(&info,
android::pdx::opcodes::DUMP_STATE);
info.recv_len = kRecvBufSize;
Message message{info};
const std::string kReply = "foo";
EXPECT_CALL(*service_, DumpState(kRecvBufSize)).WillOnce(Return(kReply));
EXPECT_CALL(
*endpoint(),
WriteMessageData(&message, IoVecDataMatcher(IoVecData{kReply}), 1))
.WillOnce(Return(kReply.size()));
EXPECT_CALL(*endpoint(), MessageReply(&message, kReply.size()))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(service_->Service::HandleMessage(message));
}
TEST_F(ServiceTest, HandleMessageOnDumpStateTooLarge) {
const size_t kRecvBufSize = 3;
MessageInfo info;
SetupMessageInfoAndDefaultExpectations(&info,
android::pdx::opcodes::DUMP_STATE);
info.recv_len = kRecvBufSize;
Message message{info};
const std::string kReply = "0123456789";
const std::string kActualReply = kReply.substr(0, kRecvBufSize);
EXPECT_CALL(*service_, DumpState(kRecvBufSize)).WillOnce(Return(kReply));
EXPECT_CALL(
*endpoint(),
WriteMessageData(&message, IoVecDataMatcher(IoVecData{kActualReply}), 1))
.WillOnce(Return(kActualReply.size()));
EXPECT_CALL(*endpoint(), MessageReply(&message, kActualReply.size()))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(service_->Service::HandleMessage(message));
}
TEST_F(ServiceTest, HandleMessageOnDumpStateFail) {
const size_t kRecvBufSize = 1000;
MessageInfo info;
SetupMessageInfoAndDefaultExpectations(&info,
android::pdx::opcodes::DUMP_STATE);
info.recv_len = kRecvBufSize;
Message message{info};
const std::string kReply = "foo";
EXPECT_CALL(*service_, DumpState(kRecvBufSize)).WillOnce(Return(kReply));
EXPECT_CALL(
*endpoint(),
WriteMessageData(&message, IoVecDataMatcher(IoVecData{kReply}), 1))
.WillOnce(Return(1));
EXPECT_CALL(*endpoint(), MessageReply(&message, -EIO))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(service_->Service::HandleMessage(message));
}
TEST_F(ServiceTest, HandleMessageCustom) {
MessageInfo info;
SetupMessageInfoAndDefaultExpectations(&info, kTestOp);
Message message{info};
EXPECT_CALL(*endpoint(), MessageReply(&message, -EOPNOTSUPP))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(service_->Service::HandleMessage(message));
}
TEST_F(ServiceTest, ReplyMessageWithoutService) {
MessageInfo info;
SetupMessageInfo(&info, kTestOp);
EXPECT_CALL(*endpoint(), AllocateMessageState()).WillOnce(Return(nullptr));
Message message{info};
EXPECT_FALSE(message.IsServiceExpired());
service_.reset();
EXPECT_TRUE(message.IsServiceExpired());
EXPECT_EQ(EINVAL, message.Reply(12).error());
}
TEST_F(ServiceTest, ReceiveAndDispatchMessage) {
MessageInfo info;
SetupMessageInfoAndDefaultExpectations(&info, kTestOp);
ExpectDefaultHandleMessage();
auto on_receive = [&info](Message* message) -> Status<void> {
*message = Message{info};
return {};
};
EXPECT_CALL(*endpoint(), MessageReceive(_)).WillOnce(Invoke(on_receive));
EXPECT_CALL(*service_, HandleMessage(_)).WillOnce(Return(Status<void>{}));
EXPECT_TRUE(service_->ReceiveAndDispatch());
}
TEST_F(ServiceTest, ReceiveAndDispatchImpulse) {
MessageInfo info;
SetupMessageInfoAndDefaultExpectations(&info, kTestOp, true);
auto on_receive = [&info](Message* message) -> Status<void> {
*message = Message{info};
return {};
};
EXPECT_CALL(*endpoint(), MessageReceive(_)).WillOnce(Invoke(on_receive));
EXPECT_CALL(*service_, HandleImpulse(_));
EXPECT_TRUE(service_->ReceiveAndDispatch());
}
TEST_F(ServiceTest, Cancel) {
EXPECT_CALL(*endpoint(), Cancel()).WillOnce(Return(Status<void>{}));
EXPECT_TRUE(service_->Cancel());
}
///////////////////////////////////////////////////////////////////////////////
// Message class tests
///////////////////////////////////////////////////////////////////////////////
TEST_F(ServiceMessageTest, Reply) {
EXPECT_CALL(*endpoint(), MessageReply(message_.get(), 12))
.WillOnce(Return(Status<void>{}));
EXPECT_FALSE(message_->replied());
EXPECT_TRUE(message_->Reply(12));
EXPECT_TRUE(message_->replied());
EXPECT_EQ(EINVAL, message_->Reply(12).error()); // Already replied.
}
TEST_F(ServiceMessageTest, ReplyFail) {
EXPECT_CALL(*endpoint(), MessageReply(message_.get(), 12))
.WillOnce(Return(ErrorStatus{EIO}));
EXPECT_EQ(EIO, message_->Reply(12).error());
ExpectDefaultHandleMessage();
}
TEST_F(ServiceMessageTest, ReplyError) {
EXPECT_CALL(*endpoint(), MessageReply(message_.get(), -12))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(message_->ReplyError(12));
}
TEST_F(ServiceMessageTest, ReplyFileDescriptor) {
EXPECT_CALL(*endpoint(), MessageReplyFd(message_.get(), 5))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(message_->ReplyFileDescriptor(5));
}
TEST_F(ServiceMessageTest, ReplyLocalFileHandle) {
const int kFakeFd = 12345;
LocalHandle handle{kFakeFd};
EXPECT_CALL(*endpoint(), MessageReplyFd(message_.get(), kFakeFd))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(message_->Reply(handle));
handle.Release(); // Make sure we do not close the fake file descriptor.
}
TEST_F(ServiceMessageTest, ReplyLocalFileHandleError) {
LocalHandle handle{-EINVAL};
EXPECT_CALL(*endpoint(), MessageReply(message_.get(), -EINVAL))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(message_->Reply(handle));
}
TEST_F(ServiceMessageTest, ReplyBorrowedFileHandle) {
const int kFakeFd = 12345;
BorrowedHandle handle{kFakeFd};
EXPECT_CALL(*endpoint(), MessageReplyFd(message_.get(), kFakeFd))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(message_->Reply(handle));
}
TEST_F(ServiceMessageTest, ReplyBorrowedFileHandleError) {
BorrowedHandle handle{-EACCES};
EXPECT_CALL(*endpoint(), MessageReply(message_.get(), -EACCES))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(message_->Reply(handle));
}
TEST_F(ServiceMessageTest, ReplyRemoteFileHandle) {
RemoteHandle handle{123};
EXPECT_CALL(*endpoint(), MessageReply(message_.get(), handle.Get()))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(message_->Reply(handle));
}
TEST_F(ServiceMessageTest, ReplyRemoteFileHandleError) {
RemoteHandle handle{-EIO};
EXPECT_CALL(*endpoint(), MessageReply(message_.get(), -EIO))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(message_->Reply(handle));
}
TEST_F(ServiceMessageTest, ReplyLocalChannelHandle) {
LocalChannelHandle handle{nullptr, 12345};
EXPECT_CALL(*endpoint(), MessageReplyChannelHandle(
message_.get(), A<const LocalChannelHandle&>()))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(message_->Reply(handle));
}
TEST_F(ServiceMessageTest, ReplyBorrowedChannelHandle) {
BorrowedChannelHandle handle{12345};
EXPECT_CALL(*endpoint(),
MessageReplyChannelHandle(message_.get(),
A<const BorrowedChannelHandle&>()))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(message_->Reply(handle));
}
TEST_F(ServiceMessageTest, ReplyRemoteChannelHandle) {
RemoteChannelHandle handle{12345};
EXPECT_CALL(*endpoint(), MessageReplyChannelHandle(
message_.get(), A<const RemoteChannelHandle&>()))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(message_->Reply(handle));
}
TEST_F(ServiceMessageTest, ReplyStatusInt) {
Status<int> status{123};
EXPECT_CALL(*endpoint(), MessageReply(message_.get(), status.get()))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(message_->Reply(status));
}
TEST_F(ServiceMessageTest, ReplyStatusError) {
Status<int> status{ErrorStatus{EIO}};
EXPECT_CALL(*endpoint(), MessageReply(message_.get(), -status.error()))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(message_->Reply(status));
}
TEST_F(ServiceMessageTest, Read) {
ExpectDefaultHandleMessage();
void* const kDataBuffer = IntToPtr(12345);
const size_t kDataSize = 100;
EXPECT_CALL(
*endpoint(),
ReadMessageData(message_.get(), IoVecMatcher(kDataBuffer, kDataSize), 1))
.WillOnce(Return(50))
.WillOnce(Return(ErrorStatus{EACCES}));
EXPECT_EQ(50u, message_->Read(kDataBuffer, kDataSize).get());
EXPECT_EQ(EACCES, message_->Read(kDataBuffer, kDataSize).error());
}
TEST_F(ServiceMessageTest, ReadVector) {
ExpectDefaultHandleMessage();
char buffer1[10];
char buffer2[20];
iovec vec[] = {{buffer1, sizeof(buffer1)}, {buffer2, sizeof(buffer2)}};
EXPECT_CALL(*endpoint(),
ReadMessageData(
message_.get(),
IoVecMatcher(IoVecArray{std::begin(vec), std::end(vec)}), 2))
.WillOnce(Return(30))
.WillOnce(Return(15))
.WillOnce(Return(ErrorStatus{EBADF}));
EXPECT_EQ(30u, message_->ReadVector(vec, 2).get());
EXPECT_EQ(15u, message_->ReadVector(vec).get());
EXPECT_EQ(EBADF, message_->ReadVector(vec).error());
}
TEST_F(ServiceMessageTest, Write) {
ExpectDefaultHandleMessage();
void* const kDataBuffer = IntToPtr(12345);
const size_t kDataSize = 100;
EXPECT_CALL(
*endpoint(),
WriteMessageData(message_.get(), IoVecMatcher(kDataBuffer, kDataSize), 1))
.WillOnce(Return(50))
.WillOnce(Return(ErrorStatus{EBADMSG}));
EXPECT_EQ(50u, message_->Write(kDataBuffer, kDataSize).get());
EXPECT_EQ(EBADMSG, message_->Write(kDataBuffer, kDataSize).error());
}
TEST_F(ServiceMessageTest, WriteVector) {
ExpectDefaultHandleMessage();
char buffer1[10];
char buffer2[20];
iovec vec[] = {{buffer1, sizeof(buffer1)}, {buffer2, sizeof(buffer2)}};
EXPECT_CALL(*endpoint(),
WriteMessageData(
message_.get(),
IoVecMatcher(IoVecArray{std::begin(vec), std::end(vec)}), 2))
.WillOnce(Return(30))
.WillOnce(Return(15))
.WillOnce(Return(ErrorStatus{EIO}));
EXPECT_EQ(30u, message_->WriteVector(vec, 2).get());
EXPECT_EQ(15u, message_->WriteVector(vec).get());
EXPECT_EQ(EIO, message_->WriteVector(vec, 2).error());
}
TEST_F(ServiceMessageTest, PushLocalFileHandle) {
ExpectDefaultHandleMessage();
const int kFakeFd = 12345;
LocalHandle handle{kFakeFd};
EXPECT_CALL(*endpoint(),
PushFileHandle(message_.get(), Matcher<const LocalHandle&>(
FileHandleMatcher(kFakeFd))))
.WillOnce(Return(12))
.WillOnce(Return(ErrorStatus{EIO}));
EXPECT_EQ(12, message_->PushFileHandle(handle).get());
EXPECT_EQ(EIO, message_->PushFileHandle(handle).error());
handle.Release(); // Make sure we do not close the fake file descriptor.
}
TEST_F(ServiceMessageTest, PushBorrowedFileHandle) {
ExpectDefaultHandleMessage();
const int kFakeFd = 12345;
BorrowedHandle handle{kFakeFd};
EXPECT_CALL(*endpoint(),
PushFileHandle(message_.get(), Matcher<const BorrowedHandle&>(
FileHandleMatcher(kFakeFd))))
.WillOnce(Return(13))
.WillOnce(Return(ErrorStatus{EACCES}));
EXPECT_EQ(13, message_->PushFileHandle(handle).get());
EXPECT_EQ(EACCES, message_->PushFileHandle(handle).error());
}
TEST_F(ServiceMessageTest, PushRemoteFileHandle) {
ExpectDefaultHandleMessage();
const int kFakeFd = 12345;
RemoteHandle handle{kFakeFd};
EXPECT_CALL(*endpoint(),
PushFileHandle(message_.get(), Matcher<const RemoteHandle&>(
FileHandleMatcher(kFakeFd))))
.WillOnce(Return(kFakeFd))
.WillOnce(Return(ErrorStatus{EIO}));
EXPECT_EQ(kFakeFd, message_->PushFileHandle(handle).get());
EXPECT_EQ(EIO, message_->PushFileHandle(handle).error());
}
TEST_F(ServiceMessageTest, PushLocalChannelHandle) {
ExpectDefaultHandleMessage();
int32_t kValue = 12345;
LocalChannelHandle handle{nullptr, kValue};
EXPECT_CALL(*endpoint(), PushChannelHandle(message_.get(),
Matcher<const LocalChannelHandle&>(
ChannelHandleMatcher(kValue))))
.WillOnce(Return(7))
.WillOnce(Return(ErrorStatus{EIO}));
EXPECT_EQ(7, message_->PushChannelHandle(handle).get());
EXPECT_EQ(EIO, message_->PushChannelHandle(handle).error());
}
TEST_F(ServiceMessageTest, PushBorrowedChannelHandle) {
ExpectDefaultHandleMessage();
int32_t kValue = 12345;
BorrowedChannelHandle handle{kValue};
EXPECT_CALL(
*endpoint(),
PushChannelHandle(message_.get(), Matcher<const BorrowedChannelHandle&>(
ChannelHandleMatcher(kValue))))
.WillOnce(Return(8))
.WillOnce(Return(ErrorStatus{EIO}));
EXPECT_EQ(8, message_->PushChannelHandle(handle).get());
EXPECT_EQ(EIO, message_->PushChannelHandle(handle).error());
}
TEST_F(ServiceMessageTest, PushRemoteChannelHandle) {
ExpectDefaultHandleMessage();
int32_t kValue = 12345;
RemoteChannelHandle handle{kValue};
EXPECT_CALL(
*endpoint(),
PushChannelHandle(message_.get(), Matcher<const RemoteChannelHandle&>(
ChannelHandleMatcher(kValue))))
.WillOnce(Return(kValue))
.WillOnce(Return(ErrorStatus{EIO}));
EXPECT_EQ(kValue, message_->PushChannelHandle(handle).get());
EXPECT_EQ(EIO, message_->PushChannelHandle(handle).error());
}
TEST_F(ServiceMessageTest, GetFileHandle) {
ExpectDefaultHandleMessage();
auto make_file_handle = [](FileReference ref) { return LocalHandle{ref}; };
EXPECT_CALL(*endpoint(), GetFileHandle(message_.get(), _))
.WillOnce(WithArg<1>(Invoke(make_file_handle)));
LocalHandle handle;
FileReference kRef = 12345;
EXPECT_TRUE(message_->GetFileHandle(kRef, &handle));
EXPECT_EQ(kRef, handle.Get());
handle.Release(); // Make sure we do not close the fake file descriptor.
}
TEST_F(ServiceMessageTest, GetFileHandleInvalid) {
ExpectDefaultHandleMessage();
LocalHandle handle;
FileReference kRef = -12;
EXPECT_TRUE(message_->GetFileHandle(kRef, &handle));
EXPECT_EQ(kRef, handle.Get());
}
TEST_F(ServiceMessageTest, GetFileHandleError) {
ExpectDefaultHandleMessage();
EXPECT_CALL(*endpoint(), GetFileHandle(message_.get(), _))
.WillOnce(WithoutArgs(Invoke([] { return LocalHandle{-EIO}; })));
LocalHandle handle;
FileReference kRef = 12345;
EXPECT_FALSE(message_->GetFileHandle(kRef, &handle));
EXPECT_EQ(-EIO, handle.Get());
}
TEST_F(ServiceMessageTest, GetChannelHandle) {
ExpectDefaultHandleMessage();
auto make_channel_handle = [](ChannelReference ref) {
return LocalChannelHandle{nullptr, ref};
};
EXPECT_CALL(*endpoint(), GetChannelHandle(message_.get(), _))
.WillOnce(WithArg<1>(Invoke(make_channel_handle)));
LocalChannelHandle handle;
ChannelReference kRef = 12345;
EXPECT_TRUE(message_->GetChannelHandle(kRef, &handle));
EXPECT_EQ(kRef, handle.value());
}
TEST_F(ServiceMessageTest, GetChannelHandleInvalid) {
ExpectDefaultHandleMessage();
LocalChannelHandle handle;
ChannelReference kRef = -12;
EXPECT_TRUE(message_->GetChannelHandle(kRef, &handle));
EXPECT_EQ(-12, handle.value());
}
TEST_F(ServiceMessageTest, GetChannelHandleError) {
ExpectDefaultHandleMessage();
EXPECT_CALL(*endpoint(), GetChannelHandle(message_.get(), _))
.WillOnce(WithoutArgs(Invoke([] {
return LocalChannelHandle{nullptr, -EIO};
})));
LocalChannelHandle handle;
ChannelReference kRef = 12345;
EXPECT_FALSE(message_->GetChannelHandle(kRef, &handle));
EXPECT_EQ(-EIO, handle.value());
}
TEST_F(ServiceMessageTest, ModifyChannelEvents) {
ExpectDefaultHandleMessage();
int kClearMask = 1;
int kSetMask = 2;
EXPECT_CALL(*endpoint(), ModifyChannelEvents(kTestCid, kClearMask, kSetMask))
.WillOnce(Return(Status<void>{}));
EXPECT_TRUE(message_->ModifyChannelEvents(kClearMask, kSetMask));
}
TEST_F(ServiceMessageTest, PushChannelSameService) {
ExpectDefaultHandleMessage();
int kFlags = 123;
int32_t kValue = 12;
EXPECT_CALL(*endpoint(), PushChannel(message_.get(), kFlags, nullptr, _))
.WillOnce(DoAll(SetArgPointee<3>(kTestCid),
Return(ByMove(RemoteChannelHandle{kValue}))));
int channel_id = -1;
auto status = message_->PushChannel(kFlags, nullptr, &channel_id);
ASSERT_TRUE(status);
EXPECT_EQ(kValue, status.get().value());
EXPECT_EQ(kTestCid, channel_id);
}
TEST_F(ServiceMessageTest, PushChannelFailure) {
ExpectDefaultHandleMessage();
int kFlags = 123;
EXPECT_CALL(*endpoint(), PushChannel(message_.get(), kFlags, nullptr, _))
.WillOnce(Return(ByMove(ErrorStatus{EIO})));
int channel_id = -1;
auto status = message_->PushChannel(kFlags, nullptr, &channel_id);
ASSERT_FALSE(status);
EXPECT_EQ(EIO, status.error());
}
TEST_F(ServiceMessageTest, PushChannelDifferentService) {
ExpectDefaultHandleMessage();
auto endpoint2 = std::make_unique<testing::StrictMock<MockEndpoint>>();
EXPECT_CALL(*endpoint2, SetService(_))
.Times(2)
.WillRepeatedly(Return(Status<void>{}));
auto service2 =
std::make_shared<MockService>("MockSvc2", std::move(endpoint2));
int kFlags = 123;
int32_t kValue = 12;
EXPECT_CALL(*static_cast<MockEndpoint*>(service2->endpoint()),
PushChannel(message_.get(), kFlags, nullptr, _))
.WillOnce(DoAll(SetArgPointee<3>(kTestCid),
Return(ByMove(RemoteChannelHandle{kValue}))));
int channel_id = -1;
auto status =
message_->PushChannel(service2.get(), kFlags, nullptr, &channel_id);
ASSERT_TRUE(status);
EXPECT_EQ(kValue, status.get().value());
EXPECT_EQ(kTestCid, channel_id);
}
TEST_F(ServiceMessageTest, CheckChannelSameService) {
ExpectDefaultHandleMessage();
auto test_channel = std::make_shared<Channel>();
ChannelReference kRef = 123;
EXPECT_CALL(*endpoint(), CheckChannel(message_.get(), kRef, _))
.WillOnce(DoAll(SetArgPointee<2>(test_channel.get()), Return(kTestCid)));
std::shared_ptr<Channel> channel;
auto status = message_->CheckChannel(kRef, &channel);
ASSERT_TRUE(status);
EXPECT_EQ(kTestCid, status.get());
EXPECT_EQ(test_channel, channel);
}
TEST_F(ServiceMessageTest, CheckChannelFailure) {
ExpectDefaultHandleMessage();
ChannelReference kRef = 123;
EXPECT_CALL(*endpoint(), CheckChannel(message_.get(), kRef, _))
.WillOnce(Return(ByMove(ErrorStatus{EOPNOTSUPP})));
std::shared_ptr<Channel> channel;
auto status = message_->CheckChannel(kRef, &channel);
ASSERT_FALSE(status);
EXPECT_EQ(EOPNOTSUPP, status.error());
}
TEST_F(ServiceMessageTest, CheckChannelDifferentService) {
ExpectDefaultHandleMessage();
auto endpoint2 = std::make_unique<testing::StrictMock<MockEndpoint>>();
EXPECT_CALL(*endpoint2, SetService(_))
.Times(2)
.WillRepeatedly(Return(Status<void>{}));
auto service2 =
std::make_shared<MockService>("MockSvc2", std::move(endpoint2));
auto test_channel = std::make_shared<Channel>();
ChannelReference kRef = 123;
EXPECT_CALL(*static_cast<MockEndpoint*>(service2->endpoint()),
CheckChannel(message_.get(), kRef, _))
.WillOnce(DoAll(SetArgPointee<2>(test_channel.get()), Return(kTestCid)));
std::shared_ptr<Channel> channel;
auto status = message_->CheckChannel(service2.get(), kRef, &channel);
ASSERT_TRUE(status);
EXPECT_EQ(kTestCid, status.get());
EXPECT_EQ(test_channel, channel);
}