Description
Problem
I am working on a library which requires some tests to be run as root. However, only some of the tests actually need root and so I designed the test suite such that the tests that require root are only run when you actually have root. It seems the most rust-like way of doing this (given how restrictive libtest is) is to create a dummy feature _test_as_root
and then do:
#[test]
#[cfg_attr(not(feature = "_test_as_root"), ignore)]
fn test_fn() {}
(The alternative is to make the test always pass if it is running as root, but this is less than ideal
Given that sudo cargo
doesn't work in general, and is quite painful to get working, it would be ideal if I could just do this in CI:
% cargo test # runs as a regular user
% cargo test --features _test_as_root # runs as root
Using the suggestion from #5999 (comment), it seems like setting a runner
with target.'cfg(feature = "_test_as_root")
would work. However:
% cat .cargo/config
[target.'cfg(feature = "_test_as_root")']
runner = "sudo -E"
% cargo test --features _test_as_root
# the tests that require root fail because the tests don't run as root
If you use target.x86_64-unknown-linux-gnu
it works. It seem that the cfg(feature=...)
is never matched? Even if you change runner
to false
or some non-existent command the tests still run as if the setting wasn't there.
The docs states that the format of target.'cfg(...)'
matches the conditional compilation spec (which includes reference to cfg(feature = ...)
so it seems like this should work.
Steps
Run this script:
#!/bin/bash
set -xEeuo pipefail
cargo init --vcs none --lib example
pushd example
mkdir -p .cargo
cat >.cargo/config.toml <<EOF
[target.'cfg(feature = "_test_as_root")']
runner = "sudo -E"
EOF
cat >>Cargo.toml <<EOF
libc = "*"
[features]
_test_as_root = []
EOF
cat >>src/lib.rs <<EOF
#[test]
#[cfg_attr(not(feature = "_test_as_root"), ignore)]
fn test_only_as_root() {
assert_eq!(unsafe { libc::geteuid() }, 0, "not running as root");
}
EOF
Then note that:
cargo test
succeeds andtest_only_as_root
is ignored.cargo test --features _test_as_root
fails because the.cargo/config.toml
had no effect.
Possible Solution(s)
Parse [target.'cfg(feature = ...)']
configurations? I don't know if there is some technical restriction that stops feature
from being understood by cargo
when parsing .cargo/config.toml
.
Notes
In my particular case, using #5999 (comment) this issue can be worked around by using environment variables like so:
% cargo test
% CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER='sudo -E' cargo test --features _test_as_root
But this is fairly ugly and unlike [target.'cfg(feature = "_test_as_root")']
the feature and test runner are now decoupled and so the test will no longer run as root on different targets.
Version
cargo 1.80.0 (376290515 2024-07-16)
release: 1.80.0
commit-hash: 37629051518c3df9ac2c1744589362a02ecafa99
commit-date: 2024-07-16
host: x86_64-unknown-linux-gnu
libgit2: 1.7.2 (sys:0.18.3 vendored)
libcurl: 8.6.0-DEV (sys:0.4.72+curl-8.6.0 vendored ssl:OpenSSL/1.1.1w)
ssl: OpenSSL 1.1.1w 11 Sep 2023
os: openSUSE 20240716.0.0 [64-bit]