blob: 8f1b36d25817c86cef7d2a2f078515b8b885ac4d [file] [log] [blame]
// Copyright 2019 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/fidl/llcpp/server.h>
#include <lib/fidl/llcpp/server_end.h>
#include <lib/zx/object.h>
#include <zircon/errors.h>
#include <zircon/status.h>
#include <zircon/syscalls/object.h>
#include <gtest/gtest.h>
#include <llcpptest/protocol/test/llcpp/fidl.h>
namespace llcpp_test = ::llcpp::llcpptest::protocol::test;
TEST(ServerEnd, Trivial) {
fidl::ServerEnd<llcpp_test::Frobinator> server_end;
EXPECT_FALSE(server_end.is_valid());
}
TEST(ServerEnd, Control) {
zx::channel h1, h2;
ASSERT_EQ(ZX_OK, zx::channel::create(0, &h1, &h2));
zx_handle_t saved1 = h1.get();
// Test initializing with channel.
fidl::ServerEnd<llcpp_test::Frobinator> server_end(std::move(h1));
EXPECT_TRUE(server_end.is_valid());
EXPECT_EQ(saved1, server_end.channel().get());
// Test move semantics.
fidl::ServerEnd<llcpp_test::Frobinator> server_end_2 = std::move(server_end);
EXPECT_FALSE(server_end.is_valid());
EXPECT_TRUE(server_end_2.is_valid());
EXPECT_EQ(saved1, server_end_2.channel().get());
h1 = server_end_2.TakeChannel();
EXPECT_EQ(saved1, h1.get());
EXPECT_FALSE(server_end_2.is_valid());
zx_handle_t saved2 = h2.get();
server_end.channel() = std::move(h2);
EXPECT_TRUE(server_end.is_valid());
EXPECT_EQ(saved2, server_end.channel().get());
// Test RAII channel management.
server_end = {};
EXPECT_FALSE(server_end.is_valid());
EXPECT_EQ(ZX_ERR_PEER_CLOSED, h1.write(0, "a", 1, nullptr, 0));
}
TEST(ServerEnd, Close) {
async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread);
auto endpoints = fidl::CreateEndpoints<llcpp_test::Frobinator>();
ASSERT_EQ(endpoints.status_value(), ZX_OK);
class EventHandler : public llcpp_test::Frobinator::AsyncEventHandler {
public:
EventHandler() = default;
fidl::UnbindInfo recorded_unbind_info() const { return recorded_unbind_info_; }
void Unbound(fidl::UnbindInfo unbind_info) override { recorded_unbind_info_ = unbind_info; }
private:
fidl::UnbindInfo recorded_unbind_info_;
};
auto event_handler = std::make_shared<EventHandler>();
fidl::Client<llcpp_test::Frobinator> client(std::move(endpoints->client), loop.dispatcher(),
event_handler);
fidl::ServerEnd<llcpp_test::Frobinator> server_end(std::move(endpoints->server));
EXPECT_TRUE(server_end.is_valid());
constexpr zx_status_t kSysError = ZX_ERR_INVALID_ARGS;
EXPECT_EQ(ZX_OK, server_end.Close(kSysError));
EXPECT_FALSE(server_end.is_valid());
loop.RunUntilIdle();
EXPECT_EQ(fidl::UnbindInfo::Reason::kPeerClosed, event_handler->recorded_unbind_info().reason);
EXPECT_EQ(kSysError, event_handler->recorded_unbind_info().status);
}
TEST(ServerEnd, CloseTwice) {
zx::channel h1, h2;
ASSERT_EQ(ZX_OK, zx::channel::create(0, &h1, &h2));
fidl::ServerEnd<llcpp_test::Frobinator> server_end(std::move(h2));
EXPECT_EQ(ZX_OK, server_end.Close(ZX_OK));
ASSERT_DEATH(server_end.Close(ZX_OK), "Cannot close an invalid ServerEnd.");
}