| // 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/async/wait.h> |
| #include <lib/fidl/cpp/binding.h> |
| #include <lib/fidl/cpp/message_part.h> |
| #include <lib/fidl/cpp/test/test_util.h> |
| #include <lib/fidl/txn_header.h> |
| #include <zircon/errors.h> |
| #include <zircon/fidl.h> |
| #include <zircon/status.h> |
| #include <zircon/types.h> |
| |
| #include <atomic> |
| #include <memory> |
| #include <thread> |
| #include <vector> |
| |
| #include <example/cpp/fidl.h> |
| #include <gtest/gtest.h> |
| #include <transformerintegration/test/cpp/fidl.h> |
| |
| namespace test = ::transformerintegration::test; |
| |
| namespace { |
| |
| // The v1 version of |example/Sandwich4|. |
| // This excerpt of bytes is taken directly from zircon/system/utest/fidl/transformer_tests.cc. |
| constexpr uint8_t sandwich4_case1_v1[] = { |
| 0x01, 0x02, 0x03, 0x04, // Sandwich4.before |
| 0x00, 0x00, 0x00, 0x00, // Sandwich4.before (padding) |
| |
| 0x04, 0x00, 0x00, 0x00, // UnionSize36Alignment4.tag, i.e. Sandwich4.the_union |
| 0x00, 0x00, 0x00, 0x00, // UnionSize36Alignment4.tag (padding) |
| 0x20, 0x00, 0x00, 0x00, // UnionSize36Alignment4.env.num_bytes |
| 0x00, 0x00, 0x00, 0x00, // UnionSize36Alignment4.env.num_handle |
| 0xff, 0xff, 0xff, 0xff, // UnionSize36Alignment4.env.presence |
| 0xff, 0xff, 0xff, 0xff, // UnionSize36Alignment4.env.presence [cont.] |
| |
| 0x05, 0x06, 0x07, 0x08, // Sandwich4.after |
| 0x00, 0x00, 0x00, 0x00, // Sandwich4.after (padding) |
| |
| 0xa0, 0xa1, 0xa2, 0xa3, // UnionSize36Alignment4.data, i.e. Sandwich4.the_union.data |
| 0xa4, 0xa5, 0xa6, 0xa7, // UnionSize36Alignment4.data [cont.] |
| 0xa8, 0xa9, 0xaa, 0xab, // UnionSize36Alignment4.data [cont.] |
| 0xac, 0xad, 0xae, 0xaf, // UnionSize36Alignment4.data [cont.] |
| 0xb0, 0xb1, 0xb2, 0xb3, // UnionSize36Alignment4.data [cont.] |
| 0xb4, 0xb5, 0xb6, 0xb7, // UnionSize36Alignment4.data [cont.] |
| 0xb8, 0xb9, 0xba, 0xbb, // UnionSize36Alignment4.data [cont.] |
| 0xbc, 0xbd, 0xbe, 0xbf, // UnionSize36Alignment4.data [cont.] |
| }; |
| |
| class TransformerIntegrationTest : public ::testing::Test { |
| protected: |
| virtual void SetUp() override { |
| ASSERT_EQ(zx::channel::create(0, &client_end_, &server_end_), ZX_OK); |
| loop_ = std::make_unique<async::Loop>(&kAsyncLoopConfigAttachToCurrentThread); |
| } |
| |
| virtual void TearDown() override { loop_->Shutdown(); } |
| |
| zx::channel& client_end() { return client_end_; } |
| zx::channel& server_end() { return server_end_; } |
| |
| static void InitSandwich(::example::Sandwich4* sandwich) { |
| sandwich->before = 0x04030201u; |
| sandwich->after = 0x08070605; |
| std::array<uint8_t, 32> array; |
| for (size_t i = 0; i < array.size(); i++) { |
| array[i] = static_cast<uint8_t>(0xa0 + i); |
| } |
| sandwich->the_union.set_variant(array); |
| } |
| |
| async::Loop* loop() const { return loop_.get(); } |
| |
| private: |
| zx::channel client_end_; |
| zx::channel server_end_; |
| std::unique_ptr<async::Loop> loop_; |
| }; |
| |
| TEST_F(TransformerIntegrationTest, ReadPathUnionEvent) { |
| std::vector<uint8_t> response(sizeof(fidl_message_header_t) + sizeof(sandwich4_case1_v1)); |
| auto response_hdr = reinterpret_cast<fidl_message_header_t*>(&response[0]); |
| fidl_init_txn_header(response_hdr, 0, |
| test::internal::kReceiveXunionsForUnions_UnionEvent_Ordinal); |
| memcpy(&response[sizeof(fidl_message_header_t)], sandwich4_case1_v1, sizeof(sandwich4_case1_v1)); |
| ASSERT_EQ(ZX_OK, server_end().write(0, &response[0], response.size(), nullptr, 0)); |
| |
| test::ReceiveXunionsForUnionsPtr client; |
| client.Bind(std::move(client_end()), loop()->dispatcher()); |
| client.events().UnionEvent = [this](::example::Sandwich4 sandwich) { |
| EXPECT_EQ(example::UnionSize36Alignment4::Tag::kVariant, sandwich.the_union.Which()); |
| EXPECT_EQ(0x04030201u, sandwich.before); |
| EXPECT_EQ(0x08070605u, sandwich.after); |
| loop()->Quit(); |
| }; |
| ASSERT_EQ(ZX_ERR_CANCELED, loop()->Run()); |
| } |
| |
| TEST_F(TransformerIntegrationTest, ReadPathSendUnion) { |
| class TestServer : public test::ReceiveXunionsForUnions { |
| public: |
| void SendUnion(::example::Sandwich4 sandwich, SendUnionCallback callback) override { |
| reply_called_ += 1; |
| EXPECT_EQ(example::UnionSize36Alignment4::Tag::kVariant, sandwich.the_union.Which()); |
| EXPECT_EQ(0x04030201u, sandwich.before); |
| EXPECT_EQ(0x08070605u, sandwich.after); |
| callback(true); |
| } |
| |
| void ReceiveUnion(ReceiveUnionCallback callback) override { |
| FAIL() << "Never used in the test"; |
| } |
| |
| int reply_called() const { return reply_called_; } |
| |
| private: |
| int reply_called_ = 0; |
| }; |
| std::vector<uint8_t> request(sizeof(fidl_message_header_t) + sizeof(sandwich4_case1_v1)); |
| auto request_hdr = reinterpret_cast<fidl_message_header_t*>(&request[0]); |
| fidl_init_txn_header(request_hdr, 1, test::internal::kReceiveXunionsForUnions_SendUnion_Ordinal); |
| memcpy(&request[sizeof(fidl_message_header_t)], sandwich4_case1_v1, sizeof(sandwich4_case1_v1)); |
| ASSERT_EQ(ZX_OK, client_end().write(0, &request[0], request.size(), nullptr, 0)); |
| |
| TestServer server_impl; |
| fidl::Binding<test::ReceiveXunionsForUnions> binding(&server_impl, std::move(server_end()), |
| loop()->dispatcher()); |
| loop()->RunUntilIdle(); |
| ASSERT_EQ(1, server_impl.reply_called()); |
| } |
| |
| TEST_F(TransformerIntegrationTest, ReadPathReceiveUnion) { |
| test::ReceiveXunionsForUnionsPtr client; |
| client.Bind(std::move(client_end()), loop()->dispatcher()); |
| |
| // Send the method response from the server end, on another thread |
| std::thread server_thread([&, this] { |
| // Wait for request |
| zx_signals_t observed; |
| zx_status_t status = server_end().wait_one(ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED, |
| zx::time::infinite(), &observed); |
| if ((observed & ZX_CHANNEL_READABLE) == 0) { |
| FAIL() << "Failed to observe a readable channel signal"; |
| } |
| ASSERT_EQ(ZX_OK, status); |
| std::vector<uint8_t> request_buffer(ZX_CHANNEL_MAX_MSG_BYTES); |
| zx_handle_t handles[ZX_CHANNEL_MAX_MSG_HANDLES]; |
| uint32_t actual_bytes = 0u; |
| uint32_t actual_handles = 0u; |
| status = server_end().read(0, &request_buffer[0], handles, request_buffer.size(), |
| ZX_CHANNEL_MAX_MSG_HANDLES, &actual_bytes, &actual_handles); |
| ASSERT_EQ(ZX_OK, status); |
| ASSERT_GE(actual_bytes, sizeof(fidl_message_header_t)); |
| ASSERT_EQ(actual_handles, 0u); |
| auto request_hdr = reinterpret_cast<fidl_message_header_t*>(&request_buffer[0]); |
| // Send response with xunion |
| std::vector<uint8_t> response(sizeof(fidl_message_header_t) + sizeof(sandwich4_case1_v1)); |
| auto response_hdr = reinterpret_cast<fidl_message_header_t*>(&response[0]); |
| fidl_init_txn_header(response_hdr, 1, |
| test::internal::kReceiveXunionsForUnions_ReceiveUnion_Ordinal); |
| response_hdr->txid = request_hdr->txid; |
| memcpy(&response[sizeof(fidl_message_header_t)], sandwich4_case1_v1, |
| sizeof(sandwich4_case1_v1)); |
| ASSERT_EQ(ZX_OK, server_end().write(0, &response[0], response.size(), nullptr, 0)); |
| }); |
| |
| std::atomic<bool> response_received = false; |
| client->ReceiveUnion([this, &response_received](::example::Sandwich4 sandwich) { |
| EXPECT_EQ(example::UnionSize36Alignment4::Tag::kVariant, sandwich.the_union.Which()); |
| EXPECT_EQ(0x04030201u, sandwich.before); |
| EXPECT_EQ(0x08070605u, sandwich.after); |
| response_received.store(true); |
| loop()->Quit(); |
| }); |
| |
| loop()->Run(); |
| server_thread.join(); |
| ASSERT_TRUE(response_received.load()); |
| } |
| |
| } // namespace |