| // 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. |
| |
| use { |
| anyhow::{Context as _, Error}, |
| fidl_fuchsia_sys::{ComponentControllerEvent, EnvironmentOptions, TerminationReason}, |
| fidl_fuchsia_test_echos::{ |
| EchoExposedByParentRequest, EchoExposedByParentRequestStream, EchoExposedBySiblingMarker, |
| EchoHiddenByParentRequest, EchoHiddenByParentRequestStream, |
| }, |
| fuchsia_async as fasync, |
| fuchsia_component::{ |
| client::AppBuilder, fuchsia_single_component_package_url, server::ServiceFs, |
| }, |
| futures::prelude::*, |
| }; |
| |
| fn echo_exposed_server(stream: EchoExposedByParentRequestStream) -> impl Future<Output = ()> { |
| stream |
| .err_into::<anyhow::Error>() |
| .try_for_each(|EchoExposedByParentRequest::Echo { value, responder }| async move { |
| responder.send(value).context("sending response")?; |
| Ok(()) |
| }) |
| .unwrap_or_else(|e: anyhow::Error| panic!("error running echo server: {:?}", e)) |
| } |
| |
| fn echo_hidden_server(stream: EchoHiddenByParentRequestStream) -> impl Future<Output = ()> { |
| stream |
| .err_into::<anyhow::Error>() |
| .try_for_each(|EchoHiddenByParentRequest::Echo { value, responder }| async move { |
| responder.send(value).context("sending response")?; |
| Ok(()) |
| }) |
| .unwrap_or_else(|e: anyhow::Error| panic!("error running echo server: {:?}", e)) |
| } |
| |
| const CHILD_SIBLING_URL: &str = |
| fuchsia_single_component_package_url!("fuchsia_component_test_middle_sibling"); |
| const CHILD_URL: &str = fuchsia_single_component_package_url!("fuchsia_component_test_middle"); |
| const ENV_NAME: &str = "fuchsia_component_middle_test_environment"; |
| |
| enum Services { |
| Exposed(EchoExposedByParentRequestStream), |
| Hidden(EchoHiddenByParentRequestStream), |
| } |
| |
| #[fasync::run_singlethreaded] |
| async fn main() -> Result<(), Error> { |
| println!("connecting to {}", CHILD_URL); |
| let mut sibling = AppBuilder::new(CHILD_SIBLING_URL); |
| |
| let mut fs = ServiceFs::new(); |
| fs.add_fidl_service(Services::Exposed) |
| .add_fidl_service(Services::Hidden) |
| .add_proxy_service_to::<EchoExposedBySiblingMarker, _>(sibling.directory_request()?.clone()); |
| |
| let options = EnvironmentOptions { |
| inherit_parent_services: false, |
| use_parent_runners: false, |
| kill_on_oom: false, |
| delete_storage_on_death: false, |
| }; |
| let env = fs.create_nested_environment_with_options(ENV_NAME, options)?; |
| |
| // spawn the child components within the newly created environment |
| let sibling = sibling.spawn(env.launcher())?; |
| let child_app = AppBuilder::new(CHILD_URL).spawn(env.launcher())?; |
| |
| // spawn server to respond to child component requests |
| fasync::Task::spawn(fs.for_each_concurrent(None, |req| async { |
| match req { |
| Services::Exposed(stream) => echo_exposed_server(stream).await, |
| Services::Hidden(stream) => echo_hidden_server(stream).await, |
| } |
| })) |
| .detach(); |
| |
| // verify sibling is running by connecting directly to its service |
| let multiply_by_two = sibling.connect_to_service::<EchoExposedBySiblingMarker>()?; |
| assert_eq!(14, multiply_by_two.echo(7).await?); |
| |
| // verify sibling is running by connecting to its service through the nested environment |
| let multiply_by_two = env.connect_to_service::<EchoExposedBySiblingMarker>()?; |
| assert_eq!(14, multiply_by_two.echo(7).await?); |
| |
| // wait for middle component to exit |
| let mut component_stream = child_app.controller().take_event_stream(); |
| match component_stream |
| .next() |
| .await |
| .expect("component event stream ended before termination event")? |
| { |
| ComponentControllerEvent::OnDirectoryReady {} => { |
| panic!("middle component unexpectedly exposed a directory") |
| } |
| ComponentControllerEvent::OnTerminated { |
| return_code: 0, |
| termination_reason: TerminationReason::Exited, |
| } => {} |
| ComponentControllerEvent::OnTerminated { return_code, termination_reason } => { |
| panic!("Unexpected exit condition: {:?}", (return_code, termination_reason)) |
| } |
| } |
| |
| Ok(()) |
| } |