blob: 371721fc3007c3b3379a2c9de5b76fd0b39529ed [file] [log] [blame]
// Copyright 2020 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 <memory>
#include <gtest/gtest.h>
#include "src/lib/fidl_codec/library_loader.h"
#include "src/lib/fidl_codec/semantic.h"
#include "src/lib/fidl_codec/semantic_parser_test.h"
#include "src/lib/fidl_codec/wire_object.h"
#include "src/lib/fidl_codec/wire_types.h"
namespace fidl_codec {
namespace semantic {
constexpr uint64_t kPid = 0x1234;
constexpr uint32_t kHandle = 0x1111;
constexpr uint32_t kChannel0 = 0x1000;
constexpr uint32_t kChannel1 = 0x2000;
constexpr uint32_t kChannel2 = 0x3000;
constexpr uint32_t kChannel3 = 0x4000;
class BuiltinSemanticTest : public SemanticParserTest {
public:
BuiltinSemanticTest();
void SetHandleSemantic(std::string_view type, std::string_view path) {
handle_semantic_.AddHandleDescription(kPid, kHandle, type, path);
}
void ExecuteWrite(const MethodSemantic* method_semantic, const StructValue* request,
const StructValue* response);
void ExecuteRead(const MethodSemantic* method_semantic, const StructValue* request,
const StructValue* response);
protected:
HandleSemantic handle_semantic_;
const zx_handle_info_t channel0_;
const zx_handle_info_t channel2_;
};
BuiltinSemanticTest::BuiltinSemanticTest()
: channel0_({kChannel0, 0, 0, 0}), channel2_({kChannel2, 0, 0, 0}) {
library_loader_.ParseBuiltinSemantic();
handle_semantic_.AddLinkedHandles(kPid, kChannel0, kChannel1);
handle_semantic_.AddLinkedHandles(kPid, kChannel2, kChannel3);
}
void BuiltinSemanticTest::ExecuteWrite(const MethodSemantic* method_semantic,
const StructValue* request, const StructValue* response) {
fidl_codec::semantic::SemanticContext context(&handle_semantic_, kPid, kHandle,
ContextType::kWrite, request, response);
method_semantic->ExecuteAssignments(&context);
}
void BuiltinSemanticTest::ExecuteRead(const MethodSemantic* method_semantic,
const StructValue* request, const StructValue* response) {
fidl_codec::semantic::SemanticContext context(&handle_semantic_, kPid, kHandle,
ContextType::kRead, request, response);
method_semantic->ExecuteAssignments(&context);
}
// Check Node::Clone: request.object = handle
TEST_F(BuiltinSemanticTest, CloneWrite) {
// Checks that Node::Clone exists in fuchsia.io.
Library* library = library_loader_.GetLibraryFromName("fuchsia.io");
ASSERT_NE(library, nullptr);
library->DecodeTypes();
Interface* interface = nullptr;
library->GetInterfaceByName("fuchsia.io/Node", &interface);
ASSERT_NE(interface, nullptr);
InterfaceMethod* method = interface->GetMethodByName("Clone");
ASSERT_NE(method, nullptr);
// Checks that the builtin semantic is defined for Clone.
ASSERT_NE(method->semantic(), nullptr);
// Check that by writing on this handle:
SetHandleSemantic("dir", "/svc");
// This message (we only define the fields used by the semantic):
StructValue request(*method->request());
request.AddField("object", std::make_unique<HandleValue>(channel0_));
ExecuteWrite(method->semantic(), &request, nullptr);
// We have this handle semantic for kChannel1.
const HandleDescription* description = handle_semantic_.GetHandleDescription(kPid, kChannel1);
ASSERT_NE(description, nullptr);
ASSERT_EQ(description->type(), "dir");
ASSERT_EQ(description->path(), "/svc");
}
// Check Node::Clone: request.object = handle
TEST_F(BuiltinSemanticTest, CloneRead) {
// Checks that Node::Clone exists in fuchsia.io.
Library* library = library_loader_.GetLibraryFromName("fuchsia.io");
ASSERT_NE(library, nullptr);
library->DecodeTypes();
Interface* interface = nullptr;
library->GetInterfaceByName("fuchsia.io/Node", &interface);
ASSERT_NE(interface, nullptr);
InterfaceMethod* method = interface->GetMethodByName("Clone");
ASSERT_NE(method, nullptr);
// Checks that the builtin semantic is defined for Clone.
ASSERT_NE(method->semantic(), nullptr);
// Check that by writing on this handle:
SetHandleSemantic("dir", "/svc");
// This message (we only define the fields used by the semantic):
StructValue request(*method->request());
request.AddField("object", std::make_unique<HandleValue>(channel0_));
ExecuteRead(method->semantic(), &request, nullptr);
// We have this handle semantic for kChannel1.
const HandleDescription* description = handle_semantic_.GetHandleDescription(kPid, kChannel0);
ASSERT_NE(description, nullptr);
ASSERT_EQ(description->type(), "dir");
ASSERT_EQ(description->path(), "/svc");
}
// Check Directory::Open: request.object = handle / request.path
TEST_F(BuiltinSemanticTest, Open) {
// Checks that Directory::Open exists in fuchsia.io.
Library* library = library_loader_.GetLibraryFromName("fuchsia.io");
ASSERT_NE(library, nullptr);
library->DecodeTypes();
Interface* interface = nullptr;
library->GetInterfaceByName("fuchsia.io/Directory", &interface);
ASSERT_NE(interface, nullptr);
InterfaceMethod* method = interface->GetMethodByName("Open");
ASSERT_NE(method, nullptr);
// Checks that the builtin semantic is defined for Open.
ASSERT_NE(method->semantic(), nullptr);
// Check that by writing on this handle:
SetHandleSemantic("dir", "/svc");
// This message (we only define the fields used by the semantic):
StructValue request(*method->request());
request.AddField("path", std::make_unique<StringValue>("fuchsia.sys.Launcher"));
request.AddField("object", std::make_unique<HandleValue>(channel0_));
ExecuteWrite(method->semantic(), &request, nullptr);
// We have this handle semantic for kChannel1.
const HandleDescription* description = handle_semantic_.GetHandleDescription(kPid, kChannel1);
ASSERT_NE(description, nullptr);
ASSERT_EQ(description->type(), "dir");
ASSERT_EQ(description->path(), "/svc/fuchsia.sys.Launcher");
}
// Check Launcher::CreateComponent.
TEST_F(BuiltinSemanticTest, CreateComponent) {
// Checks that Launcher::CreateComponent exists in fuchsia.sys.
Library* library = library_loader_.GetLibraryFromName("fuchsia.sys");
ASSERT_NE(library, nullptr);
library->DecodeTypes();
Interface* interface = nullptr;
library->GetInterfaceByName("fuchsia.sys/Launcher", &interface);
ASSERT_NE(interface, nullptr);
InterfaceMethod* method = interface->GetMethodByName("CreateComponent");
ASSERT_NE(method, nullptr);
// Checks that the builtin semantic is defined for CreateComponent.
ASSERT_NE(method->semantic(), nullptr);
// Check that by writing on this handle:
SetHandleSemantic("dir", "/svc/fuchsia.sys.Launcher");
// This message (we only define the fields used by the semantic):
StructValue request(*method->request());
auto launch_info = std::make_unique<StructValue>(
method->request()->SearchMember("launch_info")->type()->AsStructType()->struct_definition());
launch_info->AddField("url",
std::make_unique<StringValue>(
"fuchsia-pkg://fuchsia.com/echo_server_cpp#meta/echo_server_cpp.cmx"));
launch_info->AddField("directory_request", std::make_unique<HandleValue>(channel0_));
request.AddField("launch_info", std::move(launch_info));
request.AddField("controller", std::make_unique<HandleValue>(channel2_));
ExecuteWrite(method->semantic(), &request, nullptr);
// We have these handle semantics for kChannel1 and kChannel3.
const HandleDescription* description_1 = handle_semantic_.GetHandleDescription(kPid, kChannel1);
ASSERT_NE(description_1, nullptr);
ASSERT_EQ(description_1->type(), "server");
ASSERT_EQ(description_1->path(),
"fuchsia-pkg://fuchsia.com/echo_server_cpp#meta/echo_server_cpp.cmx");
const HandleDescription* description_2 = handle_semantic_.GetHandleDescription(kPid, kChannel3);
ASSERT_NE(description_2, nullptr);
ASSERT_EQ(description_2->type(), "server-control");
ASSERT_EQ(description_2->path(),
"fuchsia-pkg://fuchsia.com/echo_server_cpp#meta/echo_server_cpp.cmx");
}
} // namespace semantic
} // namespace fidl_codec