| // Copyright 2019 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. |
| @available(added=7) |
| library fuchsia.modular.testing; |
| |
| using fuchsia.mem; |
| using fuchsia.modular; |
| using fuchsia.modular.session; |
| using fuchsia.element; |
| using fuchsia.sys; |
| using zx; |
| |
| /// The `TestHarness` service is used to run the modular runtime under a |
| /// hermetic environment and drive integration tests under it. Tests may use |
| /// this service to intercept components and assume their role. Additionally, |
| /// tests may use `TestHarness/ConnectToModularService()` to get capabilities |
| /// for controlling stories (using PuppetMaster) and connecting to agents |
| /// (using ComponentContext). |
| /// |
| /// Closing the `TestHarness` connection will kill the `TestHarness` environment |
| /// including the modular runtime running under it. |
| /// |
| /// On error, this connection is closed with the following epitaphs: |
| /// * `ZX_ERR_INVALID_ARGS`: Run() failed to execute succesfully. |
| /// * `ZX_ERR_BAD_STATE`: Other methods are called before Run() is called. |
| /// * `ZX_ERR_ALREADY_BOUND`: Run() was already called. |
| /// * `ZX_ERR_ALREADY_EXISTS`: The same environment service is being provided |
| /// twice. |
| @discoverable |
| protocol TestHarness { |
| /// Initializes an instance of the modular runtime in an enclosed |
| /// environment, configured with parameters provided in `spec`. Closing the |
| /// `TestHarness` connection will kill the enclosed environment. |
| /// |
| /// This protocol connection is closed if Run() fails, with the following |
| /// epitaphs: |
| /// * `ZX_ERR_INVALID_ARGS`: `spec` is mal-formed. |
| /// * `ZX_ERR_ALREADY_EXISTS`: The same environment service is being provided |
| /// twice in `spec.env_services` |
| /// * `ZX_ERR_ALREADY_BOUND`: Run() was already called. |
| Run(resource struct { |
| spec TestHarnessSpec; |
| }); |
| |
| /// This event is sent when a component specified in |
| /// `TestHarnessSpec.components_to_intercept` is created. |
| /// `startup_info.launch_info.url` contains the component URL. |
| /// |
| /// Closing `intercepted_component` will signal to the component manager |
| /// that this component has exited unexpectedly. Prefer to use |
| /// InterceptedComponent/Exit to provide exit code and reason. |
| -> OnNewComponent(resource struct { |
| startup_info fuchsia.sys.StartupInfo; |
| intercepted_component client_end:InterceptedComponent; |
| }); |
| |
| /// Tests may use this method to connect to services provided by the modular |
| /// runtime. These services share the same component namespace for any |
| /// resources they create (e.g., entities, message queues, and module |
| /// names). |
| /// |
| /// This protocol connection is closed with the following epitaphs: |
| /// * `ZX_ERR_BAD_STATE`: if `ConnectToModularService()` is called before |
| /// `Run()`. |
| /// * `ZX_ERR_INVALID_ARGS`: if `service` is not set to a value. |
| ConnectToModularService(resource struct { |
| service ModularService; |
| }); |
| |
| /// Connects to environment services injected into the TestHarness |
| /// environment. |
| ConnectToEnvironmentService(resource struct { |
| service_name string; |
| request zx.handle:CHANNEL; |
| }); |
| |
| /// Parses a JSON modular configuration string into BasemgrConfig and |
| /// SessionmgrConfig. This method may be called before `Run()` is called. |
| ParseConfig(struct { |
| config string; |
| }) -> (struct { |
| basemgr_config fuchsia.modular.session.BasemgrConfig; |
| sessionmgr_config fuchsia.modular.session.SessionmgrConfig; |
| }); |
| }; |
| |
| /// Describes which service to connect to using `ConnectToModularService()`. |
| type ModularService = strict resource union { |
| 1: puppet_master server_end:fuchsia.modular.PuppetMaster; |
| 2: component_context server_end:fuchsia.modular.ComponentContext; |
| 3: reserved; |
| 4: element_manager server_end:fuchsia.element.Manager; |
| }; |
| |
| /// InterceptedComponent represents an intercepted component's lifecycle. |
| /// Closing this connection causes the component to be killed, and is |
| /// equivalent in behaviour to the `ComponentController` being closed. |
| protocol InterceptedComponent { |
| /// Signals that component has exit'd with the specified exit code. The |
| /// values here are bubbled up to the |
| /// `fuchsia.sys.ComponentController.OnTerminated` event. The `OnKill` event |
| /// is sent, and this InterceptedComponent handle is closed. |
| Exit(struct { |
| exit_code int64; |
| reason fuchsia.sys.TerminationReason; |
| }); |
| |
| /// The event is sent when the component is killed by the associated |
| /// `fuchsia.sys.ComponentController`, or when `Exit()` is called. |
| -> OnKill(); |
| }; |
| |
| /// Defines the setup of an environment running an instance of the modular |
| /// framework used for testing purposes. This table is supplied to |
| /// `TestHarness.Run()`. A malformed `TestHarnessSpec` will cause `TestHarness` |
| /// connection to close with an epitaph of `ZX_ERR_INVALID_ARGS`. |
| /// |
| /// By default, the following services are made available to the hermetic |
| /// environment: |
| /// * fuchsia.devicesettings.DeviceSettingsManager |
| /// |
| /// Additional services may be supplied using using |
| /// `TestHarnessSpec.env_services_to_inherit` and |
| /// `TestHarnessSpec.injected_services`. Additional services override the |
| /// default services listed above. |
| type TestHarnessSpec = resource table { |
| /// Configuration for basemgr. See `fuchsia.modular.session.BasemgrConfig` |
| /// for a description of the defaults. |
| /// |
| /// The test harness will amend `basemgr_config` before passing it off to |
| /// the modular runtime in the following way: |
| /// * If `basemgr_config.base_shell.app_config.url` is not set, the test |
| /// harness will use a base shell which automatically logs into the |
| /// session. |
| /// * If `basemgr_config.session_shell_map[0].config.app_config.url` is not |
| /// set, the test harness will use a shell which automatically starts new |
| /// stories. |
| /// * If `basemgr_config.story_shell.app_config.url` is not set, the test |
| /// harness use a minimally functioning story shell which displays all |
| /// mods in a story. |
| /// |
| /// To intercept and mock the shells, users may provide fake URLs for the |
| /// shells and specify that the fake URL be intercepted using |
| /// `components_to_intercept`. |
| 1: basemgr_config fuchsia.modular.session.BasemgrConfig; |
| |
| /// Configuration for sessionmgr. See |
| /// `fuchsia.modular.session.SessionmgrConfig` for a description of the |
| /// defaults. |
| 2: sessionmgr_config fuchsia.modular.session.SessionmgrConfig; |
| |
| /// List of component URLs (and additional .cmx contents) to intercept. |
| 4: components_to_intercept vector<InterceptSpec>; |
| |
| /// Options to configure the test harness environment. Use this to inject |
| /// services into the environment. |
| /// |
| /// Optional. |
| 6: env_services EnvironmentServicesSpec; |
| |
| /// Suffix to the environment name. |
| /// The default environment name is 'mth_{random number from 0 to 99999}'. |
| /// When provided, the environment_suffix additionally appends a '_' and |
| /// the string to the end of the environment name. The overall name gets |
| /// truncated at 32 characters. |
| /// |
| /// Optional. |
| 7: environment_suffix string; |
| |
| /// DEPRECATED. Use `env_services.service_dir` to pass through services from |
| /// parent environment. |
| 3: env_services_to_inherit vector<string>; |
| |
| 5: reserved; |
| }; |
| |
| /// Options for configuring the test harness environment with services. |
| /// |
| /// If the same service is provided in more than one place, `TestHarness` |
| /// connection is closed with a `ZX_ERR_ALREADY_EXISTS` epitaph. |
| type EnvironmentServicesSpec = resource table { |
| /// A directory of services to be provided to the test harness environment. |
| /// |
| /// Optional. |
| 1: service_dir zx.handle:CHANNEL; |
| |
| /// A list of services provided by components to inject into the test |
| /// harness environment. Multiple services may be provided by the same |
| /// component, but only one instance of the component is launched to serve |
| /// its services. Components are started when one of their services is |
| /// requested, and are kept alive for the duration of the test harness |
| /// environment's life. |
| /// |
| /// Optional. |
| 2: services_from_components vector<ComponentService>; |
| }; |
| |
| /// Describes a service to be provided by a component instance. |
| type ComponentService = struct { |
| /// Name of the service. |
| name string; |
| |
| /// URL of the component which will provide the service. |
| /// The service is retrieved from this component's /out/svc namespace. |
| url fuchsia.sys.component_url; |
| }; |
| |
| /// Describes a component to intercept. Malformed parameters result in closing |
| /// `TestHarness` with a `ZX_ERR_INVALID_ARGS` epitaph. |
| type InterceptSpec = resource table { |
| /// Required. Must be a valid component URL (e.g., fuchsia-pkg://..), or is |
| /// considered malformed. |
| 1: component_url fuchsia.sys.component_url; |
| |
| /// The .cmx contents of this component's manifest. A minimal manifest is |
| /// constructed by default. If set, the contents of `extra_cmx_contents` |
| /// override the default constructed manifest, which only has the required |
| /// "program.binary" field defined. |
| /// |
| /// `extra_cmx_contents` must be a valid .cmx JSON. Example: |
| /// |
| /// { |
| /// "sandbox": { |
| /// "services": [ |
| /// "fuchsia.sys.Launcher", |
| /// ] |
| /// } |
| /// } |
| 2: extra_cmx_contents fuchsia.mem.Buffer; |
| }; |