blob: ca3e86440abe3deb90149e9fbccbebb8cf8deeab [file] [log] [blame]
// Copyright 2020 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/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/cpp/task.h>
#include <lib/async/wait.h>
#include <lib/fidl-async/cpp/bind.h>
#include <lib/fidl/llcpp/server.h>
#include <gtest/gtest.h>
#include <llcpptest/handlerights/test/llcpp/fidl.h>
namespace test = ::llcpp::llcpptest::handlerights::test;
class HandleRightsServer : public test::HandleRights::Interface {
public:
void SyncGetHandleWithTooFewRights(
SyncGetHandleWithTooFewRightsCompleter::Sync& completer) override {
zx::event ev;
ASSERT_EQ(ZX_OK, zx::event::create(0, &ev));
ASSERT_EQ(ZX_OK, ev.replace(ZX_RIGHT_TRANSFER, &ev));
completer.Reply(std::move(ev));
}
void AsyncGetHandleWithTooFewRights(
AsyncGetHandleWithTooFewRightsCompleter::Sync& completer) override {
async::PostDelayedTask(
dispatcher_,
[completer = completer.ToAsync()]() mutable {
zx::event ev;
ASSERT_EQ(ZX_OK, zx::event::create(0, &ev));
ASSERT_EQ(ZX_OK, ev.replace(ZX_RIGHT_TRANSFER, &ev));
completer.Reply(std::move(ev));
},
zx::duration::infinite());
}
void SyncGetHandleWithTooManyRights(
SyncGetHandleWithTooManyRightsCompleter::Sync& completer) override {
zx::event ev;
ASSERT_EQ(ZX_OK, zx::event::create(0, &ev));
completer.Reply(std::move(ev));
}
void AsyncGetHandleWithTooManyRights(
AsyncGetHandleWithTooManyRightsCompleter::Sync& completer) override {
zx::event ev;
ASSERT_EQ(ZX_OK, zx::event::create(0, &ev));
completer.Reply(std::move(ev));
}
void SyncGetHandleWithWrongType(SyncGetHandleWithWrongTypeCompleter::Sync& completer) override {
zx::event ev;
ASSERT_EQ(ZX_OK, zx::event::create(0, &ev));
completer.Reply(zx::channel(ev.release()));
}
void AsyncGetHandleWithWrongType(AsyncGetHandleWithWrongTypeCompleter::Sync& completer) override {
zx::event ev;
ASSERT_EQ(ZX_OK, zx::event::create(0, &ev));
completer.Reply(zx::channel(ev.release()));
}
void SendEventWithTransferAndSignal(
zx::event event, SendEventWithTransferAndSignalCompleter::Sync& completer) override {
zx_info_handle_basic_t info;
ASSERT_EQ(ZX_OK, event.get_info(ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr));
ASSERT_EQ(ZX_RIGHT_TRANSFER | ZX_RIGHT_SIGNAL, info.rights);
ASSERT_EQ(ZX_OBJ_TYPE_EVENT, info.type);
}
void SendChannel(zx::channel channel, SendChannelCompleter::Sync& completer) override {
ASSERT_TRUE(false); // Never should get here.
}
private:
async_dispatcher_t* dispatcher_;
};
class HandleRightsTest : public ::testing::Test {
protected:
virtual void SetUp() {
loop_ = std::make_unique<async::Loop>(&kAsyncLoopConfigAttachToCurrentThread);
ASSERT_EQ(loop_->StartThread("test_llcpp_handle_rights_server"), ZX_OK);
auto endpoints = fidl::CreateEndpoints<test::HandleRights>();
ASSERT_EQ(endpoints.status_value(), ZX_OK);
client_end_ = std::move(endpoints->client);
fidl::BindServer(loop_->dispatcher(), std::move(endpoints->server),
std::make_unique<HandleRightsServer>());
}
test::HandleRights::SyncClient SyncClient() {
EXPECT_TRUE(client_end_.is_valid());
return test::HandleRights::SyncClient(std::move(client_end_));
}
fidl::Client<test::HandleRights> AsyncClient(
std::shared_ptr<test::HandleRights::AsyncEventHandler> handler) {
EXPECT_TRUE(client_end_.is_valid());
return fidl::Client<test::HandleRights>(std::move(client_end_), loop_->dispatcher(),
std::move(handler));
}
private:
std::unique_ptr<async::Loop> loop_;
fidl::ClientEnd<test::HandleRights> client_end_;
};
TEST_F(HandleRightsTest, SyncGetTooFewRights) {
auto client = SyncClient();
auto resp = client.SyncGetHandleWithTooFewRights();
// The channel is closed after a rights error on the sending side.
ASSERT_EQ(resp.status(), ZX_ERR_PEER_CLOSED);
}
TEST_F(HandleRightsTest, SyncGetTooManyRights) {
auto client = SyncClient();
auto resp = client.SyncGetHandleWithTooManyRights();
ASSERT_TRUE(resp.ok());
zx_info_handle_basic_t info;
ASSERT_EQ(ZX_OK, resp->h.get_info(ZX_INFO_HANDLE_BASIC, &info, sizeof(info), nullptr, nullptr));
EXPECT_EQ(ZX_RIGHT_TRANSFER | ZX_RIGHT_SIGNAL, info.rights);
EXPECT_EQ(ZX_OBJ_TYPE_EVENT, info.type);
}
TEST_F(HandleRightsTest, SyncGetWrongType) {
auto client = SyncClient();
auto resp = client.SyncGetHandleWithWrongType();
// The channel is closed after a object type error on the sending side.
ASSERT_EQ(resp.status(), ZX_ERR_PEER_CLOSED);
}
TEST_F(HandleRightsTest, SyncSendTooFewRights) {
auto client = SyncClient();
zx::event ev;
ASSERT_EQ(ZX_OK, zx::event::create(0, &ev));
ASSERT_EQ(ZX_OK, ev.replace(ZX_RIGHT_TRANSFER, &ev));
auto resp = client.SendEventWithTransferAndSignal(std::move(ev));
// The channel is closed after a rights error on the sending side.
ASSERT_EQ(resp.status(), ZX_ERR_INVALID_ARGS);
}
TEST_F(HandleRightsTest, SyncSendTooManyRights) {
auto client = SyncClient();
zx::event ev;
ASSERT_EQ(ZX_OK, zx::event::create(0, &ev));
auto resp = client.SendEventWithTransferAndSignal(std::move(ev));
ASSERT_TRUE(resp.ok());
}
TEST_F(HandleRightsTest, SyncSendWrongType) {
auto client = SyncClient();
zx::event ev;
ASSERT_EQ(ZX_OK, zx::event::create(0, &ev));
// Send the event as a channel (type error).
auto resp = client.SendChannel(zx::channel(ev.release()));
// The channel is closed after a type error on the sending side.
ASSERT_EQ(resp.status(), ZX_ERR_WRONG_TYPE);
}
TEST_F(HandleRightsTest, AsyncSendTooFewRights) {
auto client = AsyncClient({});
zx::event ev;
ASSERT_EQ(ZX_OK, zx::event::create(0, &ev));
ASSERT_EQ(ZX_OK, ev.replace(ZX_RIGHT_TRANSFER, &ev));
auto resp = client->SendEventWithTransferAndSignal(std::move(ev));
// The channel is closed after a rights error on the sending side.
ASSERT_EQ(resp.status(), ZX_ERR_INVALID_ARGS);
}
TEST_F(HandleRightsTest, AsyncSendTooManyRights) {
auto client = AsyncClient({});
zx::event ev;
ASSERT_EQ(ZX_OK, zx::event::create(0, &ev));
auto resp = client->SendEventWithTransferAndSignal(std::move(ev));
ASSERT_TRUE(resp.ok());
}
TEST_F(HandleRightsTest, AsyncSendWrongType) {
auto client = AsyncClient({});
zx::event ev;
ASSERT_EQ(ZX_OK, zx::event::create(0, &ev));
// Send the event as a channel (type error).
auto resp = client->SendChannel(zx::channel(ev.release()));
// The channel is closed after a type error on the sending side.
ASSERT_EQ(resp.status(), ZX_ERR_WRONG_TYPE);
}