| // 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."); |
| } |