blob: 9c0f664f9530c187bd764f84a9add7c13029a166 [file] [log] [blame]
// 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.
#![cfg(test)]
use {
failure::Error,
fidl::endpoints::ClientEnd,
fidl_fuchsia_amber::ControlMarker as AmberMarker,
fidl_fuchsia_io::{DirectoryMarker, DirectoryProxy, CLONE_FLAG_SAME_RIGHTS},
fidl_fuchsia_pkg::{
ExperimentToggle as Experiment, PackageCacheMarker, PackageResolverAdminMarker,
PackageResolverAdminProxy, PackageResolverMarker, PackageResolverProxy,
RepositoryManagerMarker, RepositoryManagerProxy, UpdatePolicy,
},
fidl_fuchsia_pkg_rewrite::{
EngineMarker as RewriteEngineMarker, EngineProxy as RewriteEngineProxy,
},
fidl_fuchsia_sys::LauncherProxy,
fuchsia_async as fasync,
fuchsia_component::{
client::{App, AppBuilder},
server::{NestedEnvironment, ServiceFs},
},
fuchsia_pkg_testing::{pkgfs::TestPkgFs, Package, PackageBuilder},
fuchsia_zircon::{self as zx, Status},
futures::prelude::*,
std::fs::File,
tempfile::TempDir,
};
mod dynamic_rewrite_disabled;
mod resolve_propagates_pkgfs_failure;
mod resolve_recovers_from_http_errors;
mod resolve_succeeds;
trait PkgFs {
fn root_dir_client_end(&self) -> Result<ClientEnd<DirectoryMarker>, Error>;
}
impl PkgFs for TestPkgFs {
fn root_dir_client_end(&self) -> Result<ClientEnd<DirectoryMarker>, Error> {
TestPkgFs::root_dir_client_end(self)
}
}
struct Mounts {
pkg_resolver_data: DirOrProxy,
pkg_resolver_config_data: DirOrProxy,
}
enum DirOrProxy {
Dir(TempDir),
Proxy(DirectoryProxy),
}
trait AppBuilderExt {
fn add_dir_or_proxy_to_namespace(
self,
path: impl Into<String>,
dir_or_proxy: &DirOrProxy,
) -> Self;
}
impl AppBuilderExt for AppBuilder {
fn add_dir_or_proxy_to_namespace(
self,
path: impl Into<String>,
dir_or_proxy: &DirOrProxy,
) -> Self {
match dir_or_proxy {
DirOrProxy::Dir(d) => {
self.add_dir_to_namespace(path.into(), File::open(d.path()).unwrap()).unwrap()
}
DirOrProxy::Proxy(p) => {
self.add_handle_to_namespace(path.into(), clone_directory_proxy(p))
}
}
}
}
fn clone_directory_proxy(proxy: &DirectoryProxy) -> zx::Handle {
let (client, server) = fidl::endpoints::create_endpoints().unwrap();
proxy.clone(CLONE_FLAG_SAME_RIGHTS, server).unwrap();
client.into()
}
impl Mounts {
fn new() -> Self {
Self {
pkg_resolver_data: DirOrProxy::Dir(tempfile::tempdir().expect("/tmp to exist")),
pkg_resolver_config_data: DirOrProxy::Dir(tempfile::tempdir().expect("/tmp to exist")),
}
}
}
struct Apps {
_amber: App,
_pkg_cache: App,
_pkg_resolver: App,
}
struct Proxies {
resolver_admin: PackageResolverAdminProxy,
resolver: PackageResolverProxy,
repo_manager: RepositoryManagerProxy,
rewrite_engine: RewriteEngineProxy,
}
struct TestEnv<P = TestPkgFs> {
pkgfs: P,
env: NestedEnvironment,
apps: Apps,
proxies: Proxies,
_mounts: Mounts,
}
impl TestEnv<TestPkgFs> {
fn new() -> Self {
Self::new_with_pkg_fs(TestPkgFs::start(None).expect("pkgfs to start"))
}
fn new_with_mounts(mounts: Mounts) -> Self {
Self::new_with_pkg_fs_and_mounts(TestPkgFs::start(None).expect("pkgfs to start"), mounts)
}
async fn stop(self) {
// Tear down the environment in reverse order, ending with the storage.
drop(self.proxies);
drop(self.apps);
drop(self.env);
self.pkgfs.stop().await.expect("pkgfs to stop gracefully");
}
}
impl<P: PkgFs> TestEnv<P> {
fn new_with_pkg_fs(pkgfs: P) -> Self {
Self::new_with_pkg_fs_and_mounts(pkgfs, Mounts::new())
}
fn new_with_pkg_fs_and_mounts(pkgfs: P, mounts: Mounts) -> Self {
let mut amber =
AppBuilder::new("fuchsia-pkg://fuchsia.com/pkg-resolver-tests#meta/amber.cmx")
.add_handle_to_namespace(
"/pkgfs".to_owned(),
pkgfs.root_dir_client_end().expect("pkgfs dir to open").into(),
);
let mut pkg_cache = AppBuilder::new(
"fuchsia-pkg://fuchsia.com/pkg-resolver-tests#meta/pkg_cache.cmx".to_owned(),
)
.add_handle_to_namespace(
"/pkgfs".to_owned(),
pkgfs.root_dir_client_end().expect("pkgfs dir to open").into(),
);
let mut pkg_resolver = AppBuilder::new(
"fuchsia-pkg://fuchsia.com/pkg-resolver-tests#meta/pkg_resolver.cmx".to_owned(),
)
.add_handle_to_namespace(
"/pkgfs".to_owned(),
pkgfs.root_dir_client_end().expect("pkgfs dir to open").into(),
)
.add_dir_or_proxy_to_namespace("/data", &mounts.pkg_resolver_data)
.add_dir_or_proxy_to_namespace("/config/data", &mounts.pkg_resolver_config_data);
let mut fs = ServiceFs::new();
fs.add_proxy_service::<fidl_fuchsia_net::NameLookupMarker, _>()
.add_proxy_service::<fidl_fuchsia_posix_socket::ProviderMarker, _>()
.add_proxy_service_to::<AmberMarker, _>(amber.directory_request().unwrap().clone())
.add_proxy_service_to::<PackageCacheMarker, _>(
pkg_cache.directory_request().unwrap().clone(),
)
.add_proxy_service_to::<RepositoryManagerMarker, _>(
pkg_resolver.directory_request().unwrap().clone(),
)
.add_proxy_service_to::<PackageResolverAdminMarker, _>(
pkg_resolver.directory_request().unwrap().clone(),
)
.add_proxy_service_to::<PackageResolverMarker, _>(
pkg_resolver.directory_request().unwrap().clone(),
);
let env = fs
.create_salted_nested_environment("pkg-resolver-env")
.expect("nested environment to create successfully");
fasync::spawn(fs.collect());
let amber = amber.spawn(env.launcher()).expect("amber to launch");
let pkg_cache = pkg_cache.spawn(env.launcher()).expect("package cache to launch");
let pkg_resolver = pkg_resolver.spawn(env.launcher()).expect("package resolver to launch");
let resolver_proxy =
env.connect_to_service::<PackageResolverMarker>().expect("connect to package resolver");
let resolver_admin_proxy = env
.connect_to_service::<PackageResolverAdminMarker>()
.expect("connect to package resolver admin");
let repo_manager_proxy = env
.connect_to_service::<RepositoryManagerMarker>()
.expect("connect to repository manager");
let rewrite_engine_proxy = pkg_resolver
.connect_to_service::<RewriteEngineMarker>()
.expect("connect to rewrite engine");
Self {
env,
pkgfs,
apps: Apps { _amber: amber, _pkg_cache: pkg_cache, _pkg_resolver: pkg_resolver },
proxies: Proxies {
resolver: resolver_proxy,
resolver_admin: resolver_admin_proxy,
repo_manager: repo_manager_proxy,
rewrite_engine: rewrite_engine_proxy,
},
_mounts: mounts,
}
}
fn launcher(&self) -> &LauncherProxy {
self.env.launcher()
}
async fn set_experiment_state(&self, experiment: Experiment, state: bool) {
self.proxies
.resolver_admin
.set_experiment_state(experiment, state)
.await
.expect("experiment state to toggle");
}
async fn resolve_package(&self, url: &str) -> Result<DirectoryProxy, Status> {
let (package, package_server_end) = fidl::endpoints::create_proxy().unwrap();
let selectors: Vec<&str> = vec![];
let status = self
.proxies
.resolver
.resolve(
url,
&mut selectors.into_iter(),
&mut UpdatePolicy { fetch_if_absent: true, allow_old_versions: false },
package_server_end,
)
.await
.expect("package resolve fidl call");
Status::ok(status)?;
Ok(package)
}
}
const EMPTY_REPO_PATH: &str = "/pkg/empty-repo";
const ROLLDICE_BIN: &'static [u8] = b"#!/boot/bin/sh\necho 4\n";
const ROLLDICE_CMX: &'static [u8] = br#"{"program":{"binary":"bin/rolldice"}}"#;
fn extra_blob_contents(i: u32) -> Vec<u8> {
format!("contents of file {}", i).as_bytes().to_owned()
}
async fn make_rolldice_pkg_with_extra_blobs(n: u32) -> Result<Package, Error> {
let mut pkg = PackageBuilder::new("rolldice")
.add_resource_at("bin/rolldice", ROLLDICE_BIN)?
.add_resource_at("meta/rolldice.cmx", ROLLDICE_CMX)?;
for i in 0..n {
pkg = pkg.add_resource_at(format!("data/file{}", i), extra_blob_contents(i).as_slice())?;
}
pkg.build().await
}