| // Copyright 2021 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_TESTS_COLLECTION, TEST_TYPE_REALM_MAP}, |
| error::{FacetError, LaunchTestError}, |
| }, |
| anyhow::format_err, |
| fidl_fuchsia_component_decl as fdecl, fidl_fuchsia_component_resolution as fresolution, |
| fidl_fuchsia_data as fdata, |
| std::sync::Arc, |
| }; |
| |
| const TEST_TYPE_FACET_KEY: &'static str = "fuchsia.test.type"; |
| pub const TEST_DEPRECATED_ALLOWED_PACKAGES_FACET_KEY: &'static str = |
| "fuchsia.test.deprecated-allowed-packages"; |
| |
| /// Set of facets attached to a test component's manifest that describe how to run it. |
| #[derive(Debug)] |
| pub(crate) struct SuiteFacets { |
| pub collection: &'static str, |
| pub deprecated_allowed_packages: Option<Vec<String>>, |
| } |
| |
| pub(crate) enum ResolveStatus { |
| Unresolved, |
| Resolved(Result<SuiteFacets, LaunchTestError>), |
| } |
| |
| pub(crate) async fn get_suite_facets( |
| test_url: String, |
| resolver: Arc<fresolution::ResolverProxy>, |
| ) -> Result<SuiteFacets, LaunchTestError> { |
| let component = resolver |
| .resolve(&test_url) |
| .await |
| .map_err(|e| LaunchTestError::ResolveTest(e.into()))? |
| .map_err(|e| LaunchTestError::ResolveTest(format_err!("{:?}", e)))?; |
| let decl = component.decl.unwrap(); |
| let bytes = mem_util::bytes_from_data(&decl).map_err(LaunchTestError::ManifestIo)?; |
| let component_decl: fdecl::Component = |
| fidl::unpersist(&bytes).map_err(|e| LaunchTestError::InvalidManifest(e.into()))?; |
| |
| parse_facet(&component_decl).map_err(|e| e.into()) |
| } |
| |
| fn parse_facet(decl: &fdecl::Component) -> Result<SuiteFacets, FacetError> { |
| let mut collection = HERMETIC_TESTS_COLLECTION; |
| let mut deprecated_allowed_packages = None; |
| if let Some(obj) = &decl.facets { |
| let entries = obj.entries.as_ref().map(Vec::as_slice).unwrap_or_default(); |
| for entry in entries { |
| if entry.key == TEST_TYPE_FACET_KEY { |
| collection = parse_suite_collection(&entry)?; |
| } else if entry.key == TEST_DEPRECATED_ALLOWED_PACKAGES_FACET_KEY { |
| let test_type = entry |
| .value |
| .as_ref() |
| .ok_or(FacetError::NullFacet(TEST_DEPRECATED_ALLOWED_PACKAGES_FACET_KEY))?; |
| |
| match test_type.as_ref() { |
| fdata::DictionaryValue::StrVec(s) => { |
| deprecated_allowed_packages = Some(s.clone()); |
| } |
| _ => { |
| return Err(FacetError::InvalidFacetValue( |
| TEST_DEPRECATED_ALLOWED_PACKAGES_FACET_KEY, |
| format!("{:?}", test_type), |
| "vector of allowed packages names".to_string(), |
| )); |
| } |
| } |
| } |
| } |
| } |
| Ok(SuiteFacets { collection, deprecated_allowed_packages }) |
| } |
| |
| fn parse_suite_collection(entry: &fdata::DictionaryEntry) -> Result<&'static str, FacetError> { |
| let test_type = entry.value.as_ref().ok_or(FacetError::NullFacet(TEST_TYPE_FACET_KEY))?; |
| |
| match test_type.as_ref() { |
| fdata::DictionaryValue::Str(s) => { |
| if TEST_TYPE_REALM_MAP.contains_key(s.as_str()) { |
| return Ok(TEST_TYPE_REALM_MAP[s.as_str()]); |
| } |
| return Err(FacetError::InvalidFacetValue( |
| TEST_TYPE_FACET_KEY, |
| format!("{:?}", s), |
| format!( |
| "one of {}", |
| TEST_TYPE_REALM_MAP |
| .keys() |
| .map(|k| k.to_string()) |
| .collect::<Vec<_>>() |
| .join(", ") |
| ), |
| )); |
| } |
| fdata::DictionaryValue::StrVec(s) => { |
| return Err(FacetError::InvalidFacetValue( |
| TEST_TYPE_FACET_KEY, |
| format!("{:?}", s), |
| format!( |
| "one of {}", |
| TEST_TYPE_REALM_MAP |
| .keys() |
| .map(|k| k.to_string()) |
| .collect::<Vec<_>>() |
| .join(", ") |
| ), |
| )); |
| } |
| _ => { |
| return Err(FacetError::InvalidFacetValue( |
| TEST_TYPE_FACET_KEY, |
| format!("{:?}", test_type), |
| format!( |
| "one of {}", |
| TEST_TYPE_REALM_MAP |
| .keys() |
| .map(|k| k.to_string()) |
| .collect::<Vec<_>>() |
| .join(", ") |
| ), |
| )); |
| } |
| }; |
| } |
| |
| #[cfg(test)] |
| mod test { |
| use super::*; |
| use crate::constants::{ |
| CHROMIUM_TESTS_COLLECTION, SYSTEM_TESTS_COLLECTION, VULKAN_TESTS_COLLECTION, |
| }; |
| |
| #[test] |
| fn parse_suite_collection_works() { |
| const TEST_FACET: &str = "fuchsia.test"; |
| |
| // test that default hermetic value is true |
| let mut decl = fdecl::Component::default(); |
| assert_eq!(parse_facet(&decl).unwrap().collection, HERMETIC_TESTS_COLLECTION); |
| |
| // empty facet |
| decl.facets = Some(fdata::Dictionary { entries: vec![].into(), ..Default::default() }); |
| assert_eq!(parse_facet(&decl).unwrap().collection, HERMETIC_TESTS_COLLECTION); |
| |
| // empty facet |
| decl.facets = Some(fdata::Dictionary { entries: None, ..Default::default() }); |
| assert_eq!(parse_facet(&decl).unwrap().collection, HERMETIC_TESTS_COLLECTION); |
| |
| // make sure that the func can handle some other facet key |
| decl.facets = Some(fdata::Dictionary { |
| entries: vec![fdata::DictionaryEntry { key: "somekey".into(), value: None }].into(), |
| ..Default::default() |
| }); |
| assert_eq!(parse_facet(&decl).unwrap().collection, HERMETIC_TESTS_COLLECTION); |
| |
| // test facet with some other key works |
| decl.facets = Some(fdata::Dictionary { |
| entries: vec![ |
| fdata::DictionaryEntry { key: "somekey".into(), value: None }, |
| fdata::DictionaryEntry { |
| key: format!("{}.somekey", TEST_FACET), |
| value: Some(fdata::DictionaryValue::Str("some_string".into()).into()), |
| }, |
| ] |
| .into(), |
| ..Default::default() |
| }); |
| assert_eq!(parse_facet(&decl).unwrap().collection, HERMETIC_TESTS_COLLECTION); |
| |
| decl.facets = Some(fdata::Dictionary { |
| entries: vec![ |
| fdata::DictionaryEntry { key: "somekey".into(), value: None }, |
| fdata::DictionaryEntry { |
| key: format!("{}.somekey", TEST_FACET), |
| value: Some(fdata::DictionaryValue::Str("some_string".into()).into()), |
| }, |
| fdata::DictionaryEntry { |
| key: TEST_TYPE_FACET_KEY.into(), |
| value: Some(fdata::DictionaryValue::Str("hermetic".into()).into()), |
| }, |
| ] |
| .into(), |
| ..Default::default() |
| }); |
| assert_eq!(parse_facet(&decl).unwrap().collection, HERMETIC_TESTS_COLLECTION); |
| |
| decl.facets = Some(fdata::Dictionary { |
| entries: vec![ |
| fdata::DictionaryEntry { key: "somekey".into(), value: None }, |
| fdata::DictionaryEntry { |
| key: format!("{}.somekey", TEST_FACET), |
| value: Some(fdata::DictionaryValue::Str("some_string".into()).into()), |
| }, |
| fdata::DictionaryEntry { |
| key: TEST_TYPE_FACET_KEY.into(), |
| value: Some(fdata::DictionaryValue::Str("system".into()).into()), |
| }, |
| ] |
| .into(), |
| ..Default::default() |
| }); |
| assert_eq!(parse_facet(&decl).unwrap().collection, SYSTEM_TESTS_COLLECTION); |
| |
| decl.facets = Some(fdata::Dictionary { |
| entries: vec![ |
| fdata::DictionaryEntry { key: "somekey".into(), value: None }, |
| fdata::DictionaryEntry { |
| key: format!("{}.somekey", TEST_FACET), |
| value: Some(fdata::DictionaryValue::Str("some_string".into()).into()), |
| }, |
| fdata::DictionaryEntry { |
| key: TEST_TYPE_FACET_KEY.into(), |
| value: Some(fdata::DictionaryValue::Str("vulkan".into()).into()), |
| }, |
| ] |
| .into(), |
| ..Default::default() |
| }); |
| assert_eq!(parse_facet(&decl).unwrap().collection, VULKAN_TESTS_COLLECTION); |
| |
| decl.facets = Some(fdata::Dictionary { |
| entries: vec![ |
| fdata::DictionaryEntry { key: "somekey".into(), value: None }, |
| fdata::DictionaryEntry { |
| key: format!("{}.somekey", TEST_FACET), |
| value: Some(fdata::DictionaryValue::Str("some_string".into()).into()), |
| }, |
| fdata::DictionaryEntry { |
| key: TEST_TYPE_FACET_KEY.into(), |
| value: Some(fdata::DictionaryValue::Str("chromium".into()).into()), |
| }, |
| ] |
| .into(), |
| ..Default::default() |
| }); |
| assert_eq!(parse_facet(&decl).unwrap().collection, CHROMIUM_TESTS_COLLECTION); |
| |
| // invalid facets |
| decl.facets = Some(fdata::Dictionary { |
| entries: vec![ |
| fdata::DictionaryEntry { key: "somekey".into(), value: None }, |
| fdata::DictionaryEntry { |
| key: format!("{}.somekey", TEST_FACET), |
| value: Some(fdata::DictionaryValue::Str("some_string".into()).into()), |
| }, |
| fdata::DictionaryEntry { |
| key: TEST_TYPE_FACET_KEY.into(), |
| value: Some(fdata::DictionaryValue::Str("some_other_collection".into()).into()), |
| }, |
| ] |
| .into(), |
| ..Default::default() |
| }); |
| let _ = parse_facet(&decl).expect_err("this should have failed"); |
| |
| decl.facets = Some(fdata::Dictionary { |
| entries: vec![ |
| fdata::DictionaryEntry { key: "somekey".into(), value: None }, |
| fdata::DictionaryEntry { |
| key: format!("{}.somekey", TEST_FACET), |
| value: Some(fdata::DictionaryValue::Str("some_string".into()).into()), |
| }, |
| fdata::DictionaryEntry { key: TEST_TYPE_FACET_KEY.into(), value: None }, |
| ] |
| .into(), |
| ..Default::default() |
| }); |
| let _ = parse_facet(&decl).expect_err("this should have failed"); |
| } |
| |
| #[test] |
| fn parse_allowed_packages_works() { |
| const TEST_FACET: &str = "fuchsia.test"; |
| |
| let mut decl = fdecl::Component::default(); |
| let facet = parse_facet(&decl).unwrap(); |
| assert_eq!(facet.deprecated_allowed_packages, None); |
| |
| // empty facet |
| decl.facets = Some(fdata::Dictionary { entries: vec![].into(), ..Default::default() }); |
| let facet = parse_facet(&decl).unwrap(); |
| assert_eq!(facet.deprecated_allowed_packages, None); |
| |
| // empty facet |
| decl.facets = Some(fdata::Dictionary { entries: None, ..Default::default() }); |
| let facet = parse_facet(&decl).unwrap(); |
| assert_eq!(facet.deprecated_allowed_packages, None); |
| |
| // make sure that the func can handle some other facet key |
| decl.facets = Some(fdata::Dictionary { |
| entries: vec![fdata::DictionaryEntry { key: "somekey".into(), value: None }].into(), |
| ..Default::default() |
| }); |
| let facet = parse_facet(&decl).unwrap(); |
| assert_eq!(facet.deprecated_allowed_packages, None); |
| |
| // test facet with some other key works |
| decl.facets = Some(fdata::Dictionary { |
| entries: vec![ |
| fdata::DictionaryEntry { key: "somekey".into(), value: None }, |
| fdata::DictionaryEntry { |
| key: format!("{}.somekey", TEST_FACET), |
| value: Some(fdata::DictionaryValue::Str("some_string".into()).into()), |
| }, |
| ] |
| .into(), |
| ..Default::default() |
| }); |
| let facet = parse_facet(&decl).unwrap(); |
| assert_eq!(facet.deprecated_allowed_packages, None); |
| |
| decl.facets = Some(fdata::Dictionary { |
| entries: vec![ |
| fdata::DictionaryEntry { key: "somekey".into(), value: None }, |
| fdata::DictionaryEntry { |
| key: format!("{}.somekey", TEST_FACET), |
| value: Some(fdata::DictionaryValue::Str("some_string".into()).into()), |
| }, |
| fdata::DictionaryEntry { |
| key: TEST_DEPRECATED_ALLOWED_PACKAGES_FACET_KEY.into(), |
| value: Some( |
| fdata::DictionaryValue::StrVec(vec![ |
| "package-one".into(), |
| "package-two".into(), |
| ]) |
| .into(), |
| ), |
| }, |
| ] |
| .into(), |
| ..Default::default() |
| }); |
| let facet = parse_facet(&decl).unwrap(); |
| assert_eq!( |
| facet.deprecated_allowed_packages, |
| Some(vec!["package-one".into(), "package-two".into()]) |
| ); |
| |
| decl.facets = Some(fdata::Dictionary { |
| entries: vec![ |
| fdata::DictionaryEntry { key: "somekey".into(), value: None }, |
| fdata::DictionaryEntry { |
| key: format!("{}.somekey", TEST_FACET), |
| value: Some(fdata::DictionaryValue::Str("some_string".into()).into()), |
| }, |
| fdata::DictionaryEntry { |
| key: TEST_DEPRECATED_ALLOWED_PACKAGES_FACET_KEY.into(), |
| value: Some(fdata::DictionaryValue::StrVec(vec![]).into()), |
| }, |
| ] |
| .into(), |
| ..Default::default() |
| }); |
| let facet = parse_facet(&decl).unwrap(); |
| assert_eq!(facet.deprecated_allowed_packages, Some(vec![])); |
| |
| decl.facets = Some(fdata::Dictionary { |
| entries: vec![ |
| fdata::DictionaryEntry { key: "somekey".into(), value: None }, |
| fdata::DictionaryEntry { |
| key: format!("{}.somekey", TEST_FACET), |
| value: Some(fdata::DictionaryValue::Str("some_string".into()).into()), |
| }, |
| fdata::DictionaryEntry { |
| key: TEST_DEPRECATED_ALLOWED_PACKAGES_FACET_KEY.into(), |
| value: Some( |
| fdata::DictionaryValue::StrVec(vec![ |
| "package-one".into(), |
| "package-two".into(), |
| ]) |
| .into(), |
| ), |
| }, |
| ] |
| .into(), |
| ..Default::default() |
| }); |
| let facet = parse_facet(&decl).unwrap(); |
| assert_eq!( |
| facet.deprecated_allowed_packages, |
| Some(vec!["package-one".into(), "package-two".into()]) |
| ); |
| |
| decl.facets = Some(fdata::Dictionary { |
| entries: vec![fdata::DictionaryEntry { |
| key: TEST_DEPRECATED_ALLOWED_PACKAGES_FACET_KEY.into(), |
| value: Some(fdata::DictionaryValue::Str("something".into()).into()), |
| }] |
| .into(), |
| ..Default::default() |
| }); |
| let _ = parse_facet(&decl).expect_err("this should have failed"); |
| } |
| } |