| // 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.v2integration.test/cpp/wire.h> |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/async-loop/default.h> |
| #include <lib/fidl/cpp/wire/message.h> |
| |
| #include <iterator> |
| #include <thread> |
| |
| #include <gtest/gtest.h> |
| |
| typedef struct { |
| uint64_t ordinal; |
| uint32_t value; |
| uint16_t num_handles; |
| uint16_t flags; |
| } union_t; |
| |
| using TestProtocol = ::llcpptest_v2integration_test::TestProtocol; |
| |
| void SingleResponseServer(zx::channel ch) { |
| ZX_ASSERT(ZX_OK == ch.wait_one(ZX_CHANNEL_READABLE, zx::time::infinite(), nullptr)); |
| |
| std::unique_ptr<uint8_t[]> bytes_in = std::make_unique<uint8_t[]>(ZX_CHANNEL_MAX_MSG_BYTES); |
| ZX_ASSERT(ZX_OK == |
| ch.read_etc(0, bytes_in.get(), nullptr, ZX_CHANNEL_MAX_MSG_BYTES, 0, nullptr, nullptr)); |
| fidl_message_header_t header_in; |
| memcpy(&header_in, bytes_in.get(), sizeof(header_in)); |
| |
| fidl_message_header_t header_out = { |
| .txid = header_in.txid, |
| .at_rest_flags = {FIDL_MESSAGE_HEADER_AT_REST_FLAGS_0_USE_VERSION_V2, 0}, |
| .dynamic_flags = 0, |
| .magic_number = header_in.magic_number, |
| .ordinal = header_in.ordinal, |
| }; |
| union_t payload_out = { |
| .ordinal = 1, |
| .value = 123, |
| .num_handles = 0, |
| .flags = 1, // 1 == inlined |
| }; |
| uint8_t bytes_out[sizeof(header_out) + sizeof(payload_out)] = {}; |
| memcpy(bytes_out, &header_out, sizeof(header_out)); |
| memcpy(bytes_out + sizeof(header_out), &payload_out, sizeof(payload_out)); |
| ZX_ASSERT(ZX_OK == ch.write_etc(0, bytes_out, std::size(bytes_out), nullptr, 0)); |
| } |
| |
| // Tests an LLCPP sync client where the server returns a V2 message. |
| TEST(V2Integration, SyncCallResponseDecode) { |
| zx::channel ch1, ch2; |
| ASSERT_EQ(ZX_OK, zx::channel::create(0, &ch1, &ch2)); |
| |
| std::thread server_thread([&ch2]() { SingleResponseServer(std::move(ch2)); }); |
| |
| fidl::ClientEnd<TestProtocol> client_end(std::move(ch1)); |
| fidl::WireSyncClient<TestProtocol> client(std::move(client_end)); |
| |
| auto result = client->MethodWithResponse(); |
| ASSERT_TRUE(result.ok()); |
| ASSERT_EQ(123u, result.value().u.v()); |
| |
| server_thread.join(); |
| } |
| |
| // Tests an LLCPP async client where the server returns a V2 message. |
| TEST(V2Integration, AsyncCallResponseDecode) { |
| async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread); |
| ASSERT_EQ(ZX_OK, loop.StartThread()); |
| |
| zx::channel ch1, ch2; |
| ASSERT_EQ(ZX_OK, zx::channel::create(0, &ch1, &ch2)); |
| |
| std::thread server_thread([&ch2]() { SingleResponseServer(std::move(ch2)); }); |
| |
| fidl::ClientEnd<TestProtocol> client_end(std::move(ch1)); |
| fidl::WireSharedClient<TestProtocol> client(std::move(client_end), loop.dispatcher()); |
| |
| sync_completion_t done; |
| client->MethodWithResponse().ThenExactlyOnce( |
| [&done](fidl::WireUnownedResult<TestProtocol::MethodWithResponse>& result) { |
| ASSERT_EQ(ZX_OK, result.status()); |
| ASSERT_EQ(123u, result.value().u.v()); |
| sync_completion_signal(&done); |
| }); |
| |
| ASSERT_EQ(ZX_OK, sync_completion_wait(&done, ZX_TIME_INFINITE)); |
| server_thread.join(); |
| } |
| |
| // Tests an LLCPP server which decodes a V2 request. |
| TEST(V2Integration, ServerRequestDecode) { |
| class Server : public fidl::WireServer<TestProtocol> { |
| public: |
| Server(sync_completion_t* done) : done_(done) {} |
| |
| void MethodWithRequest(MethodWithRequestRequestView request, |
| MethodWithRequestCompleter::Sync& completer) override { |
| ASSERT_EQ(123u, request->u.v()); |
| sync_completion_signal(done_); |
| } |
| |
| void MethodWithResponse(MethodWithResponseCompleter::Sync& completer) override { |
| ZX_PANIC("Not used in this test"); |
| } |
| |
| private: |
| sync_completion_t* done_; |
| }; |
| |
| async::Loop loop(&kAsyncLoopConfigNoAttachToCurrentThread); |
| ASSERT_EQ(ZX_OK, loop.StartThread()); |
| |
| zx::channel ch1, ch2; |
| ASSERT_EQ(ZX_OK, zx::channel::create(0, &ch1, &ch2)); |
| |
| sync_completion_t done; |
| fidl::ServerEnd<TestProtocol> server_end(std::move(ch2)); |
| fidl::BindServer(loop.dispatcher(), std::move(server_end), std::make_unique<Server>(&done)); |
| |
| fidl_message_header_t header = { |
| .txid = 100, |
| .at_rest_flags = {FIDL_MESSAGE_HEADER_AT_REST_FLAGS_0_USE_VERSION_V2, 0}, |
| .dynamic_flags = 0, |
| .magic_number = kFidlWireFormatMagicNumberInitial, |
| .ordinal = 8068486508660569159ull, |
| }; |
| union_t payload = { |
| .ordinal = 1, |
| .value = 123, |
| .num_handles = 0, |
| .flags = 1, // 1 == inlined |
| }; |
| uint8_t bytes[sizeof(header) + sizeof(payload)] = {}; |
| memcpy(bytes, &header, sizeof(header)); |
| memcpy(bytes + sizeof(header), &payload, sizeof(payload)); |
| ASSERT_EQ(ZX_OK, ch1.write_etc(0, bytes, std::size(bytes), nullptr, 0)); |
| |
| ASSERT_EQ(ZX_OK, sync_completion_wait(&done, ZX_TIME_INFINITE)); |
| } |