Skip to content

Commit 0b397c4

Browse files
authored
Merge pull request #7401 from RenjiSann/coverage
Fix coverage files generation
2 parents f1f3a5d + c539f01 commit 0b397c4

File tree

11 files changed

+262
-204
lines changed

11 files changed

+262
-204
lines changed

.config/nextest.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,10 @@ status-level = "all"
44
final-status-level = "skip"
55
failure-output = "immediate-final"
66
fail-fast = false
7+
8+
[profile.coverage]
9+
retries = 0
10+
status-level = "all"
11+
final-status-level = "skip"
12+
failure-output = "immediate-final"
13+
fail-fast = false

.github/workflows/CICD.yml

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: CICD
22

33
# spell-checker:ignore (abbrev/names) CICD CodeCOV MacOS MinGW MSVC musl taiki
44
# spell-checker:ignore (env/flags) Awarnings Ccodegen Coverflow Cpanic Dwarnings RUSTDOCFLAGS RUSTFLAGS Zpanic CARGOFLAGS
5-
# spell-checker:ignore (jargon) SHAs deps dequote softprops subshell toolchain fuzzers dedupe devel
5+
# spell-checker:ignore (jargon) SHAs deps dequote softprops subshell toolchain fuzzers dedupe devel profdata
66
# spell-checker:ignore (people) Peltoche rivy dtolnay Anson dawidd
77
# spell-checker:ignore (shell/tools) binutils choco clippy dmake dpkg esac fakeroot fdesc fdescfs gmake grcov halium lcov libclang libfuse libssl limactl mkdir nextest nocross pacman popd printf pushd redoxer rsync rustc rustfmt rustup shopt sccache utmpdump xargs
88
# spell-checker:ignore (misc) aarch alnum armhf bindir busytest coreutils defconfig DESTDIR gecos getenforce gnueabihf issuecomment maint manpages msys multisize noconfirm nullglob onexitbegin onexitend pell runtest Swatinem tempfile testsuite toybox uutils
@@ -1001,6 +1001,123 @@ jobs:
10011001
name: toybox-result.json
10021002
path: ${{ steps.vars.outputs.TEST_SUMMARY_FILE }}
10031003

