blob: 99ccc698c43342c985cfe08ae73e029b1b49a2cf [file] [log] [blame]
#include <pdx/client.h>
#include <gmock/gmock.h>
#include <sys/eventfd.h>
#include <pdx/mock_client_channel.h>
#include <pdx/mock_client_channel_factory.h>
#include <pdx/rpc/remote_method.h>
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<void*>(addr); }
inline const void* IntToConstPtr(intptr_t addr) {
return reinterpret_cast<const void*>(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<SimpleClient> {
public:
explicit SimpleClient(std::unique_ptr<ClientChannel> channel)
: BASE{std::move(channel)} {}
SimpleClient(std::unique_ptr<ClientChannelFactory> 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<FailingClient> {
public:
explicit FailingClient(std::unique_ptr<ClientChannel> channel, int error_code)
: BASE{std::move(channel)} {
Close(error_code);
}
};
class ClientChannelTest : public testing::Test {
public:
ClientChannelTest()
: client_{SimpleClient::Create(
std::make_unique<testing::StrictMock<MockClientChannel>>())} {}
MockClientChannel* mock_channel() {
return static_cast<MockClientChannel*>(client_->GetChannel());
}
std::unique_ptr<SimpleClient> client_;
};
class ClientChannelFactoryTest : public testing::Test {
public:
ClientChannelFactoryTest() {
auto factory =
std::make_unique<testing::NiceMock<MockClientChannelFactory>>();
ON_CALL(*factory, Connect(kTimeout))
.WillByDefault(Invoke(this, &ClientChannelFactoryTest::OnConnect));
client_ = SimpleClient::Create(std::move(factory), kTimeout);
}
MockClientChannel* mock_channel() {
return static_cast<MockClientChannel*>(client_->GetChannel());
}
Status<std::unique_ptr<ClientChannel>> OnConnect(int64_t /*timeout_ms*/) {
if (on_connect_error_)
return ErrorStatus(on_connect_error_);
std::unique_ptr<MockClientChannel> channel =
std::make_unique<testing::StrictMock<MockClientChannel>>();
if (on_connect_callback_)
on_connect_callback_(channel.get());
return Status<std::unique_ptr<ClientChannel>>{std::move(channel)};
}
void OnConnectCallback(std::function<void(MockClientChannel*)> 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<SimpleClient> client_;
std::function<void(MockClientChannel*)> 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<MockClientChannel>(), EACCES};
ASSERT_FALSE(failed_client1.IsInitialized());
EXPECT_EQ(-EACCES, failed_client1.error());
FailingClient failed_client2{std::make_unique<MockClientChannel>(), -EACCES};
ASSERT_FALSE(failed_client2.IsInitialized());
EXPECT_EQ(-EACCES, failed_client2.error());
auto failed_client3 =
FailingClient::Create(std::make_unique<MockClientChannel>(), 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<void>{}));
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<void>{}));
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<TestInterface::Add>(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<int> status = client_->InvokeRemoteMethod<TestInterface::Add>(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<int> status = client_->InvokeRemoteMethod<TestInterface::Add>(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<LocalHandle> status =
client_->InvokeRemoteMethod<TestInterface::GetFile>();
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<LocalHandle> status =
client_->InvokeRemoteMethod<TestInterface::GetFile>("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<LocalChannelHandle> status =
client_->InvokeRemoteMethod<TestInterface::PushChannel>();
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<LocalChannelHandle> status =
client_->InvokeRemoteMethod<TestInterface::PushChannel>();
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<const LocalHandle&>()))
.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<TestInterface::SendFile>(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<const LocalHandle&>()))
.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<TestInterface::SendFile>(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<testing::NiceMock<MockClientChannelFactory>>();
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<void>{}));
});
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<void>{}));
});
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<void>{}));
});
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<void>(1));
EXPECT_CALL(*mock_channel(),
SendWithFileHandle(kTransactionState, 2, nullptr, 0, nullptr, 0))
.WillOnce(Return(ByMove(LocalHandle{-1})));
EXPECT_TRUE(transaction_.Send<LocalHandle>(2));
EXPECT_CALL(*mock_channel(), SendWithChannelHandle(kTransactionState, 3,
nullptr, 0, nullptr, 0))
.WillOnce(Return(ByMove(LocalChannelHandle{nullptr, 1})));
EXPECT_TRUE(transaction_.Send<LocalChannelHandle>(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<void>(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<void>(1, nullptr, 0, nullptr, 0));
EXPECT_CALL(*mock_channel(),
SendWithInt(nullptr, 2, Ne(nullptr), 1, nullptr, 0))
.WillOnce(Return(0));
EXPECT_TRUE(transaction_.Send<void>(2, kSendBuffer, kSendSize, nullptr, 0));
EXPECT_CALL(*mock_channel(), SendWithInt(nullptr, 3, nullptr, 0, nullptr, 0))
.WillOnce(Return(0));
EXPECT_TRUE(transaction_.Send<void>(3, kSendBuffer, 0, nullptr, 0));
EXPECT_CALL(*mock_channel(),
SendWithInt(nullptr, 4, nullptr, 0, Ne(nullptr), 1))
.WillOnce(Return(0));
EXPECT_TRUE(
transaction_.Send<void>(4, nullptr, 0, kReceiveBuffer, kReceiveSize));
EXPECT_CALL(*mock_channel(), SendWithInt(nullptr, 5, nullptr, 0, nullptr, 0))
.WillOnce(Return(0));
EXPECT_TRUE(transaction_.Send<void>(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<void>(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<void>(1, nullptr, 0, nullptr, 0));
EXPECT_CALL(*mock_channel(), SendWithInt(nullptr, 2, send, 3, recv, 4))
.WillOnce(Return(0));
EXPECT_TRUE(transaction_.SendVector<void>(2, send, 3, recv, 4));
EXPECT_CALL(*mock_channel(), SendWithInt(nullptr, 3, send, 3, nullptr, 0))
.WillOnce(Return(0));
EXPECT_TRUE(transaction_.SendVector<void>(3, send, nullptr));
EXPECT_CALL(*mock_channel(), SendWithInt(nullptr, 4, nullptr, 0, recv, 4))
.WillOnce(Return(0));
EXPECT_TRUE(transaction_.SendVector<void>(4, nullptr, recv));
EXPECT_CALL(*mock_channel(), SendWithInt(nullptr, 5, send, 3, recv, 4))
.WillOnce(Return(0));
EXPECT_TRUE(transaction_.SendVector<void>(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<const LocalHandle&>()))
.WillOnce(Return(1));
EXPECT_EQ(1, transaction_.PushFileHandle(LocalHandle{-1}).get());
EXPECT_CALL(*mock_channel(),
PushFileHandle(kTransactionState, A<const BorrowedHandle&>()))
.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<const LocalChannelHandle&>()))
.WillOnce(Return(11));
EXPECT_EQ(
11, transaction_.PushChannelHandle(LocalChannelHandle{nullptr, 1}).get());
EXPECT_CALL(
*mock_channel(),
PushChannelHandle(kTransactionState, A<const BorrowedChannelHandle&>()))
.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));
}