blob: dc8ba81fd6deca0d9f4e03f3b436ee038c4cf0dc [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_CPP_TESTING_REALM_BUILDER_H_
#define LIB_SYS_CPP_TESTING_REALM_BUILDER_H_
#include <fuchsia/io2/cpp/fidl.h>
#include <fuchsia/realm/builder/cpp/fidl.h>
#include <fuchsia/sys2/cpp/fidl.h>
#include <lib/sys/cpp/component_context.h>
#include <lib/sys/cpp/service_directory.h>
#include <lib/sys/cpp/testing/internal/scoped_instance.h>
#include <zircon/system/public/zircon/types.h>
#include <memory>
#include <string>
#include <utility>
#include <variant>
#include <src/lib/fxl/macros.h>
namespace sys::testing {
// A moniker identifies a specific component instance in the component tree
// using a topological path. For example, given the following component tree:
// <root>
// / \
// a b
// /
// c
// Where components "a" and "b" are direct children of the root, and "c" is the
// only grandchild of the root, the following monikers are valid:
//
// '' (empty string) to refer to the root component.
// 'a' and 'b' to refer to the children of the root
// 'a/c' to refer to component "c".
//
// There is no leading slash.
struct Moniker {
std::string path;
};
// Endpoint to root above the created Realm. This endpoint is used to route
// capabilities from/to client of RealmBuilder.
struct AboveRoot {};
// An endpoint refers to either a source or target when routing a capability.
using Endpoint = std::variant<AboveRoot, Moniker>;
// A protocol capability. The name refers to the name of the FIDL protocol,
// e.g. `fuchsia.logger.LogSink`.
// See: https://fuchsia.dev/fuchsia-src/concepts/components/v2/capabilities/protocol.
struct Protocol {
std::string name;
};
// A directory capability.
// See: https://fuchsia.dev/fuchsia-src/concepts/components/v2/capabilities/directory.
struct Directory {
std::string name;
std::string path;
fuchsia::io2::Operations rights;
};
// A storage capability.
// See: https://fuchsia.dev/fuchsia-src/concepts/components/v2/capabilities/storage.
struct Storage {
std::string name;
std::string path;
};
// A capability to be routed from one component to another.
// See: https://fuchsia.dev/fuchsia-src/concepts/components/v2/capabilities
using Capability = std::variant<Protocol, Directory, Storage>;
// A routing of a capability from source to multiple targets.
struct CapabilityRoute {
Capability capability;
Endpoint source;
std::vector<Endpoint> targets;
};
// A reference to a component via its component URL.
// For example, `fuchsia-pkg://fuchsia.com/foo#meta/bar.cm`.
struct ComponentUrl {
std::string url;
};
// A reference to a component via its legacy component URL.
// For example, `fuchsia-pkg://fuchsia.com/foo#meta/bar.cmx`.
struct LegacyComponentUrl {
std::string url;
};
// The source of a component. If it's `ComponentUrl`, then it will be located
// via its component URL.
using Source = std::variant<ComponentUrl, LegacyComponentUrl>;
// A component as referred to by its source.
struct Component {
Source source;
// Flag used to determine if component should be started eagerly or not.
// If started eagerly, then it will start as soon as it's resolved.
// Otherwise, the component will start once another component requests
// a capability that it offers.
bool eager = false;
};
// A Realm is a subtree of the a component instance. This library allows users
// to create realms at runtime in an idiomatic and ergonomic way. Users can
// create arbitrarily deep subtrees, and route capabilities between any of the
// created components.
// For more information about RealmBuilder, see the following link.
// https://fuchsia.dev/fuchsia-src/development/components/v2/realm_builder
// For examples on how to use this library, see the integration tests
// found at //sdk/cpp/tests/realm_builder_test.cc
class Realm {
public:
Realm(Realm&& other) = default;
Realm& operator=(Realm&& other) = default;
FXL_DISALLOW_COPY_AND_ASSIGN(Realm);
// Connect to exposed directory of the root component.
template <typename Interface>
zx_status_t Connect(fidl::InterfaceRequest<Interface> request) const {
return root_.ConnectAtExposedDir<Interface>(std::move(request));
}
class Builder;
private:
explicit Realm(internal::ScopedInstance root);
internal::ScopedInstance root_;
};
// A builder class for a Realm object. Use this class to construct a Realm.
class Realm::Builder {
public:
// Factory method to create a new RealmBuilder object.
// |context| must not be NULL and must outlive the RealmBuilder object and
// created Realm object.
static Builder New(const sys::ComponentContext* context);
Builder(Builder&&) = default;
Builder& operator=(Builder&&) = default;
FXL_DISALLOW_COPY_AND_ASSIGN(Builder);
// Insert a component at the specified moniker. If a component already exists
// at the provided moniker, this method will panic. Furthermore, this
// method will create all parts of the moniker if non-existent. For example,
// given the moniker `foo/bar`. The library will create a component at path
// `foo` before adding its child `bar`.
Builder& AddComponent(Moniker moniker, Component component);
// Route a capability from one component to another.
Builder& AddRoute(CapabilityRoute route);
// Build the Realm object add prepared by the associated builder methods,
// e.g. |AddComponent|.
// |context| must not be NULL and must outlive the lifetime of the created
// Realm object.
// This function can only be called once per RealmBuilder instance.
// Multiple invocations will result in a panic.
Realm Build(const sys::ComponentContext* context);
private:
Builder(fuchsia::realm::builder::FrameworkIntermediarySyncPtr framework_intermediary_proxy,
ServiceDirectory framework_intermediary_exposed_dir);
bool realm_commited_;
fuchsia::realm::builder::FrameworkIntermediarySyncPtr framework_intermediary_proxy_;
ServiceDirectory framework_intermediary_exposed_dir_;
};
} // namespace sys::testing
#endif // LIB_SYS_CPP_TESTING_REALM_BUILDER_H_