Fix hanging issue when Bazel failed to upload action inputs (#16819)

Fixes #16422.

Closes #16423.
Closes #16445.

Closes #16464.

PiperOrigin-RevId: 480896881
Change-Id: I33019dbe8a088410280759465100a512a0f61bc1
diff --git a/src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionCache.java b/src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionCache.java
index c01ce30..6a3cfeb 100644
--- a/src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionCache.java
+++ b/src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionCache.java
@@ -222,11 +222,6 @@
 
                 @Override
                 public void onError(@NonNull Throwable e) {
-                  Disposable d = uploadTask.disposable.get();
-                  if (d != null && d.isDisposed()) {
-                    return;
-                  }
-
                   completion.onError(e);
                 }
               });
diff --git a/src/test/java/com/google/devtools/build/lib/remote/RemoteCacheTest.java b/src/test/java/com/google/devtools/build/lib/remote/RemoteCacheTest.java
index 2406c0e..77e9815 100644
--- a/src/test/java/com/google/devtools/build/lib/remote/RemoteCacheTest.java
+++ b/src/test/java/com/google/devtools/build/lib/remote/RemoteCacheTest.java
@@ -25,6 +25,8 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSortedMap;
+import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListeningScheduledExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
 import com.google.common.util.concurrent.SettableFuture;
@@ -71,6 +73,7 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -435,6 +438,29 @@
     assertThat(remoteCache.casUploadCache.getFinishedTasks()).hasSize(2);
   }
 
+  @Test
+  public void ensureInputsPresent_uploadFailed_propagateErrors() throws Exception {
+    RemoteCacheClient cacheProtocol = spy(new InMemoryCacheClient());
+    doAnswer(invocationOnMock -> Futures.immediateFailedFuture(new IOException("upload failed")))
+        .when(cacheProtocol)
+        .uploadBlob(any(), any(), any());
+    doAnswer(invocationOnMock -> Futures.immediateFailedFuture(new IOException("upload failed")))
+        .when(cacheProtocol)
+        .uploadFile(any(), any(), any());
+    RemoteExecutionCache remoteCache = spy(newRemoteExecutionCache(cacheProtocol));
+    Path path = fs.getPath("/execroot/foo");
+    FileSystemUtils.writeContentAsLatin1(path, "bar");
+    SortedMap<PathFragment, Path> inputs = ImmutableSortedMap.of(PathFragment.create("foo"), path);
+    MerkleTree merkleTree = MerkleTree.build(inputs, digestUtil);
+
+    IOException e =
+        Assert.assertThrows(
+            IOException.class,
+            () -> remoteCache.ensureInputsPresent(context, merkleTree, ImmutableMap.of(), false));
+
+    assertThat(e).hasMessageThat().contains("upload failed");
+  }
+
   private InMemoryRemoteCache newRemoteCache() {
     RemoteOptions options = Options.getDefaults(RemoteOptions.class);
     return new InMemoryRemoteCache(options, digestUtil);