test_manager_lib/
facet.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::constants::{HERMETIC_TESTS_COLLECTION, TEST_TYPE_REALM_MAP};
6use crate::error::{FacetError, LaunchTestError};
7use anyhow::format_err;
8use std::sync::Arc;
9use {
10    fidl_fuchsia_component_decl as fdecl, fidl_fuchsia_component_resolution as fresolution,
11    fidl_fuchsia_data as fdata,
12};
13
14const TEST_TYPE_FACET_KEY: &'static str = "fuchsia.test.type";
15pub const TEST_DEPRECATED_ALLOWED_PACKAGES_FACET_KEY: &'static str =
16    "fuchsia.test.deprecated-allowed-packages";
17
18/// Set of facets attached to a test component's manifest that describe how to run it.
19#[derive(Debug)]
20pub(crate) struct SuiteFacets {
21    pub collection: &'static str,
22    pub deprecated_allowed_packages: Option<Vec<String>>,
23}
24
25pub(crate) enum ResolveStatus {
26    Unresolved,
27    Resolved(Result<SuiteFacets, LaunchTestError>),
28}
29
30pub(crate) async fn get_suite_facets(
31    test_url: String,
32    resolver: Arc<fresolution::ResolverProxy>,
33) -> Result<SuiteFacets, LaunchTestError> {
34    let component = resolver
35        .resolve(&test_url)
36        .await
37        .map_err(|e| LaunchTestError::ResolveTest(e.into()))?
38        .map_err(|e| LaunchTestError::ResolveTest(format_err!("{:?}", e)))?;
39    let decl = component.decl.unwrap();
40    let bytes = mem_util::bytes_from_data(&decl).map_err(LaunchTestError::ManifestIo)?;
41    let component_decl: fdecl::Component =
42        fidl::unpersist(&bytes).map_err(|e| LaunchTestError::InvalidManifest(e.into()))?;
43
44    parse_facet(&component_decl).map_err(|e| e.into())
45}
46
47fn parse_facet(decl: &fdecl::Component) -> Result<SuiteFacets, FacetError> {
48    let mut collection = HERMETIC_TESTS_COLLECTION;
49    let mut deprecated_allowed_packages = None;
50    if let Some(obj) = &decl.facets {
51        let entries = obj.entries.as_ref().map(Vec::as_slice).unwrap_or_default();
52        for entry in entries {
53            if entry.key == TEST_TYPE_FACET_KEY {
54                collection = parse_suite_collection(&entry)?;
55            } else if entry.key == TEST_DEPRECATED_ALLOWED_PACKAGES_FACET_KEY {
56                let test_type = entry
57                    .value
58                    .as_ref()
59                    .ok_or(FacetError::NullFacet(TEST_DEPRECATED_ALLOWED_PACKAGES_FACET_KEY))?;
60
61                match test_type.as_ref() {
62                    fdata::DictionaryValue::StrVec(s) => {
63                        deprecated_allowed_packages = Some(s.clone());
64                    }
65                    _ => {
66                        return Err(FacetError::InvalidFacetValue(
67                            TEST_DEPRECATED_ALLOWED_PACKAGES_FACET_KEY,
68                            format!("{:?}", test_type),
69                            "vector of allowed packages names".to_string(),
70                        ));
71                    }
72                }
73            }
74        }
75    }
76    Ok(SuiteFacets { collection, deprecated_allowed_packages })
77}
78
79fn parse_suite_collection(entry: &fdata::DictionaryEntry) -> Result<&'static str, FacetError> {
80    let test_type = entry.value.as_ref().ok_or(FacetError::NullFacet(TEST_TYPE_FACET_KEY))?;
81
82    match test_type.as_ref() {
83        fdata::DictionaryValue::Str(s) => {
84            if TEST_TYPE_REALM_MAP.contains_key(s.as_str()) {
85                return Ok(TEST_TYPE_REALM_MAP[s.as_str()]);
86            }
87            return Err(FacetError::InvalidFacetValue(
88                TEST_TYPE_FACET_KEY,
89                format!("{:?}", s),
90                format!(
91                    "one of {}",
92                    TEST_TYPE_REALM_MAP
93                        .keys()
94                        .map(|k| k.to_string())
95                        .collect::<Vec<_>>()
96                        .join(", ")
97                ),
98            ));
99        }
100        fdata::DictionaryValue::StrVec(s) => {
101            return Err(FacetError::InvalidFacetValue(
102                TEST_TYPE_FACET_KEY,
103                format!("{:?}", s),
104                format!(
105                    "one of {}",
106                    TEST_TYPE_REALM_MAP
107                        .keys()
108                        .map(|k| k.to_string())
109                        .collect::<Vec<_>>()
110                        .join(", ")
111                ),
112            ));
113        }
114        _ => {
115            return Err(FacetError::InvalidFacetValue(
116                TEST_TYPE_FACET_KEY,
117                format!("{:?}", test_type),
118                format!(
119                    "one of {}",
120                    TEST_TYPE_REALM_MAP
121                        .keys()
122                        .map(|k| k.to_string())
123                        .collect::<Vec<_>>()
124                        .join(", ")
125                ),
126            ));
127        }
128    };
129}
130
131#[cfg(test)]
132mod test {
133    use super::*;
134    use crate::constants::{
135        CHROMIUM_TESTS_COLLECTION, SYSTEM_TESTS_COLLECTION, VULKAN_TESTS_COLLECTION,
136    };
137
138    #[test]
139    fn parse_suite_collection_works() {
140        const TEST_FACET: &str = "fuchsia.test";
141
142        // test that default hermetic value is true
143        let mut decl = fdecl::Component::default();
144        assert_eq!(parse_facet(&decl).unwrap().collection, HERMETIC_TESTS_COLLECTION);
145
146        // empty facet
147        decl.facets = Some(fdata::Dictionary { entries: vec![].into(), ..Default::default() });
148        assert_eq!(parse_facet(&decl).unwrap().collection, HERMETIC_TESTS_COLLECTION);
149
150        // empty facet
151        decl.facets = Some(fdata::Dictionary { entries: None, ..Default::default() });
152        assert_eq!(parse_facet(&decl).unwrap().collection, HERMETIC_TESTS_COLLECTION);
153
154        // make sure that the func can handle some other facet key
155        decl.facets = Some(fdata::Dictionary {
156            entries: vec![fdata::DictionaryEntry { key: "somekey".into(), value: None }].into(),
157            ..Default::default()
158        });
159        assert_eq!(parse_facet(&decl).unwrap().collection, HERMETIC_TESTS_COLLECTION);
160
161        // test facet with some other key works
162        decl.facets = Some(fdata::Dictionary {
163            entries: vec![
164                fdata::DictionaryEntry { key: "somekey".into(), value: None },
165                fdata::DictionaryEntry {
166                    key: format!("{}.somekey", TEST_FACET),
167                    value: Some(fdata::DictionaryValue::Str("some_string".into()).into()),
168                },
169            ]
170            .into(),
171            ..Default::default()
172        });
173        assert_eq!(parse_facet(&decl).unwrap().collection, HERMETIC_TESTS_COLLECTION);
174
175        decl.facets = Some(fdata::Dictionary {
176            entries: vec![
177                fdata::DictionaryEntry { key: "somekey".into(), value: None },
178                fdata::DictionaryEntry {
179                    key: format!("{}.somekey", TEST_FACET),
180                    value: Some(fdata::DictionaryValue::Str("some_string".into()).into()),
181                },
182                fdata::DictionaryEntry {
183                    key: TEST_TYPE_FACET_KEY.into(),
184                    value: Some(fdata::DictionaryValue::Str("hermetic".into()).into()),
185                },
186            ]
187            .into(),
188            ..Default::default()
189        });
190        assert_eq!(parse_facet(&decl).unwrap().collection, HERMETIC_TESTS_COLLECTION);
191
192        decl.facets = Some(fdata::Dictionary {
193            entries: vec![
194                fdata::DictionaryEntry { key: "somekey".into(), value: None },
195                fdata::DictionaryEntry {
196                    key: format!("{}.somekey", TEST_FACET),
197                    value: Some(fdata::DictionaryValue::Str("some_string".into()).into()),
198                },
199                fdata::DictionaryEntry {
200                    key: TEST_TYPE_FACET_KEY.into(),
201                    value: Some(fdata::DictionaryValue::Str("system".into()).into()),
202                },
203            ]
204            .into(),
205            ..Default::default()
206        });
207        assert_eq!(parse_facet(&decl).unwrap().collection, SYSTEM_TESTS_COLLECTION);
208
209        decl.facets = Some(fdata::Dictionary {
210            entries: vec![
211                fdata::DictionaryEntry { key: "somekey".into(), value: None },
212                fdata::DictionaryEntry {
213                    key: format!("{}.somekey", TEST_FACET),
214                    value: Some(fdata::DictionaryValue::Str("some_string".into()).into()),
215                },
216                fdata::DictionaryEntry {
217                    key: TEST_TYPE_FACET_KEY.into(),
218                    value: Some(fdata::DictionaryValue::Str("vulkan".into()).into()),
219                },
220            ]
221            .into(),
222            ..Default::default()
223        });
224        assert_eq!(parse_facet(&decl).unwrap().collection, VULKAN_TESTS_COLLECTION);
225
226        decl.facets = Some(fdata::Dictionary {
227            entries: vec![
228                fdata::DictionaryEntry { key: "somekey".into(), value: None },
229                fdata::DictionaryEntry {
230                    key: format!("{}.somekey", TEST_FACET),
231                    value: Some(fdata::DictionaryValue::Str("some_string".into()).into()),
232                },
233                fdata::DictionaryEntry {
234                    key: TEST_TYPE_FACET_KEY.into(),
235                    value: Some(fdata::DictionaryValue::Str("chromium".into()).into()),
236                },
237            ]
238            .into(),
239            ..Default::default()
240        });
241        assert_eq!(parse_facet(&decl).unwrap().collection, CHROMIUM_TESTS_COLLECTION);
242
243        // invalid facets
244        decl.facets = Some(fdata::Dictionary {
245            entries: vec![
246                fdata::DictionaryEntry { key: "somekey".into(), value: None },
247                fdata::DictionaryEntry {
248                    key: format!("{}.somekey", TEST_FACET),
249                    value: Some(fdata::DictionaryValue::Str("some_string".into()).into()),
250                },
251                fdata::DictionaryEntry {
252                    key: TEST_TYPE_FACET_KEY.into(),
253                    value: Some(fdata::DictionaryValue::Str("some_other_collection".into()).into()),
254                },
255            ]
256            .into(),
257            ..Default::default()
258        });
259        let _ = parse_facet(&decl).expect_err("this should have failed");
260
261        decl.facets = Some(fdata::Dictionary {
262            entries: vec![
263                fdata::DictionaryEntry { key: "somekey".into(), value: None },
264                fdata::DictionaryEntry {
265                    key: format!("{}.somekey", TEST_FACET),
266                    value: Some(fdata::DictionaryValue::Str("some_string".into()).into()),
267                },
268                fdata::DictionaryEntry { key: TEST_TYPE_FACET_KEY.into(), value: None },
269            ]
270            .into(),
271            ..Default::default()
272        });
273        let _ = parse_facet(&decl).expect_err("this should have failed");
274    }
275
276    #[test]
277    fn parse_allowed_packages_works() {
278        const TEST_FACET: &str = "fuchsia.test";
279
280        let mut decl = fdecl::Component::default();
281        let facet = parse_facet(&decl).unwrap();
282        assert_eq!(facet.deprecated_allowed_packages, None);
283
284        // empty facet
285        decl.facets = Some(fdata::Dictionary { entries: vec![].into(), ..Default::default() });
286        let facet = parse_facet(&decl).unwrap();
287        assert_eq!(facet.deprecated_allowed_packages, None);
288
289        // empty facet
290        decl.facets = Some(fdata::Dictionary { entries: None, ..Default::default() });
291        let facet = parse_facet(&decl).unwrap();
292        assert_eq!(facet.deprecated_allowed_packages, None);
293
294        // make sure that the func can handle some other facet key
295        decl.facets = Some(fdata::Dictionary {
296            entries: vec![fdata::DictionaryEntry { key: "somekey".into(), value: None }].into(),
297            ..Default::default()
298        });
299        let facet = parse_facet(&decl).unwrap();
300        assert_eq!(facet.deprecated_allowed_packages, None);
301
302        // test facet with some other key works
303        decl.facets = Some(fdata::Dictionary {
304            entries: vec![
305                fdata::DictionaryEntry { key: "somekey".into(), value: None },
306                fdata::DictionaryEntry {
307                    key: format!("{}.somekey", TEST_FACET),
308                    value: Some(fdata::DictionaryValue::Str("some_string".into()).into()),
309                },
310            ]
311            .into(),
312            ..Default::default()
313        });
314        let facet = parse_facet(&decl).unwrap();
315        assert_eq!(facet.deprecated_allowed_packages, None);
316
317        decl.facets = Some(fdata::Dictionary {
318            entries: vec![
319                fdata::DictionaryEntry { key: "somekey".into(), value: None },
320                fdata::DictionaryEntry {
321                    key: format!("{}.somekey", TEST_FACET),
322                    value: Some(fdata::DictionaryValue::Str("some_string".into()).into()),
323                },
324                fdata::DictionaryEntry {
325                    key: TEST_DEPRECATED_ALLOWED_PACKAGES_FACET_KEY.into(),
326                    value: Some(
327                        fdata::DictionaryValue::StrVec(vec![
328                            "package-one".into(),
329                            "package-two".into(),
330                        ])
331                        .into(),
332                    ),
333                },
334            ]
335            .into(),
336            ..Default::default()
337        });
338        let facet = parse_facet(&decl).unwrap();
339        assert_eq!(
340            facet.deprecated_allowed_packages,
341            Some(vec!["package-one".into(), "package-two".into()])
342        );
343
344        decl.facets = Some(fdata::Dictionary {
345            entries: vec![
346                fdata::DictionaryEntry { key: "somekey".into(), value: None },
347                fdata::DictionaryEntry {
348                    key: format!("{}.somekey", TEST_FACET),
349                    value: Some(fdata::DictionaryValue::Str("some_string".into()).into()),
350                },
351                fdata::DictionaryEntry {
352                    key: TEST_DEPRECATED_ALLOWED_PACKAGES_FACET_KEY.into(),
353                    value: Some(fdata::DictionaryValue::StrVec(vec![]).into()),
354                },
355            ]
356            .into(),
357            ..Default::default()
358        });
359        let facet = parse_facet(&decl).unwrap();
360        assert_eq!(facet.deprecated_allowed_packages, Some(vec![]));
361
362        decl.facets = Some(fdata::Dictionary {
363            entries: vec![
364                fdata::DictionaryEntry { key: "somekey".into(), value: None },
365                fdata::DictionaryEntry {
366                    key: format!("{}.somekey", TEST_FACET),
367                    value: Some(fdata::DictionaryValue::Str("some_string".into()).into()),
368                },
369                fdata::DictionaryEntry {
370                    key: TEST_DEPRECATED_ALLOWED_PACKAGES_FACET_KEY.into(),
371                    value: Some(
372                        fdata::DictionaryValue::StrVec(vec![
373                            "package-one".into(),
374                            "package-two".into(),
375                        ])
376                        .into(),
377                    ),
378                },
379            ]
380            .into(),
381            ..Default::default()
382        });
383        let facet = parse_facet(&decl).unwrap();
384        assert_eq!(
385            facet.deprecated_allowed_packages,
386            Some(vec!["package-one".into(), "package-two".into()])
387        );
388
389        decl.facets = Some(fdata::Dictionary {
390            entries: vec![fdata::DictionaryEntry {
391                key: TEST_DEPRECATED_ALLOWED_PACKAGES_FACET_KEY.into(),
392                value: Some(fdata::DictionaryValue::Str("something".into()).into()),
393            }]
394            .into(),
395            ..Default::default()
396        });
397        let _ = parse_facet(&decl).expect_err("this should have failed");
398    }
399}