From bcfc147dbca2e1016991738aa18a97a10b9ccaef Mon Sep 17 00:00:00 2001 From: Daniel Hofstetter Date: Fri, 19 Apr 2024 16:10:09 +0200 Subject: [PATCH] slabtop: add -o/--once --- src/uu/slabtop/src/slabtop.rs | 62 ++++++++++++++++++++--------------- tests/by-util/test_slabtop.rs | 59 ++++++++++++++++++++++++++++++++- 2 files changed, 93 insertions(+), 28 deletions(-) diff --git a/src/uu/slabtop/src/slabtop.rs b/src/uu/slabtop/src/slabtop.rs index 7fb0f09..73c77cc 100644 --- a/src/uu/slabtop/src/slabtop.rs +++ b/src/uu/slabtop/src/slabtop.rs @@ -4,7 +4,7 @@ // file that was distributed with this source code. use crate::parse::SlabInfo; -use clap::{arg, crate_version, Command}; +use clap::{arg, crate_version, ArgAction, Command}; use uucore::{error::UResult, format_usage, help_about, help_usage}; const ABOUT: &str = help_about!("slabtop.md"); @@ -24,12 +24,43 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let slabinfo = SlabInfo::new()?.sort(*sort_flag, false); + if matches.get_flag("once") { + output_header(&slabinfo); + println!(); + output_list(&slabinfo); + } else { + // TODO: implement TUI + output_header(&slabinfo); + println!(); + output_list(&slabinfo); + } + + Ok(()) +} + +fn to_kb(byte: u64) -> f64 { + byte as f64 / 1024.0 +} + +fn percentage(numerator: u64, denominator: u64) -> f64 { + if denominator == 0 { + return 0.0; + } + + let numerator = numerator as f64; + let denominator = denominator as f64; + + (numerator / denominator) * 100.0 +} + +fn output_header(slabinfo: &SlabInfo) { println!( r" Active / Total Objects (% used) : {} / {} ({:.1}%)", slabinfo.total_active_objs(), slabinfo.total_objs(), percentage(slabinfo.total_active_objs(), slabinfo.total_objs()) ); + println!( r" Active / Total Slabs (% used) : {} / {} ({:.1}%)", slabinfo.total_active_slabs(), @@ -58,38 +89,15 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { to_kb(slabinfo.object_avg()), to_kb(slabinfo.object_maximum()) ); +} - // separate header info and slab list - println!(); - - // TODO: TUI Implementation +fn output_list(info: &SlabInfo) { let title = format!( "{:>6} {:>6} {:>4} {:>8} {:>6} {:>8} {:>10} {:<}", "OBJS", "ACTIVE", "USE", "OBJ SIZE", "SLABS", "OBJ/SLAB", "CACHE SIZE", "NAME" ); println!("{}", title); - output(&slabinfo); - - Ok(()) -} - -fn to_kb(byte: u64) -> f64 { - byte as f64 / 1024.0 -} - -fn percentage(numerator: u64, denominator: u64) -> f64 { - if denominator == 0 { - return 0.0; - } - - let numerator = numerator as f64; - let denominator = denominator as f64; - - (numerator / denominator) * 100.0 -} - -fn output(info: &SlabInfo) { for name in info.names() { let objs = info.fetch(name, "num_objs").unwrap_or_default(); let active = info.fetch(name, "active_objs").unwrap_or_default(); @@ -121,7 +129,7 @@ pub fn uu_app() -> Command { .infer_long_args(true) .args([ // arg!(-d --delay "delay updates"), - // arg!(-o --once "only display once, then exit"), + arg!(-o --once "only display once, then exit").action(ArgAction::SetTrue), arg!(-s --sort "specify sort criteria by character (see below)"), ]) .after_help( diff --git a/tests/by-util/test_slabtop.rs b/tests/by-util/test_slabtop.rs index 2576bdc..e287375 100644 --- a/tests/by-util/test_slabtop.rs +++ b/tests/by-util/test_slabtop.rs @@ -3,6 +3,8 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. +#[cfg(target_os = "linux")] +use crate::common::util::run_ucmd_as_root; use crate::common::util::TestScenario; #[test] @@ -11,6 +13,61 @@ fn test_invalid_arg() { } #[test] -fn test_slabtop() { +fn test_help() { new_ucmd!().arg("--help").succeeds().code_is(0); } + +#[cfg(target_os = "linux")] +#[test] +fn test_without_args_as_non_root() { + new_ucmd!() + .fails() + .code_is(1) + .stderr_contains("Permission denied"); +} + +// TODO: tests some temporary behavior; in the future a TUI should be used +// if there are no args +#[cfg(target_os = "linux")] +#[test] +fn test_without_args_as_root() { + let ts = TestScenario::new(util_name!()); + + if let Ok(result) = run_ucmd_as_root(&ts, &[]) { + result + .success() + .stdout_contains("Active / Total Objects") + .stdout_contains("OBJS"); + } else { + print!("Test skipped; requires root user"); + } +} + +#[cfg(target_os = "linux")] +#[test] +fn test_once_as_non_root() { + for arg in ["-o", "--once"] { + new_ucmd!() + .arg(arg) + .fails() + .code_is(1) + .stderr_contains("Permission denied"); + } +} + +#[cfg(target_os = "linux")] +#[test] +fn test_once_as_root() { + let ts = TestScenario::new(util_name!()); + + for arg in ["-o", "--once"] { + if let Ok(result) = run_ucmd_as_root(&ts, &[arg]) { + result + .success() + .stdout_contains("Active / Total Objects") + .stdout_contains("OBJS"); + } else { + print!("Test skipped; requires root user"); + } + } +}