From 3b4b76997615007546c81ea558eb0c209bcfe045 Mon Sep 17 00:00:00 2001 From: Martin Kunkel <41590858+martinkunkel2@users.noreply.github.com> Date: Sun, 3 Aug 2025 14:38:49 +0200 Subject: [PATCH] tests: fix execution on WSL2, Ubuntu 24.04 (#8235) * tests: fix execution on WSL2, Ubuntu 24.04 Skip incompatible parts of tests to ensure that cargo nextest run --features unix executes successfully in WSL2, Ubuntu 24.04 distribution. Changes * Skip tests that required sys/kernel/profiling which is not available in WSL2 default configuration. * Use timezones in tests that are part of the standard tzdata list and not only available in backwards list. Backwards list is not installed by default in Ubuntu 24.04 (package tzdata-legacy). * check that /proc/modules is not empty when expecting content, because it is empty in WSL2 default configuration. * Skip logname test not only in WSL1, also in WSL2. * Add workflow for WSL2 This will setup WSL2 on windows-latest runner, install Ubuntu-24.04, and run the feat_os_unix tests. * wsl2: implemented review findings --------- Co-authored-by: Sylvestre Ledru --- .github/workflows/wsl2.yml | 69 +++++++++++++++++++++++++++++++++++ src/uucore/src/lib/mods/os.rs | 5 +++ tests/by-util/test_cp.rs | 21 +++++++++++ tests/by-util/test_head.rs | 18 +++++++-- tests/by-util/test_logname.rs | 2 +- tests/by-util/test_wc.rs | 15 +++++--- 6 files changed, 120 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/wsl2.yml diff --git a/.github/workflows/wsl2.yml b/.github/workflows/wsl2.yml new file mode 100644 index 000000000..89bd7d37f --- /dev/null +++ b/.github/workflows/wsl2.yml @@ -0,0 +1,69 @@ +name: WSL2 + +# spell-checker:ignore nextest noprofile norc + +on: + pull_request: + push: + branches: + - '*' + +permissions: + contents: read # to fetch code (actions/checkout) + +# End the current execution if there is a new changeset in the PR. +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +jobs: + test: + name: Test + runs-on: ${{ matrix.job.os }} + timeout-minutes: 45 + strategy: + fail-fast: false + matrix: + job: + - { os: windows-latest, distribution: Ubuntu-24.04, features: feat_os_unix} + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Install WSL2 + uses: Vampire/setup-wsl@v6.0.0 + with: + additional-packages: build-essential + distribution: ${{ matrix.job.distribution }} + use-cache: 'true' + wsl-version: 2 + - name: Set up WSL2 user + shell: wsl-bash {0} + run: | + useradd -m -p password user + - name: Set up WSL2 shell command + uses: Vampire/setup-wsl@v6.0.0 + with: + distribution: ${{ matrix.job.distribution }} + wsl-shell-command: bash -c "sudo -u user bash --noprofile --norc -euo pipefail '{0}'" + # it is required to use WSL2's linux file system, so we do a second checkout there + - name: Checkout source in WSL2 + shell: wsl-bash {0} + run: | + git clone "$(pwd)" "$HOME/src" + - name: Install rust and nextest + shell: wsl-bash {0} + run: | + curl https://sh.rustup.rs -sSf --output rustup.sh + sh rustup.sh -y --profile=minimal + curl -LsSf https://get.nexte.st/latest/linux | tar zxf - -C "$HOME/.cargo/bin" + - name: Test + shell: wsl-bash {0} + run: | + cd "$HOME/src" + # chmod tests expect umask 0022 + umask 0022 + . "$HOME/.cargo/env" + export CARGO_TERM_COLOR=always + export RUST_BACKTRACE=1 + cargo nextest run --hide-progress-bar --profile ci --features '${{ matrix.job.features }}' diff --git a/src/uucore/src/lib/mods/os.rs b/src/uucore/src/lib/mods/os.rs index 9c96bd7a0..fca4578dd 100644 --- a/src/uucore/src/lib/mods/os.rs +++ b/src/uucore/src/lib/mods/os.rs @@ -37,3 +37,8 @@ pub fn is_wsl_2() -> bool { } false } + +/// Test if the program is running under WSL +pub fn is_wsl() -> bool { + is_wsl_1() || is_wsl_2() +} diff --git a/tests/by-util/test_cp.rs b/tests/by-util/test_cp.rs index c8d50b048..11a411a47 100644 --- a/tests/by-util/test_cp.rs +++ b/tests/by-util/test_cp.rs @@ -4400,6 +4400,13 @@ fn test_cp_default_virtual_file() { use std::os::unix::prelude::MetadataExt; let ts = TestScenario::new(util_name!()); + + // in case the kernel was not built with profiling support, e.g. WSL + if !ts.fixtures.file_exists("/sys/kernel/profiling") { + println!("test skipped: /sys/kernel/profiling does not exist"); + return; + } + let at = &ts.fixtures; ts.ucmd().arg("/sys/kernel/profiling").arg("b").succeeds(); @@ -4483,6 +4490,13 @@ fn test_cp_debug_sparse_always_sparse_virtual_file() { // This file has existed at least since 2008, so we assume that it is present on "all" Linux kernels. // https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-profiling let ts = TestScenario::new(util_name!()); + + // in case the kernel was not built with profiling support, e.g. WSL + if !ts.fixtures.file_exists("/sys/kernel/profiling") { + println!("test skipped: /sys/kernel/profiling does not exist"); + return; + } + ts.ucmd() .arg("--debug") .arg("--sparse=always") @@ -4657,6 +4671,13 @@ fn test_cp_debug_default_sparse_virtual_file() { // This file has existed at least since 2008, so we assume that it is present on "all" Linux kernels. // https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-profiling let ts = TestScenario::new(util_name!()); + + // in case the kernel was not built with profiling support, e.g. WSL + if !ts.fixtures.file_exists("/sys/kernel/profiling") { + println!("test skipped: /sys/kernel/profiling does not exist"); + return; + } + ts.ucmd() .arg("--debug") .arg("/sys/kernel/profiling") diff --git a/tests/by-util/test_head.rs b/tests/by-util/test_head.rs index df0f71b12..30f8378b9 100644 --- a/tests/by-util/test_head.rs +++ b/tests/by-util/test_head.rs @@ -771,7 +771,11 @@ fn test_read_backwards_bytes_proc_fs_modules() { let args = ["-c", "-1", "/proc/modules"]; let result = ts.ucmd().args(&args).succeeds(); - assert!(!result.stdout().is_empty()); + + // Only expect output if the file is not empty, e.g. it is empty in default WSL2. + if !ts.fixtures.read("/proc/modules").is_empty() { + assert!(!result.stdout().is_empty()); + } } #[cfg(all( @@ -787,7 +791,11 @@ fn test_read_backwards_lines_proc_fs_modules() { let args = ["--lines", "-1", "/proc/modules"]; let result = ts.ucmd().args(&args).succeeds(); - assert!(!result.stdout().is_empty()); + + // Only expect output if the file is not empty, e.g. it is empty in default WSL2. + if !ts.fixtures.read("/proc/modules").is_empty() { + assert!(!result.stdout().is_empty()); + } } #[cfg(all( @@ -800,7 +808,11 @@ fn test_read_backwards_lines_proc_fs_modules() { #[test] fn test_read_backwards_bytes_sys_kernel_profiling() { let ts = TestScenario::new(util_name!()); - + // in case the kernel was not built with profiling support, e.g. WSL + if !ts.fixtures.file_exists("/sys/kernel/profiling") { + println!("test skipped: /sys/kernel/profiling does not exist"); + return; + } let args = ["-c", "-1", "/sys/kernel/profiling"]; let result = ts.ucmd().args(&args).succeeds(); let stdout_str = result.stdout_str(); diff --git a/tests/by-util/test_logname.rs b/tests/by-util/test_logname.rs index 965257964..0f2da0cd4 100644 --- a/tests/by-util/test_logname.rs +++ b/tests/by-util/test_logname.rs @@ -19,7 +19,7 @@ fn test_normal() { for (key, value) in env::vars() { println!("{key}: {value}"); } - if (is_ci() || uucore::os::is_wsl_1()) && result.stderr_str().contains("no login name") { + if (is_ci() || uucore::os::is_wsl()) && result.stderr_str().contains("no login name") { // ToDO: investigate WSL failure // In the CI, some server are failing to return logname. // As seems to be a configuration issue, ignoring it diff --git a/tests/by-util/test_wc.rs b/tests/by-util/test_wc.rs index 3589a34ef..be3469a3f 100644 --- a/tests/by-util/test_wc.rs +++ b/tests/by-util/test_wc.rs @@ -466,15 +466,18 @@ fn test_files_from_pseudo_filesystem() { assert_ne!(result.stdout_str(), "0 /proc/cpuinfo\n"); // the following block fails on Android with a "Permission denied" error + // also skip in case the kernel was not built with profiling support, e.g. WSL #[cfg(target_os = "linux")] { let (at, mut ucmd) = at_and_ucmd!(); - let result = ucmd.arg("-c").arg("/sys/kernel/profiling").succeeds(); - let actual = at.read("/sys/kernel/profiling").len(); - assert_eq!( - result.stdout_str(), - format!("{actual} /sys/kernel/profiling\n") - ); + if at.file_exists("/sys/kernel/profiling") { + let result = ucmd.arg("-c").arg("/sys/kernel/profiling").succeeds(); + let actual = at.read("/sys/kernel/profiling").len(); + assert_eq!( + result.stdout_str(), + format!("{actual} /sys/kernel/profiling\n") + ); + } } }