mock_boot_arguments/
lib.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 fuchsia_hash::Hash;
6use futures::TryStreamExt as _;
7use std::collections::HashMap;
8use std::sync::Arc;
9
10static PKGFS_BOOT_ARG_KEY: &str = "zircon.system.pkgfs.cmd";
11static PKGFS_BOOT_ARG_VALUE_PREFIX: &str = "bin/pkgsvr+";
12
13/// Serves fuchsia.boot/Arguments.GetString from a supplied arguments map.
14/// Panics on unexpected fidl methods.
15/// GetString panics on unexpected keys.
16/// GetStrings returns None for unexpected keys.
17pub struct MockBootArgumentsService {
18    args: HashMap<String, Option<String>>,
19}
20
21impl MockBootArgumentsService {
22    /// Inserts pkgfs boot arg into arguments map using `system_image` hash.
23    pub fn insert_pkgfs_boot_arg(&mut self, system_image: Hash) {
24        let system_image = format!("{PKGFS_BOOT_ARG_VALUE_PREFIX}{system_image}");
25        assert_eq!(self.args.insert(PKGFS_BOOT_ARG_KEY.to_string(), Some(system_image)), None);
26    }
27
28    pub fn new(args: HashMap<String, Option<String>>) -> Self {
29        Self { args }
30    }
31
32    /// Serves fuchsia.boot/Arguments requests on the given request stream.
33    pub async fn handle_request_stream(
34        self: Arc<Self>,
35        mut stream: fidl_fuchsia_boot::ArgumentsRequestStream,
36    ) {
37        while let Some(event) =
38            stream.try_next().await.expect("received fuchsia.boot/Arguments request")
39        {
40            match event {
41                fidl_fuchsia_boot::ArgumentsRequest::GetString { key, responder } => {
42                    if let Some(value) = self.args.get(&key) {
43                        responder.send(value.as_deref()).unwrap();
44                    } else {
45                        panic!("unexpected fuchsia.boot/Arguments.GetString key {key:?}");
46                    }
47                }
48                fidl_fuchsia_boot::ArgumentsRequest::GetStrings { keys, responder } => {
49                    let mut values: Vec<Option<String>> = vec![];
50                    for key in keys {
51                        if let Some(value) = self.args.get(&key) {
52                            values.push(value.clone());
53                        } else {
54                            values.push(None);
55                        }
56                    }
57                    responder
58                        .send(&values)
59                        .expect("Error sending boot_arguments strings response.");
60                }
61                req => {
62                    panic!("unexpected fuchsia.boot/Arguments request {req:?}");
63                }
64            }
65        }
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72    use fuchsia_async as fasync;
73    use maplit::hashmap;
74
75    #[test]
76    fn insert_pkgfs_boot_arg_some() {
77        let mut mock = MockBootArgumentsService::new(HashMap::new());
78        mock.insert_pkgfs_boot_arg(Hash::from([0; 32]));
79        assert_eq!(
80            mock.args,
81            hashmap! {
82                "zircon.system.pkgfs.cmd".to_string() =>
83                Some("bin/pkgsvr+0000000000000000000000000000000000000000000000000000000000000000"
84                    .to_string()
85                )
86            }
87        );
88    }
89
90    #[fasync::run_singlethreaded(test)]
91    async fn get_strings_request() {
92        let mock = Arc::new(MockBootArgumentsService::new(hashmap! {
93            "some-key".to_string() => Some("some-value".to_string()),
94            "some-key-2".to_string() => Some("some-value-2".to_string())
95        }));
96        let (proxy, stream) =
97            fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_boot::ArgumentsMarker>();
98        fasync::Task::spawn(mock.handle_request_stream(stream)).detach();
99
100        let keys = &["some-key".to_string(), "missing-key".to_string(), "some-key-2".to_string()];
101        let values = proxy.get_strings(keys).await.unwrap();
102        assert_eq!(
103            values,
104            vec![Some("some-value".to_string()), None, Some("some-value-2".to_string())]
105        );
106    }
107
108    #[fasync::run_singlethreaded(test)]
109    async fn handle_request_stream() {
110        let mock = Arc::new(MockBootArgumentsService::new(
111            hashmap! {"some-key".to_string() => Some("some-value".to_string())},
112        ));
113        let (proxy, stream) =
114            fidl::endpoints::create_proxy_and_stream::<fidl_fuchsia_boot::ArgumentsMarker>();
115        fasync::Task::spawn(mock.handle_request_stream(stream)).detach();
116
117        let value = proxy.get_string("some-key").await.unwrap();
118
119        assert_eq!(value, Some("some-value".to_string()));
120    }
121}