integration_tests/
env.rs

1// Copyright (c) The nextest Contributors
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4use camino::Utf8PathBuf;
5
6/// Environment info captured before sanitization.
7#[derive(Debug)]
8pub struct TestEnvInfo {
9    /// The workspace root, from `NEXTEST_WORKSPACE_ROOT`.
10    pub workspace_root: Utf8PathBuf,
11    /// Path to the cargo-nextest-dup binary.
12    pub cargo_nextest_dup_bin: Utf8PathBuf,
13    /// Path to the fake_interceptor binary.
14    pub fake_interceptor_bin: Utf8PathBuf,
15    /// Path to the rustc_shim binary.
16    pub rustc_shim_bin: Utf8PathBuf,
17    /// Path to the passthrough binary.
18    pub passthrough_bin: Utf8PathBuf,
19    /// Path to the grab_foreground binary (Unix only).
20    #[cfg(unix)]
21    pub grab_foreground_bin: Utf8PathBuf,
22}
23
24/// Sets up environment variables for a setup script.
25///
26/// Setup scripts don't have access to `CARGO_BIN_EXE_*` or `NEXTEST_BIN_EXE_*`
27/// variables, so this only performs sanitization without capturing binary paths.
28pub fn set_env_vars_for_script() {
29    // SAFETY:
30    // https://nexte.st/docs/configuration/env-vars/#altering-the-environment-within-tests
31    unsafe {
32        sanitize_env();
33    }
34}
35
36/// Sets up environment variables for a test.
37///
38/// This captures binary paths from `NEXTEST_BIN_EXE_*` variables before
39/// sanitizing the environment.
40#[track_caller]
41pub fn set_env_vars_for_test() -> TestEnvInfo {
42    // Capture required values before sanitization removes NEXTEST_* and
43    // CARGO_* variables.
44    let workspace_root: Utf8PathBuf = std::env::var("NEXTEST_WORKSPACE_ROOT")
45        .expect("NEXTEST_WORKSPACE_ROOT should be set")
46        .into();
47    let cargo_nextest_dup_bin: Utf8PathBuf = std::env::var("NEXTEST_BIN_EXE_cargo_nextest_dup")
48        .expect("NEXTEST_BIN_EXE_cargo_nextest_dup should be set")
49        .into();
50    let fake_interceptor_bin: Utf8PathBuf = std::env::var("NEXTEST_BIN_EXE_fake_interceptor")
51        .expect("NEXTEST_BIN_EXE_fake_interceptor should be set")
52        .into();
53    let rustc_shim_bin: Utf8PathBuf = std::env::var("NEXTEST_BIN_EXE_rustc_shim")
54        .expect("NEXTEST_BIN_EXE_rustc_shim should be set")
55        .into();
56    let passthrough_bin: Utf8PathBuf = std::env::var("NEXTEST_BIN_EXE_passthrough")
57        .expect("NEXTEST_BIN_EXE_passthrough should be set")
58        .into();
59    #[cfg(unix)]
60    let grab_foreground_bin: Utf8PathBuf = std::env::var("NEXTEST_BIN_EXE_grab_foreground")
61        .expect("NEXTEST_BIN_EXE_grab_foreground should be set")
62        .into();
63
64    // Ensure NEXTEST_PROFILE is set (we're running under nextest).
65    std::env::var("NEXTEST_PROFILE").expect("NEXTEST_PROFILE should be set");
66
67    // SAFETY:
68    // https://nexte.st/docs/configuration/env-vars/#altering-the-environment-within-tests
69    unsafe {
70        sanitize_env();
71    }
72
73    TestEnvInfo {
74        workspace_root,
75        cargo_nextest_dup_bin,
76        fake_interceptor_bin,
77        rustc_shim_bin,
78        passthrough_bin,
79        #[cfg(unix)]
80        grab_foreground_bin,
81    }
82}
83
84/// Sanitizes the environment by removing `NEXTEST_*` and `CARGO_*` variables
85/// and setting up variables needed for integration tests.
86///
87/// # Safety
88///
89/// This function modifies the process environment, which is not thread-safe.
90/// See <https://nexte.st/docs/configuration/env-vars/#altering-the-environment-within-tests>.
91unsafe fn sanitize_env() {
92    // Sanitize the environment by removing all NEXTEST_* and CARGO_* variables
93    // from the parent environment. This ensures deterministic behavior regardless
94    // of what the parent process has set. We'll then set specific variables below.
95
96    // Collect keys first to avoid mutating while iterating.
97    let keys_to_remove: Vec<_> = std::env::vars()
98        .filter(|(key, _)| key.starts_with("NEXTEST_") || key.starts_with("CARGO_"))
99        .map(|(key, _)| key)
100        .collect();
101    for key in keys_to_remove {
102        std::env::remove_var(&key);
103    }
104
105    // The dynamic library tests require this flag.
106    std::env::set_var("RUSTFLAGS", "-C prefer-dynamic");
107
108    // Set CARGO_TERM_COLOR to never to ensure that ANSI color codes don't
109    // interfere with the output.
110    std::env::set_var("CARGO_TERM_COLOR", "never");
111
112    // This environment variable is required to test the #[bench] fixture.
113    // Note that THIS IS FOR TEST CODE ONLY. NEVER USE THIS IN PRODUCTION.
114    std::env::set_var("RUSTC_BOOTSTRAP", "1");
115
116    // Disable the tests which check for environment variables being set in
117    // `config.toml`, as they won't be in the search path when running
118    // integration tests.
119    std::env::set_var("__NEXTEST_NO_CHECK_CARGO_ENV_VARS", "1");
120
121    // Display empty STDOUT and STDERR lines in the output of failed tests.
122    // This allows tests which make sure outputs are being displayed to
123    // work.
124    std::env::set_var("__NEXTEST_DISPLAY_EMPTY_OUTPUTS", "1");
125
126    // Remove OUT_DIR from the environment, as it interferes with tests
127    // (some of them expect that OUT_DIR isn't set.)
128    std::env::remove_var("OUT_DIR");
129
130    // Set NEXTEST_SHOW_PROGRESS to counter to ensure user config doesn't
131    // affect test output.
132    std::env::set_var("NEXTEST_SHOW_PROGRESS", "counter");
133
134    // Skip user config loading entirely for test isolation. This prevents
135    // the user's personal config from affecting test results. (Note that
136    // some config tests pass in --user-config-file, which overrides this
137    // environment variable.)
138    std::env::set_var("NEXTEST_USER_CONFIG_FILE", "none");
139}