bazel-integration-testing icon indicating copy to clipboard operation
bazel-integration-testing copied to clipboard

Executable and runfiles "teleportation"

Open hchauvin opened this issue 6 years ago • 1 comments

Sorry in advance for the cheesy name :)

Imagine you want to write an integration test for a rule that depends on an executable with runfiles that is somewhat expensive to make (let's say, a rule for a language and you want to test some side effects of its compiler). One way to do that with speed while retaining a certain level of isolation and generality would be to:

  1. Build the executable in the invoking bazel environment.
  2. Gather all the runfiles in a runfile manifest.
  3. Add the manifest, the executable and the executable's runfiles as runfiles to, e.g., bazel_java_integration_test.
  4. Reproduce the runfile tree in the integration environment by symlinking with the information provided in 3.

Pseudo-code:

BUILD file:

java_binary(
    name = "bin",
    ...
)

teleportation_manifest(
    name = "bin_with_manifest",
    binary = ":bin",
)

bazel_java_integration_test(
    name = "test",
    data = [":bin_with_manifest"],
)

Test suite:

public class Test {
  ...

  @Before
  public void setUp() {
    driver.setUp();

    driver.teleportExecutable(
        WorkspaceDriver.getRunfile(".../bin_with_manifest.txt"),
        "to/some/package",
        "target");

    driver.scratchFile(
        "foo/BUILD",
        "sh_test(",
        "    ...,",
        "    data = [\"//to/some/package:target\"]",
        ")");
  }
}

hchauvin avatar Apr 23 '18 16:04 hchauvin

Oops I just saw #32 and #45 which are definitely relevant, sorry for the duplicate, I don't know how I could have missed that. I also saw https://github.com/bazelbuild/rules_scala/pull/364.

I actually did a proof of concept with https://github.com/bazelbuild/rules_kotlin/pull/52 (about code coverage). Relevant files are here: https://github.com/bazelbuild/rules_kotlin/tree/4c2b07476a9fe41334ed1e1f9dc96cfe9cdf4b23/tests/integrationtests/jvm/coverage With this in place and a shared download cache (see #63), I am able to run those tests in under two minutes.

@ittaiz What do you have in mind when you allude to buildifier rules in #32?

======

Concerning a question that arose in https://github.com/bazelbuild/rules_scala/pull/364, one way I found to import the current workspace to the integration environment is to pass the workspace as data:

bazel_java_integration_test(
      ...,
      data = ["//:WORKSPACE"],
)

From that, you can unwrap the symlink and have an integration WORKSPACE as such:

local_repository(
      name = "rule_to_test",
      path = "%realpath%",
)

But that is horrible because now only changes in the WORKSPACE file triggers an integration test and you rebuild your rule's dependency every single time.

One way to avoid that would be to both have a dependency on the WORKSPACE and some form of stamping that is done every single time, but I am not aware of anything in Bazel to do that and it would anyway defeat the purpose of Bazel, especially in the context of a monorepo. I think it is better to be explicit.

hchauvin avatar Apr 23 '18 17:04 hchauvin