system_update_committer/
reboot.rs1use anyhow::{Context, anyhow};
6use fidl_fuchsia_hardware_power_statecontrol::{
7 AdminProxy as PowerStateControlProxy, ShutdownAction, ShutdownOptions, ShutdownReason,
8};
9use fuchsia_async as fasync;
10use log::error;
11use zx::Status;
12
13pub(super) async fn wait_and_reboot(timer: fasync::Timer, proxy: &PowerStateControlProxy) {
15 let () = timer.await;
16 if let Err(e) = async move {
17 proxy
18 .shutdown(&ShutdownOptions {
19 action: Some(ShutdownAction::Reboot),
20 reasons: Some(vec![ShutdownReason::RetrySystemUpdate]),
21 ..Default::default()
22 })
23 .await
24 .context("while performing reboot call")?
25 .map_err(Status::from_raw)
26 .context("reboot responded with")
27 }
28 .await
29 {
30 error!("error initiating reboot: {:#}", anyhow!(e));
31 }
32}
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37 use fidl_fuchsia_hardware_power_statecontrol::{
38 ShutdownAction, ShutdownOptions, ShutdownReason,
39 };
40 use fuchsia_sync::Mutex;
41 use futures::channel::oneshot;
42 use futures::pin_mut;
43 use futures::task::Poll;
44 use mock_reboot::MockRebootService;
45 use std::sync::Arc;
46 use std::time::Duration;
47
48 #[test]
49 fn test_wait_and_reboot_success() {
50 let mut executor = fasync::TestExecutor::new_with_fake_time();
51
52 let (sender, recv) = oneshot::channel();
54 let sender = Arc::new(Mutex::new(Some(sender)));
55 let mock = Arc::new(MockRebootService::new(Box::new(move |options: ShutdownOptions| {
56 sender.lock().take().unwrap().send(options).unwrap();
57 Ok(())
58 })));
59 let proxy = mock.spawn_reboot_service();
60
61 let timer_duration = 5;
63 let reboot_fut =
64 wait_and_reboot(fasync::Timer::new(Duration::from_secs(timer_duration)), &proxy);
65 pin_mut!(reboot_fut);
66 pin_mut!(recv);
67
68 executor.set_fake_time(fasync::MonotonicInstant::after(
71 Duration::from_secs(timer_duration - 1).into(),
72 ));
73 assert!(!executor.wake_expired_timers());
74 match executor.run_until_stalled(&mut reboot_fut) {
75 Poll::Ready(res) => panic!("future unexpectedly completed with response: {res:?}"),
76 Poll::Pending => {}
77 };
78 match executor.run_until_stalled(&mut recv) {
79 Poll::Ready(res) => panic!("future unexpectedly completed with response: {res:?}"),
80 Poll::Pending => {}
81 };
82
83 executor.set_fake_time(fasync::MonotonicInstant::after(Duration::from_secs(1).into()));
86 assert!(executor.wake_expired_timers());
87 match executor.run_until_stalled(&mut recv) {
88 Poll::Ready(res) => panic!("future unexpectedly completed with response: {res:?}"),
89 Poll::Pending => {}
90 };
91 match executor.run_until_stalled(&mut reboot_fut) {
92 Poll::Ready(_) => {}
93 Poll::Pending => panic!("future unexpectedly pending"),
94 };
95 match executor.run_until_stalled(&mut recv) {
96 Poll::Ready(res) => assert_eq!(
97 res,
98 Ok(ShutdownOptions {
99 action: Some(ShutdownAction::Reboot),
100 reasons: Some(vec![ShutdownReason::RetrySystemUpdate]),
101 ..Default::default()
102 })
103 ),
104 Poll::Pending => panic!("future unexpectedly pending"),
105 };
106 }
107}