I'd like to check a text file in our monorepo codebase via JUnit tests. JUnit tests are executed via bazel test command. How can I configure Bazel to pass the source code directory path (not cached compiled JAR file path) to my unit tests? it could be CLI args, environment variables, etc.
Add a comment
|
1 Answer
One way to do this is to use the data attribute which makes files available to tests (and other binaries) at runtime, and for Java there's the Runfiles library provided with Bazel for finding data files. E.g.:
BUILD:
java_test(
name = "TextFileTest",
srcs = ["javatests/txtfile/TextFileTest.java"],
data = ["text.txt"],
deps = [
"@bazel_tools//tools/java/runfiles:runfiles",
"@maven//:junit_junit",
],
)
WORKSPACE:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
RULES_JVM_EXTERNAL_TAG = "4.2"
RULES_JVM_EXTERNAL_SHA = "cd1a77b7b02e8e008439ca76fd34f5b07aecb8c752961f9640dea15e9e5ba1ca"
http_archive(
name = "rules_jvm_external",
strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
sha256 = RULES_JVM_EXTERNAL_SHA,
url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG,
)
load("@rules_jvm_external//:defs.bzl", "maven_install")
maven_install(
artifacts = [
"junit:junit:4.13.2",
],
repositories = [
"https://repo1.maven.org/maven2",
],
)
javatests/txtfile/TextFileTest.java:
package txtfile;
import com.google.devtools.build.runfiles.Runfiles;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.Path;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class TextFileTest {
@Test
public void testTextFile() throws Exception {
Runfiles runfiles = Runfiles.create();
Path path = Paths.get(runfiles.rlocation("__main__/text.txt"));
String line = Files.readAllLines(path).get(0);
Assert.assertEquals(line, "this is text");
}
}
text.txt:
this is text
$ bazel test TextFileTest
INFO: Build option --test_sharding_strategy has changed, discarding analysis cache.
INFO: Analyzed target //:TextFileTest (0 packages loaded, 547 targets configured).
INFO: Found 1 test target...
Target //:TextFileTest up-to-date:
bazel-bin/TextFileTest.jar
bazel-bin/TextFileTest
INFO: Elapsed time: 0.288s, Critical Path: 0.01s
INFO: 1 process: 1 internal.
INFO: Build completed successfully, 1 total action
//:TextFileTest (cached) PASSED in 0.3s
Executed 0 out of 1 test: 1 test passes.
INFO: Build completed successfully, 1 total action
Note that in runfiles.rlocation("__main__/text.txt") the __main__ is the workspace name, which by default is __main__. If there's a workspace(name = "workspace name") in the WORKSPACE file, then the workspace name would be set from that.
5 Comments
Poulad
Thanks for the snippet. This is not exactly what I'm looking for. This gets me the path to text.txt inside Bazel's sandbox, e.g.
/home/username/.cache/bazel/_bazel_username/fb0aa84527816b9bbc697a27654311ce/sandbox/linux-sandbox/24/execroot/myworkspace/bazel-out/k8-fastbuild/bin/javatest/mytarget.runfiles/myworkspace/text.txt. however, I want the absolute path to the local Git repository of my project(source files outside of Bazel sandbox) e.g. /home/username/Documents/myproject.ahumesky
Bazel doesn't provide this in general because it would make it easier to write things that don't work with sandboxing, or with remote execution, or are non-reproducible. But, if you really need this, you can take advantage of the fact that (on linux and mac) data files in the runfiles tree are symlinks to files in the source tree. So
toRealPath() will give you the path in the workspace, and you can get the workspace root based on where the data file is.Poulad
that's a nice trick. I decided to write a separate python script for the CI check I needed to do. It's better to respect the sandboxing practices of Bazel.
ahumesky
Yeah that sounds best
ahumesky
Though one way that might be better than what I described above is to use
--action_env. It would need to be specified on the command line every time though (something like --action_env=WORKSPACE_DIR=$(pwd), if you're invoking bazel from the workspace root)