| #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, "") { | |
| for (const iovec& item : iovec_array) { | |
| if (arg->iov_base != item.iov_base || arg->iov_len != item.iov_len) | |
| return false; | |
| arg++; | |
| } | |
| return true; | |
| } | |
| using IoVecData = std::vector<std::string>; | |
| MATCHER_P(IoVecDataMatcher, iovec_data, "") { | |
| for (const std::string& item : iovec_data) { | |
| std::string data{reinterpret_cast<const char*>(arg->iov_base), | |
| arg->iov_len}; | |
| if (data != item) | |
| return false; | |
| 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); | |
| } |