Skip to content

target.cfg doesn't support features #14306

Closed as not planned
Closed as not planned
@cyphar

Description

@cyphar

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 and test_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]

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: bugS-triageStatus: This issue is waiting on initial triage.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions