| // 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 <lib/async-loop/cpp/loop.h> |
| #include <lib/fidl/cpp/client.h> |
| #include <lib/fidl/cpp/wire/connect_service.h> |
| |
| #include <array> |
| |
| #include <zxtest/zxtest.h> |
| |
| #include "src/lib/fidl/llcpp/tests/dispatcher/test_messages.h" |
| |
| namespace { |
| |
| class TestProtocol { |
| public: |
| using Transport = fidl::internal::ChannelTransport; |
| TestProtocol() = delete; |
| }; |
| |
| } // namespace |
| |
| // Fake client implementations. |
| namespace fidl { |
| |
| template <> |
| struct IsProtocol<TestProtocol> : public std::true_type {}; |
| |
| template <> |
| class AsyncEventHandler<TestProtocol> : public fidl::internal::AsyncEventHandler, |
| public fidl::internal::BaseEventHandlerInterface {}; |
| |
| namespace internal { |
| |
| template <> |
| class WireWeakAsyncClientImpl<TestProtocol> : public fidl::internal::ClientImplBase { |
| public: |
| using ClientImplBase::ClientImplBase; |
| |
| void SomeWireMethod() { |
| fidl_testing::GoodMessage msg; |
| fidl::Status result = _client_base()->MakeSyncCallWith( |
| [&](const std::shared_ptr<fidl::internal::AnyTransport>& transport) { |
| // The input to this call has no handles. |
| ZX_ASSERT(msg.message().handle_actual() == 0); |
| auto copied_bytes = msg.message().CopyBytes(); |
| zx_status_t status = zx_channel_write_etc( |
| transport->get<fidl::internal::ChannelTransport>()->get(), 0, copied_bytes.data(), |
| static_cast<uint32_t>(copied_bytes.size()), nullptr, 0); |
| EXPECT_OK(status); |
| return fidl::Status::Ok(); |
| }); |
| EXPECT_OK(result.status()); |
| } |
| }; |
| |
| template <> |
| class NaturalEventDispatcher<TestProtocol> |
| : public IncomingEventDispatcher<fidl::AsyncEventHandler<TestProtocol>> { |
| public: |
| using IncomingEventDispatcher<fidl::AsyncEventHandler<TestProtocol>>::IncomingEventDispatcher; |
| |
| private: |
| ::fidl::Status DispatchEvent(fidl::IncomingHeaderAndMessage& msg, |
| MessageStorageViewBase* storage_view) override { |
| ZX_PANIC("Not used in this test"); |
| } |
| }; |
| |
| template <> |
| class NaturalClientImpl<TestProtocol> : public NaturalClientBase { |
| public: |
| using NaturalClientBase::NaturalClientBase; |
| |
| void SomeNaturalMethod() const { |
| fidl_testing::GoodMessage msg; |
| fidl::OutgoingMessage outgoing = msg.message(); |
| fidl::Status result = client_base().SendOneWay(outgoing); |
| EXPECT_OK(result.status()); |
| } |
| }; |
| |
| } // namespace internal |
| } // namespace fidl |
| |
| namespace { |
| |
| class ClientFixture : public zxtest::Test { |
| public: |
| ClientFixture() : loop_(&kAsyncLoopConfigNeverAttachToThread) {} |
| |
| void SetUp() override { |
| zx::result endpoints = fidl::CreateEndpoints<TestProtocol>(); |
| ASSERT_OK(endpoints.status_value()); |
| endpoints_ = std::move(*endpoints); |
| } |
| |
| async::Loop& loop() { return loop_; } |
| |
| fidl::Endpoints<TestProtocol>& endpoints() { return endpoints_; } |
| |
| fidl::IncomingHeaderAndMessage ReadFromServer() { |
| return fidl::MessageRead( |
| endpoints_.server.channel(), |
| fidl::ChannelMessageStorageView{ |
| .bytes = |
| fidl::BufferSpan(read_buffer_.data(), static_cast<uint32_t>(read_buffer_.size())), |
| .handles = nullptr, |
| .handle_metadata = nullptr, |
| .handle_capacity = 0, |
| }); |
| } |
| |
| private: |
| async::Loop loop_; |
| fidl::Endpoints<TestProtocol> endpoints_; |
| FIDL_ALIGNDECL std::array<uint8_t, ZX_CHANNEL_MAX_MSG_BYTES> read_buffer_; |
| }; |
| |
| class Client : public ClientFixture {}; |
| class SharedClient : public ClientFixture {}; |
| |
| TEST_F(Client, DefaultConstruction) { |
| fidl::Client<TestProtocol> client; |
| EXPECT_FALSE(client.is_valid()); |
| } |
| |
| TEST_F(SharedClient, DefaultConstruction) { |
| fidl::SharedClient<TestProtocol> client; |
| EXPECT_FALSE(client.is_valid()); |
| } |
| |
| TEST_F(Client, InvalidAccess) { |
| fidl::Client<TestProtocol> client; |
| ASSERT_DEATH([&] { client->SomeNaturalMethod(); }); |
| ASSERT_DEATH([&] { client.wire()->SomeWireMethod(); }); |
| } |
| |
| TEST_F(SharedClient, InvalidAccess) { |
| fidl::SharedClient<TestProtocol> client; |
| ASSERT_DEATH([&] { client->SomeNaturalMethod(); }); |
| ASSERT_DEATH([&] { client.wire()->SomeWireMethod(); }); |
| ASSERT_DEATH([&] { client.AsyncTeardown(); }); |
| } |
| |
| TEST_F(Client, Move) { |
| fidl::Client<TestProtocol> client; |
| client.Bind(std::move(endpoints().client), loop().dispatcher()); |
| EXPECT_TRUE(client.is_valid()); |
| |
| fidl::Client<TestProtocol> client2 = std::move(client); |
| EXPECT_FALSE(client.is_valid()); |
| EXPECT_TRUE(client2.is_valid()); |
| ASSERT_DEATH([&] { client->SomeNaturalMethod(); }); |
| } |
| |
| TEST_F(SharedClient, Move) { |
| fidl::SharedClient<TestProtocol> client; |
| client.Bind(std::move(endpoints().client), loop().dispatcher()); |
| EXPECT_TRUE(client.is_valid()); |
| |
| fidl::SharedClient<TestProtocol> client2 = std::move(client); |
| EXPECT_FALSE(client.is_valid()); |
| EXPECT_TRUE(client2.is_valid()); |
| ASSERT_DEATH([&] { client->SomeNaturalMethod(); }); |
| } |
| |
| TEST_F(SharedClient, Clone) { |
| fidl::SharedClient<TestProtocol> client; |
| client.Bind(std::move(endpoints().client), loop().dispatcher()); |
| EXPECT_TRUE(client.is_valid()); |
| |
| fidl::SharedClient<TestProtocol> client2 = client.Clone(); |
| EXPECT_TRUE(client.is_valid()); |
| EXPECT_TRUE(client2.is_valid()); |
| ASSERT_NO_DEATH([&] { client->SomeNaturalMethod(); }); |
| ASSERT_NO_DEATH([&] { client2->SomeNaturalMethod(); }); |
| } |
| |
| TEST_F(Client, WireCall) { |
| fidl::Client client(std::move(endpoints().client), loop().dispatcher()); |
| client.wire()->SomeWireMethod(); |
| auto msg = ReadFromServer(); |
| EXPECT_OK(msg.status()); |
| } |
| |
| TEST_F(SharedClient, WireCall) { |
| fidl::SharedClient client(std::move(endpoints().client), loop().dispatcher()); |
| client.wire()->SomeWireMethod(); |
| auto msg = ReadFromServer(); |
| EXPECT_OK(msg.status()); |
| } |
| |
| TEST_F(Client, NaturalCall) { |
| fidl::Client client(std::move(endpoints().client), loop().dispatcher()); |
| client->SomeNaturalMethod(); |
| auto msg = ReadFromServer(); |
| EXPECT_OK(msg.status()); |
| } |
| |
| TEST_F(SharedClient, NaturalCall) { |
| fidl::SharedClient client(std::move(endpoints().client), loop().dispatcher()); |
| client->SomeNaturalMethod(); |
| auto msg = ReadFromServer(); |
| EXPECT_OK(msg.status()); |
| } |
| |
| } // namespace |