// Copyright 2018 The Bazel Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.devtools.build.runfiles; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.fail; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.util.Collections; import java.util.Map; import javax.annotation.Nullable; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** Unit tests for {@link Runfiles}. */ @RunWith(JUnit4.class) public final class RunfilesTest { private static boolean isWindows() { return File.separatorChar == '\\'; } private void assertRlocationArg(Runfiles runfiles, String path, @Nullable String error) throws Exception { try { runfiles.rlocation(path); fail(); } catch (IllegalArgumentException e) { if (error != null) { assertThat(e).hasMessageThat().contains(error); } } } @Test public void testRlocationArgumentValidation() throws Exception { Path dir = Files.createTempDirectory( FileSystems.getDefault().getPath(System.getenv("TEST_TMPDIR")), null); Runfiles r = Runfiles.create(ImmutableMap.of("RUNFILES_DIR", dir.toString())); assertRlocationArg(r, null, null); assertRlocationArg(r, "", null); assertRlocationArg(r, "../foo", "is not normalized"); assertRlocationArg(r, "foo/..", "is not normalized"); assertRlocationArg(r, "foo/../bar", "is not normalized"); assertRlocationArg(r, "./foo", "is not normalized"); assertRlocationArg(r, "foo/.", "is not normalized"); assertRlocationArg(r, "foo/./bar", "is not normalized"); assertRlocationArg(r, "//foobar", "is not normalized"); assertRlocationArg(r, "foo//", "is not normalized"); assertRlocationArg(r, "foo//bar", "is not normalized"); assertRlocationArg(r, "\\foo", "path is absolute without a drive letter"); } @Test public void testCreatesManifestBasedRunfiles() throws Exception { try (MockFile mf = new MockFile(ImmutableList.of("a/b c/d"))) { Runfiles r = Runfiles.create( ImmutableMap.of( "RUNFILES_MANIFEST_ONLY", "1", "RUNFILES_MANIFEST_FILE", mf.path.toString(), "RUNFILES_DIR", "ignored when RUNFILES_MANIFEST_ONLY=1", "JAVA_RUNFILES", "ignored when RUNFILES_DIR has a value", "TEST_SRCDIR", "should always be ignored")); assertThat(r.rlocation("a/b")).isEqualTo("c/d"); assertThat(r.rlocation("foo")).isNull(); if (isWindows()) { assertThat(r.rlocation("c:/foo")).isEqualTo("c:/foo"); assertThat(r.rlocation("c:\\foo")).isEqualTo("c:\\foo"); } else { assertThat(r.rlocation("/foo")).isEqualTo("/foo"); } } } @Test public void testCreatesDirectoryBasedRunfiles() throws Exception { Path dir = Files.createTempDirectory( FileSystems.getDefault().getPath(System.getenv("TEST_TMPDIR")), null); Runfiles r = Runfiles.create( ImmutableMap.of( "RUNFILES_MANIFEST_FILE", "ignored when RUNFILES_MANIFEST_ONLY is not set to 1", "RUNFILES_DIR", dir.toString(), "JAVA_RUNFILES", "ignored when RUNFILES_DIR has a value", "TEST_SRCDIR", "should always be ignored")); assertThat(r.rlocation("a/b")).endsWith("/a/b"); assertThat(r.rlocation("foo")).endsWith("/foo"); r = Runfiles.create( ImmutableMap.of( "RUNFILES_MANIFEST_FILE", "ignored when RUNFILES_MANIFEST_ONLY is not set to 1", "RUNFILES_DIR", "", "JAVA_RUNFILES", dir.toString(), "TEST_SRCDIR", "should always be ignored")); assertThat(r.rlocation("a/b")).endsWith("/a/b"); assertThat(r.rlocation("foo")).endsWith("/foo"); } @Test public void testIgnoresTestSrcdirWhenJavaRunfilesIsUndefinedAndJustFails() throws Exception { Path dir = Files.createTempDirectory( FileSystems.getDefault().getPath(System.getenv("TEST_TMPDIR")), null); Runfiles.create( ImmutableMap.of( "RUNFILES_DIR", dir.toString(), "RUNFILES_MANIFEST_FILE", "ignored when RUNFILES_MANIFEST_ONLY is not set to 1", "TEST_SRCDIR", "should always be ignored")); Runfiles.create( ImmutableMap.of( "JAVA_RUNFILES", dir.toString(), "RUNFILES_MANIFEST_FILE", "ignored when RUNFILES_MANIFEST_ONLY is not set to 1", "TEST_SRCDIR", "should always be ignored")); try { // The method must ignore TEST_SRCDIR, for the scenario when Bazel runs a test which itself // runs Bazel to build and run java_binary. The java_binary should not pick up the test's // TEST_SRCDIR. Runfiles.create( ImmutableMap.of( "RUNFILES_DIR", "", "JAVA_RUNFILES", "", "RUNFILES_MANIFEST_FILE", "ignored when RUNFILES_MANIFEST_ONLY is not set to 1", "TEST_SRCDIR", "should always be ignored")); fail(); } catch (IOException e) { assertThat(e).hasMessageThat().contains("$RUNFILES_DIR and $JAVA_RUNFILES"); } } @Test public void testFailsToCreateManifestBasedBecauseManifestDoesNotExist() throws Exception { try { Runfiles.create( ImmutableMap.of( "RUNFILES_MANIFEST_ONLY", "1", "RUNFILES_MANIFEST_FILE", "non-existing path")); fail(); } catch (IOException e) { assertThat(e).hasMessageThat().contains("non-existing path"); } } @Test public void testManifestBasedEnvVars() throws Exception { Path dir = Files.createTempDirectory( FileSystems.getDefault().getPath(System.getenv("TEST_TMPDIR")), null); Path mf = dir.resolve("MANIFEST"); Files.write(mf, Collections.emptyList(), StandardCharsets.UTF_8); Map envvars = Runfiles.create( ImmutableMap.of( "RUNFILES_MANIFEST_ONLY", "1", "RUNFILES_MANIFEST_FILE", mf.toString(), "RUNFILES_DIR", "ignored when RUNFILES_MANIFEST_ONLY=1", "JAVA_RUNFILES", "ignored when RUNFILES_DIR has a value", "TEST_SRCDIR", "should always be ignored")) .getEnvVars(); assertThat(envvars.keySet()) .containsExactly( "RUNFILES_MANIFEST_ONLY", "RUNFILES_MANIFEST_FILE", "RUNFILES_DIR", "JAVA_RUNFILES"); assertThat(envvars.get("RUNFILES_MANIFEST_ONLY")).isEqualTo("1"); assertThat(envvars.get("RUNFILES_MANIFEST_FILE")).isEqualTo(mf.toString()); assertThat(envvars.get("RUNFILES_DIR")).isEqualTo(dir.toString()); assertThat(envvars.get("JAVA_RUNFILES")).isEqualTo(dir.toString()); Path rfDir = dir.resolve("foo.runfiles"); Files.createDirectories(rfDir); mf = dir.resolve("foo.runfiles_manifest"); Files.write(mf, Collections.emptyList(), StandardCharsets.UTF_8); envvars = Runfiles.create( ImmutableMap.of( "RUNFILES_MANIFEST_ONLY", "1", "RUNFILES_MANIFEST_FILE", mf.toString(), "RUNFILES_DIR", "ignored when RUNFILES_MANIFEST_ONLY=1", "JAVA_RUNFILES", "ignored when RUNFILES_DIR has a value", "TEST_SRCDIR", "should always be ignored")) .getEnvVars(); assertThat(envvars.get("RUNFILES_MANIFEST_ONLY")).isEqualTo("1"); assertThat(envvars.get("RUNFILES_MANIFEST_FILE")).isEqualTo(mf.toString()); assertThat(envvars.get("RUNFILES_DIR")).isEqualTo(rfDir.toString()); assertThat(envvars.get("JAVA_RUNFILES")).isEqualTo(rfDir.toString()); } @Test public void testDirectoryBasedEnvVars() throws Exception { Path dir = Files.createTempDirectory( FileSystems.getDefault().getPath(System.getenv("TEST_TMPDIR")), null); Map envvars = Runfiles.create( ImmutableMap.of( "RUNFILES_MANIFEST_FILE", "ignored when RUNFILES_MANIFEST_ONLY is not set to 1", "RUNFILES_DIR", dir.toString(), "JAVA_RUNFILES", "ignored when RUNFILES_DIR has a value", "TEST_SRCDIR", "should always be ignored")) .getEnvVars(); assertThat(envvars.keySet()).containsExactly("RUNFILES_DIR", "JAVA_RUNFILES"); assertThat(envvars.get("RUNFILES_DIR")).isEqualTo(dir.toString()); assertThat(envvars.get("JAVA_RUNFILES")).isEqualTo(dir.toString()); } @Test public void testDirectoryBasedRlocation() throws Exception { // The DirectoryBased implementation simply joins the runfiles directory and the runfile's path // on a "/". DirectoryBased does not perform any normalization, nor does it check that the path // exists. File dir = new File(System.getenv("TEST_TMPDIR"), "mock/runfiles"); assertThat(dir.mkdirs()).isTrue(); Runfiles r = Runfiles.createDirectoryBasedForTesting(dir.toString()); // Escaping for "\": once for string and once for regex. assertThat(r.rlocation("arg")).matches(".*[/\\\\]mock[/\\\\]runfiles[/\\\\]arg"); } @Test public void testManifestBasedRlocation() throws Exception { try (MockFile mf = new MockFile( ImmutableList.of( "Foo/runfile1 C:/Actual Path\\runfile1", "Foo/Bar/runfile2 D:\\the path\\run file 2.txt"))) { Runfiles r = Runfiles.createManifestBasedForTesting(mf.path.toString()); assertThat(r.rlocation("Foo/runfile1")).isEqualTo("C:/Actual Path\\runfile1"); assertThat(r.rlocation("Foo/Bar/runfile2")).isEqualTo("D:\\the path\\run file 2.txt"); assertThat(r.rlocation("unknown")).isNull(); } } @Test public void testDirectoryBasedCtorArgumentValidation() throws Exception { try { Runfiles.createDirectoryBasedForTesting(null); fail(); } catch (IllegalArgumentException e) { // expected } try { Runfiles.createDirectoryBasedForTesting(""); fail(); } catch (IllegalArgumentException e) { // expected } try { Runfiles.createDirectoryBasedForTesting("non-existent directory is bad"); fail(); } catch (IllegalArgumentException e) { // expected } Runfiles.createDirectoryBasedForTesting(System.getenv("TEST_TMPDIR")); } @Test public void testManifestBasedCtorArgumentValidation() throws Exception { try { Runfiles.createManifestBasedForTesting(null); fail(); } catch (IllegalArgumentException e) { // expected } try { Runfiles.createManifestBasedForTesting(""); fail(); } catch (IllegalArgumentException e) { // expected } try (MockFile mf = new MockFile(ImmutableList.of("a b"))) { Runfiles.createManifestBasedForTesting(mf.path.toString()); } } }