Skip to main content

fdf_component/testing/
node.rs

1// Copyright 2025 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
5//! This module provides a mock for the driver framework provided Node and NodeController.
6
7use anyhow::Result;
8use fidl::endpoints::ServerEnd;
9use fidl_fuchsia_device_fs as fdf_devfs;
10use fidl_fuchsia_driver_framework as fdf_fidl;
11use fuchsia_async as fasync;
12use fuchsia_sync::Mutex;
13use futures::TryStreamExt;
14use std::collections::HashMap;
15use std::sync::{Arc, Weak};
16use zx;
17
18/// This represents a node in the NodeManage.
19pub type NodeId = usize;
20
21/// The TestNode backs the driver framework provided protocols Node and NodeController.
22struct TestNode {
23    id: NodeId,
24    context: Weak<NodeManager>,
25    name: String,
26    children: HashMap<String, NodeId>,
27    properties: Vec<fdf_fidl::NodeProperty2>,
28    parent: Option<NodeId>,
29    devfs_connector_client: Option<fdf_devfs::ConnectorProxy>,
30    scope: fasync::Scope,
31}
32
33impl TestNode {
34    fn serve_node(&self, server_end: ServerEnd<fdf_fidl::NodeMarker>) {
35        let mut stream = server_end.into_stream();
36        let node_id = self.id;
37        let context = self.context.clone();
38        self.scope.spawn(async move {
39            while let Some(request) = stream.try_next().await.unwrap() {
40                if let fdf_fidl::NodeRequest::AddChild { args, controller, node, responder } =
41                    request
42                {
43                    let name = args.name.as_ref().unwrap();
44                    if let Some(manager) = context.upgrade() {
45                        let _ = manager.new_node(
46                            name,
47                            Some(node_id),
48                            args.properties2,
49                            Some(controller),
50                            node,
51                            args.devfs_args,
52                        );
53                    }
54
55                    let _ = responder.send(Ok(()));
56                }
57            }
58
59            if let Some(manager) = context.upgrade() {
60                manager.remove_node(&node_id);
61            }
62        });
63    }
64
65    fn serve_controller(&self, server_end: ServerEnd<fdf_fidl::NodeControllerMarker>) {
66        let mut stream = server_end.into_stream();
67        let node_id = self.id;
68        let context = self.context.clone();
69        self.scope.spawn(async move {
70            while let Some(request) = stream.try_next().await.unwrap() {
71                match request {
72                    fdf_fidl::NodeControllerRequest::Remove { control_handle: _ } => {
73                        if let Some(manager) = context.upgrade() {
74                            manager.remove_node(&node_id);
75                        }
76                    }
77                    fdf_fidl::NodeControllerRequest::RequestBind { payload: _, responder } => {
78                        let _ = responder.send(Ok(()));
79                    }
80                    _ => (),
81                }
82            }
83        });
84    }
85}
86
87pub(crate) struct NodeManager {
88    nodes: Mutex<HashMap<NodeId, TestNode>>,
89    next_id: Mutex<NodeId>,
90}
91
92/// A handle to nodes running inside the test.
93pub struct NodeHandle {
94    manager: Weak<NodeManager>,
95    id: NodeId,
96}
97
98impl NodeHandle {
99    pub(crate) fn new(manager: Weak<NodeManager>, id: NodeId) -> Self {
100        Self { manager, id }
101    }
102
103    /// Gets the name of the node.
104    pub fn name(&self) -> String {
105        self.manager.upgrade().expect("manager").name(&self.id)
106    }
107
108    /// Gets the children of the node.
109    pub fn children(&self) -> HashMap<String, NodeHandle> {
110        self.manager
111            .upgrade()
112            .expect("manager")
113            .children(&self.id)
114            .into_iter()
115            .map(|(n, id)| (n, NodeHandle::new(self.manager.clone(), id)))
116            .collect()
117    }
118
119    /// Gets the properties of the node.
120    pub fn properties(&self) -> Vec<fdf_fidl::NodeProperty2> {
121        self.manager.upgrade().expect("manager").properties(&self.id)
122    }
123
124    /// Gets the parent of the node.
125    pub fn parent(&self) -> Option<NodeHandle> {
126        self.manager
127            .upgrade()
128            .expect("manager")
129            .parent(&self.id)
130            .map(|id| NodeHandle::new(self.manager.clone(), id))
131    }
132
133    /// Connects to the node's devfs entry.
134    pub async fn connect_to_device(&self) -> Result<zx::Channel, anyhow::Error> {
135        self.manager.upgrade().expect("manager").connect_to_device(self.id).await
136    }
137}
138
139impl NodeManager {
140    pub(crate) fn new() -> Arc<Self> {
141        Arc::new(Self { nodes: Mutex::new(HashMap::new()), next_id: Mutex::new(0) })
142    }
143
144    pub(crate) fn create_root_node(
145        self: &Arc<Self>,
146        node: ServerEnd<fdf_fidl::NodeMarker>,
147    ) -> NodeId {
148        self.new_node("root", None, None, None, Some(node), None)
149    }
150
151    fn new_node(
152        self: &Arc<Self>,
153        name: &str,
154        parent: Option<NodeId>,
155        properties: Option<Vec<fdf_fidl::NodeProperty2>>,
156        controller: Option<ServerEnd<fdf_fidl::NodeControllerMarker>>,
157        node: Option<ServerEnd<fdf_fidl::NodeMarker>>,
158        devfs_args: Option<fdf_fidl::DevfsAddArgs>,
159    ) -> NodeId {
160        let mut next_id = self.next_id.lock();
161        let child_id = *next_id;
162        *next_id += 1;
163        drop(next_id);
164
165        let devfs_connector_client = {
166            if let Some(fdf_fidl::DevfsAddArgs { connector: Some(client), .. }) = devfs_args {
167                Some(client.into_proxy())
168            } else {
169                None
170            }
171        };
172
173        let child_node = TestNode {
174            id: child_id,
175            context: Arc::downgrade(self),
176            name: name.to_string(),
177            children: HashMap::new(),
178            properties: properties.unwrap_or_default(),
179            parent,
180            devfs_connector_client,
181            scope: fasync::Scope::new(),
182        };
183
184        if let Some(parent_id) = parent {
185            let mut nodes = self.nodes.lock();
186            nodes.get_mut(&parent_id).expect("parent").children.insert(name.to_string(), child_id);
187            log::info!("adding child {name} to parent {parent_id}");
188        }
189
190        if let Some(controller) = controller {
191            child_node.serve_controller(controller);
192        }
193
194        if let Some(node) = node {
195            child_node.serve_node(node);
196        }
197
198        self.nodes.lock().insert(child_id, child_node);
199        child_id
200    }
201
202    async fn connect_to_device(&self, node_id: NodeId) -> Result<zx::Channel, anyhow::Error> {
203        let (client_end, server_end) = zx::Channel::create();
204        let nodes = self.nodes.lock();
205        let node = nodes.get(&node_id).expect("node");
206        if let Some(connector) = node.devfs_connector_client.as_ref() {
207            connector.connect(server_end).unwrap();
208            Ok(client_end)
209        } else {
210            Err(anyhow::anyhow!("Devfs connector not found"))
211        }
212    }
213
214    fn children(self: &Arc<Self>, node_id: &NodeId) -> HashMap<String, NodeId> {
215        let nodes = self.nodes.lock();
216        nodes.get(node_id).expect("node").children.clone()
217    }
218
219    fn parent(&self, node_id: &NodeId) -> Option<NodeId> {
220        let nodes = self.nodes.lock();
221        nodes.get(node_id).expect("node").parent
222    }
223
224    fn name(&self, node_id: &NodeId) -> String {
225        let nodes = self.nodes.lock();
226        nodes.get(node_id).expect("node").name.clone()
227    }
228
229    fn properties(&self, node_id: &NodeId) -> Vec<fdf_fidl::NodeProperty2> {
230        let nodes = self.nodes.lock();
231        nodes.get(node_id).expect("node").properties.clone()
232    }
233
234    fn remove_node(self: &Arc<Self>, node_id: &NodeId) {
235        let children = self.children(node_id);
236        for child_id in children.values() {
237            self.remove_node(child_id);
238        }
239
240        if let Some(parent_id) = self.parent(node_id) {
241            let name = self.name(node_id);
242            let mut nodes = self.nodes.lock();
243            nodes.get_mut(&parent_id).expect("parent").children.remove(&name);
244        }
245
246        self.nodes.lock().remove(node_id);
247    }
248}