Skip to content

Commit 238b998

Browse files
authored
Do not use test launcher when not needed (#960)
This backwards compatible change does 2 things: it uses testing.TestEnvironment to populate the environment for the rust_test execution. This is a new discovery that we were not aware of, and it mostly removes most common duties from our test launcher. stops using test launcher for situations when it is not needed (when there is no {pwd} placeholder expansion needed in environment variable values). What will likely follow is an incompatible change that removes {pwd} expansion altogether (after I do the reserach to see if it is used :)
1 parent e83c39d commit 238b998

File tree

8 files changed

+93
-21
lines changed

8 files changed

+93
-21
lines changed

docs/defs.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,7 @@ Run the test with `bazel build //hello_lib:hello_lib_test`.
550550
| <a id="rust_test-data"></a>data | List of files used by this rule at compile time and runtime.<br><br>If including data at compile time with include_str!() and similar, prefer <code>compile_data</code> over <code>data</code>, to prevent the data also being included in the runfiles. | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | optional | [] |
551551
| <a id="rust_test-deps"></a>deps | List of other libraries to be linked to this library target.<br><br>These can be either other <code>rust_library</code> targets or <code>cc_library</code> targets if linking a native library. | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | optional | [] |
552552
| <a id="rust_test-edition"></a>edition | The rust edition to use for this crate. Defaults to the edition specified in the rust_toolchain. | String | optional | "" |
553-
| <a id="rust_test-env"></a>env | Specifies additional environment variables to set when the test is executed by bazel test. Values are subject to <code>$(execpath)</code> and ["Make variable"](https://docs.bazel.build/versions/master/be/make-variables.html) substitution. | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | optional | {} |
553+
| <a id="rust_test-env"></a>env | Specifies additional environment variables to set when the test is executed by bazel test. Values are subject to <code>$(rootpath)</code>, <code>$(execpath)</code>, location, and ["Make variable"](https://docs.bazel.build/versions/master/be/make-variables.html) substitution.<br><br>Execpath returns absolute path, and in order to be able to construct the absolute path we need to wrap the test binary in a launcher. Using a launcher comes with complications, such as more complicated debugger attachment. | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | optional | {} |
554554
| <a id="rust_test-proc_macro_deps"></a>proc_macro_deps | List of <code>rust_library</code> targets with kind <code>proc-macro</code> used to help build this library target. | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | optional | [] |
555555
| <a id="rust_test-rustc_env"></a>rustc_env | Dictionary of additional <code>"key": "value"</code> environment variables to set for rustc.<br><br>rust_test()/rust_binary() rules can use $(rootpath //package:target) to pass in the location of a generated file or external tool. Cargo build scripts that wish to expand locations should use cargo_build_script()'s build_script_env argument instead, as build scripts are run in a different environment - see cargo_build_script()'s documentation for more. | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | optional | {} |
556556
| <a id="rust_test-rustc_env_files"></a>rustc_env_files | Files containing additional environment variables to set for rustc.<br><br>These files should contain a single variable per line, of format <code>NAME=value</code>, and newlines may be included in a value by ending a line with a trailing back-slash (<code>\</code>).<br><br>The order that these files will be processed is unspecified, so multiple definitions of a particular variable are discouraged. | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | optional | [] |

docs/flatten.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1094,7 +1094,7 @@ Run the test with `bazel build //hello_lib:hello_lib_test`.
10941094
| <a id="rust_test-data"></a>data | List of files used by this rule at compile time and runtime.<br><br>If including data at compile time with include_str!() and similar, prefer <code>compile_data</code> over <code>data</code>, to prevent the data also being included in the runfiles. | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | optional | [] |
10951095
| <a id="rust_test-deps"></a>deps | List of other libraries to be linked to this library target.<br><br>These can be either other <code>rust_library</code> targets or <code>cc_library</code> targets if linking a native library. | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | optional | [] |
10961096
| <a id="rust_test-edition"></a>edition | The rust edition to use for this crate. Defaults to the edition specified in the rust_toolchain. | String | optional | "" |
1097-
| <a id="rust_test-env"></a>env | Specifies additional environment variables to set when the test is executed by bazel test. Values are subject to <code>$(execpath)</code> and ["Make variable"](https://docs.bazel.build/versions/master/be/make-variables.html) substitution. | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | optional | {} |
1097+
| <a id="rust_test-env"></a>env | Specifies additional environment variables to set when the test is executed by bazel test. Values are subject to <code>$(rootpath)</code>, <code>$(execpath)</code>, location, and ["Make variable"](https://docs.bazel.build/versions/master/be/make-variables.html) substitution.<br><br>Execpath returns absolute path, and in order to be able to construct the absolute path we need to wrap the test binary in a launcher. Using a launcher comes with complications, such as more complicated debugger attachment. | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | optional | {} |
10981098
| <a id="rust_test-proc_macro_deps"></a>proc_macro_deps | List of <code>rust_library</code> targets with kind <code>proc-macro</code> used to help build this library target. | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | optional | [] |
10991099
| <a id="rust_test-rustc_env"></a>rustc_env | Dictionary of additional <code>"key": "value"</code> environment variables to set for rustc.<br><br>rust_test()/rust_binary() rules can use $(rootpath //package:target) to pass in the location of a generated file or external tool. Cargo build scripts that wish to expand locations should use cargo_build_script()'s build_script_env argument instead, as build scripts are run in a different environment - see cargo_build_script()'s documentation for more. | <a href="https://bazel.build/docs/skylark/lib/dict.html">Dictionary: String -> String</a> | optional | {} |
11001100
| <a id="rust_test-rustc_env_files"></a>rustc_env_files | Files containing additional environment variables to set for rustc.<br><br>These files should contain a single variable per line, of format <code>NAME=value</code>, and newlines may be included in a value by ending a line with a trailing back-slash (<code>\</code>).<br><br>The order that these files will be processed is unspecified, so multiple definitions of a particular variable are discouraged. | <a href="https://bazel.build/docs/build-ref.html#labels">List of labels</a> | optional | [] |

rust/private/rust.bzl

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -306,13 +306,14 @@ def _rust_binary_impl(ctx):
306306
),
307307
)
308308

309-
def _create_test_launcher(ctx, toolchain, output, providers):
309+
def _create_test_launcher(ctx, toolchain, output, env, providers):
310310
"""Create a process wrapper to ensure runtime environment variables are defined for the test binary
311311
312312
Args:
313313
ctx (ctx): The rule's context object
314314
toolchain (rust_toolchain): The current rust toolchain
315315
output (File): The output File that will be produced, depends on crate type.
316+
env (dict): Dict of environment variables
316317
providers (list): Providers from a rust compile action. See `rustc_compile_action`
317318
318319
Returns:
@@ -337,20 +338,12 @@ def _create_test_launcher(ctx, toolchain, output, providers):
337338
is_executable = True,
338339
)
339340

340-
# Get data attribute
341-
data = getattr(ctx.attr, "data", [])
342-
343341
# Expand the environment variables and write them to a file
344342
environ_file = ctx.actions.declare_file(launcher_filename + ".launchfiles/env")
345-
environ = expand_dict_value_locations(
346-
ctx,
347-
getattr(ctx.attr, "env", {}),
348-
data,
349-
)
350343

351344
# Convert the environment variables into a list to be written into a file.
352345
environ_list = []
353-
for key, value in sorted(environ.items()):
346+
for key, value in sorted(env.items()):
354347
environ_list.extend([key, value])
355348

356349
ctx.actions.write(
@@ -454,8 +447,21 @@ def _rust_test_common(ctx, toolchain, output):
454447
crate_info = crate_info,
455448
rust_flags = ["--test"] if ctx.attr.use_libtest_harness else ["--cfg", "test"],
456449
)
450+
data = getattr(ctx.attr, "data", [])
451+
452+
env = expand_dict_value_locations(
453+
ctx,
454+
getattr(ctx.attr, "env", {}),
455+
data,
456+
)
457+
providers.append(testing.TestEnvironment(env))
457458

458-
return _create_test_launcher(ctx, toolchain, output, providers)
459+
if any(["{pwd}" in v for v in env.values()]):
460+
# Some of the environment variables require expanding {pwd} placeholder at runtime,
461+
# we need a launcher for that.
462+
return _create_test_launcher(ctx, toolchain, output, env, providers)
463+
else:
464+
return providers
459465

460466
def _rust_test_impl(ctx):
461467
"""The implementation of the `rust_test` rule
@@ -630,8 +636,12 @@ _rust_test_attrs = {
630636
mandatory = False,
631637
doc = dedent("""\
632638
Specifies additional environment variables to set when the test is executed by bazel test.
633-
Values are subject to `$(execpath)` and
639+
Values are subject to `$(rootpath)`, `$(execpath)`, location, and
634640
["Make variable"](https://docs.bazel.build/versions/master/be/make-variables.html) substitution.
641+
642+
Execpath returns absolute path, and in order to be able to construct the absolute path we
643+
need to wrap the test binary in a launcher. Using a launcher comes with complications, such as
644+
more complicated debugger attachment.
635645
"""),
636646
),
637647
"use_libtest_harness": attr.bool(

test/test_env/BUILD.bazel

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,5 @@ rust_test(
2626
env = {
2727
"FERRIS_SAYS": "Hello fellow Rustaceans!",
2828
"HELLO_WORLD_BIN_ROOTPATH": "$(rootpath :hello-world)",
29-
"HELLO_WORLD_SRC_EXECPATH": "$(execpath :hello_world_main)",
3029
},
3130
)

test/test_env/tests/run.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,4 @@ fn run() {
2626
);
2727
assert!(!hello_world_bin.is_absolute());
2828
assert!(hello_world_bin.exists());
29-
30-
// Ensure `execpath` expanded variables map to real files and have absolute paths
31-
let hello_world_src =
32-
std::path::PathBuf::from(std::env::var("HELLO_WORLD_SRC_EXECPATH").unwrap());
33-
assert!(hello_world_src.is_absolute());
34-
assert!(hello_world_src.exists());
3529
}

test/test_env_launcher/BUILD.bazel

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
load(
2+
"//rust:rust.bzl",
3+
"rust_binary",
4+
"rust_test",
5+
)
6+
7+
rust_binary(
8+
name = "hello-world",
9+
srcs = ["src/main.rs"],
10+
edition = "2018",
11+
)
12+
13+
filegroup(
14+
name = "hello_world_main",
15+
srcs = ["src/main.rs"],
16+
)
17+
18+
rust_test(
19+
name = "test",
20+
srcs = ["tests/run.rs"],
21+
data = [
22+
":hello-world",
23+
":hello_world_main",
24+
],
25+
edition = "2018",
26+
env = {
27+
"FERRIS_SAYS": "Hello fellow Rustaceans!",
28+
"HELLO_WORLD_BIN_ROOTPATH": "$(rootpath :hello-world)",
29+
"HELLO_WORLD_SRC_EXECPATH": "$(execpath :hello_world_main)",
30+
},
31+
)

test/test_env_launcher/src/main.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main() {
2+
println!("Hello world");
3+
}

test/test_env_launcher/tests/run.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#[test]
2+
fn run() {
3+
let path = env!("CARGO_BIN_EXE_hello-world");
4+
let output = std::process::Command::new(path)
5+
.output()
6+
.expect("Failed to run process");
7+
assert_eq!(&b"Hello world\n"[..], output.stdout.as_slice());
8+
9+
// Test the `env` attribute of `rust_test` at run time
10+
assert_eq!(
11+
std::env::var("FERRIS_SAYS").unwrap(),
12+
"Hello fellow Rustaceans!"
13+
);
14+
15+
// Test the behavior of `rootpath` and that a binary can be found relative to current_dir
16+
let hello_world_bin =
17+
std::path::PathBuf::from(std::env::var_os("HELLO_WORLD_BIN_ROOTPATH").unwrap());
18+
19+
assert_eq!(
20+
hello_world_bin.as_path(),
21+
std::path::Path::new(if std::env::consts::OS == "windows" {
22+
"test/test_env_launcher/hello-world.exe"
23+
} else {
24+
"test/test_env_launcher/hello-world"
25+
})
26+
);
27+
assert!(!hello_world_bin.is_absolute());
28+
assert!(hello_world_bin.exists());
29+
30+
// Ensure `execpath` expanded variables map to real files and have absolute paths
31+
let hello_world_src =
32+
std::path::PathBuf::from(std::env::var("HELLO_WORLD_SRC_EXECPATH").unwrap());
33+
assert!(hello_world_src.is_absolute());
34+
assert!(hello_world_src.exists());
35+
}

0 commit comments

Comments
 (0)