blob: 3a0af540406d27ea12779d4fec00beea44612a56 [file] [log] [blame]
// Copyright 2023 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 {
crate::constants::{HERMETIC_RESOLVER_REALM_NAME, TEST_ROOT_COLLECTION, WRAPPER_REALM_NAME},
anyhow::{format_err, Error},
fidl_fuchsia_component_decl as fdecl, fidl_fuchsia_component_test as ftest,
fuchsia_component_test::{
error::Error as RealmBuilderError, Capability, RealmBuilder, Ref, Route, SubRealmBuilder,
},
};
pub(crate) fn map_offers(offers: Vec<fdecl::Offer>) -> Result<Vec<ftest::Capability>, Error> {
let mut capabilities = vec![];
for offer_decl in offers {
match offer_decl {
fdecl::Offer::Protocol(fdecl::OfferProtocol {
target_name: Some(target_name), ..
}) if target_name != "fuchsia.logger.LogSink"
&& target_name != "fuchsia.inspect.InspectSink" =>
{
capabilities.push(
Capability::protocol_by_name(target_name).availability_same_as_target().into(),
);
}
fdecl::Offer::Directory(fdecl::OfferDirectory {
target_name: Some(target_name),
..
}) => {
capabilities
.push(Capability::directory(target_name).availability_same_as_target().into());
}
fdecl::Offer::Storage(fdecl::OfferStorage {
target_name: Some(target_name), ..
}) => {
let use_path = format!("/{}", target_name);
capabilities.push(
Capability::storage(target_name)
.path(use_path)
.availability_same_as_target()
.into(),
);
}
fdecl::Offer::EventStream(fdecl::OfferEventStream {
target_name: Some(target_name),
..
}) => {
capabilities.push(Capability::event_stream(target_name.clone()).into());
}
fdecl::Offer::Service(fdecl::OfferService { .. })
| fdecl::Offer::Runner(fdecl::OfferRunner { .. })
| fdecl::Offer::Resolver(fdecl::OfferResolver { .. }) => {
return Err(format_err!(
"Services, runners, and resolvers are not supported by realm builder"
));
}
_ => {
// Ignore anything else that is routed to the test collection
}
}
}
Ok(capabilities)
}
pub(crate) async fn apply_offers(
builder: &RealmBuilder,
wrapper_realm: &SubRealmBuilder,
offers: &Vec<ftest::Capability>,
) -> Result<(), RealmBuilderError> {
for capability in offers {
let (capability_for_test_wrapper, capability_for_test_root) =
if let ftest::Capability::EventStream(event_stream) = &capability {
// In case of event stream, we route that stream to both the test wrapper and test root,
// scoping each of them to only those realms respectively. The outcome is that wrapper and
// root see only their own events.
let mut test_wrapper_event_stream = event_stream.clone();
test_wrapper_event_stream.scope = Some(vec![Ref::child(WRAPPER_REALM_NAME).into()]);
let mut test_root_event_stream = event_stream.clone();
test_root_event_stream.scope = Some(vec![
Ref::collection(TEST_ROOT_COLLECTION).into(),
Ref::child(HERMETIC_RESOLVER_REALM_NAME).into(),
]);
(
ftest::Capability::EventStream(test_wrapper_event_stream),
ftest::Capability::EventStream(test_root_event_stream),
)
} else {
// we simply route non event capabilities to both test wrapper and test root.
(capability.clone(), capability.clone())
};
builder
.add_route(
Route::new()
.capability(capability_for_test_wrapper.clone())
.from(Ref::parent())
.to(wrapper_realm),
)
.await?;
wrapper_realm
.add_route(
Route::new()
.capability(capability_for_test_root.clone())
.from(Ref::parent())
.to(Ref::collection(TEST_ROOT_COLLECTION)),
)
.await?;
}
Ok(())
}