bazelbuild / bazel

a fast, scalable, multi-language and extensible build system
https://bazel.build
Apache License 2.0
22.99k stars 4.03k forks source link

FileNotFoundException for absolute path that exists #2541

Closed venantius closed 7 years ago

venantius commented 7 years ago

Description of the problem / feature request / question:

Okay, I know, this sounds like one of those problems that rookies run into and it probably is, but hopefully we can indulge the exercise anyways.

Here's the situation: we have two Java tests for a server application that expect to be able to load a Dropwizard configuration file. They look up the location of this file using the system property testConfigFile. So in my case, I've added the following configuration to our GenTestRules as follows:

GenTestRules(
    name = "GeneratedTestRules",
    test_files = glob(["src/test/java/**/*.java"]),
    jvm_flags=['-DtestConfigFile=/Users/william_jarvis/airlab-beta/repos/treehouse/projects/sundance/server/sundance.test.yml'],
    deps = ["server_test"],
)

The catch is that while the flag is passed along successfully, the tests still fail with the following exception:

java.lang.RuntimeException: java.io.FileNotFoundException: File /Users/william_jarvis/airlab-beta/repos/treehouse/projects/sundance/server/sundance.test.yml not found
    at io.dropwizard.testing.junit.DropwizardAppRule.startIfRequired(DropwizardAppRule.java:109)
    at io.dropwizard.testing.junit.DropwizardAppRule.access$000(DropwizardAppRule.java:30)
    at io.dropwizard.testing.junit.DropwizardAppRule$1.evaluate(DropwizardAppRule.java:55)
    at org.junit.rules.RunRules.evaluate(RunRules.java:20)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at com.google.testing.junit.runner.internal.junit4.CancellableRequestFactory$CancellableRunner.run(CancellableRequestFactory.java:89)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
    at com.google.testing.junit.runner.junit4.JUnit4Runner.run(JUnit4Runner.java:112)
    at com.google.testing.junit.runner.BazelTestRunner.runTestsInSuite(BazelTestRunner.java:146)
    at com.google.testing.junit.runner.BazelTestRunner.main(BazelTestRunner.java:84)
Caused by: java.io.FileNotFoundException: File /Users/william_jarvis/airlab-beta/repos/treehouse/projects/sundance/server/sundance.test.yml not found
    at io.dropwizard.configuration.FileConfigurationSourceProvider.open(FileConfigurationSourceProvider.java:14)
    at io.dropwizard.configuration.ConfigurationFactory.build(ConfigurationFactory.java:75)
    at io.dropwizard.cli.ConfiguredCommand.parseConfiguration(ConfiguredCommand.java:114)
    at io.dropwizard.cli.ConfiguredCommand.run(ConfiguredCommand.java:63)
    at io.dropwizard.testing.junit.DropwizardAppRule.startIfRequired(DropwizardAppRule.java:107)
    ... 10 more

So for some reason the test runner doesn't think the file at that path actually exists.

(aside: it's worth noting that it's possible that Dropwizard thinks the file doesn't exist for a weird reason and it's being re-thrown as a FileNotFoundException -- this is the relevant code from within io.dropwizard.configuration.FileConfigurationSourceProvider.open): https://github.com/dropwizard/dropwizard/blob/901a459af922491bb556d62e046d1475760fb8ce/dropwizard-configuration/src/main/java/io/dropwizard/configuration/FileConfigurationSourceProvider.java#L14

SO, anyways, the thing I'm trying to figure out is: that path is to a file that exists - I can copy and paste the path into a terminal and open it in Vim. So why doesn't the test think it's there? Does Bazel do something that would affect the behavior of absolute paths here?

Environment info

MacOS Sierra 10.12.3 Bazel 0.4.4-homebrew

venantius commented 7 years ago

My problem is similar to the problem encountered here, but I'm curious as to how to specify this path as a JVM flag (i.e. -Dk=v) rather than make modifications to the upstream file-opening code in Dropwizard:

https://groups.google.com/forum/#!topic/bazel-discuss/VUC8kTEXDYo

It sounds from that conversation like I should be using data to make the given yml file available at runtime for the tests, but after having added a data argument I'm not sure what sort of path I should be providing.

dslomov commented 7 years ago

What is GenTestRules? In general the issue you are seeing is that you try to refer to a file in your command that is not an input to your rule. This is a problem because Bazel cannot detect the change in that file, so it cannot rerun you test as it should if that file has changed. Bazel uses sandboxing of rule execution to prevent that: that is why you see a FileNotFoundError. The right thing to do here is:

venantius commented 7 years ago

GenTestRules is an open-source Google macro for auto-generating java_test rules -- see here for context.

I don't know what you mean when you say "add a .yml file to your workspace" -- there isn't a workspace rule that I'm aware of for just adding a file. Would I use something like filegroup?

venantius commented 7 years ago

Leaving a comment here for posterity to help out the next poor sap (or me, when I forget):

The final solution here (that actually works) looks like the following:

GenTestRules(
    name = "GeneratedTestRules",
    test_files = glob(["src/test/java/**/*.java"]),
    jvm_flags=['-DtestConfigFile=$(location :server_yml)'],
    deps = ["server_test"],
    data = ["server_yml"],
)

filegroup(
    name = "server_yml",
    srcs = ["sundance.test.yml"],
)

So the key things are:

  1. The filegroup (which uses srcs, not data)
  2. The data arg on GenTestRules/java_test
  3. The $(location target) in jvm_flags

If you don't have any of those, it doesn't work.