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") + ); + } } }