blob: d73ecd131ff7a9151a30f7219b2396714028f176 [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.
#ifndef LIB_SYS_COMPONENT_CPP_TESTING_INTERNAL_LOCAL_COMPONENT_RUNNER_H_
#define LIB_SYS_COMPONENT_CPP_TESTING_INTERNAL_LOCAL_COMPONENT_RUNNER_H_
#include <fuchsia/component/runner/cpp/fidl.h>
#include <fuchsia/component/test/cpp/fidl.h>
#include <lib/async/dispatcher.h>
#include <lib/fidl/cpp/binding.h>
#include <lib/fidl/cpp/interface_handle.h>
#include <lib/fidl/cpp/interface_request.h>
#include <lib/fit/function.h>
#include <lib/sys/component/cpp/testing/realm_builder_types.h>
#include <map>
#include <memory>
namespace component_testing {
namespace internal {
class LocalComponentRunner;
class LocalComponentInstance final : public fuchsia::component::runner::ComponentController {
public:
// Constructed by the LocalComponentRunner when the runner receives a request
// to start a local component. The runner may optionally pass an on_exit
// callback. This callback is not set for `LocalComponent*` component types
// because they must stay alive for the lifetime of the Realm.
explicit LocalComponentInstance(
fidl::InterfaceRequest<fuchsia::component::runner::ComponentController> controller,
async_dispatcher_t* dispatcher,
fit::function<void(LocalComponentInstance*, std::unique_ptr<LocalComponentHandles>)> on_start,
fit::closure on_exit);
LocalComponentInstance(LocalComponentInstance&& other) = delete;
LocalComponentInstance& operator=(LocalComponentInstance&& other) = delete;
LocalComponentInstance(const LocalComponentInstance& other) = delete;
LocalComponentInstance& operator=(const LocalComponentInstance& other) = delete;
// Called after constructing the |LocalComponentInstance|, to start the
// component.
void Start(std::unique_ptr<LocalComponentHandles> handles);
// Saves a closure to be called if component manager calls
// |ComponentController::Stop()|. This closure should not be set for
// |LocalComponent|s added by raw pointer because the Realm does not control
// the lifecycle of the |LocalComponent| and the pointer could be invalid.
void SetOnStop(fit::closure on_stop);
// Returns true after Start() and before Exit().
bool IsRunning();
private:
// fuchsia::component::runner::ComponentController
void Stop() override;
// fuchsia::component::runner::ComponentController
void Kill() override;
// If on_exit is set, close the ComponentController and call the given on_exit
// function.
void Exit(zx_status_t);
fidl::Binding<fuchsia::component::runner::ComponentController> binding_;
// If a |LocalComponentImpl| calls `Exit()` during
// `LocalComponentImpl::OnStart()`, the LocalComponentInstance will _not_
// immediately call `LocalComponentInstance::Exit()`. It will save the
// provided status, and call `LocalComponentInstance::Exit()` after the
// component has `started_`.
cpp17::optional<zx_status_t> pending_exit_status_;
// Set to true at the beginning of `Start()`, and false at the completion
// of `Start()`.
bool starting_;
// Set to true at the completion of `Start()`.
bool started_;
// Called when starting the component.
fit::function<void(LocalComponentInstance*, std::unique_ptr<LocalComponentHandles>)> on_start_;
// Called when the component is exiting, purposefully or as a result of a
// ComponentController::Kill().
fit::closure on_exit_;
// Called when the ComponentController::Stop() method is called.
fit::closure on_stop_;
};
using LocalComponents = std::map<std::string, LocalComponentKind>;
using LocalComponentInstances = std::map<std::string, std::unique_ptr<LocalComponentInstance>>;
class LocalComponentRunner final : fuchsia::component::runner::ComponentRunner {
public:
LocalComponentRunner(LocalComponents components, async_dispatcher_t* dispatcher);
LocalComponentRunner(LocalComponentRunner&& other) = delete;
LocalComponentRunner& operator=(LocalComponentRunner&& other) = delete;
LocalComponentRunner(const LocalComponentRunner& other) = delete;
LocalComponentRunner& operator=(const LocalComponentRunner& other) = delete;
fidl::InterfaceHandle<fuchsia::component::runner::ComponentRunner> NewBinding();
void Start(
fuchsia::component::runner::ComponentStartInfo start_info,
fidl::InterfaceRequest<fuchsia::component::runner::ComponentController> controller) override;
class Builder;
private:
// Returns true if the runner has a component with the given name that is
// ready to be started (either it has not started, or it has stopped and
// can be started again).
bool ContainsReadyComponent(std::string name) const;
// The list of components that are not running but can be started.
LocalComponents ready_components_;
// ComponentInstance objects for components that have been started.
LocalComponentInstances running_components_;
fidl::Binding<fuchsia::component::runner::ComponentRunner> binding_;
async_dispatcher_t* dispatcher_;
};
class LocalComponentRunner::Builder final {
public:
Builder() = default;
Builder(LocalComponentRunner::Builder&& other) = default;
Builder& operator=(LocalComponentRunner::Builder&& other) = default;
Builder(const LocalComponentRunner::Builder& other) = delete;
Builder& operator=(const LocalComponentRunner::Builder& other) = delete;
std::unique_ptr<LocalComponentRunner> Build(async_dispatcher_t* dispatcher);
void Register(std::string name, LocalComponentKind mock);
private:
bool Contains(std::string name) const;
LocalComponents components_;
};
} // namespace internal
} // namespace component_testing
#endif // LIB_SYS_COMPONENT_CPP_TESTING_INTERNAL_LOCAL_COMPONENT_RUNNER_H_