From 54cbb69d373766e884cf38778da01d8f82344ef1 Mon Sep 17 00:00:00 2001 From: Jan Scheer Date: Sun, 13 Jun 2021 15:39:31 +0200 Subject: [PATCH] id/tests: fix tests if run on macOS --- .github/workflows/CICD.yml | 1 + .github/workflows/GNU.yml | 6 + src/uu/id/src/id.rs | 13 +-- tests/by-util/test_id.rs | 232 +++++++++++++++++++++++-------------- 4 files changed, 160 insertions(+), 92 deletions(-) diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index a8ed1b704..fcaddd310 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -235,6 +235,7 @@ jobs: # { os, target, cargo-options, features, use-cross, toolchain } - { os: ubuntu-latest , target: arm-unknown-linux-gnueabihf , features: feat_os_unix_gnueabihf , use-cross: use-cross } - { os: ubuntu-latest , target: aarch64-unknown-linux-gnu , features: feat_os_unix_gnueabihf , use-cross: use-cross } + - { os: ubuntu-latest , target: x86_64-unknown-linux-gnu , features: feat_os_unix , use-cross: use-cross } - { os: ubuntu-16.04 , target: x86_64-unknown-linux-gnu , features: feat_os_unix , use-cross: use-cross } # - { os: ubuntu-18.04 , target: i586-unknown-linux-gnu , features: feat_os_unix , use-cross: use-cross } ## note: older windows platform; not required, dev-FYI only # - { os: ubuntu-18.04 , target: i586-unknown-linux-gnu , features: feat_os_unix , use-cross: use-cross } ## note: older windows platform; not required, dev-FYI only diff --git a/.github/workflows/GNU.yml b/.github/workflows/GNU.yml index e9227e38e..1202de87f 100644 --- a/.github/workflows/GNU.yml +++ b/.github/workflows/GNU.yml @@ -45,8 +45,14 @@ jobs: - name: Run GNU tests shell: bash run: | + # bash uutils/util/run-gnu-test.sh + bash uutils/util/run-gnu-test.sh tests/id/context.sh # TODO: remove after debugging + sudo bash uutils/util/run-gnu-test.sh tests/id/setgid.sh # TODO: remove after debugging + bash uutils/util/run-gnu-test.sh tests/id/smack.sh # TODO: remove after debugging bash uutils/util/run-gnu-test.sh tests/id/uid.sh # TODO: remove after debugging bash uutils/util/run-gnu-test.sh tests/id/zero.sh # TODO: remove after debugging + bash uutils/util/run-gnu-test.sh tests/id/no-context.sh # TODO: remove after debugging + bash uutils/util/run-gnu-test.sh tests/id/gnu-zero-uids.sh # todo: remove after debugging - name: Extract tests info shell: bash run: | diff --git a/src/uu/id/src/id.rs b/src/uu/id/src/id.rs index 6afb23d67..35f641b3f 100644 --- a/src/uu/id/src/id.rs +++ b/src/uu/id/src/id.rs @@ -24,7 +24,7 @@ // * Help text based on BSD's `id`. // -// spell-checker:ignore (ToDO) asid auditid auditinfo auid cstr egid emod euid getaudit getlogin gflag nflag pline rflag termid uflag gsflag zflag +// spell-checker:ignore (ToDO) asid auditid auditinfo auid cstr egid emod euid getaudit getlogin gflag nflag pline rflag termid uflag gsflag zflag testsuite #![allow(non_camel_case_types)] #![allow(dead_code)] @@ -92,7 +92,7 @@ struct State { rflag: bool, // --real zflag: bool, // --zero ids: Option, - // The behaviour for calling GNU's `id` and calling GNU's `id $USER` is similar but different. + // The behavior for calling GNU's `id` and calling GNU's `id $USER` is similar but different. // * The SELinux context is only displayed without a specified user. // * The `getgroups` system call is only used without a specified user, this causes // the order of the displayed groups to be different between `id` and `id $USER`. @@ -336,12 +336,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 { ); } + let groups = entries::get_groups_gnu(Some(gid)).unwrap(); let groups = if state.user_specified { - possible_pw - .map(|p| p.belongs_to()) - .unwrap_or_else(|| entries::get_groups_gnu(Some(gid)).unwrap()) + possible_pw.map(|p| p.belongs_to()).unwrap() } else { - entries::get_groups_gnu(Some(gid)).unwrap() + groups.clone() }; if state.gsflag { @@ -517,7 +516,7 @@ fn id_print(state: &State, groups: Vec) { .join(",") ); - // placeholder ("-Z" is NotImplemented): + // NOTE: placeholder ("-Z" is NotImplemented): // if !state.user_specified { // // print SElinux context (does not depend on "-Z") // print!(" context={}", get_selinux_contexts().join(":")); diff --git a/tests/by-util/test_id.rs b/tests/by-util/test_id.rs index 9e1a218ea..4c41e3131 100644 --- a/tests/by-util/test_id.rs +++ b/tests/by-util/test_id.rs @@ -12,11 +12,29 @@ use crate::common::util::*; // whoami: "runner" // +// spell-checker:ignore (ToDO) testsuite coreutil + +const VERSION_EXPECTED: &str = "8.30"; // 8.32 +const UUTILS_WARNING: &str = "uutils-tests-warning"; +const UUTILS_INFO: &str = "uutils-tests-info"; + +macro_rules! unwrap_or_return { + ( $e:expr ) => { + match $e { + Ok(x) => x, + Err(e) => { + println!("{}: test skipped: {}", UUTILS_INFO, e); + return; + } + } + }; +} + fn whoami() -> String { - // Use environment variable to get current user instead of invoking `whoami` - // and fall back to user "nobody" on error. + // Use environment variable to get current user instead of + // invoking `whoami` and fall back to user "nobody" on error. std::env::var("USER").unwrap_or_else(|e| { - println!("warning: {}, using \"nobody\" instead", e); + println!("{}: {}, using \"nobody\" instead", UUTILS_WARNING, e); "nobody".to_string() }) } @@ -25,20 +43,23 @@ fn whoami() -> String { #[cfg(unix)] fn test_id_no_specified_user() { let result = new_ucmd!().run(); - let expected_result = expected_result(&[]); - let mut exp_stdout = expected_result.stdout_str().to_string(); + let exp_result = unwrap_or_return!(expected_result(&[])); + let mut _exp_stdout = exp_result.stdout_str().to_string(); - // uu_id does not support selinux context. Remove 'context' part from exp_stdout: - let context_offset = expected_result - .stdout_str() - .find(" context") - .unwrap_or(exp_stdout.len()); - exp_stdout.replace_range(context_offset.., "\n"); + #[cfg(target_os = "linux")] + { + // NOTE: Strip 'context' part from exp_stdout (remove if SElinux gets added): + let context_offset = exp_result + .stdout_str() + .find(" context=") + .unwrap_or_else(|| _exp_stdout.len()); + _exp_stdout.replace_range(context_offset.., "\n"); + } result - .stdout_is(exp_stdout) - .stderr_is(expected_result.stderr_str()) - .code_is(expected_result.code()); + .stdout_is(_exp_stdout) + .stderr_is(exp_result.stderr_str()) + .code_is(exp_result.code()); } #[test] @@ -47,53 +68,53 @@ fn test_id_single_user() { let test_users = [&whoami()[..]]; let scene = TestScenario::new(util_name!()); - let mut exp_result = expected_result(&test_users); + let mut exp_result = unwrap_or_return!(expected_result(&test_users)); scene .ucmd() .args(&test_users) .run() .stdout_is(exp_result.stdout_str()) - .stderr_is(exp_result.stderr_str()) + .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); // u/g/G z/n for &opt in &["--user", "--group", "--groups"] { let mut args = vec![opt]; args.extend_from_slice(&test_users); - exp_result = expected_result(&args); + exp_result = unwrap_or_return!(expected_result(&args)); scene .ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) - .stderr_is(exp_result.stderr_str()) + .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.push("--zero"); - exp_result = expected_result(&args); + exp_result = unwrap_or_return!(expected_result(&args)); scene .ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) - .stderr_is(exp_result.stderr_str()) + .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.push("--name"); - exp_result = expected_result(&args); + exp_result = unwrap_or_return!(expected_result(&args)); scene .ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) - .stderr_is(exp_result.stderr_str()) + .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.pop(); - exp_result = expected_result(&args); + exp_result = unwrap_or_return!(expected_result(&args)); scene .ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) - .stderr_is(exp_result.stderr_str()) + .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); } } @@ -103,11 +124,16 @@ fn test_id_single_user() { fn test_id_single_user_non_existing() { let args = &["hopefully_non_existing_username"]; let result = new_ucmd!().args(args).run(); - let expected_result = expected_result(args); + let exp_result = unwrap_or_return!(expected_result(args)); + + // coreutils 8.32: $ LC_ALL=C id foobar + // macOS: stderr: "id: 'foobar': no such user: Invalid argument" + // linux: stderr: "id: 'foobar': no such user" + // It is unkown why the output on macOS is different. result - .stdout_is(expected_result.stdout_str()) - .stderr_is(expected_result.stderr_str()) - .code_is(expected_result.code()); + .stdout_is(exp_result.stdout_str()) + .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) + .code_is(exp_result.code()); } #[test] @@ -117,11 +143,11 @@ fn test_id_name() { for &opt in &["--user", "--group", "--groups"] { let args = [opt, "--name"]; let result = scene.ucmd().args(&args).run(); - let expected_result = expected_result(&args); + let exp_result = unwrap_or_return!(expected_result(&args)); result - .stdout_is(expected_result.stdout_str()) - .stderr_is(expected_result.stderr_str()) - .code_is(expected_result.code()); + .stdout_is(exp_result.stdout_str()) + .stderr_is(exp_result.stderr_str()) + .code_is(exp_result.code()); if opt == "--user" { assert_eq!(result.stdout_str().trim_end(), whoami()); @@ -136,11 +162,11 @@ fn test_id_real() { for &opt in &["--user", "--group", "--groups"] { let args = [opt, "--real"]; let result = scene.ucmd().args(&args).run(); - let expected_result = expected_result(&args); + let exp_result = unwrap_or_return!(expected_result(&args)); result - .stdout_is(expected_result.stdout_str()) - .stderr_is(expected_result.stderr_str()) - .code_is(expected_result.code()); + .stdout_is(exp_result.stdout_str()) + .stderr_is(exp_result.stderr_str()) + .code_is(exp_result.code()); } } @@ -159,7 +185,6 @@ fn test_id_pretty_print() { // stdout = // stderr = ', tests/common/util.rs:157:13 println!("test skipped:"); - return; } else { result.success().stdout_contains(username); } @@ -181,53 +206,53 @@ fn test_id_multiple_users() { let test_users = ["root", "man", "postfix", "sshd", &whoami()]; let scene = TestScenario::new(util_name!()); - let mut exp_result = expected_result(&test_users); + let mut exp_result = unwrap_or_return!(expected_result(&test_users)); scene .ucmd() .args(&test_users) .run() .stdout_is(exp_result.stdout_str()) - .stderr_is(exp_result.stderr_str()) + .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); // u/g/G z/n for &opt in &["--user", "--group", "--groups"] { let mut args = vec![opt]; args.extend_from_slice(&test_users); - exp_result = expected_result(&args); + exp_result = unwrap_or_return!(expected_result(&args)); scene .ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) - .stderr_is(exp_result.stderr_str()) + .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.push("--zero"); - exp_result = expected_result(&args); + exp_result = unwrap_or_return!(expected_result(&args)); scene .ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) - .stderr_is(exp_result.stderr_str()) + .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.push("--name"); - exp_result = expected_result(&args); + exp_result = unwrap_or_return!(expected_result(&args)); scene .ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) - .stderr_is(exp_result.stderr_str()) + .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.pop(); - exp_result = expected_result(&args); + exp_result = unwrap_or_return!(expected_result(&args)); scene .ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) - .stderr_is(exp_result.stderr_str()) + .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); } } @@ -249,53 +274,53 @@ fn test_id_multiple_users_non_existing() { ]; let scene = TestScenario::new(util_name!()); - let mut exp_result = expected_result(&test_users); + let mut exp_result = unwrap_or_return!(expected_result(&test_users)); scene .ucmd() .args(&test_users) .run() .stdout_is(exp_result.stdout_str()) - .stderr_is(exp_result.stderr_str()) + .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); // u/g/G z/n for &opt in &["--user", "--group", "--groups"] { let mut args = vec![opt]; args.extend_from_slice(&test_users); - exp_result = expected_result(&args); + exp_result = unwrap_or_return!(expected_result(&args)); scene .ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) - .stderr_is(exp_result.stderr_str()) + .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.push("--zero"); - exp_result = expected_result(&args); + exp_result = unwrap_or_return!(expected_result(&args)); scene .ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) - .stderr_is(exp_result.stderr_str()) + .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.push("--name"); - exp_result = expected_result(&args); + exp_result = unwrap_or_return!(expected_result(&args)); scene .ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) - .stderr_is(exp_result.stderr_str()) + .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); args.pop(); - exp_result = expected_result(&args); + exp_result = unwrap_or_return!(expected_result(&args)); scene .ucmd() .args(&args) .run() .stdout_is(exp_result.stdout_str()) - .stderr_is(exp_result.stderr_str()) + .stderr_is(exp_result.stderr_str().replace(": Invalid argument", "")) .code_is(exp_result.code()); } } @@ -311,12 +336,12 @@ fn test_id_default_format() { .ucmd() .args(&args) .fails() - .stderr_only(expected_result(&args).stderr_str()); + .stderr_only(unwrap_or_return!(expected_result(&args)).stderr_str()); for &opt2 in &["--user", "--group", "--groups"] { // u/g/G n/r let args = [opt2, opt1]; let result = scene.ucmd().args(&args).run(); - let exp_result = expected_result(&args); + let exp_result = unwrap_or_return!(expected_result(&args)); result .stdout_is(exp_result.stdout_str()) .stderr_is(exp_result.stderr_str()) @@ -330,7 +355,7 @@ fn test_id_default_format() { .ucmd() .args(&args) .succeeds() - .stdout_only(expected_result(&args).stdout_str()); + .stdout_only(unwrap_or_return!(expected_result(&args)).stdout_str()); } } @@ -344,7 +369,7 @@ fn test_id_zero() { .ucmd() .args(&[z_flag]) .fails() - .stderr_only(expected_result(&[z_flag]).stderr_str()); + .stderr_only(unwrap_or_return!(expected_result(&[z_flag])).stderr_str()); for &opt1 in &["--name", "--real"] { // id: cannot print only names or real IDs in default format let args = [opt1, z_flag]; @@ -352,12 +377,12 @@ fn test_id_zero() { .ucmd() .args(&args) .fails() - .stderr_only(expected_result(&args).stderr_str()); + .stderr_only(unwrap_or_return!(expected_result(&args)).stderr_str()); for &opt2 in &["--user", "--group", "--groups"] { // u/g/G n/r z let args = [opt2, z_flag, opt1]; let result = scene.ucmd().args(&args).run(); - let exp_result = expected_result(&args); + let exp_result = unwrap_or_return!(expected_result(&args)); result .stdout_is(exp_result.stdout_str()) .stderr_is(exp_result.stderr_str()) @@ -371,46 +396,83 @@ fn test_id_zero() { .ucmd() .args(&args) .succeeds() - .stdout_only(expected_result(&args).stdout_str()); + .stdout_only(unwrap_or_return!(expected_result(&args)).stdout_str()); } } } #[allow(clippy::needless_borrow)] #[cfg(unix)] -fn expected_result(args: &[&str]) -> CmdResult { +fn expected_result(args: &[&str]) -> Result { + // version for reference coreutil binary + #[cfg(target_os = "linux")] let util_name = util_name!(); #[cfg(all(unix, not(target_os = "linux")))] let util_name = format!("g{}", util_name!()); - let result = TestScenario::new(&util_name) + let scene = TestScenario::new(&util_name); + let version_check = scene + .cmd_keepenv(&util_name) + .env("LANGUAGE", "C") + .arg("--version") + .run(); + let version_check_string: String = version_check + .stdout_str() + .split('\n') + .collect::>() + .get(0) + .map_or_else( + || format!("{}: unexpected output format for reference coreutils '{} --version'", UUTILS_WARNING, util_name), + |s| { + if s.contains(&format!("(GNU coreutils) {}", VERSION_EXPECTED)) { + s.to_string() + } else if s.contains("(GNU coreutils)") { + // example: id (GNU coreutils) 8.32.162-4eda + let version_found = s.split_whitespace().last().unwrap()[..4].parse::().unwrap_or_default(); + let version_expected = VERSION_EXPECTED.parse::().unwrap_or_default(); + if version_found > version_expected { + format!("{}: version for the reference coreutil '{}' is higher than expected; expected: {}, found: {}", UUTILS_INFO, util_name, VERSION_EXPECTED, version_found) + } else { + format!("{}: version for the reference coreutil '{}' does not match; expected: {}, found: {}", UUTILS_WARNING, util_name, VERSION_EXPECTED, version_found) } + } else { + format!("{}: no coreutils version string found for reference coreutils '{} --version'", UUTILS_WARNING, util_name) + } + }, + ); + if version_check_string.starts_with(UUTILS_WARNING) { + return Err(version_check_string); + } + println!("{}", version_check_string); + + let result = scene .cmd_keepenv(&util_name) .env("LANGUAGE", "C") .args(args) .run(); - let mut _o = 0; - let mut _e = 0; - #[cfg(all(unix, not(target_os = "linux")))] - { - _o = if result.stdout_str().starts_with(&util_name) { - 1 - } else { - 0 - }; - _e = if result.stderr_str().starts_with(&util_name) { - 1 - } else { - 0 - }; - } + // #[cfg(all(unix, not(target_os = "linux")))] + // if cfg!(target_os = "macos") { + let (stdout, stderr): (String, String) = if cfg!(target_os = "linux") { + ( + result.stdout_str().to_string(), + result.stderr_str().to_string(), + ) + } else { + // strip 'g' prefix from results: + let from = util_name.to_string() + ":"; + let to = &from[1..]; + ( + result.stdout_str().replace(&from, to), + result.stderr_str().replace(&from, to), + ) + }; - CmdResult::new( + Ok(CmdResult::new( Some(result.tmpd()), Some(result.code()), result.succeeded(), - &result.stdout()[_o..], - &result.stderr()[_e..], - ) + stdout.as_bytes(), + stderr.as_bytes(), + )) }