1use anyhow::{format_err, Error};
6use fidl::endpoints::create_proxy;
7use fidl_fuchsia_inspect::{TreeMarker, TreeNameIteratorMarker, TreeProxy};
8use std::collections::HashMap;
9use std::future::Future;
10use std::pin::Pin;
11use zx::Vmo;
12
13#[derive(Debug)]
16pub struct LazyNode {
17 vmo: Vmo,
18 children: Option<HashMap<String, LazyNode>>,
19}
20
21impl LazyNode {
22 pub fn new(
25 channel: TreeProxy,
26 ) -> Pin<Box<dyn Future<Output = Result<LazyNode, Error>> + Send>> {
27 Box::pin(async move {
28 let fetcher = LazyNodeFetcher::new(channel);
29 let vmo = fetcher.get_vmo().await?;
30 let mut children = HashMap::new();
31 for child_name in fetcher.get_child_names().await?.iter() {
32 let child_channel = fetcher.get_child_tree_channel(child_name).await?;
33 let lazy_node = LazyNode::new(child_channel).await?;
34 children.insert(child_name.to_string(), lazy_node);
35 }
36 Ok(LazyNode { vmo, children: Some(children) })
37 })
38 }
39
40 pub fn vmo(&self) -> &Vmo {
42 &self.vmo
43 }
44
45 pub fn take_children(&mut self) -> Option<HashMap<String, LazyNode>> {
49 self.children.take()
50 }
51}
52
53struct LazyNodeFetcher {
56 channel: TreeProxy,
57}
58
59impl LazyNodeFetcher {
60 fn new(channel: TreeProxy) -> LazyNodeFetcher {
61 LazyNodeFetcher { channel }
62 }
63
64 async fn get_vmo(&self) -> Result<Vmo, Error> {
65 let tree_content = self.channel.get_content().await?;
66 tree_content.buffer.map(|b| b.vmo).ok_or(format_err!("Failed to fetch VMO."))
67 }
68
69 async fn get_child_names(&self) -> Result<Vec<String>, Error> {
70 let (name_iterator, server_end) = create_proxy::<TreeNameIteratorMarker>();
71 self.channel.list_child_names(server_end)?;
72 let mut names = vec![];
73 loop {
74 let subset = name_iterator.get_next().await?;
75 if subset.is_empty() {
76 return Ok(names);
77 }
78 names.extend(subset.into_iter());
79 }
80 }
81
82 async fn get_child_tree_channel(&self, name: &str) -> Result<TreeProxy, Error> {
83 let (child_channel, server_end) = create_proxy::<TreeMarker>();
84 self.channel.open_child(name, server_end)?;
85 Ok(child_channel)
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92 use anyhow::Context;
93 use fidl_fuchsia_inspect::{
94 TreeContent, TreeNameIteratorRequest, TreeNameIteratorRequestStream, TreeRequest,
95 TreeRequestStream,
96 };
97 use fidl_fuchsia_mem::Buffer;
98 use fuchsia_async as fasync;
99 use futures::{TryFutureExt, TryStreamExt};
100 use log::{error, warn};
101 use std::sync::Arc;
102 use zx::{self as zx, HandleBased};
103
104 const MAX_TREE_NAME_LIST_SIZE: usize = 1;
105 const SHARED_VMO: &str = "SHARED";
106 const SINGLE_CHILD_ROOT: &str = "SINGLE_CHILD_ROOT";
107 const NAMED_CHILD_NODE: &str = "NAMED_CHILD_NODE";
108 const NAMED_GRANDCHILD_NODE: &str = "NAMED_GRANDCHILD_NODE";
109 const MULTI_CHILD_ROOT: &str = "MULTI_CHILD_ROOT";
110 const ALL_NODES: [&str; 4] =
111 [SINGLE_CHILD_ROOT, NAMED_CHILD_NODE, NAMED_GRANDCHILD_NODE, MULTI_CHILD_ROOT];
112
113 #[fuchsia::test]
114 async fn complete_vmo_tree_gets_read() -> Result<(), Error> {
115 let vmos = Arc::new(TestVmos::new());
116 let tree = spawn_root_tree_server(SINGLE_CHILD_ROOT, Arc::clone(&vmos))?;
117
118 let root_tree = LazyNode::new(tree).await?;
119 let child_tree = root_tree.children.as_ref().unwrap().get(NAMED_CHILD_NODE).unwrap();
120 let grandchild_tree =
121 child_tree.children.as_ref().unwrap().get(NAMED_GRANDCHILD_NODE).unwrap();
122
123 assert_has_size(root_tree.children.as_ref().unwrap(), 1);
124 assert_has_size(child_tree.children.as_ref().unwrap(), 1);
125 assert_has_size(grandchild_tree.children.as_ref().unwrap(), 0);
126 assert_has_vmo(&vmos, SINGLE_CHILD_ROOT, &root_tree);
127 assert_has_vmo(&vmos, NAMED_CHILD_NODE, child_tree);
128 assert_has_vmo(&vmos, NAMED_GRANDCHILD_NODE, grandchild_tree);
129
130 Ok(())
131 }
132
133 #[fuchsia::test]
134 async fn repeatedly_calls_list_children_until_all_names_are_fetched() -> Result<(), Error> {
135 let vmos = Arc::new(TestVmos::new());
136 let tree = spawn_root_tree_server(MULTI_CHILD_ROOT, Arc::clone(&vmos))?;
137 let mut root_tree = LazyNode::new(tree).await?;
138
139 let children = root_tree.take_children().unwrap();
140
141 assert!(root_tree.children.is_none());
142 assert_has_size(&children, child_names(MULTI_CHILD_ROOT).len());
143 for name in child_names(MULTI_CHILD_ROOT).iter() {
144 assert!(children.contains_key(name));
145 }
146
147 Ok(())
148 }
149
150 fn spawn_root_tree_server(tree_name: &str, vmos: Arc<TestVmos>) -> Result<TreeProxy, Error> {
151 let (tree, request_stream) = fidl::endpoints::create_proxy_and_stream::<TreeMarker>();
152 spawn_tree_server(tree_name.to_string(), vmos, request_stream);
153 Ok(tree)
154 }
155
156 fn spawn_tree_server(name: String, vmos: Arc<TestVmos>, stream: TreeRequestStream) {
157 fasync::Task::spawn(async move {
158 handle_request_stream(name, vmos, stream)
159 .await
160 .unwrap_or_else(|err: Error| error!(err:?; "Couldn't run tree server"));
161 })
162 .detach();
163 }
164
165 async fn handle_request_stream(
166 name: String,
167 vmos: Arc<TestVmos>,
168 mut stream: TreeRequestStream,
169 ) -> Result<(), Error> {
170 while let Some(request) = stream.try_next().await.context("Error running tree server")? {
171 match request {
172 TreeRequest::GetContent { responder } => {
173 let vmo = vmos.get(&name);
174 let size = vmo.get_size()?;
175 let content =
176 TreeContent { buffer: Some(Buffer { vmo, size }), ..Default::default() };
177 responder.send(content)?;
178 }
179 TreeRequest::ListChildNames { tree_iterator, .. } => {
180 let request_stream = tree_iterator.into_stream();
181 spawn_tree_name_iterator_server(child_names(&name), request_stream)
182 }
183 TreeRequest::OpenChild { child_name, tree, .. } => {
184 spawn_tree_server(child_name, Arc::clone(&vmos), tree.into_stream())
185 }
186 TreeRequest::_UnknownMethod { ordinal, method_type, .. } => {
187 warn!(ordinal, method_type:?; "Unknown request");
188 }
189 }
190 }
191 Ok(())
192 }
193
194 fn spawn_tree_name_iterator_server(
195 values: Vec<String>,
196 mut stream: TreeNameIteratorRequestStream,
197 ) {
198 fasync::Task::spawn(
199 async move {
200 let mut values_iter = values.into_iter();
201 while let Some(request) =
202 stream.try_next().await.context("Error running tree iterator server")?
203 {
204 match request {
205 TreeNameIteratorRequest::GetNext { responder } => {
206 let result = values_iter
207 .by_ref()
208 .take(MAX_TREE_NAME_LIST_SIZE)
209 .collect::<Vec<String>>();
210 if result.is_empty() {
211 responder.send(&[])?;
212 return Ok(());
213 }
214 responder.send(&result)?;
215 }
216 TreeNameIteratorRequest::_UnknownMethod {
217 ordinal, method_type, ..
218 } => {
219 warn!(ordinal, method_type:?; "Unknown request");
220 }
221 }
222 }
223 Ok(())
224 }
225 .unwrap_or_else(|err: Error| {
226 error!(err:?; "Failed to running tree name iterator server");
227 }),
228 )
229 .detach()
230 }
231
232 struct TestVmos {
233 vmos: HashMap<String, zx::Vmo>,
234 default: zx::Vmo,
235 }
236
237 impl TestVmos {
238 fn new() -> TestVmos {
239 let mut vmos = HashMap::new();
240 vmos.insert(SHARED_VMO.to_string(), create_vmo(SHARED_VMO));
241 for value in ALL_NODES.iter() {
242 let vmo = create_vmo(value);
243 vmos.insert(value.to_string(), vmo);
244 }
245 TestVmos { vmos, default: create_vmo(SHARED_VMO) }
246 }
247
248 fn get(&self, value: &str) -> zx::Vmo {
249 duplicate_vmo(self.vmos.get(value).unwrap_or(&self.default))
250 }
251 }
252
253 fn assert_has_vmo(vmos: &TestVmos, name: &str, node: &LazyNode) {
254 let actual = get_vmo_as_buf(node.vmo()).unwrap();
255 let expected = get_vmo_as_buf(&vmos.get(name)).unwrap();
256 assert_eq!(actual, expected);
257 }
258
259 fn assert_has_size(map: &HashMap<String, LazyNode>, size: usize) {
260 assert_eq!(map.len(), size);
261 }
262
263 fn get_vmo_as_buf(vmo: &Vmo) -> Result<Vec<u8>, Error> {
264 let size = vmo.get_size()?;
265 let mut buffer = vec![0u8; size as usize];
266 vmo.read(&mut buffer[..], 0)?;
267 Ok(buffer)
268 }
269
270 fn create_vmo(value: &str) -> zx::Vmo {
272 let vmo = zx::Vmo::create(value.len().try_into().unwrap()).unwrap();
273 vmo.write(value.as_bytes(), 0).unwrap();
274 vmo
275 }
276
277 fn duplicate_vmo(vmo: &Vmo) -> Vmo {
278 vmo.duplicate_handle(zx::Rights::BASIC | zx::Rights::READ | zx::Rights::MAP).ok().unwrap()
279 }
280
281 fn child_names(value: &str) -> Vec<String> {
282 match value {
283 SINGLE_CHILD_ROOT => vec![NAMED_CHILD_NODE.to_string()],
284 NAMED_CHILD_NODE => vec![NAMED_GRANDCHILD_NODE.to_string()],
285 MULTI_CHILD_ROOT => vec!["a".to_string(), "b".to_string(), "c".to_string()],
286 _ => vec![],
287 }
288 }
289}