blob: 4154f7ac22f94aff7a1b499369a8465df480e096 [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/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