1004+
coverage:
1005+
name: Code Coverage
1006+
runs-on: ${{ matrix.job.os }}
1007+
timeout-minutes: 90
1008+
env:
1009+
SCCACHE_GHA_ENABLED: "true"
1010+
RUSTC_WRAPPER: "sccache"
1011+
strategy:
1012+
fail-fast: false
1013+
matrix:
1014+
job:
1015+
- { os: ubuntu-latest , features: unix, toolchain: nightly }
1016+
# FIXME: Re-enable macos code coverage
1017+
# - { os: macos-latest , features: macos, toolchain: nightly }
1018+
# FIXME: Re-enable Code Coverage on windows, which currently fails due to "profiler_builtins". See #6686.
1019+
# - { os: windows-latest , features: windows, toolchain: nightly-x86_64-pc-windows-gnu }
1020+
steps:
1021+
- uses: actions/checkout@v4
1022+
- uses: dtolnay/rust-toolchain@master
1023+
with:
1024+
toolchain: ${{ matrix.job.toolchain }}
1025+
components: rustfmt
1026+
- uses: taiki-e/install-action@v2
1027+
with:
1028+
tool: nextest,grcov@0.8.24
1029+
- uses: Swatinem/rust-cache@v2
1030+
1031+
- name: Run sccache-cache
1032+
uses: mozilla-actions/sccache-action@v0.0.6
1033+
1034+
# - name: Reattach HEAD ## may be needed for accurate code coverage info
1035+
# run: git checkout ${{ github.head_ref }}
1036+
1037+
- name: Initialize workflow variables
1038+
id: vars
1039+
shell: bash
1040+
run: |
1041+
## VARs setup
1042+
outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; }
1043+
1044+
# toolchain
1045+
TOOLCHAIN="nightly" ## default to "nightly" toolchain (required for certain required unstable compiler flags) ## !maint: refactor when stable channel has needed support
1046+
1047+
# * specify gnu-type TOOLCHAIN for windows; `grcov` requires gnu-style code coverage data files
1048+
case ${{ matrix.job.os }} in windows-*) TOOLCHAIN="$TOOLCHAIN-x86_64-pc-windows-gnu" ;; esac;
1049+
1050+
# * use requested TOOLCHAIN if specified
1051+
if [ -n "${{ matrix.job.toolchain }}" ]; then TOOLCHAIN="${{ matrix.job.toolchain }}" ; fi
1052+
outputs TOOLCHAIN
1053+
1054+
# target-specific options
1055+
1056+
# * CARGO_FEATURES_OPTION
1057+
CARGO_FEATURES_OPTION='--all-features' ; ## default to '--all-features' for code coverage
1058+
if [ -n "${{ matrix.job.features }}" ]; then CARGO_FEATURES_OPTION='--features=${{ matrix.job.features }}' ; fi
1059+
outputs CARGO_FEATURES_OPTION
1060+
1061+
# * CODECOV_FLAGS
1062+
CODECOV_FLAGS=$( echo "${{ matrix.job.os }}" | sed 's/[^[:alnum:]]/_/g' )
1063+
outputs CODECOV_FLAGS
1064+
1065+
- name: Install/setup prerequisites
1066+
shell: bash
1067+
run: |
1068+
## Install/setup prerequisites
1069+
case '${{ matrix.job.os }}' in
1070+
macos-latest) brew install coreutils ;; # needed for testing
1071+
esac
1072+
1073+
case '${{ matrix.job.os }}' in
1074+
ubuntu-latest)
1075+
# pinky is a tool to show logged-in users from utmp, and gecos fields from /etc/passwd.
1076+
# In GitHub Action *nix VMs, no accounts log in, even the "runner" account that runs the commands. The account also has empty gecos fields.
1077+
# To work around this for pinky tests, we create a fake login entry for the GH runner account...
1078+
FAKE_UTMP='[7] [999999] [tty2] [runner] [tty2] [] [0.0.0.0] [2022-02-22T22:22:22,222222+00:00]'
1079+
# ... by dumping the login records, adding our fake line, then reverse dumping ...
1080+
(utmpdump /var/run/utmp ; echo $FAKE_UTMP) | sudo utmpdump -r -o /var/run/utmp
1081+
# ... and add a full name to each account with a gecos field but no full name.
1082+
sudo sed -i 's/:,/:runner name,/' /etc/passwd
1083+
# We also create a couple optional files pinky looks for
1084+
touch /home/runner/.project
1085+
echo "foo" > /home/runner/.plan
1086+
;;
1087+
esac
1088+
1089+
case '${{ matrix.job.os }}' in
1090+
# Update binutils if MinGW due to https://github.com/rust-lang/rust/issues/112368
1091+
windows-latest) C:/msys64/usr/bin/pacman.exe -Sy --needed mingw-w64-x86_64-gcc --noconfirm ; echo "C:\msys64\mingw64\bin" >> $GITHUB_PATH ;;
1092+
esac
1093+
1094+
## Install the llvm-tools component to get access to `llvm-profdata`
1095+
rustup component add llvm-tools
1096+
1097+
- name: Run test and coverage
1098+
id: run_test_cov
1099+
run: |
1100+
outputs() { step_id="${{ github.action }}"; for var in "$@" ; do echo steps.${step_id}.outputs.${var}="${!var}"; echo "${var}=${!var}" >> $GITHUB_OUTPUT; done; }
1101+
1102+
# Run the coverage script
1103+
./util/build-run-test-coverage-linux.sh
1104+
1105+
outputs REPORT_FILE
1106+
env:
1107+
COVERAGE_DIR: ${{ github.workspace }}/coverage
1108+
FEATURES_OPTION: ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }}
1109+
# RUSTUP_TOOLCHAIN: ${{ steps.vars.outputs.TOOLCHAIN }}
1110+
1111+
- name: Upload coverage results (to Codecov.io)
1112+
uses: codecov/codecov-action@v4
1113+
with:
1114+
token: ${{ secrets.CODECOV_TOKEN }}
1115+
file: ${{ steps.run_test_cov.outputs.report }}
1116+
## flags: IntegrationTests, UnitTests, ${{ steps.vars.outputs.CODECOV_FLAGS }}
1117+
flags: ${{ steps.vars.outputs.CODECOV_FLAGS }}
1118+
name: codecov-umbrella
1119+
fail_ci_if_error: false
1120+
10041121
test_separately:
10051122
name: Separate Builds
10061123
runs-on: ${{ matrix.os }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# spell-checker:ignore (misc) direnv
22

33
target/
4+
coverage/
45
/src/*/gen_table
56
/build/
67
/tmp/

DEVELOPMENT.md

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- spell-checker:ignore (flags) Ccodegen Coverflow Cpanic Zinstrument Zpanic reimplementing toybox RUNTEST CARGOFLAGS nextest prereq autopoint gettext texinfo automake findutils shellenv libexec gnubin toolchains gsed -->
1+
<!-- spell-checker:ignore (flags) Ccodegen Coverflow Cpanic Cinstrument Zpanic reimplementing toybox RUNTEST CARGOFLAGS nextest prereq autopoint gettext texinfo automake findutils shellenv libexec gnubin toolchains gsed -->
22

33
# Setting up your local development environment
44

@@ -253,13 +253,11 @@ pkg install coreutils gsed
253253

254254
Code coverage report can be generated using [grcov](https://github.com/mozilla/grcov).
255255

256-
### Using Nightly Rust
257-
258256
To generate [gcov-based](https://github.com/mozilla/grcov#example-how-to-generate-gcda-files-for-a-rust-project) coverage report
259257

260258
```shell
261259
export CARGO_INCREMENTAL=0
262-
export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort"
260+
export RUSTFLAGS="-Cinstrument-coverage -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort"
263261
export RUSTDOCFLAGS="-Cpanic=abort"
264262
cargo build <options...> # e.g., --features feat_os_unix
265263
cargo test <options...> # e.g., --features feat_os_unix test_pathchk
@@ -269,11 +267,6 @@ grcov . -s . --binary-path ./target/debug/ -t html --branch --ignore-not-existin
269267

270268
if changes are not reflected in the report then run `cargo clean` and run the above commands.
271269

272-
### Using Stable Rust
273-
274-
If you are using stable version of Rust that doesn't enable code coverage instrumentation by default
275-
then add `-Z-Zinstrument-coverage` flag to `RUSTFLAGS` env variable specified above.
276-
277270
## Tips for setting up on Mac
278271

279272
### C Compiler and linker

tests/by-util/test_env.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -525,14 +525,20 @@ fn test_gnu_e20() {
525525
let scene = TestScenario::new(util_name!());
526526

527527
let env_bin = String::from(uutests::util::get_tests_binary()) + " " + util_name!();
528-
529-
let (input, output) = (
530-
[
531-
String::from("-i"),
532-
String::from(r#"-SA="B\_C=D" "#) + env_bin.escape_default().to_string().as_str() + "",
533-
],
534-
"A=B C=D\n",
535-
);
528+
let input = [
529+
String::from("-i"),
530+
String::from(r#"-SA="B\_C=D" "#) + env_bin.escape_default().to_string().as_str() + "",
531+
];
532+
533+
let mut output = "A=B C=D\n".to_string();
534+
535+
// Workaround for the test to pass when coverage is being run.
536+
// If enabled, the binary called by env_bin will most probably be
537+
// instrumented for coverage, and thus will set the
538+
// __LLVM_PROFILE_RT_INIT_ONCE
539+
if env::var("__LLVM_PROFILE_RT_INIT_ONCE").is_ok() {
540+
output.push_str("__LLVM_PROFILE_RT_INIT_ONCE=__LLVM_PROFILE_RT_INIT_ONCE\n");
541+
}
536542

537543
let out = scene.ucmd().args(&input).succeeds();
538544
assert_eq!(out.stdout_str(), output);

tests/uutests/src/lib/util.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1762,6 +1762,11 @@ impl UCommand {
17621762
}
17631763
}
17641764

1765+
// Forward the LLVM_PROFILE_FILE variable to the call, for coverage purposes.
1766+
if let Some(ld_preload) = env::var_os("LLVM_PROFILE_FILE") {
1767+
command.env("LLVM_PROFILE_FILE", ld_preload);
1768+
}
1769+
17651770
command
17661771
.envs(DEFAULT_ENV)
17671772
.envs(self.env_vars.iter().cloned());

util/build-code_coverage.BAT

Lines changed: 0 additions & 59 deletions
This file was deleted.

util/build-code_coverage.sh

Lines changed: 0 additions & 71 deletions
This file was deleted.

0 commit comments

Comments
 (0)