fdf_component/testing/
dut.rs1use crate::macros::{DriverRegistration, make_driver_registration};
6use crate::testing::get_driver_from_token;
7use crate::testing::harness::TestHarness;
8use crate::testing::node::NodeHandle;
9use crate::{Driver, Incoming};
10use fdf::{
11 AsyncDispatcher, AutoReleaseDispatcher, DispatcherBuilder, OnDispatcher, WeakDispatcher,
12};
13use fdf_env::Environment;
14use fdf_fidl::DriverChannel;
15use fidl_next::{Client as NextClient, ClientDispatcher, ClientEnd as NextClientEnd};
16use fidl_next_fuchsia_driver_framework::{Driver as NextDriver, DriverStartArgs};
17use fuchsia_async as fasync;
18use futures::channel::oneshot;
19use std::marker::PhantomData;
20use std::sync::{Arc, mpsc};
21use zx::Status;
22
23pub struct DriverUnderTest<'a, D> {
25 driver_outgoing: Incoming,
26 driver: Option<fdf_env::Driver<u32>>,
27 dispatcher: AutoReleaseDispatcher,
28 registration: DriverRegistration,
29 token: usize,
30 client: NextClient<NextDriver, DriverChannel>,
31 client_exit_rx: Option<mpsc::Receiver<()>>,
32 started: bool,
33 harness: &'a mut TestHarness<D>,
34 node_id: usize,
35 _d: PhantomData<D>,
36}
37
38impl<D> Drop for DriverUnderTest<'_, D> {
39 fn drop(&mut self) {
40 if !self.started {
41 self.client_exit_rx.take().expect("exit rx").recv().unwrap();
42 }
43 assert!(
44 self.client_exit_rx.is_none(),
45 "DriverUnderTest's stop_driver must be called before letting it go out of scope."
46 );
47
48 let (shutdown_tx, shutdown_rx) = mpsc::channel();
49 let destroy_fn = self.registration.v1.destroy.unwrap();
50 let driver_token = self.token;
51 self.driver.take().expect("driver").shutdown(move |driver_ref| {
52 let driver_value = unsafe { Box::from_raw(driver_ref.0 as *mut u32) };
54 assert_eq!(*driver_value, 0x1337);
55
56 unsafe {
59 destroy_fn(driver_token as *mut _);
60 }
61
62 shutdown_tx.send(()).unwrap();
63 });
64
65 shutdown_rx.recv().unwrap();
66 }
67}
68
69impl<'a, D: Driver> DriverUnderTest<'a, D> {
70 pub(crate) async fn new(
71 harness: &'a mut TestHarness<D>,
72 fdf_env_environment: Arc<Environment>,
73 driver_outgoing: Incoming,
74 node_id: usize,
75 ) -> Self {
76 let driver_value_ptr = Box::into_raw(Box::new(0x1337_u32));
78
79 let driver = fdf_env_environment.new_driver(driver_value_ptr);
80 let dispatcher_builder = DispatcherBuilder::new()
81 .name("driver_under_test")
82 .shutdown_observer(move |dispatcher| {
83 assert!(
86 !fdf_env_environment
87 .dispatcher_has_queued_tasks(dispatcher.as_dispatcher_ref())
88 );
89 });
90
91 let registration = make_driver_registration::<D>();
92 let dispatcher =
93 AutoReleaseDispatcher::from(driver.new_dispatcher(dispatcher_builder).unwrap());
94 let (server_chan, client_chan) = fdf::Channel::<[fidl_next::Chunk]>::create();
95 let channel_handle = server_chan.into_driver_handle().into_raw().get();
96 let (client_exit_tx, client_exit_rx) = mpsc::channel();
97 let (token_tx, token_rx) = oneshot::channel();
98 let initialize_fn = registration.v1.initialize.unwrap();
99 dispatcher
100 .post_task_sync(move |status| {
101 assert_eq!(status, Status::OK);
102 token_tx.send(unsafe { initialize_fn(channel_handle) }.addr()).unwrap();
105 })
106 .unwrap();
107 let token = token_rx.await.unwrap();
108
109 let client_end: NextClientEnd<NextDriver, DriverChannel> =
110 NextClientEnd::from_untyped(DriverChannel::new(client_chan));
111 let client_dispatcher = ClientDispatcher::new(client_end);
112 let client = client_dispatcher.client();
113 WeakDispatcher::from(&dispatcher)
114 .spawn(async move {
115 client_dispatcher.run_client().await.unwrap_err();
119 client_exit_tx.send(()).unwrap();
120 })
121 .unwrap();
122
123 Self {
124 driver_outgoing,
125 driver: Some(driver),
126 dispatcher,
127 registration,
128 token,
129 client,
130 client_exit_rx: Some(client_exit_rx),
131 started: false,
132 harness,
133 node_id,
134 _d: PhantomData,
135 }
136 }
137
138 pub(crate) async fn start_driver(&mut self, start_args: DriverStartArgs) -> Result<(), Status> {
139 let start_result = self.client.start(start_args).await.expect("start call success");
140 match start_result {
141 fidl_next::FlexibleResult::Ok(_) => {
142 self.started = true;
143 Ok(())
144 }
145 fidl_next::FlexibleResult::Err(e) => Err(Status::from_raw(e)),
146 fidl_next::FlexibleResult::FrameworkErr(e) => {
147 log::error!("DriverUnderTest::start failed with framework error: {:?}", e);
148 Err(Status::INTERNAL)
149 }
150 }
151 }
152
153 pub fn driver_outgoing(&self) -> &Incoming {
156 &self.driver_outgoing
157 }
158
159 pub fn get_driver(&self) -> Option<&'_ D> {
161 unsafe {
162 get_driver_from_token(self.token)
164 }
165 }
166
167 pub fn dispatcher(&self) -> WeakDispatcher {
169 WeakDispatcher::from(&self.dispatcher)
170 }
171
172 pub fn node(&self) -> NodeHandle {
174 NodeHandle::new(self.harness.node_manager(), self.node_id)
175 }
176
177 pub fn harness(&self) -> &'_ TestHarness<D> {
179 self.harness
180 }
181
182 pub async fn stop_driver(mut self) {
184 if self.started {
186 let _stop_res = self.client.stop().await;
188 let client_exit_rx = self.client_exit_rx.take().expect("exit rx");
189 fasync::unblock(move || client_exit_rx.recv().unwrap()).await;
190 }
191 }
192}