Make --verbose_failures work again
--verbose_failures is broken since Bazel 0.28.0, Bazel won't print the
failing command for local execution even --verbose_failures is enabled.
This change fixes the problem and adds a test for it.
Fixes https://github.com/bazelbuild/bazel/issues/10572
Closes #10581.
PiperOrigin-RevId: 289854746
diff --git a/src/test/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategyTest.java b/src/test/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategyTest.java
index 29a8875..b1c42c0 100644
--- a/src/test/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategyTest.java
+++ b/src/test/java/com/google/devtools/build/lib/standalone/StandaloneSpawnStrategyTest.java
@@ -24,6 +24,7 @@
import com.google.common.eventbus.EventBus;
import com.google.devtools.build.lib.actions.ActionExecutionContext;
import com.google.devtools.build.lib.actions.ActionExecutionContext.LostInputsCheck;
+import com.google.devtools.build.lib.actions.ActionExecutionException;
import com.google.devtools.build.lib.actions.ActionInputPrefetcher;
import com.google.devtools.build.lib.actions.ActionKeyContext;
import com.google.devtools.build.lib.actions.Artifact;
@@ -64,6 +65,7 @@
import com.google.devtools.common.options.OptionsParser;
import java.io.IOException;
import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.junit.Before;
@@ -84,6 +86,8 @@
output.add(artifact);
}
};
+ private static final String WINDOWS_SYSTEM_DRIVE = "C:";
+ private static final String CMD_EXE = getWinSystemBinary("cmd.exe");
private Reporter reporter =
new Reporter(new EventBus(), PrintingEventHandler.ERRORS_AND_WARNINGS_TO_STDERR);
@@ -103,6 +107,13 @@
return testRoot;
}
+ /**
+ * We assume Windows is installed on C: and all system binaries exist under C:\Windows\System32\
+ */
+ private static String getWinSystemBinary(String binary) {
+ return WINDOWS_SYSTEM_DRIVE + "\\Windows\\System32\\" + binary;
+ }
+
@Before
public final void setUp() throws Exception {
Path testRoot = createTestRoot();
@@ -188,7 +199,9 @@
Spawn spawn = createSpawn(getTrueCommand());
executor.getContext(SpawnActionContext.class).exec(spawn, createContext());
- assertThat(out()).isEmpty();
+ if (OS.getCurrent() != OS.WINDOWS) {
+ assertThat(out()).isEmpty();
+ }
assertThat(err()).isEmpty();
}
@@ -215,62 +228,108 @@
}
@Test
- public void testBinFalseYieldsException() throws Exception {
+ public void testBinFalseYieldsException() {
ExecException e = assertThrows(ExecException.class, () -> run(createSpawn(getFalseCommand())));
assertWithMessage("got: " + e.getMessage())
- .that(e.getMessage().startsWith("false failed: error executing command"))
+ .that(e.getMessage().contains("failed: error executing command"))
.isTrue();
}
private static String getFalseCommand() {
+ if (OS.getCurrent() == OS.WINDOWS) {
+ // No false command on Windows, we use help.exe as an alternative,
+ // the caveat is that the command will have some output to stdout.
+ // Default exit code of help is 1
+ return getWinSystemBinary("help.exe");
+ }
return OS.getCurrent() == OS.DARWIN ? "/usr/bin/false" : "/bin/false";
}
private static String getTrueCommand() {
+ if (OS.getCurrent() == OS.WINDOWS) {
+ // No true command on Windows, we use whoami.exe as an alternative,
+ // the caveat is that the command will have some output to stdout.
+ // Default exit code of help is 0
+ return getWinSystemBinary("whoami.exe");
+ }
return OS.getCurrent() == OS.DARWIN ? "/usr/bin/true" : "/bin/true";
}
@Test
public void testBinEchoPrintsArguments() throws Exception {
- Spawn spawn = createSpawn("/bin/echo", "Hello,", "world.");
+ Spawn spawn;
+ if (OS.getCurrent() == OS.WINDOWS) {
+ spawn = createSpawn(CMD_EXE, "/c", "echo", "Hello,", "world.");
+ } else {
+ spawn = createSpawn("/bin/echo", "Hello,", "world.");
+ }
run(spawn);
- assertThat(out()).isEqualTo("Hello, world.\n");
+ assertThat(out()).isEqualTo("Hello, world." + System.lineSeparator());
assertThat(err()).isEmpty();
}
@Test
public void testCommandRunsInWorkingDir() throws Exception {
- Spawn spawn = createSpawn("/bin/pwd");
+ Spawn spawn;
+ if (OS.getCurrent() == OS.WINDOWS) {
+ spawn = createSpawn(CMD_EXE, "/c", "cd");
+ } else {
+ spawn = createSpawn("/bin/pwd");
+ }
run(spawn);
- assertThat(out()).isEqualTo(executor.getExecRoot() + "\n");
+ assertThat(out().replace('\\', '/')).isEqualTo(executor.getExecRoot() + System.lineSeparator());
}
@Test
public void testCommandHonorsEnvironment() throws Exception {
- if (OS.getCurrent() == OS.DARWIN) {
- // // TODO(#)3795: For some reason, we get __CF_USER_TEXT_ENCODING into the env in some
- // configurations of MacOS machines. I have been unable to reproduce on my Mac, or to track
- // down where that env var is coming from.
- return;
- }
Spawn spawn =
new SimpleSpawn(
new ActionsTestUtil.NullAction(),
- ImmutableList.of("/usr/bin/env"),
+ OS.getCurrent() == OS.WINDOWS
+ ? ImmutableList.of(CMD_EXE, "/c", "set")
+ : ImmutableList.of("/usr/bin/env"),
/*environment=*/ ImmutableMap.of("foo", "bar", "baz", "boo"),
/*executionInfo=*/ ImmutableMap.of(),
/*inputs=*/ NestedSetBuilder.emptySet(Order.STABLE_ORDER),
/*outputs=*/ ImmutableSet.of(),
ResourceSet.ZERO);
run(spawn);
- assertThat(Sets.newHashSet(out().split("\n"))).isEqualTo(Sets.newHashSet("foo=bar", "baz=boo"));
+ HashSet<String> environment = Sets.newHashSet(out().split(System.lineSeparator()));
+ if (OS.getCurrent() == OS.WINDOWS || OS.getCurrent() == OS.DARWIN) {
+ // On Windows and macOS, we may have some other env vars
+ // (eg. SystemRoot or __CF_USER_TEXT_ENCODING).
+ assertThat(environment).contains("foo=bar");
+ assertThat(environment).contains("baz=boo");
+ } else {
+ assertThat(environment).isEqualTo(Sets.newHashSet("foo=bar", "baz=boo"));
+ }
}
@Test
public void testStandardError() throws Exception {
- Spawn spawn = createSpawn("/bin/sh", "-c", "echo Oops! >&2");
+ Spawn spawn;
+ if (OS.getCurrent() == OS.WINDOWS) {
+ spawn = createSpawn(CMD_EXE, "/c", "echo Oops!>&2");
+ } else {
+ spawn = createSpawn("/bin/sh", "-c", "echo Oops! >&2");
+ }
run(spawn);
- assertThat(err()).isEqualTo("Oops!\n");
+ assertThat(err()).isEqualTo("Oops!" + System.lineSeparator());
assertThat(out()).isEmpty();
}
+
+ /**
+ * Regression test for https://github.com/bazelbuild/bazel/issues/10572 Make sure we do have the
+ * command line executed in the error message of ActionExecutionException when --verbose_failures
+ * is enabled.
+ */
+ @Test
+ public void testVerboseFailures() {
+ ExecException e = assertThrows(ExecException.class, () -> run(createSpawn(getFalseCommand())));
+ ActionExecutionException actionExecutionException =
+ e.toActionExecutionException("", /* verboseFailures= */ true, null);
+ assertWithMessage("got: " + actionExecutionException.getMessage())
+ .that(actionExecutionException.getMessage().contains("failed: error executing command"))
+ .isTrue();
+ }
}