Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package mdevctl for openSUSE:Factory checked in at 2022-12-13 18:54:32 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/mdevctl (Old) and /work/SRC/openSUSE:Factory/.mdevctl.new.1835 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "mdevctl" Tue Dec 13 18:54:32 2022 rev:6 rq:1042231 version:1.2.0 Changes: -------- --- /work/SRC/openSUSE:Factory/mdevctl/mdevctl.changes 2022-03-24 22:56:51.668183938 +0100 +++ /work/SRC/openSUSE:Factory/.mdevctl.new.1835/mdevctl.changes 2022-12-13 18:54:34.610918125 +0100 @@ -1,0 +2,11 @@ +Sun Dec 11 18:19:52 UTC 2022 - [email protected] + +- Update to version 1.2.0: + * Port CLI to clap v3 + * start: provide useful hint for parent with wrong case + * tests: Add ability to test error messages + * tests: extract function for checking pass/fail expectations + * MDev::create() does not need to be public + * Fix new clippy warning + +------------------------------------------------------------------- Old: ---- mdevctl-1.1.0.tar.xz vendor.tar.xz New: ---- _servicedata cargo_config mdevctl-1.2.0.tar.xz vendor.tar.zst ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ mdevctl.spec ++++++ --- /var/tmp/diff_new_pack.BdDHoT/_old 2022-12-13 18:54:35.390922288 +0100 +++ /var/tmp/diff_new_pack.BdDHoT/_new 2022-12-13 18:54:35.398922330 +0100 @@ -17,16 +17,18 @@ Name: mdevctl -Version: 1.1.0 +Version: 1.2.0 Release: 0 Summary: Mediated device management and persistence utility License: LGPL-2.1-or-later URL: https://github.com/mdevctl/mdevctl Source0: %{name}-%{version}.tar.xz -Source1: vendor.tar.xz +Source1: vendor.tar.zst +Source2: cargo_config BuildRequires: cargo BuildRequires: python3-docutils BuildRequires: rust +BuildRequires: zstd BuildRequires: pkgconfig(udev) %description ++++++ _service ++++++ --- /var/tmp/diff_new_pack.BdDHoT/_old 2022-12-13 18:54:35.474922736 +0100 +++ /var/tmp/diff_new_pack.BdDHoT/_new 2022-12-13 18:54:35.478922758 +0100 @@ -1,7 +1,7 @@ <services> <service name="tar_scm" mode="disabled"> <param name="filename">mdevctl</param> - <param name="revision">13084d837490f6c0671e2ab9a275cbe3611750c5</param> + <param name="revision">v1.2.0</param> <param name="scm">git</param> <param name="submodules">disable</param> <param name="url">https://github.com/mdevctl/mdevctl</param> @@ -14,5 +14,13 @@ <param name="compression">xz</param> </service> <service name="set_version" mode="disabled"/> + <service name="cargo_vendor" mode="disabled"> + <param name="srcdir">mdevctl-1.2.0</param> + <param name="compression">zst</param> + <param name="update">true</param> + </service> + <service name="cargo_audit" mode="disabled"> + <param name="srcdir">mdevctl-1.2.0</param> + </service> </services> ++++++ _servicedata ++++++ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/mdevctl/mdevctl</param> <param name="changesrevision">ec4b9a04ce15ad7dccef2dc99b20a53987eb16bc</param></service></servicedata> (No newline at EOF) ++++++ cargo_config ++++++ [source.crates-io] replace-with = "vendored-sources" [source.vendored-sources] directory = "vendor" (No newline at EOF) ++++++ mdevctl-1.1.0.tar.xz -> mdevctl-1.2.0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mdevctl-1.1.0/.gitignore new/mdevctl-1.2.0/.gitignore --- old/mdevctl-1.1.0/.gitignore 1970-01-01 01:00:00.000000000 +0100 +++ new/mdevctl-1.2.0/.gitignore 2022-08-05 18:01:16.000000000 +0200 @@ -0,0 +1,7 @@ +/target +*.sw? +Cargo.lock +Makefile +mdevctl.spec +/vendor/ +/*.rpm diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mdevctl-1.1.0/Cargo.toml new/mdevctl-1.2.0/Cargo.toml --- old/mdevctl-1.1.0/Cargo.toml 2022-02-28 18:10:22.000000000 +0100 +++ new/mdevctl-1.2.0/Cargo.toml 2022-08-05 18:01:16.000000000 +0200 @@ -1,7 +1,7 @@ [package] name = "mdevctl" # For now, just bump the y version on release (x.y.z) -version = "1.1.0" +version = "1.2.0" authors = ["Jonathon Jongsma <[email protected]>"] edition = "2018" license = "LGPL-2.1" @@ -13,13 +13,14 @@ [dependencies] anyhow = "1.0" +clap = { version = "3.1.18", features = ["derive"]} env_logger = "0.8.3" log = "0.4" serde_json = {version = "1.0", features = ["preserve_order"]} -structopt = "0.3.13" uuid = {version = "0.8.2", features = ["v4"]} tempfile = "3" [build-dependencies] -structopt = "0.3.13" +clap = { version = "3.1.18", features = ["derive"]} +clap_complete = "3.0.6" uuid = "0.8.2" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mdevctl-1.1.0/build.rs new/mdevctl-1.2.0/build.rs --- old/mdevctl-1.1.0/build.rs 2022-02-28 18:10:22.000000000 +0100 +++ new/mdevctl-1.2.0/build.rs 2022-08-05 18:01:16.000000000 +0200 @@ -1,9 +1,9 @@ +use clap::CommandFactory; +use clap_complete::{generate_to, Shell}; use std::env; use std::fs; use std::path::{Path, PathBuf}; use std::process::Command; -use structopt::clap::Shell; -use structopt::StructOpt; #[path = "src/cli.rs"] mod cli; @@ -44,13 +44,18 @@ .expect("Unable to generate manpage. Is 'rst2man' installed? You can specify a custom 'rst2man' executable by setting the RST2MAN environment variable."); } +fn generate_completion(cmd: &mut clap::Command, outdir: &PathBuf) { + let name = cmd.get_name().to_string(); + generate_to(Shell::Bash, cmd, name, outdir).expect("Unable to generate shell completion files"); +} + fn main() { let outdir = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR environment variable not defined")); // generate bash completions for both executables - cli::MdevctlCommands::clap().gen_completions("mdevctl", Shell::Bash, &outdir); - cli::LsmdevOptions::clap().gen_completions("lsmdev", Shell::Bash, &outdir); + generate_completion(&mut cli::MdevctlCommands::command(), &outdir); + generate_completion(&mut cli::LsmdevOptions::command(), &outdir); // generate manpage generate_manpage(outdir); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mdevctl-1.1.0/mdevctl.rst new/mdevctl-1.2.0/mdevctl.rst --- old/mdevctl-1.1.0/mdevctl.rst 2022-02-28 18:10:22.000000000 +0100 +++ new/mdevctl-1.2.0/mdevctl.rst 2022-08-05 18:01:16.000000000 +0200 @@ -63,7 +63,8 @@ for the ``modify`` command. ``-p|--parent=PARENT`` - Specify or identify the device by its parent device. + Specify or identify the device by its parent device. Note that the parent + device is specified by its kernel sysfs name and is case-sensitive. ``-t|--type=TYPE`` Specify or identify the device by its type. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mdevctl-1.1.0/src/cli.rs new/mdevctl-1.2.0/src/cli.rs --- old/mdevctl-1.1.0/src/cli.rs 2022-02-28 18:10:22.000000000 +0100 +++ new/mdevctl-1.2.0/src/cli.rs 2022-08-05 18:01:16.000000000 +0200 @@ -1,21 +1,21 @@ //! Command line options for mdevctl +pub use clap::Parser; use std::path::PathBuf; -pub use structopt::StructOpt; use uuid::Uuid; -#[derive(StructOpt, Debug)] -#[structopt(about = "List mediated devices")] +#[derive(Parser, Debug)] +#[clap(version, about = "List mediated devices", name = "lsmdev")] pub struct LsmdevOptions { - #[structopt(short, long, help = "Show defined devices")] + #[clap(short, long, help = "Show defined devices")] pub defined: bool, - #[structopt(long, help = "Output device list in json format")] + #[clap(long, help = "Output device list in json format")] pub dumpjson: bool, - #[structopt(short, long, help = "Print additional information about the devices")] + #[clap(short, long, help = "Print additional information about the devices")] pub verbose: bool, - #[structopt(short, long, help = "List devices matching the specified UUID")] + #[clap(short, long, help = "List devices matching the specified UUID")] pub uuid: Option<Uuid>, - #[structopt( + #[clap( short, long, help = "List devices associated with the specified Parent device" @@ -24,16 +24,10 @@ } // command-line argument definitions. -#[derive(StructOpt)] -#[structopt( - about = "A mediated device management utility for Linux", - global_settings = &[ - structopt::clap::AppSettings::VersionlessSubcommands, - structopt::clap::AppSettings::UnifiedHelpMessage, - ] -)] +#[derive(Parser)] +#[clap(version, about = "A mediated device management utility for Linux")] pub enum MdevctlCommands { - #[structopt( + #[clap( about = "Define a persistent mediated device", long_about = "Define a persistent mediated device\n\n\ If the device specified by the UUID currently exists, 'parent' and 'type' may be \ @@ -43,34 +37,34 @@ Running devices are unaffected by this command." )] Define { - #[structopt( + #[clap( short, long, - required_unless("parent"), + required_unless_present("parent"), help = "Assign UUID to the device" )] uuid: Option<Uuid>, - #[structopt( + #[clap( short, long, help = "Automatically start device on parent availability" )] auto: bool, - #[structopt( + #[clap( short, long, - required_unless("uuid"), + required_unless_present("uuid"), help = "Specify the parent of the device" )] parent: Option<String>, - #[structopt( + #[clap( name = "type", short, long, help = "Specify the mdev type of the device" )] mdev_type: Option<String>, - #[structopt( + #[clap( long, parse(from_os_str), conflicts_with_all(&["type", "auto"]), help = "Specify device details in JSON format" @@ -78,7 +72,7 @@ jsonfile: Option<PathBuf>, }, - #[structopt( + #[clap( about = "Undefine a persistent mediated device", long_about = "Undefine, or remove a config for an mdev device\n\n\ If a UUID exists for multiple parents, all will be removed unless a parent is @@ -86,13 +80,13 @@ Running devices are unaffected by this command." )] Undefine { - #[structopt(short, long, help = "UUID of the device to be undefined")] + #[clap(short, long, help = "UUID of the device to be undefined")] uuid: Uuid, - #[structopt(short, long, help = "Parent of the device to be undefined")] + #[clap(short, long, help = "Parent of the device to be undefined")] parent: Option<String>, }, - #[structopt( + #[clap( about = "Modify the definition of a mediated device", long_about = "Modify the definition of a mediated device\n\n\ The 'parent' option further identifies a UUID if it is not unique. The parent for a \ @@ -107,18 +101,18 @@ Running devices are unaffected by this command." )] Modify { - #[structopt(short, long, help = "UUID of the mdev to modify")] + #[clap(short, long, help = "UUID of the mdev to modify")] uuid: Uuid, - #[structopt(short, long, help = "Parent of the mdev to modify")] + #[clap(short, long, help = "Parent of the mdev to modify")] parent: Option<String>, - #[structopt( + #[clap( name = "type", short, long, help = "Modify the mdev type for this device" )] mdev_type: Option<String>, - #[structopt( + #[clap( long, conflicts_with("delattr"), requires("value"), @@ -126,19 +120,19 @@ value_name = "attr_name" )] addattr: Option<String>, - #[structopt(long, help = "Delete an attribute")] + #[clap(long, help = "Delete an attribute")] delattr: bool, - #[structopt(long, short, help = "Index of the attribute to modify")] + #[clap(long, short, help = "Index of the attribute to modify")] index: Option<u32>, - #[structopt( + #[clap( long, help = "Value for the attribute specified by --addattr", value_name = "attr_value" )] value: Option<String>, - #[structopt(short, long, help = "Device will be started automatically")] + #[clap(short, long, help = "Device will be started automatically")] auto: bool, - #[structopt( + #[clap( short, long, conflicts_with("auto"), @@ -146,7 +140,7 @@ )] manual: bool, }, - #[structopt( + #[clap( about = "Start a mediated device", long_about = "Start a mediated device\n\n\ If the UUID is previously defined and unique, the UUID is sufficient to start the \ @@ -159,23 +153,23 @@ attributes to be applied to the started device." )] Start { - #[structopt( + #[clap( short, long, - required_unless("parent"), + required_unless_present("parent"), help = "UUID of the device to start" )] uuid: Option<Uuid>, - #[structopt( + #[clap( short, long, - required_unless("uuid"), + required_unless_present("uuid"), help = "Parent of the device to start" )] parent: Option<String>, - #[structopt(name = "type", short, long, help = "Mdev type of the device to start")] + #[clap(name = "type", short, long, help = "Mdev type of the device to start")] mdev_type: Option<String>, - #[structopt( + #[clap( long, parse(from_os_str), conflicts_with("type"), @@ -183,12 +177,12 @@ )] jsonfile: Option<PathBuf>, }, - #[structopt(about = "Stop a mediated device")] + #[clap(about = "Stop a mediated device")] Stop { - #[structopt(short, long, help = "UUID of the device to stop")] + #[clap(short, long, help = "UUID of the device to stop")] uuid: Uuid, }, - #[structopt( + #[clap( about = "List mediated devices", long_about = "List mediated devices\n\n\ With no options, information about the currently running mediated devices is \ @@ -202,18 +196,18 @@ include attributes for the device(s)." )] List(LsmdevOptions), - #[structopt( + #[clap( about = "List available mediated device types", long_about = "List available mediated device types\n\n\ Specifying a 'parent' lists only the types provided by the given parent device. \ The 'dumpjson' option provides output in machine readable JSON format." )] Types { - #[structopt(short, long, help = "Show supported types for the specified parent")] + #[clap(short, long, help = "Show supported types for the specified parent")] parent: Option<String>, - #[structopt(long, help = "Output mdev types list in JSON format")] + #[clap(long, help = "Output mdev types list in JSON format")] dumpjson: bool, }, - #[structopt(setting = structopt::clap::AppSettings::Hidden)] + #[clap(hide = true)] StartParentMdevs { parent: String }, } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mdevctl-1.1.0/src/main.rs new/mdevctl-1.2.0/src/main.rs --- old/mdevctl-1.1.0/src/main.rs 2022-02-28 18:10:22.000000000 +0100 +++ new/mdevctl-1.2.0/src/main.rs 2022-08-05 18:01:16.000000000 +0200 @@ -6,6 +6,7 @@ //! See `mdevctl help` or the manpage for more information. use anyhow::{anyhow, ensure, Context, Result}; +use clap::Parser; use log::{debug, warn}; use std::cmp::Ordering; use std::collections::BTreeMap; @@ -13,7 +14,6 @@ use std::io::Read; use std::path::PathBuf; use std::vec::Vec; -use structopt::StructOpt; use uuid::Uuid; use crate::callouts::*; @@ -625,7 +625,7 @@ if path.exists() { t.description = fs::read_to_string(&path)? .trim() - .replace("\n", ", ") + .replace('\n', ", ") .to_string(); } @@ -737,7 +737,7 @@ match exe.to_str() { Some(val) if val.ends_with("lsmdev") => { debug!("running as 'lsmdev'"); - let opts = LsmdevOptions::from_args(); + let opts = LsmdevOptions::parse(); list_command( &env, opts.defined, @@ -747,7 +747,7 @@ opts.parent, ) } - _ => match MdevctlCommands::from_args() { + _ => match MdevctlCommands::parse() { MdevctlCommands::Define { uuid, auto, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mdevctl-1.1.0/src/mdev.rs new/mdevctl-1.2.0/src/mdev.rs --- old/mdevctl-1.1.0/src/mdev.rs 2022-02-28 18:10:22.000000000 +0100 +++ new/mdevctl-1.2.0/src/mdev.rs 2022-08-05 18:01:16.000000000 +0200 @@ -287,7 +287,31 @@ } } - pub fn create(&mut self) -> Result<()> { + fn find_parent_dir(&self) -> Result<PathBuf> { + let parent = self.parent()?; + let path: PathBuf = self.env.parent_base().join(&parent); + + if path.is_dir() { + return Ok(path); + } + + // check if there's a similar parent dir with different capitalization + let parentsdir = self.env.parent_base().read_dir()?; + for subdir in parentsdir { + let dir = subdir?; + let parentname = dir.file_name(); + if parentname.to_string_lossy().to_lowercase() == parent.to_lowercase() { + return Err(anyhow!( + "Unable to find parent device '{}'. Did you mean '{}'?", + parent, + parentname.to_string_lossy() + )); + } + } + Err(anyhow!("Unable to find parent device '{}'", parent)) + } + + fn create(&mut self) -> Result<()> { debug!("Creating mdev {:?}", self.uuid); let parent = self.parent()?; let mdev_type = self.mdev_type()?; @@ -303,11 +327,8 @@ return Err(anyhow!("Device already exists")); } - let mut path: PathBuf = self - .env - .parent_base() - .join(&parent) - .join("mdev_supported_types"); + let mut path = self.find_parent_dir()?; + path.push("mdev_supported_types"); debug!("Checking parent for mdev support: {:?}", path); if !path.is_dir() { return Err(anyhow!( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mdevctl-1.1.0/src/tests.rs new/mdevctl-1.2.0/src/tests.rs --- old/mdevctl-1.1.0/src/tests.rs 2022-02-28 18:10:22.000000000 +0100 +++ new/mdevctl-1.2.0/src/tests.rs 2022-08-05 18:01:16.000000000 +0200 @@ -1,4 +1,4 @@ -use anyhow::Result; +use anyhow::{anyhow, Result}; use log::info; use std::collections::BTreeMap; use std::env; @@ -19,10 +19,23 @@ let _ = logger().is_test(true).try_init(); } -#[derive(PartialEq)] -enum Expect { +fn assert_result<T: std::fmt::Debug>(res: Result<T>, expect: Expect, testname: &str) -> Result<T> { + match expect { + Expect::Fail(msg) => { + let e = res.expect_err(format!("Expected {} to fail", testname).as_str()); + if let Some(msg) = msg { + assert_eq!(msg, e.to_string()); + } + Err(anyhow!(e)) + } + Expect::Pass => Ok(res.expect(format!("Expected {} to pass", testname).as_str())), + } +} + +#[derive(PartialEq, Clone, Copy)] +enum Expect<'a> { Pass, - Fail, + Fail(Option<&'a str>), } #[derive(Debug)] @@ -192,19 +205,14 @@ let test = TestEnvironment::new("load-json", uuid); let res = test.load_from_json(uuid, parent, &format!("{}.in", uuid)); - if expect == Expect::Fail { - info!("{:?}", res); - res.expect_err("Expected command to fail"); - return; + if let Ok(dev) = assert_result(res, expect, "load-json") { + let jsonval = dev.to_json(false).unwrap(); + let jsonstr = serde_json::to_string_pretty(&jsonval).unwrap(); + + test.compare_to_file(&format!("{}.out", uuid), &jsonstr); + assert_eq!(uuid, dev.uuid.to_hyphenated().to_string()); + assert_eq!(Some(parent.to_string()), dev.parent); } - - let dev = res.expect("Command failed unexpectedly"); - let jsonval = dev.to_json(false).unwrap(); - let jsonstr = serde_json::to_string_pretty(&jsonval).unwrap(); - - test.compare_to_file(&format!("{}.out", uuid), &jsonstr); - assert_eq!(uuid, dev.uuid.to_hyphenated().to_string()); - assert_eq!(Some(parent.to_string()), dev.parent); } #[test] @@ -235,19 +243,19 @@ test_load_json_helper( "b6f7e33f-ea28-4f9d-8c42-797ff0ec2888", "0000:00:03.0", - Expect::Fail, + Expect::Fail(None), ); // json file has malformed attributes - an array of strings test_load_json_helper( "fe7a39db-973b-47b4-9b77-1d7b97267d59", "0000:00:03.0", - Expect::Fail, + Expect::Fail(None), ); // json file has malformed attributes - no array test_load_json_helper( "37ccb149-a0ce-49e3-8391-a952ef07bdc2", "0000:00:03.0", - Expect::Fail, + Expect::Fail(None), ); } @@ -267,12 +275,7 @@ use crate::define_command; let res = define_command(&test, uuid, false, parent, mdev_type, None); - if expect == Expect::Fail { - res.expect_err("expected callout to fail"); - return; - } - - assert!(res.is_ok()); + let _ = assert_result(res, expect, "define callout"); } fn test_define_helper<F>( @@ -298,20 +301,16 @@ setupfn(&test); - let def = define_command_helper(&test, uuid, auto, parent, mdev_type, jsonfile); - if expect == Expect::Fail { - def.expect_err("expected define command to fail"); - return; + let res = define_command_helper(&test, uuid, auto, parent, mdev_type, jsonfile); + if let Ok(def) = assert_result(res, expect, "define command") { + let path = def.persist_path().unwrap(); + assert!(!path.exists()); + def.define().expect("Failed to define device"); + assert!(path.exists()); + assert!(def.is_defined()); + let filecontents = fs::read_to_string(&path).unwrap(); + test.compare_to_file(&format!("{}.expected", testname), &filecontents); } - - let def = def.expect("define command failed unexpectedly"); - let path = def.persist_path().unwrap(); - assert!(!path.exists()); - def.define().expect("Failed to define device"); - assert!(path.exists()); - assert!(def.is_defined()); - let filecontents = fs::read_to_string(&path).unwrap(); - test.compare_to_file(&format!("{}.expected", testname), &filecontents); } #[test] @@ -322,7 +321,7 @@ const DEFAULT_PARENT: &str = "0000:00:03.0"; test_define_helper( "no-uuid-no-type", - Expect::Fail, + Expect::Fail(None), None, true, Some(DEFAULT_PARENT.to_string()), @@ -366,7 +365,7 @@ // invalid to specify an separate mdev_type if defining via jsonfile test_define_helper( "jsonfile-type", - Expect::Fail, + Expect::Fail(None), Uuid::parse_str(DEFAULT_UUID).ok(), false, Some(DEFAULT_PARENT.to_string()), @@ -388,7 +387,7 @@ // If uuid is already active, specifying mdev_type will result in an error test_define_helper( "uuid-running-no-parent", - Expect::Fail, + Expect::Fail(None), Uuid::parse_str(DEFAULT_UUID).ok(), false, None, @@ -442,7 +441,7 @@ // defining a device that is already defined should result in an error test_define_helper( "uuid-already-defined", - Expect::Fail, + Expect::Fail(None), Uuid::parse_str(DEFAULT_UUID).ok(), false, Some(DEFAULT_PARENT.to_string()), @@ -466,7 +465,7 @@ ); test_define_command_callout( "define-with-callout-all-fail", - Expect::Fail, + Expect::Fail(None), Uuid::parse_str(DEFAULT_UUID).ok(), Some(DEFAULT_PARENT.to_string()), Some("i915-GVTg_V5_4".to_string()), @@ -488,7 +487,7 @@ ); test_define_command_callout( "define-with-callout-all-bad-json", - Expect::Fail, + Expect::Fail(None), Uuid::parse_str(DEFAULT_UUID).ok(), Some(DEFAULT_PARENT.to_string()), Some("i915-GVTg_V5_4".to_string()), @@ -531,13 +530,10 @@ auto, manual, ); - if expect == Expect::Fail { - assert!(result.is_err()); + if assert_result(result, expect, "modify command").is_err() { return; } - result.expect("Modify command failed unexpectedly"); - let def = crate::get_defined_device(&test, uuid, parent.as_ref()) .expect("Couldn't find defined device"); let path = def.persist_path().unwrap(); @@ -555,7 +551,7 @@ const PARENT: &str = "0000:00:03.0"; test_modify_helper( "device-not-defined", - Expect::Fail, + Expect::Fail(None), UUID, None, None, @@ -681,7 +677,7 @@ ); test_modify_helper( "multiple-noparent", - Expect::Fail, + Expect::Fail(None), UUID, None, None, @@ -715,7 +711,7 @@ ); test_modify_helper( "auto-manual", - Expect::Fail, + Expect::Fail(None), UUID, Some(PARENT.to_string()), None, @@ -744,13 +740,10 @@ let result = crate::undefine_command(&test, uuid, parent.clone()); - if expect == Expect::Fail { - result.expect_err("undefine command should have failed"); + if assert_result(result, expect, "undefine command").is_err() { return; } - result.expect("undefine command should have succeeded"); - let devs = crate::defined_devices(&test, Some(&uuid), parent.as_ref()) .expect("failed to query defined devices"); assert!(devs.is_empty()); @@ -793,7 +786,7 @@ }); test_undefine_helper( "nonexistent", - Expect::Fail, + Expect::Fail(None), UUID, Some(PARENT.to_string()), |_| {}, @@ -815,13 +808,7 @@ use crate::start_command; let res = start_command(&test, uuid, parent, mdev_type, None); - - if expect == Expect::Fail { - res.expect_err("expected callout to fail"); - return; - } - - assert!(res.is_ok()); + let _ = assert_result(res, expect, "start callout"); } fn test_start_helper<F>( @@ -840,33 +827,27 @@ setupfn(&test); let uuid = uuid.map(|s| Uuid::parse_str(s.as_ref()).unwrap()); - let dev = crate::start_command_helper(&test, uuid, parent, mdev_type, jsonfile); + let result = crate::start_command_helper(&test, uuid, parent, mdev_type, jsonfile); - if expect_setup == Expect::Fail { - dev.expect_err("start command should have failed"); - return; - } - let mut dev = dev.expect("Couldn't run start command"); - - let result = dev.start(); - if expect_execute == Expect::Fail { - result.expect_err("start command should have failed"); - return; - } - result.expect("Couldn't start the device"); + if let Ok(mut dev) = assert_result(result, expect_setup, "start command setup") { + let result = dev.start(); + if assert_result(result, expect_execute, "start command").is_err() { + return; + } - let create_path = test - .parent_base() - .join(dev.parent.unwrap()) - .join("mdev_supported_types") - .join(dev.mdev_type.unwrap()) - .join("create"); - assert!(create_path.exists()); - if uuid.is_some() { - assert_eq!(uuid.unwrap(), dev.uuid); + let create_path = test + .parent_base() + .join(dev.parent.unwrap()) + .join("mdev_supported_types") + .join(dev.mdev_type.unwrap()) + .join("create"); + assert!(create_path.exists()); + if uuid.is_some() { + assert_eq!(uuid.unwrap(), dev.uuid); + } + let contents = fs::read_to_string(create_path).expect("Unable to read 'create' file"); + assert_eq!(dev.uuid.to_hyphenated().to_string(), contents); } - let contents = fs::read_to_string(create_path).expect("Unable to read 'create' file"); - assert_eq!(dev.uuid.to_hyphenated().to_string(), contents); } #[test] @@ -876,6 +857,7 @@ const UUID: &str = "976d8cc2-4bfc-43b9-b9f9-f4af2de91ab9"; const PARENT: &str = "0000:00:03.0"; const PARENT2: &str = "0000:00:02.0"; + const PARENT3: &str = "0000:2b:00.0"; const MDEV_TYPE: &str = "arbitrary_type"; test_start_helper( @@ -904,8 +886,8 @@ ); test_start_helper( "no-uuid-no-parent", - Expect::Fail, - Expect::Fail, + Expect::Fail(None), + Expect::Fail(None), None, None, Some(MDEV_TYPE.to_string()), @@ -916,8 +898,8 @@ ); test_start_helper( "no-uuid-no-type", - Expect::Fail, - Expect::Fail, + Expect::Fail(None), + Expect::Fail(None), None, Some(PARENT.to_string()), None, @@ -928,8 +910,8 @@ ); test_start_helper( "no-parent", - Expect::Fail, - Expect::Fail, + Expect::Fail(None), + Expect::Fail(None), Some(UUID.to_string()), None, Some(MDEV_TYPE.to_string()), @@ -939,8 +921,8 @@ // should fail if there is no defined device with the given uuid test_start_helper( "no-type", - Expect::Fail, - Expect::Fail, + Expect::Fail(None), + Expect::Fail(None), Some(UUID.to_string()), Some(PARENT.to_string()), None, @@ -992,8 +974,8 @@ // if there are multiple defined devices with the same UUID, must disambiguate with parent test_start_helper( "defined-multiple-underspecified", - Expect::Fail, - Expect::Fail, + Expect::Fail(None), + Expect::Fail(None), Some(UUID.to_string()), None, None, @@ -1024,8 +1006,8 @@ // type. See https://github.com/mdevctl/mdevctl/issues/38 test_start_helper( "defined-diff-type", - Expect::Fail, - Expect::Fail, + Expect::Fail(None), + Expect::Fail(None), Some(UUID.to_string()), Some(PARENT.to_string()), Some("wrong-type".to_string()), @@ -1038,7 +1020,7 @@ test_start_helper( "already-running", Expect::Pass, - Expect::Fail, + Expect::Fail(None), Some(UUID.to_string()), Some(PARENT.to_string()), Some(MDEV_TYPE.to_string()), @@ -1051,7 +1033,7 @@ test_start_helper( "no-instances", Expect::Pass, - Expect::Fail, + Expect::Fail(None), Some(UUID.to_string()), Some(PARENT.to_string()), Some(MDEV_TYPE.to_string()), @@ -1090,7 +1072,7 @@ ); test_start_command_callout( "defined-multiple", - Expect::Fail, + Expect::Fail(None), Uuid::parse_str(UUID).ok(), Some(PARENT.to_string()), Some(MDEV_TYPE.to_string()), @@ -1102,6 +1084,37 @@ test.populate_callout_script("rc1.sh"); }, ); + test_start_helper( + "missing-parent", + Expect::Pass, + Expect::Fail(Some( + format!("Unable to find parent device '{}'", PARENT).as_str(), + )), + Some(UUID.to_string()), + Some(PARENT.to_string()), + Some(MDEV_TYPE.to_string()), + None, + |_| {}, + ); + test_start_helper( + "parent-case", + Expect::Pass, + Expect::Fail(Some( + format!( + "Unable to find parent device '{}'. Did you mean '{}'?", + PARENT3.to_string().to_uppercase(), + PARENT3.to_string() + ) + .as_str(), + )), + Some(UUID.to_string()), + Some(PARENT3.to_string().to_uppercase()), + Some(MDEV_TYPE.to_string()), + None, + |test| { + test.populate_parent_device(PARENT3, MDEV_TYPE, 1, "vfio-pci", "test device", None); + }, + ); // TODO: test attributes -- difficult because executing the 'start' command by writing to // the 'create' file in sysfs does not automatically create the device file structure in @@ -1165,22 +1178,14 @@ setupfn(&test); let res = list_command_helper(&test, defined, false, verbose, uuid, parent.clone()); - if expect == Expect::Fail { - res.expect_err("expected list command to fail"); - return; + if let Ok(output) = assert_result(res, expect, "list json command") { + test.compare_to_file(&format!("{}.text", subtest), &output); } - let output = res.expect("list command failed unexpectedly"); - test.compare_to_file(&format!("{}.text", subtest), &output); - let res = list_command_helper(&test, defined, true, verbose, uuid, parent.clone()); - if expect == Expect::Fail { - res.expect_err("expected list command to fail"); - return; + if let Ok(output) = assert_result(res, expect, "list command") { + test.compare_to_file(&format!("{}.json", subtest), &output); } - - let output = res.expect("list command failed unexpectedly"); - test.compare_to_file(&format!("{}.json", subtest), &output); } #[test] @@ -1413,23 +1418,15 @@ // test text output let res = types_command_helper(test, parent.clone(), false); - if expect == Expect::Fail { - res.expect_err("expected types command to fail"); - return; + if let Ok(output) = assert_result(res, expect, "types command") { + test.compare_to_file(&format!("{}.text", subtest), &output); } - let output = res.expect("types command failed unexpectedly"); - test.compare_to_file(&format!("{}.text", subtest), &output); - // test JSON output let res = types_command_helper(test, parent.clone(), true); - if expect == Expect::Fail { - res.expect_err("expected types command to fail"); - return; + if let Ok(output) = assert_result(res, expect, "types json command") { + test.compare_to_file(&format!("{}.json", subtest), &output); } - - let output = res.expect("types command failed unexpectedly"); - test.compare_to_file(&format!("{}.json", subtest), &output); } #[test] @@ -1515,13 +1512,7 @@ empty_mdev.parent = Some(parent.to_string()); let res = Callout::invoke(&mut empty_mdev, action, |_empty_mdev| Ok(())); - - if expect == Expect::Fail { - res.expect_err("expected callout to fail"); - return; - } - - assert!(res.is_ok()); + let _ = assert_result(res, expect, "invoke callout"); } fn test_get_callout<F>( @@ -1542,13 +1533,7 @@ empty_mdev.parent = Some(parent.to_string()); let res = Callout::get_attributes(&mut empty_mdev); - - if expect == Expect::Fail { - res.expect_err("expected callout to fail"); - return; - } - - assert!(res.is_ok()); + let _ = assert_result(res, expect, "get callout"); } #[test] @@ -1571,7 +1556,7 @@ ); test_invoke_callout( "test_callout_all_fail", - Expect::Fail, + Expect::Fail(None), Action::Test, Uuid::parse_str(DEFAULT_UUID).unwrap(), DEFAULT_PARENT, @@ -1597,7 +1582,7 @@ // return error code 1. test_invoke_callout( "test_callout_type_c", - Expect::Fail, + Expect::Fail(None), Action::Test, Uuid::parse_str(DEFAULT_UUID).unwrap(), "parent_c", @@ -1692,7 +1677,7 @@ ); test_get_callout( "test_callout_bad_json", - Expect::Fail, + Expect::Fail(None), Uuid::parse_str(DEFAULT_UUID).unwrap(), DEFAULT_PARENT, DEFAULT_TYPE,
