mock_reboot/
lib.rs
1use anyhow::Error;
6use fidl_fuchsia_hardware_power_statecontrol::{
7 AdminPerformRebootResult, AdminProxy, AdminRequest, AdminRequestStream, RebootOptions,
8};
9use fuchsia_async as fasync;
10use futures::{TryFutureExt, TryStreamExt};
11use std::sync::Arc;
12
13pub struct MockRebootService {
14 call_hook: Box<dyn Fn(RebootOptions) -> AdminPerformRebootResult + Send + Sync>,
15}
16
17impl MockRebootService {
18 pub fn new(
22 call_hook: Box<dyn Fn(RebootOptions) -> AdminPerformRebootResult + Send + Sync>,
23 ) -> Self {
24 Self { call_hook }
25 }
26
27 pub async fn run_reboot_service(
30 self: Arc<Self>,
31 mut stream: AdminRequestStream,
32 ) -> Result<(), Error> {
33 while let Some(event) = stream.try_next().await.expect("received request") {
34 match event {
35 AdminRequest::PerformReboot { options, responder } => {
36 let result = (self.call_hook)(options);
37 responder.send(result)?;
38 }
39 _ => {
40 panic!("unhandled RebootService method {event:?}");
41 }
42 }
43 }
44 Ok(())
45 }
46
47 pub fn spawn_reboot_service(self: Arc<Self>) -> AdminProxy {
50 let (proxy, stream) = fidl::endpoints::create_proxy_and_stream::<
51 fidl_fuchsia_hardware_power_statecontrol::AdminMarker,
52 >();
53
54 fasync::Task::spawn(
55 self.run_reboot_service(stream)
56 .unwrap_or_else(|e| panic!("error running reboot service: {e:?}")),
57 )
58 .detach();
59
60 proxy
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67 use fidl_fuchsia_hardware_power_statecontrol::RebootReason2;
68 use fuchsia_async as fasync;
69 use std::sync::atomic::{AtomicU32, Ordering};
70
71 #[fasync::run_singlethreaded(test)]
72 async fn test_mock_reboot() {
73 let reboot_service = Arc::new(MockRebootService::new(Box::new(|_| Ok(()))));
74
75 let reboot_service_clone = Arc::clone(&reboot_service);
76 let proxy = reboot_service_clone.spawn_reboot_service();
77
78 proxy
79 .perform_reboot(&RebootOptions {
80 reasons: Some(vec![RebootReason2::SystemUpdate]),
81 ..Default::default()
82 })
83 .await
84 .expect("made reboot call")
85 .expect("reboot call succeeded");
86 }
87
88 #[fasync::run_singlethreaded(test)]
89 async fn test_mock_reboot_fails() {
90 let reboot_service =
91 Arc::new(MockRebootService::new(Box::new(|_| Err(zx::Status::INTERNAL.into_raw()))));
92
93 let reboot_service_clone = Arc::clone(&reboot_service);
94 let proxy = reboot_service_clone.spawn_reboot_service();
95
96 let reboot_result = proxy
97 .perform_reboot(&RebootOptions {
98 reasons: Some(vec![RebootReason2::SystemUpdate]),
99 ..Default::default()
100 })
101 .await
102 .expect("made reboot call");
103 assert_eq!(reboot_result, Err(zx::Status::INTERNAL.into_raw()));
104 }
105
106 #[fasync::run_singlethreaded(test)]
107 async fn test_mock_reboot_call_hook() {
108 let reboot_service = Arc::new(MockRebootService::new(Box::new(|options| {
109 if let Some(reasons) = options.reasons {
110 match &reasons[..] {
111 [RebootReason2::UserRequest] => Ok(()),
112 _ => Err(zx::Status::NOT_SUPPORTED.into_raw()),
113 }
114 } else {
115 Err(zx::Status::NOT_SUPPORTED.into_raw())
116 }
117 })));
118
119 let reboot_service_clone = Arc::clone(&reboot_service);
120 let proxy = reboot_service_clone.spawn_reboot_service();
121
122 let () = proxy
124 .perform_reboot(&RebootOptions {
125 reasons: Some(vec![RebootReason2::UserRequest]),
126 ..Default::default()
127 })
128 .await
129 .expect("made reboot call")
130 .expect("reboot call succeeded");
131
132 let error_reboot_result = proxy
134 .perform_reboot(&RebootOptions {
135 reasons: Some(vec![RebootReason2::SystemUpdate]),
136 ..Default::default()
137 })
138 .await
139 .expect("made reboot call");
140 assert_eq!(error_reboot_result, Err(zx::Status::NOT_SUPPORTED.into_raw()));
141 }
142
143 #[fasync::run_singlethreaded(test)]
144 async fn test_mock_reboot_with_external_state() {
145 let called = Arc::new(AtomicU32::new(0));
146 let called_clone = Arc::clone(&called);
147 let reboot_service = Arc::new(MockRebootService::new(Box::new(move |_| {
148 called_clone.fetch_add(1, Ordering::SeqCst);
149 Ok(())
150 })));
151
152 let reboot_service_clone = Arc::clone(&reboot_service);
153 let proxy = reboot_service_clone.spawn_reboot_service();
154
155 proxy
156 .perform_reboot(&RebootOptions {
157 reasons: Some(vec![RebootReason2::SystemUpdate]),
158 ..Default::default()
159 })
160 .await
161 .expect("made reboot call")
162 .expect("reboot call succeeded");
163 assert_eq!(called.load(Ordering::SeqCst), 1);
164 }
165}