Support unreadable files

--
MOS_MIGRATED_REVID=112507181
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java
index 5ca1354..aae3254 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/ArtifactFunctionTest.java
@@ -21,7 +21,7 @@
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.fail;
 
-import com.google.common.base.Predicates;
+import com.google.common.base.Predicate;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
@@ -64,6 +64,8 @@
 import org.junit.runners.JUnit4;
 
 import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -82,6 +84,14 @@
   private static final SkyKey OWNER_KEY = new SkyKey(SkyFunctions.ACTION_LOOKUP, "OWNER");
   private static final ActionLookupKey ALL_OWNER = new SingletonActionLookupKey();
 
+  private PathFragment allowedMissingInput = null;
+  private Predicate<PathFragment> allowedMissingInputsPredicate = new Predicate<PathFragment>() {
+    @Override
+    public boolean apply(PathFragment input) {
+      return input.equals(allowedMissingInput);
+    }
+  };
+
   private Set<Action> actions;
   private boolean fastDigest = false;
   private RecordingDifferencer differencer = new RecordingDifferencer();
@@ -102,8 +112,7 @@
             ImmutableMap.<SkyFunctionName, SkyFunction>builder()
                 .put(SkyFunctions.FILE_STATE, new FileStateFunction(tsgm, externalFilesHelper))
                 .put(SkyFunctions.FILE, new FileFunction(pkgLocator))
-                .put(SkyFunctions.ARTIFACT,
-                    new ArtifactFunction(Predicates.<PathFragment>alwaysFalse()))
+                .put(SkyFunctions.ARTIFACT, new ArtifactFunction(allowedMissingInputsPredicate))
                 .put(SkyFunctions.ACTION_EXECUTION, new SimpleActionExecutionFunction())
                 .put(SkyFunctions.PACKAGE,
                     new PackageFunction(null, null, null, null, null, null, null))
@@ -152,6 +161,52 @@
   }
 
   @Test
+  public void testMissingMandatoryAllowedMissingArtifact() throws Throwable {
+    Artifact input = createSourceArtifact("allowedMissing");
+    allowedMissingInput = input.getRootRelativePath();
+    assertThat(evaluateArtifactValue(input, /*mandatory=*/ true))
+        .isEqualTo(FileArtifactValue.MISSING_FILE_MARKER);
+  }
+
+  @Test
+  public void testUnreadableMandatoryAllowedMissingArtifact() throws Throwable {
+    Artifact input = createSourceArtifact("allowedMissing");
+    file(input.getPath(), "allowedMissing");
+    input.getPath().chmod(0);
+
+    allowedMissingInput = input.getRootRelativePath();
+    assertThat(evaluateArtifactValue(input, /*mandatory=*/ true))
+        .isEqualTo(FileArtifactValue.MISSING_FILE_MARKER);
+  }
+
+  @Test
+  public void testUnreadableInputWithFsWithAvailableDigest() throws Throwable {
+    final byte[] expectedDigest = MessageDigest.getInstance("md5").digest(
+        "someunreadablecontent".getBytes(StandardCharsets.UTF_8));
+    setupRoot(
+        new CustomInMemoryFs() {
+          @Override
+          public byte[] getMD5Digest(Path path) throws IOException {
+            return path.getBaseName().equals("unreadable")
+                ? expectedDigest
+                : super.getMD5Digest(path);
+          }
+        });
+
+    Artifact input = createSourceArtifact("unreadable");
+    Path inputPath = input.getPath();
+    file(inputPath, "dummynotused");
+    inputPath.chmod(0);
+
+    FileArtifactValue value =
+        (FileArtifactValue) evaluateArtifactValue(input, /*mandatory=*/ true);
+
+    FileStatus stat = inputPath.stat();
+    assertThat(value.getSize()).isEqualTo(stat.getSize());
+    assertThat(value.getDigest()).isEqualTo(expectedDigest);
+  }
+
+  @Test
   public void testMissingMandatoryArtifact() throws Throwable {
     Artifact input = createSourceArtifact("input1");
     try {