blob: d1f696db2776a543e7aac0bf72afff94b41d1e71 [file] [log] [blame]
// 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 <fuchsia/component/runner/cpp/fidl.h>
#include <fuchsia/component/test/cpp/fidl.h>
#include <fuchsia/data/cpp/fidl.h>
#include <fuchsia/io/cpp/fidl.h>
#include <lib/async/dispatcher.h>
#include <lib/fdio/namespace.h>
#include <lib/fidl/cpp/interface_request.h>
#include <lib/sys/component/cpp/testing/internal/errors.h>
#include <lib/sys/component/cpp/testing/internal/local_component_runner.h>
#include <lib/sys/component/cpp/testing/realm_builder_types.h>
#include <zircon/assert.h>
#include <zircon/status.h>
#include <cstddef>
#include <memory>
#include <optional>
namespace component_testing {
namespace internal {
namespace {
std::string ExtractLocalComponentName(const fuchsia::data::Dictionary& program) {
ZX_ASSERT_MSG(program.has_entries(), "Received empty program from Component Manager");
for (const auto& entry : program.entries()) {
if (entry.key == fuchsia::component::test::LOCAL_COMPONENT_NAME_KEY) {
ZX_ASSERT_MSG(entry.value->is_str(), "Received local component key of wrong type");
return entry.value->str();
}
}
ZX_PANIC("Received program without local component key");
}
std::unique_ptr<LocalComponentHandles> CreateFromStartInfo(
fuchsia::component::runner::ComponentStartInfo start_info, async_dispatcher_t* dispatcher) {
fdio_ns_t* ns;
ZX_COMPONENT_ASSERT_STATUS_OK("CreateFromStartInfo", fdio_ns_create(&ns));
for (auto& entry : *start_info.mutable_ns()) {
ZX_COMPONENT_ASSERT_STATUS_OK(
"CreateFromStartInfo",
fdio_ns_bind(ns, entry.path().c_str(), entry.mutable_directory()->TakeChannel().release()));
}
sys::OutgoingDirectory outgoing_dir;
outgoing_dir.Serve(start_info.mutable_outgoing_dir()->TakeChannel(), dispatcher);
return std::make_unique<LocalComponentHandles>(ns, std::move(outgoing_dir));
}
} // namespace
ComponentController::ComponentController() : binding_(this) {}
void ComponentController::Stop() {}
void ComponentController::Kill() {}
RegisteredComponent::RegisteredComponent(LocalComponent* component)
: component_(component), controller_(std::make_unique<ComponentController>()) {}
// TODO(fxbug.dev/89831): Implement fuchsia.component.runner/ComponentController.
void RegisteredComponent::Start(
std::unique_ptr<LocalComponentHandles> handles,
fidl::InterfaceRequest<fuchsia::component::runner::ComponentController> controller,
async_dispatcher_t* dispatcher) {
controller_->Bind(std::move(controller), dispatcher);
component_->Start(std::move(handles));
}
LocalComponentRunner::LocalComponentRunner(LocalComponentRegistry components,
async_dispatcher_t* dispatcher)
: components_(std::move(components)), dispatcher_(dispatcher), binding_(this) {}
fidl::InterfaceHandle<fuchsia::component::runner::ComponentRunner>
LocalComponentRunner::NewBinding() {
return binding_.NewBinding(dispatcher_);
}
void LocalComponentRunner::Start(
fuchsia::component::runner::ComponentStartInfo start_info,
fidl::InterfaceRequest<fuchsia::component::runner::ComponentController> controller) {
ZX_ASSERT_MSG(start_info.has_program(), "Component manager sent start_info without program");
std::string name = ExtractLocalComponentName(start_info.program());
ZX_ASSERT_MSG(Contains(name), "Component manager sent unregistered local component name id: %s",
name.c_str());
auto& component = components_[name];
component->Start(CreateFromStartInfo(std::move(start_info), dispatcher_), std::move(controller),
dispatcher_);
}
bool LocalComponentRunner::Contains(std::string name) const {
return components_.find(name) != components_.cend();
}
std::unique_ptr<LocalComponentRunner> LocalComponentRunner::Builder::Build(
async_dispatcher_t* dispatcher) {
return std::make_unique<LocalComponentRunner>(components_, dispatcher);
}
void LocalComponentRunner::Builder::Register(std::string name, LocalComponent* mock) {
ZX_ASSERT_MSG(!Contains(name), "Local component with same name being added: %s", name.c_str());
components_[name] = std::make_shared<RegisteredComponent>(mock);
}
bool LocalComponentRunner::Builder::Contains(std::string name) const {
return components_.find(name) != components_.cend();
}
} // namespace internal
} // namespace component_testing