blob: 79cb83af7405193eff6c4c2febb41f3d073904e3 [file] [log] [blame]
// Copyright 2022 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 SRC_UI_TESTING_UI_TEST_REALM_UI_TEST_REALM_H_
#define SRC_UI_TESTING_UI_TEST_REALM_UI_TEST_REALM_H_
#include <lib/sys/component/cpp/testing/realm_builder.h>
#include <lib/sys/component/cpp/testing/realm_builder_types.h>
#include <lib/sys/cpp/service_directory.h>
#include <memory>
#include <optional>
#include "src/lib/fxl/macros.h"
namespace ui_testing {
// DPR constants.
constexpr auto kDefaultDevicePixelRatio = 1.f;
constexpr auto kMediumResolutionDevicePixelRatio = 1.25f;
constexpr auto kHighResolutionDevicePixelRatio = 2.f;
// Library class to manage test realm on behalf of UI integration test clients.
//
// TEST REALM
//
// UITestRealm own a RealmBuilder realm encapsulating the relevant portion of
// the UI stack. The realm comprises two main parts:
//
// (1) The ui layer component. This component runs the portion of the UI stack
// specified by the client via the UITestRealm::Config argument passed
// to the UITestRealm constructor. This portion of the realm is
// (mostly) specified statically in //src/ui/testing/ui_test_manager/meta.
// (2) The client subrealm. This subrealm is a RealmBuilder Realm, owned and
// configured by the client, containing any additional test-sepcific
// components.
//
// The component topology of the test is:
//
// test_manager
// / \
// test fixture component realm builder server
// /
// ui test realm root
// / \
// client subrealm (ui layer components)
// |
// (test-specific
// components)
//
// Clients can configure the scene owner, which specifies which ui layer
// component to use (layers are specified statically in
// //src/ui/testing/ui_test_manager/meta). Clients can also specify the set of
// ui services that must be routed to the client subrealm, and the set of client
// services that must be exposed out of the top-level realm. UITestRealm will
// configure all necessary routes between the ui layer component, the client
// subrealm, and the top-level realm.
//
// CLIENT SUBREALM
//
// The client can specify the test-specific portion of the component topology
// within its own subrealm (see AddSubrealm() below). Important notes on the client
// subrealm:
//
// (1) A client subrealm should NOT contain any UI services (scenic, root
// presenter, scene manager, input pipeline, text manager, or a11y manager).
// (2) A client MUST expose fuchsia.ui.app.ViewProvider from its subrealm if
// specifies a scene owner.
// (3) Clients can consume required ui services from ParentRef(), provided
// they request those services in Config::ui_to_client_services.
//
// INPUT
//
// UITestManager enables configurations with or without input.
//
// * If clients specify a scene owner via Config::scene_owner and set
// Config::use_input = true, then UITestManager assumes input pipeline will
// own input for the test scene (either as a standalone component with root
// presenter or as part of scene manager).
// * If a client does not specify a scene owner, but sets Config::use_input = true,
// then UITestManager will expose raw scenic input APIs out of the test realm.
// * If clients set Config::use_input = false, then UITestManager will not
// any input APIs out of the test realm.
//
// ACCESSIBILITY
//
// UITestManager enables configurations without accessibility, and also allows
// clients to opt into using a real or fake a11y manager. In general, clients
// should not request accessibility unless it's explicitly required. For cases
// where accessibility is required, clients should prefer using the fake a11y
// manager for tests that require a11y services, but do not test a11y
// functionality (e.g. tests that run a chromium view). Clients should only use
// a real a11y manager for tests that explicitly exercise accessibility-specific
// behavior.
class UITestRealm {
public:
enum class SceneOwnerType {
ROOT_PRESENTER = 1,
SCENE_MANAGER = 2,
};
enum class AccessibilityOwnerType {
// Use the fake a11y manager. Clients should prefer using the fake a11y
// manager for tests that require a11y services, but do not test a11y
// functionality (e.g. tests that run a chromium client).
FAKE = 1,
// Use the real a11y manager. Clients should only use the real a11y manager
// for tests that exercise accessibility-specific functionality.
REAL = 2,
};
struct Config {
// Specifies the entity that owns the root of the scene, if any.
// If std::nullopt, then no scene owner will be present in the test realm.
//
// For now, UITestManager assumes that the entity that input pipeline owns
// input if scene_owner is not std::nullopt. We may revisit this assumption
// if the need arises.
//
// Furthermore, if a scene owner is specified, the client promises to expose
// fuchsia.ui.app.ViewProvider from its subrealm.
std::optional<SceneOwnerType> scene_owner;
// Specifies the entity that owns accessibility in the test realm, if any.
// If std::nullopt, then no a11y services will be present in the test realm.
std::optional<AccessibilityOwnerType> accessibility_owner;
// Instructs UITestManager to expose input APIs out of the test realm.
//
// If |scene_owner| has a value, input pipeline will own input and
// the top-level realm will expose the following services:
// * fuchsia.input.injection.InputDeviceRegistry
// * fuchsia.ui.policy.DeviceListenerRegistry
// * fuchsia.ui.pointerinjector.configuration.Setup
//
// If |scene_owner| is std::nullopt, the top-level realm exposes the raw scenic
// input API:
// * fuchsia.ui.pointerinjector.Registry
bool use_input = false;
// List of ui services required by components in the client subrealm.
// UITestManager will route these services from the ui layer component to the
// client subrealm.
std::vector<std::string> ui_to_client_services;
// List of capabilities to pass-through from the parent to the client subrealm.
std::vector<component_testing::Capability> passthrough_capabilities;
// List of non-ui services the test manager needs to expose to the test fixture.
// By specifying services here, the client promises to expose them from its subrealm.
std::vector<std::string> exposed_client_services;
// List of client realm services to route to the ui layer component.
//
// *** Use cases for this field are ~very~ rare.
// *** This optoin will NOT be available to OOT clients.
std::vector<std::string> client_to_ui_services;
// Clockwise display rotation, in degrees. Display rotation MUST be a multiple of 90 degrees.
int display_rotation = 0;
// Device pixel ratio for the fake display.
//
// Must result in integer logical display dimensions.
float device_pixel_ratio = kDefaultDevicePixelRatio;
// Indicates which graphics composition API to use (true -> flatland, false
// -> gfx).
bool use_flatland = false;
// Idle threshold minutes for the activity service.
int idle_threshold_minutes = 1;
};
explicit UITestRealm(Config config);
~UITestRealm() = default;
// Adds a child to the realm under construction, and returns the new child.
// Must NOT be called after BuildRealm().
component_testing::Realm AddSubrealm();
// Calls realm_builder_.Build();
void Build();
// Returns a clone of the realm's exposed services directory.
// Clients should call this method once, and retain the handle returned.
//
// MUST be called AFTER Build().
std::unique_ptr<sys::ServiceDirectory> CloneExposedServicesDirectory();
component_testing::RealmRoot* realm_root() { return realm_root_.get(); }
const Config& config() { return config_; }
private:
// Helper methods to configure the test realm.
void ConfigureClientSubrealm();
void ConfigureAccessibility();
void RouteConfigData();
void ConfigureSceneOwner();
void ConfigureSceneProvider();
void ConfigureActivityService();
// Helper method to route a set of services from the specified source to the
// spceified targets.
void RouteServices(std::vector<std::string> services, component_testing::Ref source,
std::vector<component_testing::Ref> targets);
// Helper method to determine the component url used to instantiate the base
// UI realm.
std::string CalculateBaseRealmUrl();
Config config_;
component_testing::RealmBuilder realm_builder_ =
component_testing::RealmBuilder::CreateFromRelativeUrl(CalculateBaseRealmUrl());
std::shared_ptr<component_testing::RealmRoot> realm_root_;
// Some tests may not need a dedicated subrealm. Those clients will not call
// AddSubrealm(), so UITestManager will crash if it tries to add routes
// to/from the missing subrealm.
//
// NOTE: This piece of state is temporary, and can be removed once the client
// owns a full RealmBuilder instance, as opposed to a child realm.
bool has_client_subrealm_ = false;
// Add state as necessary.
FXL_DISALLOW_COPY_ASSIGN_AND_MOVE(UITestRealm);
};
} // namespace ui_testing
#endif // SRC_UI_TESTING_UI_TEST_REALM_UI_TEST_REALM_H_