Skip to main content

driver_tools/subcommands/health_check/
args.rs

1// Copyright 2026 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
5use argh::{ArgsInfo, FromArgs};
6use std::str::FromStr;
7
8#[derive(ArgsInfo, FromArgs, Debug, PartialEq)]
9#[argh(
10    subcommand,
11    name = "health-check",
12    description = "Run an active health check on a bound driver or all bound drivers.",
13    example = "To run a fast health check on the display driver:
14
15    $ driver health-check dev/sys/platform/display --level fast",
16    note = "Condition ages (for example, last observed 1.5s ago) are only computed when the tool runs on the target; from a host ffx the raw boot-timeline nanoseconds are printed instead."
17)]
18pub struct HealthCheckCommand {
19    /// exact component moniker or topological path of the target node.
20    #[argh(positional)]
21    pub moniker: Option<String>,
22
23    /// health check depth level: ping, fast (default), or deep.
24    #[argh(option, short = 'l', long = "level", default = "HealthCheckLevelArg::Fast")]
25    pub level: HealthCheckLevelArg,
26
27    /// run health checks across all bound driver nodes.
28    #[argh(switch, short = 'a', long = "all")]
29    pub all: bool,
30}
31
32/// The depth of a health check, see `fuchsia.driver.framework/HealthCheckRequest`.
33#[derive(Clone, Copy, Debug, PartialEq)]
34pub enum HealthCheckLevelArg {
35    Ping,
36    Fast,
37    Deep,
38}
39
40impl FromStr for HealthCheckLevelArg {
41    type Err = &'static str;
42
43    fn from_str(s: &str) -> Result<Self, Self::Err> {
44        match s.to_lowercase().as_str() {
45            "ping" => Ok(HealthCheckLevelArg::Ping),
46            "fast" => Ok(HealthCheckLevelArg::Fast),
47            "deep" => Ok(HealthCheckLevelArg::Deep),
48            _ => Err("Invalid health check level. Must be 'ping', 'fast', or 'deep'"),
49        }
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn test_parse_args_defaults_and_flags() {
59        let cmd = HealthCheckCommand::from_args(&["health-check"], &["dev/sys/platform/display"])
60            .unwrap();
61        assert_eq!(cmd.moniker.as_deref(), Some("dev/sys/platform/display"));
62        assert_eq!(cmd.level, HealthCheckLevelArg::Fast);
63        assert!(!cmd.all);
64
65        let all_cmd =
66            HealthCheckCommand::from_args(&["health-check"], &["--all", "-l", "deep"]).unwrap();
67        assert_eq!(all_cmd.moniker, None);
68        assert_eq!(all_cmd.level, HealthCheckLevelArg::Deep);
69        assert!(all_cmd.all);
70    }
71
72    #[test]
73    fn test_parse_level() {
74        assert_eq!("ping".parse::<HealthCheckLevelArg>().unwrap(), HealthCheckLevelArg::Ping);
75        assert_eq!("FAST".parse::<HealthCheckLevelArg>().unwrap(), HealthCheckLevelArg::Fast);
76        assert_eq!("Deep".parse::<HealthCheckLevelArg>().unwrap(), HealthCheckLevelArg::Deep);
77        assert!("invalid".parse::<HealthCheckLevelArg>().is_err());
78        assert!(HealthCheckCommand::from_args(&["health-check"], &["--level", "slow"]).is_err());
79    }
80}