blob: 625cc2cb0e63837c221a1822a5b9cd0c22c42ab3 [file] [log] [blame]
// Copyright 2021 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 <fidl/llcpptest.dispatcher.handle.ownership.test/cpp/wire.h>
#include <fidl/llcpptest.dispatcher.handle.ownership.test/cpp/wire_test_base.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/fidl/cpp/wire/client.h>
#include <lib/fidl/cpp/wire/server.h>
#include <zircon/syscalls.h>
#include <zircon/types.h>
#include <zxtest/zxtest.h>
// These tests verify that the dispatchers properly close any unused handles
// ignored by the user method handlers.
namespace {
namespace test = ::llcpptest_dispatcher_handle_ownership_test;
// Creates a pair of |zx::eventpair|.
auto CreateEventPair() {
struct {
zx::eventpair e1;
zx::eventpair e2;
} ret;
zx_status_t status = zx::eventpair::create(0, &ret.e1, &ret.e2);
ZX_ASSERT(status == ZX_OK);
return ret;
}
TEST(DispatcherHandleOwnership, ServerReceiveOneWay) {
auto [local, remote] = fidl::Endpoints<test::Protocol>::Create();
class Server : public fidl::WireServer<test::Protocol> {
public:
void SendResource(SendResourceRequestView request,
SendResourceCompleter::Sync& completer) override {
// The handles in |request| should be closed by the bindings runtime after we return.
}
void GetResource(GetResourceCompleter::Sync& completer) override {
ZX_PANIC("Not used in test");
}
};
async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
fidl::BindServer(loop.dispatcher(), std::move(remote), std::make_unique<Server>());
fidl::WireClient client(std::move(local), loop.dispatcher());
auto [observer, send] = CreateEventPair();
fidl::Arena allocator;
auto result = client->SendResource(
test::wire::Resource::Builder(allocator).handle(std::move(send)).Build());
ASSERT_TRUE(result.ok());
ASSERT_OK(loop.RunUntilIdle());
zx_signals_t signals;
ASSERT_OK(observer.wait_one(ZX_EVENTPAIR_PEER_CLOSED, zx::time::infinite_past(), &signals));
ASSERT_EQ(signals, ZX_EVENTPAIR_PEER_CLOSED);
}
TEST(DispatcherHandleOwnership, ClientReceiveTwoWay) {
auto [local, remote] = fidl::Endpoints<test::Protocol>::Create();
class Server : public fidl::WireServer<test::Protocol> {
public:
void SendResource(SendResourceRequestView request,
SendResourceCompleter::Sync& completer) override {
ZX_PANIC("Not used in test");
}
void GetResource(GetResourceCompleter::Sync& completer) override {
auto [observer, send] = CreateEventPair();
fidl::Arena allocator;
observer_ = std::move(observer);
completer.Reply(test::wire::Resource::Builder(allocator).handle(std::move(send)).Build());
}
const zx::eventpair& observer() const { return observer_; }
private:
zx::eventpair observer_;
};
async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
auto server = std::make_shared<Server>();
fidl::BindServer(loop.dispatcher(), std::move(remote), server);
fidl::WireClient client(std::move(local), loop.dispatcher());
// Test the managed overload.
{
client->GetResource().ThenExactlyOnce(
[&](fidl::WireUnownedResult<test::Protocol::GetResource>& result) {
ASSERT_TRUE(result.ok());
// The handles in |r| should be closed by the bindings runtime after we return.
});
ASSERT_OK(loop.RunUntilIdle());
zx_signals_t signals;
ASSERT_OK(
server->observer().wait_one(ZX_EVENTPAIR_PEER_CLOSED, zx::time::infinite_past(), &signals));
ASSERT_EQ(signals, ZX_EVENTPAIR_PEER_CLOSED);
}
// Test the caller-allocating overload.
{
class ResponseContext final : public fidl::WireResponseContext<test::Protocol::GetResource> {
void OnResult(fidl::WireUnownedResult<test::Protocol::GetResource>& r) override {
// The handles in |r| should be closed by the bindings runtime after we return.
ASSERT_OK(r.status());
}
};
ResponseContext context;
fidl::AsyncClientBuffer<test::Protocol::GetResource> buffer;
client.buffer(buffer.view())->GetResource().ThenExactlyOnce(&context);
ASSERT_OK(loop.RunUntilIdle());
zx_signals_t signals;
ASSERT_OK(
server->observer().wait_one(ZX_EVENTPAIR_PEER_CLOSED, zx::time::infinite_past(), &signals));
ASSERT_EQ(signals, ZX_EVENTPAIR_PEER_CLOSED);
}
}
TEST(DispatcherHandleOwnership, ClientReceiveEvent) {
auto [local, remote] = fidl::Endpoints<test::Protocol>::Create();
class Server : public fidl::testing::WireTestBase<test::Protocol> {
public:
void NotImplemented_(const std::string& name, fidl::CompleterBase& completer) override {
FAIL("%s not used by test", name.c_str());
}
};
async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
auto server = std::make_shared<Server>();
auto server_binding = fidl::BindServer(loop.dispatcher(), std::move(remote), server);
auto [observer, send] = CreateEventPair();
fidl::Arena allocator;
ASSERT_OK(fidl::WireSendEvent(server_binding)
->ResourceEvent(
test::wire::Resource::Builder(allocator).handle(std::move(send)).Build()));
class EventHandler final : public fidl::WireAsyncEventHandler<test::Protocol> {
public:
void ResourceEvent(fidl::WireEvent<test::Protocol::ResourceEvent>* r) override {
// The handles in |r| should be closed by the bindings runtime after we return.
}
};
EventHandler event_handler;
fidl::WireClient client(std::move(local), loop.dispatcher(), &event_handler);
ASSERT_OK(loop.RunUntilIdle());
zx_signals_t signals;
ASSERT_OK(observer.wait_one(ZX_EVENTPAIR_PEER_CLOSED, zx::time::infinite_past(), &signals));
ASSERT_EQ(signals, ZX_EVENTPAIR_PEER_CLOSED);
}
} // namespace