| // 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 { |
| crate::amber_connector::AmberConnect, |
| crate::cache::PackageCache, |
| crate::font_package_manager::FontPackageManager, |
| crate::repository_manager::RepositoryManager, |
| crate::rewrite_manager::RewriteManager, |
| failure::Error, |
| fidl::endpoints::ServerEnd, |
| fidl_fuchsia_io::{self, DirectoryMarker}, |
| fidl_fuchsia_pkg::{ |
| FontResolverRequest, FontResolverRequestStream, PackageResolverRequest, |
| PackageResolverRequestStream, UpdatePolicy, |
| }, |
| fuchsia_syslog::{fx_log_err, fx_log_info, fx_log_warn}, |
| fuchsia_url::pkg_url::{ParseError, PkgUrl}, |
| fuchsia_zircon::Status, |
| futures::prelude::*, |
| parking_lot::RwLock, |
| std::sync::Arc, |
| }; |
| |
| pub async fn run_resolver_service<A>( |
| rewrites: Arc<RwLock<RewriteManager>>, |
| repo_manager: Arc<RwLock<RepositoryManager<A>>>, |
| cache: PackageCache, |
| mut stream: PackageResolverRequestStream, |
| ) -> Result<(), Error> |
| where |
| A: AmberConnect, |
| { |
| while let Some(event) = stream.try_next().await? { |
| let PackageResolverRequest::Resolve { |
| package_url, |
| selectors, |
| update_policy, |
| dir, |
| responder, |
| } = event; |
| |
| let status = |
| resolve(&rewrites, &repo_manager, &cache, package_url, selectors, update_policy, dir) |
| .await; |
| |
| responder.send(Status::from(status).into_raw())?; |
| } |
| |
| Ok(()) |
| } |
| |
| /// Resolve the package. |
| /// |
| /// FIXME: at the moment, we are proxying to Amber to resolve a package name and variant to a |
| /// merkleroot. Because of this, we cant' implement the update policy, so we just ignore it. |
| async fn resolve<'a, A>( |
| rewrites: &'a Arc<RwLock<RewriteManager>>, |
| repo_manager: &'a Arc<RwLock<RepositoryManager<A>>>, |
| cache: &'a PackageCache, |
| pkg_url: String, |
| selectors: Vec<String>, |
| _update_policy: UpdatePolicy, |
| dir_request: ServerEnd<DirectoryMarker>, |
| ) -> Result<(), Status> |
| where |
| A: AmberConnect, |
| { |
| let url = PkgUrl::parse(&pkg_url).map_err(|err| handle_bad_package_url(err, &pkg_url))?; |
| let url = rewrites.read().rewrite(url); |
| |
| // While the fuchsia-pkg:// spec allows resource paths, the package resolver should not be |
| // given one. |
| if url.resource().is_some() { |
| fx_log_err!("package url should not contain a resource name: {}", url); |
| return Err(Status::INVALID_ARGS); |
| } |
| |
| // FIXME: need to implement selectors. |
| if !selectors.is_empty() { |
| fx_log_warn!("resolve does not support selectors yet"); |
| } |
| |
| let fut = repo_manager.read().get_package(&url, cache); |
| let merkle = fut.await?; |
| |
| fx_log_info!( |
| "resolved {} as {} with the selectors {:?} to {}", |
| pkg_url, |
| url, |
| selectors, |
| merkle |
| ); |
| |
| cache.open(merkle, &selectors, dir_request).await?; |
| |
| Ok(()) |
| } |
| |
| /// Run a service that only resolves registered font packages. |
| pub async fn run_font_resolver_service<A>( |
| font_package_manager: Arc<FontPackageManager>, |
| rewrites: Arc<RwLock<RewriteManager>>, |
| repo_manager: Arc<RwLock<RepositoryManager<A>>>, |
| cache: PackageCache, |
| mut stream: FontResolverRequestStream, |
| ) -> Result<(), Error> |
| where |
| A: AmberConnect, |
| { |
| while let Some(event) = stream.try_next().await? { |
| let FontResolverRequest::Resolve { package_url, directory_request, responder } = event; |
| |
| let result = resolve_font( |
| &font_package_manager, |
| &rewrites, |
| &repo_manager, |
| &cache, |
| package_url, |
| directory_request, |
| ) |
| .await; |
| |
| responder.send(Status::from(result).into_raw())?; |
| } |
| Ok(()) |
| } |
| |
| /// Resolve a single font package. |
| async fn resolve_font<'a, A>( |
| font_package_manager: &'a Arc<FontPackageManager>, |
| rewrites: &'a Arc<RwLock<RewriteManager>>, |
| repo_manager: &'a Arc<RwLock<RepositoryManager<A>>>, |
| cache: &'a PackageCache, |
| package_url: String, |
| directory_request: ServerEnd<DirectoryMarker>, |
| ) -> Result<(), Status> |
| where |
| A: AmberConnect, |
| { |
| match PkgUrl::parse(&package_url) { |
| Err(err) => handle_bad_package_url(err, &package_url), |
| Ok(parsed_package_url) => { |
| if !font_package_manager.is_font_package(&parsed_package_url) { |
| fx_log_err!("tried to resolve unknown font package: {}", package_url); |
| Err(Status::NOT_FOUND) |
| } else { |
| resolve( |
| &rewrites, |
| &repo_manager, |
| &cache, |
| package_url, |
| vec![], |
| UpdatePolicy { fetch_if_absent: true, allow_old_versions: true }, |
| directory_request, |
| ) |
| .await |
| } |
| } |
| } |
| } |
| |
| fn handle_bad_package_url(parse_error: ParseError, pkg_url: &str) -> Result<(), Status> { |
| fx_log_err!("failed to parse package url {:?}: {}", pkg_url, parse_error); |
| Err(Status::INVALID_ARGS) |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use super::*; |
| use crate::experiment::{Experiment, Experiments}; |
| use crate::font_package_manager::FontPackageManagerBuilder; |
| use crate::repository_manager::RepositoryManagerBuilder; |
| use crate::rewrite_manager::{tests::make_rule_config, RewriteManagerBuilder}; |
| use crate::test_util::{ |
| create_dir, MockAmberBuilder, MockAmberConnector, MockAmberMode, MockPackageCache, Package, |
| PackageKind, |
| }; |
| use fidl::endpoints; |
| use fidl_fuchsia_amber::FetchResultProxy; |
| use fidl_fuchsia_io::DirectoryProxy; |
| use fidl_fuchsia_pkg::{self, PackageCacheProxy, UpdatePolicy}; |
| use fidl_fuchsia_pkg_ext::{BlobId, RepositoryConfigBuilder, RepositoryConfigs, RepositoryKey}; |
| use files_async; |
| use fuchsia_url::pkg_url::RepoUrl; |
| use fuchsia_url_rewrite::Rule; |
| use fuchsia_zircon::Status; |
| use std::fs; |
| use std::path::Path; |
| use std::str; |
| use std::sync::Arc; |
| use tempfile::TempDir; |
| |
| async fn wait_for_update_to_complete( |
| result_proxy: FetchResultProxy, |
| _url: &PkgUrl, |
| ) -> Result<BlobId, Status> { |
| use fidl_fuchsia_amber::FetchResultEvent; |
| match result_proxy.take_event_stream().into_future().await { |
| (Some(Ok(FetchResultEvent::OnSuccess { merkle })), _) => match merkle.parse() { |
| Ok(merkle) => Ok(merkle), |
| Err(err) => { |
| fx_log_err!("{:?} is not a valid merkleroot: {:?}", merkle, err); |
| return Err(Status::INTERNAL); |
| } |
| }, |
| (Some(Ok(FetchResultEvent::OnError { result, message })), _) => { |
| let status = Status::from_raw(result); |
| fx_log_err!("error fetching package: {}: {}", status, message); |
| return Err(status); |
| } |
| (Some(Err(err)), _) => { |
| fx_log_err!("error communicating with amber: {}", err); |
| return Err(Status::INTERNAL); |
| } |
| (None, _) => { |
| fx_log_err!("amber unexpectedly closed fetch result channel"); |
| return Err(Status::INTERNAL); |
| } |
| } |
| } |
| |
| struct ResolveTest { |
| _static_repo_dir: tempfile::TempDir, |
| _dynamic_repo_dir: tempfile::TempDir, |
| amber_connector: MockAmberConnector, |
| rewrite_manager: Arc<RwLock<RewriteManager>>, |
| repo_manager: Arc<RwLock<RepositoryManager<MockAmberConnector>>>, |
| font_package_manager: Arc<FontPackageManager>, |
| cache: PackageCache, |
| pkgfs: Arc<TempDir>, |
| } |
| |
| impl ResolveTest { |
| fn check_dir(&self, dir_path: &Path, want_files: &Vec<String>) { |
| let mut files: Vec<String> = fs::read_dir(&dir_path) |
| .expect("could not read dir") |
| .into_iter() |
| .map(|entry| { |
| entry |
| .expect("get directory entry") |
| .file_name() |
| .to_str() |
| .expect("valid utf8") |
| .into() |
| }) |
| .collect(); |
| files.sort_unstable(); |
| assert_eq!(&files, want_files); |
| } |
| |
| async fn check_dir_async<'a>( |
| &'a self, |
| dir: &'a DirectoryProxy, |
| want_files: &'a Vec<String>, |
| ) { |
| let entries = files_async::readdir(dir).await.expect("could not read dir"); |
| let mut files: Vec<_> = entries.into_iter().map(|f| f.name).collect(); |
| files.sort_unstable(); |
| assert_eq!(&files, want_files); |
| } |
| |
| async fn check_amber_update<'a>( |
| &'a self, |
| name: &'a str, |
| variant: Option<&'a str>, |
| merkle: Option<&'a str>, |
| expected_res: Result<String, Status>, |
| ) { |
| let amber = self.repo_manager.read().connect_to_amber().unwrap(); |
| let (repo, repo_server_end) = fidl::endpoints::create_proxy().unwrap(); |
| let status = amber |
| .open_repository( |
| RepositoryConfigBuilder::new("fuchsia-pkg://fuchsia.com".parse().unwrap()) |
| .add_root_key(RepositoryKey::Ed25519(vec![1; 32])) |
| .build() |
| .into(), |
| repo_server_end, |
| ) |
| .await |
| .unwrap(); |
| Status::ok(status).unwrap(); |
| let (result_proxy, result_server_end) = fidl::endpoints::create_proxy().unwrap(); |
| repo.get_update_complete(name, variant, merkle, result_server_end) |
| .expect("error communicating with amber"); |
| let expected_res = expected_res.map(|r| r.parse().expect("could not parse blob")); |
| |
| let path = match variant { |
| None => format!("/{}", name), |
| Some(variant) => format!("/{}/{}", name, variant), |
| }; |
| |
| let url = |
| PkgUrl::new_package("fuchsia.com".to_string(), path, merkle.map(|s| s.to_string())) |
| .unwrap(); |
| |
| let res = wait_for_update_to_complete(result_proxy, &url).await; |
| assert_eq!(res, expected_res); |
| } |
| |
| async fn run_resolve<'a>( |
| &'a self, |
| url: &'a str, |
| expected_res: Result<Vec<String>, Status>, |
| ) { |
| let selectors = vec![]; |
| let update_policy = UpdatePolicy { fetch_if_absent: true, allow_old_versions: false }; |
| let (dir, dir_server_end) = fidl::endpoints::create_proxy::<DirectoryMarker>().unwrap(); |
| let res = resolve( |
| &self.rewrite_manager, |
| &self.repo_manager, |
| &self.cache, |
| url.to_string(), |
| selectors, |
| update_policy, |
| dir_server_end, |
| ) |
| .await; |
| if res.is_ok() { |
| let expected_files = expected_res.as_ref().unwrap(); |
| self.check_dir_async(&dir, expected_files).await; |
| } |
| assert_eq!(res, expected_res.map(|_s| ()), "unexpected result for {}", url); |
| } |
| |
| async fn run_resolve_font<'a>( |
| &'a self, |
| url: &'a str, |
| expected_res: Result<Vec<String>, Status>, |
| ) { |
| let (dir, dir_server_end) = fidl::endpoints::create_proxy::<DirectoryMarker>().unwrap(); |
| let res = resolve_font( |
| &self.font_package_manager, |
| &self.rewrite_manager, |
| &self.repo_manager, |
| &self.cache, |
| url.to_string(), |
| dir_server_end, |
| ) |
| .await; |
| if res.is_ok() { |
| let expected_files = expected_res.as_ref().unwrap(); |
| self.check_dir_async(&dir, expected_files).await; |
| } |
| assert_eq!(res, expected_res.map(|_s| ()), "unexpected result for {}", url); |
| } |
| } |
| |
| struct ResolveTestBuilder { |
| pkgfs: Arc<TempDir>, |
| amber: MockAmberBuilder, |
| static_repos: Vec<(String, RepositoryConfigs)>, |
| static_rewrite_rules: Vec<Rule>, |
| dynamic_rewrite_rules: Vec<Rule>, |
| font_package_urls: Vec<String>, |
| experiments: Option<Experiments>, |
| } |
| |
| impl ResolveTestBuilder { |
| fn new() -> Self { |
| let pkgfs = Arc::new(TempDir::new().expect("failed to create tmp dir")); |
| fs::create_dir(pkgfs.path().join("install")).expect("failed to create pkgfs/install"); |
| fs::create_dir(pkgfs.path().join("needs")).expect("failed to create pkgfs/needs"); |
| fs::create_dir(pkgfs.path().join("versions")).expect("failed to create pkgfs/versions"); |
| let amber = MockAmberBuilder::new(pkgfs.clone()); |
| ResolveTestBuilder { |
| pkgfs: pkgfs.clone(), |
| amber: amber, |
| static_repos: vec![], |
| static_rewrite_rules: vec![], |
| dynamic_rewrite_rules: vec![], |
| font_package_urls: vec![], |
| experiments: None, |
| } |
| } |
| |
| fn experiments(mut self, experiments: Experiments) -> Self { |
| self.experiments = Some(experiments); |
| self |
| } |
| |
| fn source_packages<I: IntoIterator<Item = Package>>(self, packages: I) -> Self { |
| self.static_repo("fuchsia-pkg://fuchsia.com", packages.into_iter().collect()) |
| } |
| |
| fn static_repo(mut self, url: &str, packages: Vec<Package>) -> Self { |
| let url = RepoUrl::parse(url).unwrap(); |
| let name = format!("{}.json", url.host()); |
| |
| let config = RepositoryConfigBuilder::new(url) |
| .add_root_key(RepositoryKey::Ed25519(vec![1; 32])) |
| .build(); |
| |
| self.amber = self.amber.repo(config.clone().into(), packages); |
| |
| self.static_repos.push((name, RepositoryConfigs::Version1(vec![config]))); |
| |
| self |
| } |
| |
| fn amber_mode(mut self, mode: Arc<RwLock<MockAmberMode>>) -> Self { |
| self.amber = self.amber.mode(mode); |
| self |
| } |
| |
| fn static_rewrite_rules<I: IntoIterator<Item = Rule>>(mut self, rules: I) -> Self { |
| self.static_rewrite_rules.extend(rules); |
| self |
| } |
| |
| fn font_package_urls<S: Into<String>, I: IntoIterator<Item = S>>( |
| mut self, |
| urls: I, |
| ) -> Self { |
| self.font_package_urls.extend(urls.into_iter().map(Into::into)); |
| self |
| } |
| |
| fn build(self) -> ResolveTest { |
| let amber = self.amber.build(); |
| let amber_connector = MockAmberConnector::new(amber); |
| |
| let cache = Arc::new( |
| MockPackageCache::new(self.pkgfs.clone()).expect("failed to create cache"), |
| ); |
| let cache_proxy: PackageCacheProxy = |
| endpoints::spawn_local_stream_handler(move |req| { |
| let cache = cache.clone(); |
| async move { |
| cache.open(req); |
| } |
| }) |
| .expect("failed to spawn handler"); |
| let pkgfs_install = { |
| let f = fs::File::open(self.pkgfs.path().join("install")).expect("pkgfs to open"); |
| let chan = fuchsia_async::Channel::from_channel( |
| fdio::clone_channel(&f).expect("pkgfs channel to clone"), |
| ) |
| .unwrap(); |
| DirectoryProxy::new(chan) |
| }; |
| let pkgfs_needs = { |
| let f = fs::File::open(self.pkgfs.path().join("needs")).expect("pkgfs to open"); |
| let chan = fuchsia_async::Channel::from_channel( |
| fdio::clone_channel(&f).expect("pkgfs channel to clone"), |
| ) |
| .unwrap(); |
| DirectoryProxy::new(chan) |
| }; |
| |
| let cache = PackageCache::new(cache_proxy, pkgfs_install, pkgfs_needs); |
| |
| let dynamic_rule_config = make_rule_config(self.dynamic_rewrite_rules); |
| let rewrite_manager = RewriteManagerBuilder::new(Some(&dynamic_rule_config)) |
| .unwrap() |
| .static_rules(self.static_rewrite_rules) |
| .build(); |
| |
| let static_repo_dir = |
| create_dir(self.static_repos.iter().map(|(name, config)| (&**name, config))); |
| let dynamic_repo_dir = TempDir::new().unwrap(); |
| |
| let dynamic_configs_path = dynamic_repo_dir.path().join("config"); |
| let repo_manager = RepositoryManagerBuilder::new( |
| dynamic_configs_path, |
| amber_connector.clone(), |
| self.experiments.unwrap_or_else(Experiments::none), |
| ) |
| .unwrap() |
| .load_static_configs_dir(static_repo_dir.path()) |
| .unwrap() |
| .build(); |
| |
| let font_config_dir = create_dir(vec![("font_packages.json", self.font_package_urls)]); |
| let font_package_manager = FontPackageManagerBuilder::new() |
| .add_registry_file(font_config_dir.path().join("font_packages.json")) |
| .unwrap() |
| .build(); |
| |
| ResolveTest { |
| _static_repo_dir: static_repo_dir, |
| _dynamic_repo_dir: dynamic_repo_dir, |
| amber_connector: amber_connector, |
| rewrite_manager: Arc::new(RwLock::new(rewrite_manager)), |
| repo_manager: Arc::new(RwLock::new(repo_manager)), |
| font_package_manager: Arc::new(font_package_manager), |
| pkgfs: self.pkgfs, |
| cache, |
| } |
| } |
| } |
| |
| fn gen_merkle(c: char) -> String { |
| (0..64).map(|_| c).collect() |
| } |
| |
| fn gen_merkle_file(c: char) -> String { |
| format!("{}_file", gen_merkle(c)) |
| } |
| |
| #[fuchsia_async::run_singlethreaded(test)] |
| async fn test_mock_amber() { |
| let test = ResolveTestBuilder::new() |
| .source_packages(vec![ |
| Package::new("foo", "0", &gen_merkle('a'), PackageKind::Ok), |
| Package::new("bar", "stable", &gen_merkle('b'), PackageKind::Ok), |
| Package::new("baz", "stable", &gen_merkle('c'), PackageKind::Ok), |
| Package::new("buz", "0", &gen_merkle('c'), PackageKind::Ok), |
| ]) |
| .build(); |
| |
| // Name |
| test.check_amber_update("foo", None, None, Ok(gen_merkle('a'))).await; |
| |
| // Name and variant |
| test.check_amber_update("bar", Some("stable"), None, Ok(gen_merkle('b'))).await; |
| |
| // Name, variant, and merkle |
| let merkle = gen_merkle('c'); |
| test.check_amber_update("baz", Some("stable"), Some(&merkle), Ok(gen_merkle('c'))).await; |
| |
| // Nonexistent package |
| test.check_amber_update("nonexistent", None, None, Err(Status::NOT_FOUND)).await; |
| |
| // no merkle('d') since we didn't ask to update "buz". |
| test.check_dir( |
| &test.pkgfs.path().join("versions"), |
| &vec![gen_merkle('a'), gen_merkle('b'), gen_merkle('c')], |
| ); |
| } |
| |
| #[fuchsia_async::run_singlethreaded(test)] |
| async fn test_resolve_package() { |
| let test = ResolveTestBuilder::new() |
| .source_packages(vec![ |
| Package::new("foo", "0", &gen_merkle('a'), PackageKind::Ok), |
| Package::new("bar", "stable", &gen_merkle('b'), PackageKind::Ok), |
| ]) |
| .build(); |
| |
| // Package name |
| test.run_resolve("fuchsia-pkg://fuchsia.com/foo", Ok(vec![gen_merkle_file('a')])).await; |
| |
| // Package name and variant |
| test.run_resolve("fuchsia-pkg://fuchsia.com/bar/stable", Ok(vec![gen_merkle_file('b')])) |
| .await; |
| |
| // Package name, variant, and merkle |
| let url = format!("fuchsia-pkg://fuchsia.com/bar/stable?hash={}", gen_merkle('b')); |
| test.run_resolve(&url, Ok(vec![gen_merkle_file('b')])).await; |
| } |
| |
| #[fuchsia_async::run_singlethreaded(test)] |
| async fn test_download_blob_experiment_calls_correct_amber_api() { |
| let experiments = Arc::new(RwLock::new(crate::experiment::State::new_test())); |
| let mode = Arc::new(RwLock::new(MockAmberMode::GetUpdateComplete)); |
| |
| let test = ResolveTestBuilder::new() |
| .source_packages(vec![ |
| Package::new("foo", "0", &gen_merkle('a'), PackageKind::Ok), |
| Package::new( |
| "bar", |
| "0", |
| &gen_merkle('b'), |
| PackageKind::Error(Status::NOT_FOUND, "test merkle for not found".to_string()), |
| ), |
| ]) |
| .experiments(Arc::clone(&experiments).into()) |
| .amber_mode(Arc::clone(&mode)) |
| .build(); |
| |
| // Succeeds without experiment enabled. |
| test.run_resolve("fuchsia-pkg://fuchsia.com/foo", Ok(vec![gen_merkle_file('a')])).await; |
| |
| // Picks up new experiment state, calls the correct amber API, and fails as expected. |
| experiments.write().set_state(Experiment::DownloadBlob, true); |
| *mode.write() = MockAmberMode::MerkleFor; |
| test.run_resolve("fuchsia-pkg://fuchsia.com/bar", Err(Status::NOT_FOUND)).await; |
| |
| // Succeeds after disabling experiment. |
| experiments.write().set_state(Experiment::DownloadBlob, false); |
| *mode.write() = MockAmberMode::GetUpdateComplete; |
| test.run_resolve("fuchsia-pkg://fuchsia.com/foo", Ok(vec![gen_merkle_file('a')])).await; |
| } |
| |
| #[fuchsia_async::run_singlethreaded(test)] |
| async fn test_resolve_package_error() { |
| let test = ResolveTestBuilder::new() |
| .source_packages(vec![ |
| Package::new("foo", "stable", &gen_merkle('a'), PackageKind::Ok), |
| Package::new( |
| "unavailable", |
| "0", |
| &gen_merkle('a'), |
| PackageKind::Error( |
| Status::UNAVAILABLE, |
| "not found in 1 active sources. last error: ".to_string(), |
| ), |
| ), |
| ]) |
| .build(); |
| |
| // Missing package |
| test.run_resolve("fuchsia-pkg://fuchsia.com/foo/beta", Err(Status::NOT_FOUND)).await; |
| |
| // Unavailable package |
| test.run_resolve("fuchsia-pkg://fuchsia.com/unavailable/0", Err(Status::UNAVAILABLE)).await; |
| |
| // Bad package URL |
| test.run_resolve("fuchsia-pkg://fuchsia.com/foo!", Err(Status::INVALID_ARGS)).await; |
| |
| // No package name |
| test.run_resolve("fuchsia-pkg://fuchsia.com", Err(Status::INVALID_ARGS)).await; |
| } |
| |
| #[fuchsia_async::run_singlethreaded(test)] |
| async fn test_resolve_package_unknown_host() { |
| let test = ResolveTestBuilder::new() |
| .source_packages(vec![ |
| Package::new("foo", "0", &gen_merkle('a'), PackageKind::Ok), |
| Package::new("bar", "stable", &gen_merkle('b'), PackageKind::Ok), |
| ]) |
| .static_rewrite_rules(vec![Rule::new( |
| "example.com".to_owned(), |
| "fuchsia.com".to_owned(), |
| "/foo/".to_owned(), |
| "/foo/".to_owned(), |
| ) |
| .unwrap()]) |
| .build(); |
| |
| test.run_resolve("fuchsia-pkg://example.com/foo/0", Ok(vec![gen_merkle_file('a')])).await; |
| test.run_resolve("fuchsia-pkg://fuchsia.com/foo/0", Ok(vec![gen_merkle_file('a')])).await; |
| test.run_resolve("fuchsia-pkg://example.com/bar/stable", Err(Status::NOT_FOUND)).await; |
| test.run_resolve("fuchsia-pkg://fuchsia.com/bar/stable", Ok(vec![gen_merkle_file('b')])) |
| .await; |
| } |
| |
| #[fuchsia_async::run_singlethreaded(test)] |
| async fn test_open_repo_resolve_package() { |
| let test = ResolveTestBuilder::new() |
| .static_repo( |
| "fuchsia-pkg://example.com", |
| vec![ |
| Package::new("foo", "0", &gen_merkle('a'), PackageKind::Ok), |
| Package::new("bar", "stable", &gen_merkle('b'), PackageKind::Ok), |
| ], |
| ) |
| .build(); |
| |
| // Package name |
| test.run_resolve("fuchsia-pkg://example.com/foo", Ok(vec![gen_merkle_file('a')])).await; |
| |
| // Package name and variant |
| test.run_resolve("fuchsia-pkg://example.com/bar/stable", Ok(vec![gen_merkle_file('b')])) |
| .await; |
| |
| // Package name, variant, and merkle |
| let url = format!("fuchsia-pkg://example.com/bar/stable?hash={}", gen_merkle('b')); |
| test.run_resolve(&url, Ok(vec![gen_merkle_file('b')])).await; |
| } |
| |
| #[fuchsia_async::run_singlethreaded(test)] |
| async fn test_open_repo_resolve_package_error() { |
| let test = ResolveTestBuilder::new() |
| .static_repo( |
| "fuchsia-pkg://example.com", |
| vec![ |
| Package::new("foo", "stable", &gen_merkle('a'), PackageKind::Ok), |
| Package::new( |
| "unavailable", |
| "0", |
| &gen_merkle('a'), |
| PackageKind::Error( |
| Status::UNAVAILABLE, |
| "not found in 1 active sources. last error: ".to_string(), |
| ), |
| ), |
| ], |
| ) |
| .build(); |
| |
| // Missing package |
| test.run_resolve("fuchsia-pkg://example.com/foo/beta", Err(Status::NOT_FOUND)).await; |
| |
| // Unavailable package |
| test.run_resolve("fuchsia-pkg://example.com/unavailable/0", Err(Status::UNAVAILABLE)).await; |
| |
| // Bad package URL |
| test.run_resolve("fuchsia-pkg://example.com/foo!", Err(Status::INVALID_ARGS)).await; |
| |
| // No package name |
| test.run_resolve("fuchsia-pkg://example.com", Err(Status::INVALID_ARGS)).await; |
| } |
| |
| #[fuchsia_async::run_singlethreaded(test)] |
| async fn test_open_repo_resolve_package_unknown_host() { |
| let test = ResolveTestBuilder::new() |
| .static_repo( |
| "fuchsia-pkg://oem.com", |
| vec![ |
| Package::new("foo", "0", &gen_merkle('a'), PackageKind::Ok), |
| Package::new("bar", "stable", &gen_merkle('b'), PackageKind::Ok), |
| ], |
| ) |
| .static_rewrite_rules(vec![Rule::new( |
| "example.com".to_owned(), |
| "oem.com".to_owned(), |
| "/foo/".to_owned(), |
| "/foo/".to_owned(), |
| ) |
| .unwrap()]) |
| .build(); |
| |
| test.run_resolve("fuchsia-pkg://example.com/foo/0", Ok(vec![gen_merkle_file('a')])).await; |
| test.run_resolve("fuchsia-pkg://oem.com/foo/0", Ok(vec![gen_merkle_file('a')])).await; |
| test.run_resolve("fuchsia-pkg://example.com/bar/stable", Err(Status::NOT_FOUND)).await; |
| |
| test.run_resolve("fuchsia-pkg://oem.com/bar/stable", Ok(vec![gen_merkle_file('b')])).await; |
| } |
| |
| #[fuchsia_async::run_singlethreaded(test)] |
| async fn test_open_repo_reconnect() { |
| // Setup the initial amber with our test package. |
| let mut test = ResolveTestBuilder::new() |
| .static_repo( |
| "fuchsia-pkg://example.com", |
| vec![Package::new("foo", "0", &gen_merkle('a'), PackageKind::Ok)], |
| ) |
| .build(); |
| |
| test.run_resolve("fuchsia-pkg://example.com/foo/0", Ok(vec![gen_merkle_file('a')])).await; |
| |
| dbg!(); |
| |
| // Verify that swapping the amber connection doesn't impact anything, because the config |
| // hasn't changed. |
| let url = RepoUrl::parse("fuchsia-pkg://example.com").unwrap(); |
| let config = RepositoryConfigBuilder::new(url) |
| .add_root_key(RepositoryKey::Ed25519(vec![2; 32])) |
| .build(); |
| test.amber_connector.set_amber( |
| MockAmberBuilder::new(test.pkgfs.clone()) |
| .repo( |
| config.clone().into(), |
| vec![Package::new("foo", "0", &gen_merkle('b'), PackageKind::Ok)], |
| ) |
| .build(), |
| ); |
| |
| test.run_resolve("fuchsia-pkg://example.com/foo/0", Ok(vec![gen_merkle_file('a')])).await; |
| |
| dbg!(); |
| |
| // Change the config for example.com, which will cause the resolver's connection to close. |
| // The next request should connect to our new amber, which contains the new package. |
| test.repo_manager.write().insert(config); |
| |
| test.run_resolve("fuchsia-pkg://example.com/foo/0", Ok(vec![gen_merkle_file('b')])).await; |
| } |
| |
| #[fuchsia_async::run_singlethreaded(test)] |
| async fn test_resolve_font_package() { |
| let test = ResolveTestBuilder::new() |
| .source_packages(vec![ |
| Package::new("font1", "0", &gen_merkle('a'), PackageKind::Ok), |
| Package::new("font2", "0", &gen_merkle('b'), PackageKind::Ok), |
| Package::new("squares", "0", &gen_merkle('b'), PackageKind::Ok), |
| ]) |
| .font_package_urls(vec![ |
| "fuchsia-pkg://fuchsia.com/font1", |
| "fuchsia-pkg://fuchsia.com/font2", |
| ]) |
| .build(); |
| |
| test.run_resolve_font("fuchsia-pkg://fuchsia.com/font1", Ok(vec![gen_merkle_file('a')])) |
| .await; |
| test.run_resolve_font("fuchsia-pkg://fuchsia.com/font2", Ok(vec![gen_merkle_file('b')])) |
| .await; |
| test.run_resolve_font("fuchsia-pkg://fuchsia.com/squares", Err(Status::NOT_FOUND)).await; |
| } |
| } |