blob: 3b92334d554ce85fc0f5e061d24b4ec6c17d0e10 [file] [log] [blame]
// Copyright 2018 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 "garnet/bin/appmgr/integration_tests/mock_runner/mock_runner.h"
#include <memory>
#include <lib/fdio/util.h>
#include "lib/fxl/logging.h"
namespace component {
namespace testing {
FakeSubComponent::FakeSubComponent(
uint64_t id, fuchsia::sys::Package application,
fuchsia::sys::StartupInfo startup_info,
::fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller,
MockRunner* runner)
: id_(id),
return_code_(0),
alive_(true),
binding_(this),
runner_(runner),
startup_context_(StartupContext::CreateFrom(std::move(startup_info))) {
if (controller.is_valid()) {
binding_.Bind(std::move(controller));
binding_.set_error_handler([this](zx_status_t status) { Kill(); });
}
}
FakeSubComponent::~FakeSubComponent() { Kill(); }
void FakeSubComponent::Kill() {
if (!alive_) {
return;
}
alive_ = false;
SendReturnCodeIfTerminated();
// this should kill the object
runner_->ExtractComponent(id_);
}
void FakeSubComponent::SendReturnCodeIfTerminated() {
if (!alive_) {
binding_.events().OnTerminated(return_code_, TerminationReason::EXITED);
}
}
void FakeSubComponent::Detach() { binding_.set_error_handler(nullptr); }
void FakeSubComponent::PublishService(::std::string service_name,
PublishServiceCallback callback) {
// publish to root as appmgr assumes that all the components started by
// runners publish services using legacy style
std::string sname = service_name;
startup_context_->outgoing().public_dir()->AddEntry(
sname.c_str(),
fbl::AdoptRef(new fs::Service([sname, this](zx::channel channel) {
fdio_service_connect_at(service_dir_.get(), sname.c_str(),
channel.release());
return ZX_OK;
})));
callback();
}
MockRunner::MockRunner()
: loop_(&kAsyncLoopConfigAttachToThread),
context_(component::StartupContext::CreateFromStartupInfo()),
mock_binding_(this),
component_id_counter_(0) {
context_->outgoing().AddPublicService(bindings_.GetHandler(this));
mockrunner::MockRunnerPtr mock_runner;
mock_binding_.Bind(mock_runner.NewRequest());
mockrunner::MockRunnerRegistryPtr runner_registry_ptr;
context_->ConnectToEnvironmentService(runner_registry_ptr.NewRequest());
runner_registry_ptr->Register(std::move(mock_runner));
}
MockRunner::~MockRunner() = default;
void MockRunner::Crash() { exit(1); }
void MockRunner::ConnectToComponent(
uint64_t id, ::fidl::InterfaceRequest<mockrunner::MockComponent> req) {
auto it = components_.find(id);
if (it == components_.end()) {
return;
}
auto component = it->second.get();
component->AddMockControllerBinding(std::move(req));
}
void MockRunner::StartComponent(
fuchsia::sys::Package application, fuchsia::sys::StartupInfo startup_info,
::fidl::InterfaceRequest<fuchsia::sys::ComponentController> controller) {
auto id = component_id_counter_++;
mockrunner::ComponentInfo info{.unique_id = id,
.url = startup_info.launch_info.url};
auto fake_component = std::make_unique<FakeSubComponent>(
id, std::move(application), std::move(startup_info),
std::move(controller), this);
mock_binding_.events().OnComponentCreated(std::move(info));
components_.insert({id, std::move(fake_component)});
}
std::unique_ptr<FakeSubComponent> MockRunner::ExtractComponent(uint64_t id) {
auto it = components_.find(id);
if (it == components_.end()) {
return nullptr;
}
auto component = std::move(it->second);
components_.erase(it);
// send event
mock_binding_.events().OnComponentKilled(id);
return component;
}
} // namespace testing
} // namespace component