blob: ba1cb866bc7f85625b56a590329cfcacfc358589 [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 {
anyhow::Error,
fidl_fuchsia_amber_ext::{self as types, SourceConfigBuilder},
fidl_fuchsia_pkg::{
PackageCacheRequest, PackageCacheRequestStream, PackageIndexEntry,
PackageIndexIteratorRequest, RepositoryManagerMarker, RepositoryManagerProxy,
},
fidl_fuchsia_pkg_ext::{
MirrorConfigBuilder, RepositoryConfig, RepositoryConfigBuilder, RepositoryKey,
},
fidl_fuchsia_pkg_rewrite::{
EngineMarker as RewriteEngineMarker, EngineProxy as RewriteEngineProxy,
},
fidl_fuchsia_pkg_rewrite_ext::Rule,
fuchsia_async as fasync,
fuchsia_component::{
client::{App, AppBuilder, Output},
server::{NestedEnvironment, ServiceFs},
},
fuchsia_url::pkg_url::RepoUrl,
futures::prelude::*,
http::Uri,
parking_lot::Mutex,
serde::Serialize,
std::sync::Arc,
std::{convert::TryInto, fs::File},
};
const ROOT_KEY_1: &str = "be0b983f7396da675c40c6b93e47fced7c1e9ea8a32a1fe952ba8f519760b307";
const ROOT_KEY_2: &str = "00112233445566778899aabbccddeeffffeeddccbbaa99887766554433221100";
fn amberctl() -> AppBuilder {
AppBuilder::new("fuchsia-pkg://fuchsia.com/amberctl-tests#meta/amberctl.cmx".to_owned())
}
struct Mounts {
_misc: tempfile::TempDir,
pkgfs: tempfile::TempDir,
config_data: tempfile::TempDir,
}
impl Mounts {
fn new() -> Self {
let misc = tempfile::tempdir().expect("/tmp to exist");
let config_data = tempfile::tempdir().expect("/tmp to exist");
let pkgfs = tempfile::tempdir().expect("/tmp to exist");
std::fs::create_dir(pkgfs.path().join("install")).expect("mkdir pkgfs/install");
std::fs::create_dir(pkgfs.path().join("needs")).expect("mkdir pkgfs/needs");
Self { _misc: misc, pkgfs, config_data }
}
}
struct Proxies {
repo_manager: RepositoryManagerProxy,
rewrite_engine: RewriteEngineProxy,
}
struct MockUpdateManager {
called: Mutex<u32>,
check_now_result: Mutex<fidl_fuchsia_update::ManagerCheckNowResult>,
}
impl MockUpdateManager {
fn new_with_check_now_result(res: fidl_fuchsia_update::ManagerCheckNowResult) -> Self {
Self { called: Mutex::new(0), check_now_result: Mutex::new(res) }
}
async fn run(
self: Arc<Self>,
mut stream: fidl_fuchsia_update::ManagerRequestStream,
) -> Result<(), Error> {
while let Some(event) = stream.try_next().await? {
match event {
fidl_fuchsia_update::ManagerRequest::CheckNow { options, monitor, responder } => {
eprintln!("TEST: Got update check request with options {:?}", options);
assert_eq!(
options,
fidl_fuchsia_update::CheckOptions {
initiator: Some(fidl_fuchsia_update::Initiator::User),
allow_attaching_to_existing_update_check: Some(false),
}
);
assert_eq!(monitor, None);
*self.called.lock() += 1;
responder.send(&mut *self.check_now_result.lock())?;
}
fidl_fuchsia_update::ManagerRequest::PerformPendingReboot { responder: _ } => {
panic!("amberctl should never call PerformPendingReboot");
}
}
}
Ok(())
}
}
struct MockSpaceManager {
called: Mutex<u32>,
}
impl MockSpaceManager {
fn new() -> Self {
Self { called: Mutex::new(0) }
}
async fn run(
self: Arc<Self>,
mut stream: fidl_fuchsia_space::ManagerRequestStream,
) -> Result<(), Error> {
while let Some(event) = stream.try_next().await? {
*self.called.lock() += 1;
let fidl_fuchsia_space::ManagerRequest::Gc { responder } = event;
responder.send(&mut Ok(()))?;
}
Ok(())
}
}
struct TestEnv {
_pkg_cache: Arc<MockPackageCacheService>,
_pkg_resolver: App,
_mounts: Mounts,
env: NestedEnvironment,
proxies: Proxies,
}
#[derive(Serialize)]
struct Config {
enable_dynamic_configuration: bool,
}
impl TestEnv {
fn new() -> Self {
Self::new_with_mounts(Mounts::new())
}
fn new_with_mounts(mounts: Mounts) -> Self {
let mut pkg_resolver = AppBuilder::new(
"fuchsia-pkg://fuchsia.com/amberctl-tests#meta/pkg-resolver-isolated.cmx".to_owned(),
)
.add_dir_to_namespace(
"/pkgfs".to_owned(),
File::open(mounts.pkgfs.path()).expect("/pkgfs temp dir to open"),
)
.expect("/pkgfs to mount")
.add_dir_to_namespace("/config/ssl".to_owned(), File::open("/pkg/data/ssl").unwrap())
.expect("/config/ssl to mount")
.add_dir_to_namespace(
"/config/data".to_owned(),
File::open(mounts.config_data.path()).unwrap(),
)
.expect("/config/data to mount");
let f = File::create(mounts.config_data.path().join("config.json")).unwrap();
serde_json::to_writer(
std::io::BufWriter::new(f),
&Config { enable_dynamic_configuration: true },
)
.unwrap();
let mut fs = ServiceFs::new();
fs.add_proxy_service_to::<RepositoryManagerMarker, _>(
pkg_resolver.directory_request().unwrap().clone(),
)
.add_proxy_service_to::<RewriteEngineMarker, _>(
pkg_resolver.directory_request().unwrap().clone(),
);
let pkg_cache = Arc::new(MockPackageCacheService::new());
let pkg_cache_clone = Arc::clone(&pkg_cache);
fs.add_fidl_service(move |stream: PackageCacheRequestStream| {
fasync::Task::spawn(
Arc::clone(&pkg_cache_clone)
.run_service(stream)
.unwrap_or_else(|e| panic!("error running mock cache service: {:?}", e)),
)
.detach()
});
let env = fs
.create_salted_nested_environment("amberctl_env")
.expect("nested environment to create successfully");
fasync::Task::spawn(fs.collect()).detach();
let pkg_resolver = pkg_resolver.spawn(env.launcher()).expect("package resolver to launch");
let repo_manager_proxy = env
.connect_to_service::<RepositoryManagerMarker>()
.expect("connect to repository manager");
let rewrite_engine_proxy =
env.connect_to_service::<RewriteEngineMarker>().expect("connect to rewrite engine");
Self {
_pkg_cache: pkg_cache,
_pkg_resolver: pkg_resolver,
_mounts: mounts,
env,
proxies: Proxies {
repo_manager: repo_manager_proxy,
rewrite_engine: rewrite_engine_proxy,
},
}
}
async fn _run_amberctl(&self, builder: AppBuilder) -> String {
let fut = builder.output(self.env.launcher()).expect("amberctl to launch");
let output = fut.await.expect("amberctl to run");
output.ok().expect("amberctl to succeed");
String::from_utf8(output.stdout).unwrap()
}
async fn run_amberctl<'a>(&'a self, args: &'a [impl std::fmt::Debug + AsRef<str>]) -> String {
self._run_amberctl(amberctl().args(args.into_iter().map(|s| s.as_ref()))).await
}
// Runs "amberctl list_srcs" and returns a vec of fuchsia-pkg URIs from the output
async fn run_amberctl_list_srcs(&self) -> Vec<String> {
let mut res = vec![];
let output = self.run_amberctl(&["list_srcs"]).await;
for (pos, _) in output.match_indices("\"fuchsia-pkg") {
let (_, suffix) = output.split_at(pos + 1);
let url = suffix.split('"').next().unwrap();
res.push(url.to_owned());
}
res
}
async fn run_amberctl_add_static_src(&self, name: &'static str) {
self._run_amberctl(
amberctl()
.add_dir_to_namespace(
"/configs".to_string(),
File::open("/pkg/data/sources").expect("/pkg/data/sources to exist"),
)
.expect("static /configs to mount")
.arg("add_src")
.arg(format!("-f=/configs/{}", name)),
)
.await;
}
async fn run_amberctl_add_src(&self, source: types::SourceConfig) {
let config_dir = tempfile::tempdir().expect("temp config dir to create");
let file_path = config_dir.path().join("test.json");
let mut config_file = File::create(file_path).expect("temp config file to create");
serde_json::to_writer(&mut config_file, &source).expect("source config to serialize");
drop(config_file);
self._run_amberctl(
amberctl()
.add_dir_to_namespace(
"/configs".to_string(),
File::open(config_dir.path()).expect("temp config dir to exist"),
)
.expect("static /configs to mount")
.arg("add_src")
.arg("-f=/configs/test.json"),
)
.await;
}
async fn run_amberctl_add_repo_config(&self, source: types::SourceConfig) {
let config_dir = tempfile::tempdir().expect("temp config dir to create");
let file_path = config_dir.path().join("test.json");
let mut config_file = File::create(file_path).expect("temp config file to create");
serde_json::to_writer(&mut config_file, &source).expect("source config to serialize");
drop(config_file);
self._run_amberctl(
amberctl()
.add_dir_to_namespace(
"/configs".to_string(),
File::open(config_dir.path()).expect("temp config dir to exist"),
)
.expect("static /configs to mount")
.arg("add_repo_cfg")
.arg("-f=/configs/test.json"),
)
.await;
}
async fn resolver_list_repos(&self) -> Vec<RepositoryConfig> {
let (iterator, iterator_server_end) = fidl::endpoints::create_proxy().unwrap();
self.proxies.repo_manager.list(iterator_server_end).unwrap();
collect_iterator(|| iterator.next()).await.unwrap()
}
async fn rewrite_engine_list_rules(&self) -> Vec<Rule> {
let (iterator, iterator_server_end) = fidl::endpoints::create_proxy().unwrap();
self.proxies.rewrite_engine.list(iterator_server_end).unwrap();
collect_iterator(|| iterator.next()).await.unwrap()
}
}
async fn collect_iterator<F, E, I, O>(mut next: impl FnMut() -> F) -> Result<Vec<O>, Error>
where
F: Future<Output = Result<Vec<I>, fidl::Error>>,
I: TryInto<O, Error = E>,
Error: From<E>,
{
let mut res = Vec::new();
loop {
let more = next().await?;
if more.is_empty() {
break;
}
res.extend(more.into_iter().map(|cfg| cfg.try_into()).collect::<Result<Vec<_>, _>>()?);
}
Ok(res)
}
struct MockPackageCacheService {}
impl MockPackageCacheService {
fn new() -> Self {
Self {}
}
async fn run_service(
self: Arc<Self>,
mut stream: PackageCacheRequestStream,
) -> Result<(), Error> {
while let Some(req) = stream.try_next().await? {
match req {
PackageCacheRequest::Open { responder, .. } => {
responder.send(&mut Ok(()))?;
}
PackageCacheRequest::Get { .. } => {
panic!("PackageCacheRequest::Get should not be called");
}
PackageCacheRequest::Sync { .. } => {
panic!("PackageCacheRequest::Sync should not be called");
}
PackageCacheRequest::BasePackageIndex { iterator, control_handle: _ } => {
let mut stream = iterator.into_stream()?;
fasync::Task::spawn(
async move {
while let Some(PackageIndexIteratorRequest::Next { responder }) =
stream.try_next().await?
{
let mut eof = Vec::<PackageIndexEntry>::new();
responder.send(&mut eof.iter_mut())?;
}
Ok(())
}
.unwrap_or_else(|e: anyhow::Error| {
panic!("error serving base package index: {:?}", e)
}),
)
.detach()
}
}
}
Ok(())
}
}
struct SourceConfigGenerator {
id_prefix: String,
n: usize,
}
impl SourceConfigGenerator {
fn new(id_prefix: impl Into<String>) -> Self {
Self { id_prefix: id_prefix.into(), n: 0 }
}
}
impl Iterator for SourceConfigGenerator {
type Item = (types::SourceConfigBuilder, RepositoryConfigBuilder);
fn next(&mut self) -> Option<Self::Item> {
let id = format!("{}{:02}", &self.id_prefix, self.n);
let repo_url = format!("fuchsia-pkg://{}", &id);
let mirror_url = format!("http://example.com/{}", &id);
self.n += 1;
Some((
SourceConfigBuilder::new(id)
.repo_url(mirror_url.clone())
.add_root_key(ROOT_KEY_1)
.auto(true),
RepositoryConfigBuilder::new(RepoUrl::parse(&repo_url).unwrap())
.add_root_key(RepositoryKey::Ed25519(hex::decode(ROOT_KEY_1).unwrap()))
.add_mirror(
MirrorConfigBuilder::new(mirror_url.parse::<Uri>().unwrap())
.unwrap()
.subscribe(true),
),
))
}
}
fn make_test_repo_config() -> RepositoryConfig {
RepositoryConfigBuilder::new("fuchsia-pkg://test".parse().unwrap())
.add_root_key(RepositoryKey::Ed25519(hex::decode(ROOT_KEY_1).unwrap()))
.add_mirror(
MirrorConfigBuilder::new("http://example.com".parse::<Uri>().unwrap())
.unwrap()
.subscribe(true),
)
.build()
}
#[fasync::run_singlethreaded(test)]
async fn test_services_start_with_no_config() {
let env = TestEnv::new();
assert_eq!(env.run_amberctl_list_srcs().await, Vec::<String>::new());
assert_eq!(env.resolver_list_repos().await, vec![]);
assert_eq!(env.rewrite_engine_list_rules().await, vec![]);
}
#[fasync::run_singlethreaded(test)]
async fn test_add_src() {
let env = TestEnv::new();
env.run_amberctl_add_static_src("test.json").await;
assert_eq!(env.run_amberctl_list_srcs().await, vec!["fuchsia-pkg://test"]);
assert_eq!(env.resolver_list_repos().await, vec![make_test_repo_config()]);
assert_eq!(
env.rewrite_engine_list_rules().await,
vec![Rule::new("fuchsia.com", "test", "/", "/").unwrap()]
);
}
#[fasync::run_singlethreaded(test)]
async fn test_add_repo() {
let env = TestEnv::new();
let source = SourceConfigBuilder::new("localhost")
.repo_url("http://127.0.0.1:8083")
.add_root_key(ROOT_KEY_1)
.build();
let repo = RepositoryConfigBuilder::new("fuchsia-pkg://localhost".parse().unwrap())
.add_root_key(RepositoryKey::Ed25519(hex::decode(ROOT_KEY_1).unwrap()))
.add_mirror(
MirrorConfigBuilder::new("http://127.0.0.1:8083".parse::<Uri>().unwrap()).unwrap(),
)
.build();
env.run_amberctl_add_repo_config(source).await;
assert_eq!(env.resolver_list_repos().await, vec![repo]);
assert_eq!(env.rewrite_engine_list_rules().await, vec![]);
}
#[fasync::run_singlethreaded(test)]
async fn test_add_src_with_ipv4_id() {
let env = TestEnv::new();
let source = SourceConfigBuilder::new("http://10.0.0.1:8083")
.repo_url("http://10.0.0.1:8083")
.add_root_key(ROOT_KEY_1)
.build();
let repo = RepositoryConfigBuilder::new("fuchsia-pkg://http___10_0_0_1_8083".parse().unwrap())
.add_root_key(RepositoryKey::Ed25519(hex::decode(ROOT_KEY_1).unwrap()))
.add_mirror(
MirrorConfigBuilder::new("http://10.0.0.1:8083".parse::<Uri>().unwrap()).unwrap(),
)
.build();
env.run_amberctl_add_src(source).await;
assert_eq!(env.resolver_list_repos().await, vec![repo]);
assert_eq!(
env.rewrite_engine_list_rules().await,
vec![Rule::new("fuchsia.com", "http___10_0_0_1_8083", "/", "/").unwrap()]
);
}
#[fasync::run_singlethreaded(test)]
async fn test_add_src_with_ipv6_id() {
let env = TestEnv::new();
let source = SourceConfigBuilder::new("http://[fe80::1122:3344]:8083")
.repo_url("http://[fe80::1122:3344]:8083")
.add_root_key(ROOT_KEY_1)
.build();
let repo = RepositoryConfigBuilder::new(
"fuchsia-pkg://http____fe80__1122_3344__8083".parse().unwrap(),
)
.add_root_key(RepositoryKey::Ed25519(hex::decode(ROOT_KEY_1).unwrap()))
.add_mirror(
MirrorConfigBuilder::new("http://[fe80::1122:3344]:8083".parse::<Uri>().unwrap()).unwrap(),
)
.build();
env.run_amberctl_add_src(source).await;
assert_eq!(env.resolver_list_repos().await, vec![repo]);
assert_eq!(
env.rewrite_engine_list_rules().await,
vec![Rule::new("fuchsia.com", "http____fe80__1122_3344__8083", "/", "/").unwrap()]
);
}
#[fasync::run_singlethreaded(test)]
async fn test_add_src_disables_other_sources() {
let env = TestEnv::new();
let configs = SourceConfigGenerator::new("testgen").take(3).collect::<Vec<_>>();
for (config, _) in &configs {
env.run_amberctl_add_src(config.clone().build().into()).await;
}
env.run_amberctl_add_static_src("test.json").await;
let mut repo_configs = vec![make_test_repo_config()];
for (_, repo_config) in configs {
repo_configs.push(repo_config.build());
}
assert_eq!(env.resolver_list_repos().await, repo_configs);
assert_eq!(
env.rewrite_engine_list_rules().await,
vec![Rule::new("fuchsia.com", "test", "/", "/").unwrap()]
);
}
#[fasync::run_singlethreaded(test)]
async fn test_add_repo_retains_existing_state() {
let env = TestEnv::new();
// start with an existing source.
env.run_amberctl_add_static_src("test.json").await;
// add a repo.
let source = SourceConfigBuilder::new("devhost")
.repo_url("http://10.0.0.1:8083")
.add_root_key(ROOT_KEY_1)
.build();
let repo = RepositoryConfigBuilder::new("fuchsia-pkg://devhost".parse().unwrap())
.add_root_key(RepositoryKey::Ed25519(hex::decode(ROOT_KEY_1).unwrap()))
.add_mirror(
MirrorConfigBuilder::new("http://10.0.0.1:8083".parse::<Uri>().unwrap()).unwrap(),
)
.build();
env.run_amberctl_add_repo_config(source).await;
// ensure adding the repo didn't remove state configured when adding the source.
assert_eq!(env.resolver_list_repos().await, vec![repo, make_test_repo_config()]);
assert_eq!(
env.rewrite_engine_list_rules().await,
vec![Rule::new("fuchsia.com", "test", "/", "/").unwrap()]
);
}
#[fasync::run_singlethreaded(test)]
async fn test_rm_src() {
let env = TestEnv::new();
let cfg_a = SourceConfigBuilder::new("http://[fe80::1122:3344]:8083")
.repo_url("http://example.com/a")
.rate_period(60)
.add_root_key(ROOT_KEY_1)
.build();
let cfg_b = SourceConfigBuilder::new("b")
.repo_url("http://example.com/b")
.rate_period(60)
.add_root_key(ROOT_KEY_2)
.build();
env.run_amberctl_add_src(cfg_a.into()).await;
env.run_amberctl_add_src(cfg_b.into()).await;
env.run_amberctl(&["rm_src", "-n", "http://[fe80::1122:3344]:8083"]).await;
assert_eq!(
env.resolver_list_repos().await,
vec![RepositoryConfigBuilder::new("fuchsia-pkg://b".parse().unwrap())
.add_root_key(RepositoryKey::Ed25519(hex::decode(ROOT_KEY_2).unwrap()))
.add_mirror(
MirrorConfigBuilder::new("http://example.com/b".parse::<Uri>().unwrap()).unwrap()
)
.build()]
);
// rm_src removes all rules, so no source remains enabled.
assert_eq!(env.rewrite_engine_list_rules().await, vec![]);
env.run_amberctl(&["rm_src", "-n", "b"]).await;
assert_eq!(env.resolver_list_repos().await, vec![]);
assert_eq!(env.rewrite_engine_list_rules().await, vec![]);
}
#[fasync::run_singlethreaded(test)]
async fn test_enable_src() {
let env = TestEnv::new();
let source = SourceConfigBuilder::new("test")
.repo_url("http://example.com")
.enabled(false)
.add_root_key(ROOT_KEY_1)
.build();
let repo = RepositoryConfigBuilder::new("fuchsia-pkg://test".parse().unwrap())
.add_root_key(RepositoryKey::Ed25519(hex::decode(ROOT_KEY_1).unwrap()))
.add_mirror(MirrorConfigBuilder::new("http://example.com".parse::<Uri>().unwrap()).unwrap())
.build();
env.run_amberctl_add_src(source.into()).await;
assert_eq!(env.resolver_list_repos().await, vec![repo.clone()]);
// Adding a disabled source does not add a rewrite rule for it.
assert_eq!(env.rewrite_engine_list_rules().await, vec![]);
env.run_amberctl(&["enable_src", "-n", "test"]).await;
assert_eq!(env.resolver_list_repos().await, vec![repo]);
assert_eq!(
env.rewrite_engine_list_rules().await,
vec![Rule::new("fuchsia.com", "test", "/", "/").unwrap()]
);
}
#[fasync::run_singlethreaded(test)]
async fn test_enable_src_disables_other_sources() {
let env = TestEnv::new();
// add some enabled sources
let mut gen = SourceConfigGenerator::new("test");
let configs = gen.by_ref().take(3).collect::<Vec<_>>();
for (config, _) in &configs {
env.run_amberctl_add_src(config.clone().build().into()).await;
}
// add an initially disabled source
let (config, repo) = gen.next().unwrap();
let c = config.enabled(false).build();
let id = c.id().to_owned();
env.run_amberctl_add_src(c.into()).await;
// verify the previously added source is still the enabled one
assert_eq!(
env.rewrite_engine_list_rules().await,
vec![Rule::new("fuchsia.com", "test02", "/", "/").unwrap()]
);
// enable the new source source and verify the repos and rules
let args = ["enable_src", "-n", &id];
env.run_amberctl(&args).await;
let mut repo_configs = vec![];
for (_, repo_config) in configs {
repo_configs.push(repo_config.build());
}
repo_configs.push(repo.build());
assert_eq!(env.resolver_list_repos().await, repo_configs);
assert_eq!(
env.rewrite_engine_list_rules().await,
vec![Rule::new("fuchsia.com", id, "/", "/").unwrap()]
);
}
#[fasync::run_singlethreaded(test)]
async fn test_disable_src_disables_all_sources() {
let env = TestEnv::new();
env.run_amberctl_add_src(
SourceConfigBuilder::new("a")
.repo_url("http://example.com/a")
.rate_period(60)
.add_root_key(ROOT_KEY_1)
.build()
.into(),
)
.await;
env.run_amberctl_add_src(
SourceConfigBuilder::new("b")
.repo_url("http://example.com/b")
.rate_period(60)
.add_root_key(ROOT_KEY_2)
.build()
.into(),
)
.await;
env.run_amberctl(&["disable_src"]).await;
assert_eq!(
env.resolver_list_repos().await,
vec![
RepositoryConfigBuilder::new("fuchsia-pkg://a".parse().unwrap())
.add_root_key(RepositoryKey::Ed25519(hex::decode(ROOT_KEY_1).unwrap()))
.add_mirror(
MirrorConfigBuilder::new("http://example.com/a".parse::<Uri>().unwrap())
.unwrap()
)
.build(),
RepositoryConfigBuilder::new("fuchsia-pkg://b".parse().unwrap())
.add_root_key(RepositoryKey::Ed25519(hex::decode(ROOT_KEY_2).unwrap()))
.add_mirror(
MirrorConfigBuilder::new("http://example.com/b".parse::<Uri>().unwrap())
.unwrap()
)
.build(),
]
);
// disabling any source clears all rewrite rules.
assert_eq!(env.rewrite_engine_list_rules().await, vec![]);
}
async fn test_system_update_impl(
check_now_result: fidl_fuchsia_update::ManagerCheckNowResult,
) -> Output {
// skip using TestEnv because we don't need to start pkg_resolver here.
let mut fs = ServiceFs::new();
let update_manager = Arc::new(MockUpdateManager::new_with_check_now_result(check_now_result));
let update_manager_clone = update_manager.clone();
fs.add_fidl_service(move |stream| {
let update_manager_clone = update_manager_clone.clone();
fasync::Task::spawn(
update_manager_clone
.run(stream)
.unwrap_or_else(|e| panic!("error running mock update manager: {:?}", e)),
)
.detach()
});
let env = fs
.create_salted_nested_environment("amberctl_env")
.expect("nested environment to create successfully");
fasync::Task::spawn(fs.collect()).detach();
let output = amberctl()
.arg("system_update")
.output(env.launcher())
.expect("amberctl to launch")
.await
.expect("amberctl to run");
assert_eq!(*update_manager.called.lock(), 1);
output
}
fn assert_stdout(output: &Output, stdout: &str, exit_code: i64) {
assert_eq!(output.exit_status.reason(), fidl_fuchsia_sys::TerminationReason::Exited);
assert_eq!(output.exit_status.code(), exit_code);
assert_eq!(std::str::from_utf8(&output.stdout).unwrap(), stdout);
assert_eq!(std::str::from_utf8(&output.stderr).unwrap(), "");
}
#[fasync::run_singlethreaded(test)]
async fn test_system_update_start_update() {
let output = test_system_update_impl(Ok(())).await;
assert_stdout(&output, "triggered a system update check\n", 0);
}
#[fasync::run_singlethreaded(test)]
async fn test_system_update_already_in_progress() {
let output =
test_system_update_impl(Err(fidl_fuchsia_update::CheckNotStartedReason::AlreadyInProgress))
.await;
assert_stdout(&output, "system update check already in progress\n", 0);
}
#[fasync::run_singlethreaded(test)]
async fn test_system_update_throttled() {
let output =
test_system_update_impl(Err(fidl_fuchsia_update::CheckNotStartedReason::Throttled)).await;
assert_stdout(&output, "system update check failed: Throttled\n", 1);
}
#[fasync::run_singlethreaded(test)]
async fn test_gc() {
// skip using TestEnv because we don't need to start pkg_resolver here.
let mut fs = ServiceFs::new();
let space_manager = Arc::new(MockSpaceManager::new());
let space_manager_clone = Arc::clone(&space_manager);
fs.add_fidl_service(move |stream| {
let space_manager_clone = Arc::clone(&space_manager_clone);
fasync::Task::spawn(
space_manager_clone
.run(stream)
.unwrap_or_else(|e| panic!("error running mock space manager: {:?}", e)),
)
.detach()
});
let env = fs
.create_salted_nested_environment("amberctl_env")
.expect("nested environment to create successfully");
fasync::Task::spawn(fs.collect()).detach();
amberctl()
.arg("gc")
.output(env.launcher())
.expect("amberctl to launch")
.await
.expect("amberctl to run")
.ok()
.expect("amberctl to succeed");
assert_eq!(*space_manager.called.lock(), 1);
}