blob: 2dd149bf9690cfb797fd810937c4dbd1a517c5ff [file] [log] [blame]
// Copyright 2018 The Fuchsia 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 <lib/fidl/cpp/message_buffer.h>
#include <lib/fidl/cpp/message_builder.h>
#include <lib/zx/channel.h>
#include "gtest/gtest.h"
#include "lib/fidl/cpp/internal/proxy_controller.h"
#include "lib/fidl/cpp/string.h"
#include "lib/fidl/cpp/test/async_loop_for_test.h"
#include "lib/fidl/cpp/test/fidl_types.h"
namespace fidl {
namespace internal {
namespace {
class CallbackMessageHandler : public MessageHandler {
public:
fit::function<zx_status_t(Message)> callback;
zx_status_t OnMessage(Message message) override {
return callback(std::move(message));
}
};
TEST(ProxyController, Trivial) { ProxyController controller; }
TEST(ProxyController, Send) {
zx::channel h1, h2;
EXPECT_EQ(ZX_OK, zx::channel::create(0, &h1, &h2));
fidl::test::AsyncLoopForTest loop;
ProxyController controller;
EXPECT_EQ(ZX_OK, controller.reader().Bind(std::move(h1)));
Encoder encoder(5u);
StringPtr string("hello!");
string.Encode(&encoder, encoder.Alloc(sizeof(fidl_string_t)));
EXPECT_EQ(ZX_OK, controller.Send(&unbounded_nonnullable_string_message_type,
encoder.GetMessage(), nullptr));
MessageBuffer buffer;
Message message = buffer.CreateEmptyMessage();
EXPECT_EQ(ZX_OK, message.Read(h2.get(), 0));
EXPECT_EQ(0u, message.txid());
EXPECT_EQ(5u, message.ordinal());
StringView* view = message.GetPayloadAs<StringView>();
EXPECT_EQ(6u, view->size());
}
TEST(ProxyController, Callback) {
zx::channel h1, h2;
EXPECT_EQ(ZX_OK, zx::channel::create(0, &h1, &h2));
fidl::test::AsyncLoopForTest loop;
ProxyController controller;
EXPECT_EQ(ZX_OK, controller.reader().Bind(std::move(h1)));
Encoder encoder(3u);
StringPtr string("hello!");
string.Encode(&encoder, encoder.Alloc(sizeof(fidl_string_t)));
int callback_count = 0;
auto handler = std::make_unique<CallbackMessageHandler>();
handler->callback = [&callback_count](Message message) {
++callback_count;
EXPECT_EQ(42u, message.ordinal());
return ZX_OK;
};
EXPECT_EQ(ZX_OK, controller.Send(&unbounded_nonnullable_string_message_type,
encoder.GetMessage(), std::move(handler)));
EXPECT_EQ(0, callback_count);
loop.RunUntilIdle();
EXPECT_EQ(0, callback_count);
MessageBuffer buffer;
Message message = buffer.CreateEmptyMessage();
EXPECT_EQ(ZX_OK, message.Read(h2.get(), 0));
EXPECT_NE(0u, message.txid());
EXPECT_EQ(3u, message.ordinal());
zx_txid_t txid = message.txid();
fidl_message_header_t header = {};
header.txid = txid;
header.ordinal = 42u;
EXPECT_EQ(ZX_OK,
h2.write(0, &header, sizeof(fidl_message_header_t), nullptr, 0));
EXPECT_EQ(0, callback_count);
loop.RunUntilIdle();
EXPECT_EQ(1, callback_count);
}
TEST(ProxyController, BadSend) {
zx::channel h1, h2;
EXPECT_EQ(ZX_OK, zx::channel::create(0, &h1, &h2));
fidl::test::AsyncLoopForTest loop;
ProxyController controller;
EXPECT_EQ(ZX_OK, controller.reader().Bind(std::move(h1)));
Encoder encoder(3u);
// Bad message format.
int error_count = 0;
controller.reader().set_error_handler(
[&error_count](zx_status_t status) {
EXPECT_EQ(ZX_ERR_PEER_CLOSED, status);
++error_count;
});
EXPECT_EQ(0, error_count);
EXPECT_EQ(ZX_ERR_INVALID_ARGS,
controller.Send(&unbounded_nonnullable_string_message_type,
encoder.GetMessage(), nullptr));
EXPECT_EQ(0, error_count);
loop.RunUntilIdle();
EXPECT_EQ(0, error_count);
EXPECT_EQ(ZX_OK, controller.reader().Unbind().replace(ZX_RIGHT_WAIT, &h1));
EXPECT_EQ(ZX_OK, controller.reader().Bind(std::move(h1)));
encoder.Reset(35u);
StringPtr string("hello!");
string.Encode(&encoder, encoder.Alloc(sizeof(fidl_string_t)));
EXPECT_EQ(0, error_count);
EXPECT_EQ(ZX_ERR_ACCESS_DENIED,
controller.Send(&unbounded_nonnullable_string_message_type,
encoder.GetMessage(), nullptr));
EXPECT_EQ(0, error_count);
}
TEST(ProxyController, BadReply) {
zx::channel h1, h2;
EXPECT_EQ(ZX_OK, zx::channel::create(0, &h1, &h2));
fidl::test::AsyncLoopForTest loop;
ProxyController controller;
EXPECT_EQ(ZX_OK, controller.reader().Bind(std::move(h1)));
zx_status_t expected_error = ZX_ERR_NOT_SUPPORTED;
int error_count = 0;
controller.reader().set_error_handler(
[&expected_error, &error_count](zx_status_t status) {
EXPECT_EQ(expected_error, status);
++error_count;
});
fidl_message_header_t header = {};
header.txid = 0;
header.ordinal = 42u;
EXPECT_EQ(ZX_OK,
h2.write(0, &header, sizeof(fidl_message_header_t), nullptr, 0));
EXPECT_EQ(0, error_count);
loop.RunUntilIdle();
EXPECT_EQ(1, error_count);
EXPECT_EQ(ZX_OK, zx::channel::create(0, &h1, &h2));
EXPECT_EQ(ZX_OK, controller.reader().Bind(std::move(h1)));
header.txid = 42u;
expected_error = ZX_ERR_NOT_FOUND;
EXPECT_EQ(ZX_OK,
h2.write(0, &header, sizeof(fidl_message_header_t), nullptr, 0));
EXPECT_EQ(1, error_count);
loop.RunUntilIdle();
EXPECT_EQ(2, error_count);
}
TEST(ProxyController, ShortReply) {
zx::channel h1, h2;
EXPECT_EQ(ZX_OK, zx::channel::create(0, &h1, &h2));
fidl::test::AsyncLoopForTest loop;
ProxyController controller;
EXPECT_EQ(ZX_OK, controller.reader().Bind(std::move(h1)));
int expected_error = ZX_ERR_NOT_SUPPORTED;
int error_count = 0;
controller.reader().set_error_handler(
[&expected_error, &error_count](zx_status_t status) {
EXPECT_EQ(expected_error, status);
++error_count;
});
fidl_message_header_t header = {};
header.txid = 0;
header.ordinal = 42u;
EXPECT_EQ(ZX_OK,
h2.write(0, &header, sizeof(fidl_message_header_t), nullptr, 0));
EXPECT_EQ(0, error_count);
loop.RunUntilIdle();
EXPECT_EQ(1, error_count);
expected_error = ZX_ERR_INVALID_ARGS;
EXPECT_EQ(ZX_OK, zx::channel::create(0, &h1, &h2));
EXPECT_EQ(ZX_OK, controller.reader().Bind(std::move(h1)));
header.txid = 42u;
EXPECT_EQ(ZX_OK, h2.write(0, "a", 1, nullptr, 0));
EXPECT_EQ(1, error_count);
loop.RunUntilIdle();
EXPECT_EQ(2, error_count);
}
TEST(ProxyController, Move) {
zx::channel h1, h2;
EXPECT_EQ(ZX_OK, zx::channel::create(0, &h1, &h2));
fidl::test::AsyncLoopForTest loop;
ProxyController controller1;
EXPECT_EQ(ZX_OK, controller1.reader().Bind(std::move(h1)));
Encoder encoder(3u);
StringPtr string("hello!");
string.Encode(&encoder, encoder.Alloc(sizeof(fidl_string_t)));
int callback_count = 0;
auto handler = std::make_unique<CallbackMessageHandler>();
handler->callback = [&callback_count](Message message) {
++callback_count;
EXPECT_EQ(42u, message.ordinal());
return ZX_OK;
};
EXPECT_EQ(ZX_OK, controller1.Send(&unbounded_nonnullable_string_message_type,
encoder.GetMessage(), std::move(handler)));
EXPECT_EQ(0, callback_count);
loop.RunUntilIdle();
EXPECT_EQ(0, callback_count);
MessageBuffer buffer;
Message message = buffer.CreateEmptyMessage();
EXPECT_EQ(ZX_OK, message.Read(h2.get(), 0));
EXPECT_NE(0u, message.txid());
EXPECT_EQ(3u, message.ordinal());
ProxyController controller2 = std::move(controller1);
EXPECT_FALSE(controller1.reader().is_bound());
EXPECT_TRUE(controller2.reader().is_bound());
zx_txid_t txid = message.txid();
fidl_message_header_t header = {};
header.txid = txid;
header.ordinal = 42u;
EXPECT_EQ(ZX_OK,
h2.write(0, &header, sizeof(fidl_message_header_t), nullptr, 0));
EXPECT_EQ(0, callback_count);
loop.RunUntilIdle();
EXPECT_EQ(1, callback_count);
}
TEST(ProxyController, Reset) {
zx::channel h1, h2;
EXPECT_EQ(ZX_OK, zx::channel::create(0, &h1, &h2));
fidl::test::AsyncLoopForTest loop;
ProxyController controller;
EXPECT_EQ(ZX_OK, controller.reader().Bind(std::move(h1)));
Encoder encoder(3u);
StringPtr string("hello!");
string.Encode(&encoder, encoder.Alloc(sizeof(fidl_string_t)));
int callback_count = 0;
auto handler = std::make_unique<CallbackMessageHandler>();
handler->callback = [&callback_count](Message message) {
++callback_count;
EXPECT_EQ(42u, message.ordinal());
return ZX_OK;
};
EXPECT_EQ(ZX_OK, controller.Send(&unbounded_nonnullable_string_message_type,
encoder.GetMessage(), std::move(handler)));
EXPECT_EQ(0, callback_count);
loop.RunUntilIdle();
EXPECT_EQ(0, callback_count);
MessageBuffer buffer;
Message message = buffer.CreateEmptyMessage();
EXPECT_EQ(ZX_OK, message.Read(h2.get(), 0));
EXPECT_NE(0u, message.txid());
EXPECT_EQ(3u, message.ordinal());
controller.Reset();
EXPECT_FALSE(controller.reader().is_bound());
zx_txid_t txid = message.txid();
fidl_message_header_t header = {};
header.txid = txid;
header.ordinal = 42u;
EXPECT_EQ(ZX_ERR_PEER_CLOSED,
h2.write(0, &header, sizeof(fidl_message_header_t), nullptr, 0));
EXPECT_EQ(0, callback_count);
loop.RunUntilIdle();
EXPECT_EQ(0, callback_count);
}
} // namespace
} // namespace internal
} // namespace fidl