This is an automated email from the ASF dual-hosted git repository.

adulceanu pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 9af2293311 OAK-9952 Add failFast option to ConsistencyChecker (#714)
9af2293311 is described below

commit 9af229331127bf3908984b0a4275796f8a868e1d
Author: jelmini <85556711+jelm...@users.noreply.github.com>
AuthorDate: Tue Sep 27 13:52:07 2022 +0200

    OAK-9952 Add failFast option to ConsistencyChecker (#714)
---
 .../segment/file/tooling/ConsistencyChecker.java   |  18 ++
 .../apache/jackrabbit/oak/segment/tool/Check.java  |  23 +-
 .../oak/segment/file/MockReadOnlyFileStore.java    |  71 +++++
 .../segment/tool/CheckInvalidRepositoryTest.java   | 353 ++++++++++++---------
 4 files changed, 317 insertions(+), 148 deletions(-)

diff --git 
a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tooling/ConsistencyChecker.java
 
b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tooling/ConsistencyChecker.java
index 840628f6b9..0a5c989873 100644
--- 
a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tooling/ConsistencyChecker.java
+++ 
b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tooling/ConsistencyChecker.java
@@ -347,6 +347,19 @@ public class ConsistencyChecker {
         Set<String> paths,
         boolean binaries,
         Integer revisionsCount
+    ) {
+        return checkConsistency(store, journal, head, checkpoints, paths, 
binaries, revisionsCount, false);
+    }
+
+    public final ConsistencyCheckResult checkConsistency(
+        ReadOnlyFileStore store,
+        Iterator<JournalEntry> journal,
+        boolean head,
+        Set<String> checkpoints,
+        Set<String> paths,
+        boolean binaries,
+        Integer revisionsCount,
+        boolean failFast
     ) {
         List<PathToCheck> headPaths = new ArrayList<>();
         Map<String, List<PathToCheck>> checkpointPaths = new HashMap<>();
@@ -391,6 +404,8 @@ public class ConsistencyChecker {
 
                 if (overall) {
                     lastValidJournalEntry = journalEntry;
+                } else if (failFast) {
+                    break;
                 }
 
                 // If every PathToCheck is assigned to a JournalEntry, stop
@@ -407,6 +422,9 @@ public class ConsistencyChecker {
                 }
             } catch (IllegalArgumentException | SegmentNotFoundException e) {
                 onCheckRevisionError(revision, e);
+                if (failFast) {
+                    break;
+                }
             }
         }
 
diff --git 
a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/Check.java
 
b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/Check.java
index edab658c81..596bdf4532 100644
--- 
a/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/Check.java
+++ 
b/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/tool/Check.java
@@ -92,6 +92,8 @@ public class Check {
 
         private PrintWriter errWriter;
 
+        private boolean failFast;
+
         private Builder() {
             // Prevent external instantiation.
         }
@@ -256,6 +258,11 @@ public class Check {
 
             return this;
         }
+        
+        public Builder withFailFast(boolean failFast) {
+            this.failFast = failFast;
+            return this;
+        }
 
         /**
          * Create an executable version of the {@link Check} command.
@@ -325,6 +332,8 @@ public class Check {
 
     private final PrintWriter err;
 
+    private final boolean failFast;
+
     private int currentNodeCount;
 
     private int currentPropertyCount;
@@ -349,6 +358,7 @@ public class Check {
         this.err = builder.errWriter;
         this.journal = journalPath(builder.path, builder.journal);
         this.revisionsCount = revisionsToCheckCount(builder.revisionsCount);
+        this.failFast = builder.failFast;
     }
 
     private static File journalPath(File segmentStore, File journal) {
@@ -411,12 +421,13 @@ public class Check {
             checkpoints,
             filterPaths,
             checkBinaries,
-            revisionsCount
+            revisionsCount,
+            failFast
         );
 
         print("\nSearched through {0} revisions and {1} checkpoints", 
result.getCheckedRevisionsCount(), checkpoints.size());
 
-        if (hasAnyRevision(result)) {
+        if (isGoodRevisionFound(result)) {
             if (checkHead) {
                 print("\nHead");
                 for (Entry<String, Revision> e : 
result.getHeadRevisions().entrySet()) {
@@ -442,6 +453,10 @@ public class Check {
         }
     }
 
+    private boolean isGoodRevisionFound(ConsistencyCheckResult result) {
+        return failFast ? hasAllRevision(result) : hasAnyRevision(result);
+    }
+
     private ConsistencyChecker newConsistencyChecker() {
         return new ConsistencyChecker() {
 
@@ -570,6 +585,10 @@ public class Check {
         return hasAnyHeadRevision(result) || hasAnyCheckpointRevision(result);
     }
 
+    private static boolean hasAllRevision(ConsistencyCheckResult result) {
+        return hasAnyHeadRevision(result) && hasAnyCheckpointRevision(result);
+    }
+
     private static boolean hasAnyHeadRevision(ConsistencyCheckResult result) {
         return result.getHeadRevisions()
             .values()
diff --git 
a/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/MockReadOnlyFileStore.java
 
b/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/MockReadOnlyFileStore.java
new file mode 100644
index 0000000000..81cc9ea82b
--- /dev/null
+++ 
b/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/MockReadOnlyFileStore.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.jackrabbit.oak.segment.file;
+
+import java.io.File;
+import java.io.IOException;
+import org.apache.jackrabbit.oak.segment.Segment;
+import org.apache.jackrabbit.oak.segment.SegmentId;
+import org.apache.jackrabbit.oak.segment.SegmentNotFoundException;
+import org.apache.jackrabbit.oak.segment.file.tar.TarPersistence;
+import org.jetbrains.annotations.NotNull;
+
+import static 
org.apache.jackrabbit.oak.segment.file.FileStoreBuilder.fileStoreBuilder;
+
+public class MockReadOnlyFileStore extends ReadOnlyFileStore {
+    private int failAfterReadSegmentCount;
+    private int readSegmentCount = 0;
+
+    @NotNull
+    public static MockReadOnlyFileStore buildMock(File path, File journalFile) 
throws InvalidFileStoreVersionException, IOException {
+        TarPersistence persistence = new TarPersistence(path, journalFile);
+        ReadOnlyRevisions revisions = new ReadOnlyRevisions(persistence);
+        MockReadOnlyFileStore store;
+        try {
+            store = new 
MockReadOnlyFileStore(fileStoreBuilder(path).withCustomPersistence(persistence));
+        } catch (InvalidFileStoreVersionException | IOException e) {
+            try {
+                revisions.close();
+            } catch (IOException re) {
+                //ignore
+            }
+            throw e;
+        }
+        store.bind(revisions);
+        return store;
+    }
+    
+    
+    MockReadOnlyFileStore(FileStoreBuilder builder) throws 
InvalidFileStoreVersionException, IOException {
+        super(builder);
+    }
+
+    public void failAfterReadSegmentCount(int count) {
+        this.failAfterReadSegmentCount = count;
+    }
+    
+    @Override
+    public @NotNull Segment readSegment(SegmentId id) {
+        readSegmentCount++;
+        if (readSegmentCount > failAfterReadSegmentCount) {
+            throw new SegmentNotFoundException(id);
+        }
+        return super.readSegment(id);
+    }
+}
diff --git 
a/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/tool/CheckInvalidRepositoryTest.java
 
b/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/tool/CheckInvalidRepositoryTest.java
index 3ca911e197..86243de59e 100644
--- 
a/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/tool/CheckInvalidRepositoryTest.java
+++ 
b/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/tool/CheckInvalidRepositoryTest.java
@@ -24,90 +24,74 @@ import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.Set;
 
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
+import java.util.Objects;
+import java.util.function.Consumer;
 import org.apache.commons.io.FileUtils;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.segment.SegmentNodeStore;
+import org.apache.jackrabbit.oak.segment.SegmentNodeStoreBuilders;
+import org.apache.jackrabbit.oak.segment.file.FileStore;
+import org.apache.jackrabbit.oak.segment.file.FileStoreBuilder;
+import org.apache.jackrabbit.oak.segment.file.InvalidFileStoreVersionException;
 import org.apache.jackrabbit.oak.segment.file.JournalEntry;
 import org.apache.jackrabbit.oak.segment.file.JournalReader;
+import org.apache.jackrabbit.oak.segment.file.MockReadOnlyFileStore;
 import org.apache.jackrabbit.oak.segment.file.tar.LocalJournalFile;
+import org.apache.jackrabbit.oak.segment.file.tooling.ConsistencyChecker;
+import 
org.apache.jackrabbit.oak.segment.file.tooling.ConsistencyChecker.ConsistencyCheckResult;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.jetbrains.annotations.NotNull;
 import org.junit.Before;
 import org.junit.Test;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
 /**
  * Tests for {@link Check} assuming an invalid repository.
  */
 public class CheckInvalidRepositoryTest extends CheckRepositoryTestBase {
 
+    private Output log;
+    
+    @Override
     @Before
     public void setup() throws Exception {
         super.setup();
         super.addInvalidRevision();
+        log = new Output();
     }
 
     @Test
     public void testInvalidRevisionFallbackOnValid() {
-        StringWriter strOut = new StringWriter();
-        StringWriter strErr = new StringWriter();
-
-        PrintWriter outWriter = new PrintWriter(strOut, true);
-        PrintWriter errWriter = new PrintWriter(strErr, true);
-
-        Set<String> filterPaths = new LinkedHashSet<>();
-        filterPaths.add("/");
-
-        Check.builder()
-            .withPath(new File(temporaryFolder.getRoot().getAbsolutePath()))
-            .withDebugInterval(Long.MAX_VALUE)
-            .withCheckHead(true)
-            .withCheckpoints(checkpoints)
-            .withCheckBinaries(true)
-            .withFilterPaths(filterPaths)
-            .withOutWriter(outWriter)
-            .withErrWriter(errWriter)
-            .build()
-            .run();
-
-        outWriter.close();
-        errWriter.close();
+        int checkResult = check(b -> b
+            .withFilterPaths(ImmutableSet.of("/"))
+        );
 
-        assertExpectedOutput(strOut.toString(), Lists.newArrayList("Checked 7 
nodes and 21 properties", "Path / is consistent",
+        assertCheckSucceeded(checkResult);
+        assertExpectedOutput(log.outString(), Lists.newArrayList("Checked 7 
nodes and 21 properties", "Path / is consistent",
             "Searched through 2 revisions"));
 
         // not sure whether first traversal will fail because of "/a" or "/z" 
-        assertExpectedOutput(strErr.toString(), Lists.newArrayList("Error 
while traversing /"));
+        assertExpectedOutput(log.errString(), Lists.newArrayList("Error while 
traversing /"));
     }
 
     @Test
     public void testPartialBrokenPathWithoutValidRevision() {
-        StringWriter strOut = new StringWriter();
-        StringWriter strErr = new StringWriter();
-
-        PrintWriter outWriter = new PrintWriter(strOut, true);
-        PrintWriter errWriter = new PrintWriter(strErr, true);
+        int checkResult = check(b -> b
+            .withFilterPaths(ImmutableSet.of("/z"))
+        );
 
-        Set<String> filterPaths = new LinkedHashSet<>();
-        filterPaths.add("/z");
-
-        Check.builder()
-            .withPath(new File(temporaryFolder.getRoot().getAbsolutePath()))
-            .withDebugInterval(Long.MAX_VALUE)
-            .withCheckBinaries(true)
-            .withCheckHead(true)
-            .withCheckpoints(checkpoints)
-            .withFilterPaths(filterPaths)
-            .withOutWriter(outWriter)
-            .withErrWriter(errWriter)
-            .build()
-            .run();
-
-        outWriter.close();
-        errWriter.close();
-
-        assertExpectedOutput(strOut.toString(), Lists.newArrayList("Checking 
head", "Checking checkpoints", "No good revision found"));
-        assertExpectedOutput(strErr.toString(),
+        assertCheckFailed(checkResult);
+        assertExpectedOutput(log.outString(), Lists.newArrayList("Checking 
head", "Checking checkpoints", "No good revision found"));
+        assertExpectedOutput(log.errString(),
             Lists.newArrayList(
                 "Error while traversing /z: 
java.lang.IllegalArgumentException: Segment reference out of bounds",
                 "Path /z not found"));
@@ -115,65 +99,28 @@ public class CheckInvalidRepositoryTest extends 
CheckRepositoryTestBase {
 
     @Test
     public void testPartialBrokenPathWithValidRevision() {
-        StringWriter strOut = new StringWriter();
-        StringWriter strErr = new StringWriter();
-
-        PrintWriter outWriter = new PrintWriter(strOut, true);
-        PrintWriter errWriter = new PrintWriter(strErr, true);
-
-        Set<String> filterPaths = new LinkedHashSet<>();
-        filterPaths.add("/a");
-
-        Check.builder()
-            .withPath(new File(temporaryFolder.getRoot().getAbsolutePath()))
-            .withDebugInterval(Long.MAX_VALUE)
-            .withCheckBinaries(true)
-            .withCheckHead(true)
-            .withCheckpoints(new HashSet<String>())
-            .withFilterPaths(filterPaths)
-            .withOutWriter(outWriter)
-            .withErrWriter(errWriter)
-            .build()
-            .run();
+        int checkResult = check(b -> b
+            .withFilterPaths(ImmutableSet.of("/a"))
+            .withCheckpoints(new HashSet<>())
+        );
 
-        outWriter.close();
-        errWriter.close();
-
-        assertExpectedOutput(strOut.toString(), Lists.newArrayList("Checked 1 
nodes and 1 properties", "Path /a is consistent",
+        assertCheckSucceeded(checkResult);
+        assertExpectedOutput(log.outString(), Lists.newArrayList("Checked 1 
nodes and 1 properties", "Path /a is consistent",
             "Searched through 2 revisions"));
-        assertExpectedOutput(strErr.toString(), Lists.newArrayList(
+        assertExpectedOutput(log.errString(), Lists.newArrayList(
             "Error while traversing /a: java.lang.IllegalArgumentException: 
Segment reference out of bounds"));
     }
 
     @Test
     public void testCorruptHeadWithValidCheckpoints() {
-        StringWriter strOut = new StringWriter();
-        StringWriter strErr = new StringWriter();
-
-        PrintWriter outWriter = new PrintWriter(strOut, true);
-        PrintWriter errWriter = new PrintWriter(strErr, true);
-
-        Set<String> filterPaths = new LinkedHashSet<>();
-        filterPaths.add("/");
-
-        Check.builder()
-            .withPath(new File(temporaryFolder.getRoot().getAbsolutePath()))
-            .withDebugInterval(Long.MAX_VALUE)
-            .withCheckBinaries(true)
-            .withCheckHead(true)
-            .withCheckpoints(checkpoints)
-            .withFilterPaths(filterPaths)
-            .withOutWriter(outWriter)
-            .withErrWriter(errWriter)
-            .build()
-            .run();
-
-        outWriter.close();
-        errWriter.close();
+        int checkResult = check(b -> b
+            .withFilterPaths(ImmutableSet.of("/"))
+        );
 
-        assertExpectedOutput(strOut.toString(), Lists.newArrayList("Checking 
head", "Checking checkpoints",
+        assertCheckSucceeded(checkResult);
+        assertExpectedOutput(log.outString(), Lists.newArrayList("Checking 
head", "Checking checkpoints",
             "Checked 7 nodes and 21 properties", "Path / is consistent", 
"Searched through 2 revisions and 2 checkpoints"));
-        assertExpectedOutput(strErr.toString(), Lists.newArrayList(
+        assertExpectedOutput(log.errString(), Lists.newArrayList(
             "Error while traversing /a: java.lang.IllegalArgumentException: 
Segment reference out of bounds"));
     }
 
@@ -181,45 +128,19 @@ public class CheckInvalidRepositoryTest extends 
CheckRepositoryTestBase {
     public void testCorruptPathInCp1NoValidRevision() throws Exception {
         corruptPathFromCheckpoint();
 
-        StringWriter strOut = new StringWriter();
-        StringWriter strErr = new StringWriter();
-
-        PrintWriter outWriter = new PrintWriter(strOut, true);
-        PrintWriter errWriter = new PrintWriter(strErr, true);
+        int checkResult = check(b -> b
+            .withFilterPaths(ImmutableSet.of("/b"))
+            .withCheckpoints(ImmutableSet.of(checkpoints.iterator().next()))
+        );
 
-        Set<String> filterPaths = new LinkedHashSet<>();
-        filterPaths.add("/b");
-
-        Set<String> cps = new HashSet<>();
-        cps.add(checkpoints.iterator().next());
-
-        Check.builder()
-            .withPath(new File(temporaryFolder.getRoot().getAbsolutePath()))
-            .withDebugInterval(Long.MAX_VALUE)
-            .withCheckBinaries(true)
-            .withCheckpoints(cps)
-            .withFilterPaths(filterPaths)
-            .withOutWriter(outWriter)
-            .withErrWriter(errWriter)
-            .build()
-            .run();
-
-        outWriter.close();
-        errWriter.close();
-
-        assertExpectedOutput(strOut.toString(), Lists.newArrayList("Searched 
through 2 revisions and 1 checkpoints", "No good revision found"));
-        assertExpectedOutput(strErr.toString(), Lists.newArrayList(
+        assertCheckFailed(checkResult);
+        assertExpectedOutput(log.outString(), Lists.newArrayList("Searched 
through 2 revisions and 1 checkpoints", "No good revision found"));
+        assertExpectedOutput(log.errString(), Lists.newArrayList(
             "Error while traversing /b: java.lang.IllegalArgumentException: 
Segment reference out of bounds"));
     }
 
     @Test
     public void testLargeJournal() throws IOException {
-        StringWriter strOut = new StringWriter();
-        StringWriter strErr = new StringWriter();
-
-        PrintWriter outWriter = new PrintWriter(strOut, true);
-        PrintWriter errWriter = new PrintWriter(strErr, true);
-
         File segmentStoreFolder = new 
File(temporaryFolder.getRoot().getAbsolutePath());
         File journalFile = new File(segmentStoreFolder, "journal.log");
         File largeJournalFile = temporaryFolder.newFile("journal.log.large");
@@ -232,24 +153,164 @@ public class CheckInvalidRepositoryTest extends 
CheckRepositoryTestBase {
         for (int k = 0; k < 10000; k++) {
             FileUtils.writeStringToFile(largeJournalFile, journalLine, true);
         }
-
-        Check.builder()
+        
+        int checkResult = check(b -> b
             .withPath(segmentStoreFolder)
             .withJournal(largeJournalFile)
+            .withFilterPaths(ImmutableSet.of("/"))
+        );
+
+        assertCheckFailed(checkResult);
+        assertExpectedOutput(log.outString(), Lists.newArrayList("No good 
revision found"));
+    }
+
+    @Test
+    public void testFailFast_withInvalidHead() {
+        int checkResult = check(b -> b
+            .withFilterPaths(ImmutableSet.of("/"))
+            .withFailFast(true)
+        );
+
+        assertCheckFailed(checkResult);
+        assertExpectedOutput(log.outString(), Lists.newArrayList("Searched 
through 1 revisions and 2 checkpoints", "No good revision found"));
+    }
+
+    @Test
+    public void testFailFast_withInvalidCheckpoints() {
+        int checkResult = check(b -> b
+            .withFilterPaths(ImmutableSet.of("/b"))
+            .withCheckpoints(ImmutableSet.of("invalid-checkpoint-id"))
+            .withFailFast(true)
+        );
+
+        assertCheckFailed(checkResult);
+        assertExpectedOutput(log.outString(), Lists.newArrayList("Path /b is 
consistent", "No good revision found"));
+        assertExpectedOutput(log.errString(), Lists.newArrayList("Checkpoint 
invalid-checkpoint-id not found in this revision!"));
+    }
+
+    @Test
+    public void testFailFast_withSegmentNotFoundException() throws Exception {
+        addMoreSegments(); // so that some segments are not loaded at 
initialization, but only when the check is performed
+
+        File path = new File(temporaryFolder.getRoot().getAbsolutePath());
+        File journalFile = new File(path, "journal.log");
+
+        MockReadOnlyFileStore mockStore = 
MockReadOnlyFileStore.buildMock(path, journalFile);
+        mockStore.failAfterReadSegmentCount(2);
+
+        ConsistencyCheckResult result = checkConsistencyFailFast(mockStore, 
journalFile);
+
+        assertNull(result.getOverallRevision());
+        assertTrue(hasAnyHeadRevision(result));
+        assertFalse(hasAnyCheckpointRevision(result));
+    }
+
+    @Test
+    public void testFallbackToAnotherRevision_withSegmentNotFoundException() 
throws Exception {
+        addMoreSegments(); // so that some segments are not loaded at 
initialization, but only when the check is performed
+
+        File path = new File(temporaryFolder.getRoot().getAbsolutePath());
+        File journalFile = new File(path, "journal.log");
+        MockReadOnlyFileStore mockStore = 
MockReadOnlyFileStore.buildMock(path, journalFile);
+        mockStore.failAfterReadSegmentCount(2);
+
+        ConsistencyCheckResult result = checkConsistencyLenient(mockStore, 
journalFile);
+        
+        assertTrue(hasAnyHeadRevision(result));
+        assertTrue(hasAnyCheckpointRevision(result));
+    }
+
+    @NotNull
+    private ConsistencyCheckResult 
checkConsistencyFailFast(MockReadOnlyFileStore mockStore, File journalFile) 
throws IOException {
+        return checkConsistency(mockStore, journalFile, true);
+    }
+
+    @NotNull
+    private ConsistencyCheckResult 
checkConsistencyLenient(MockReadOnlyFileStore mockStore, File journalFile) 
throws IOException {
+        return checkConsistency(mockStore, journalFile, false);
+    }
+
+    @NotNull
+    private ConsistencyCheckResult checkConsistency(MockReadOnlyFileStore 
store, File journalFile, boolean failFast) throws IOException {
+        return new ConsistencyChecker().checkConsistency(
+            store, new JournalReader(new LocalJournalFile(journalFile)),
+            true, checkpoints, ImmutableSet.of("/b"), true, Integer.MAX_VALUE,
+            failFast);
+    }
+
+    private void addMoreSegments() throws InvalidFileStoreVersionException, 
IOException, CommitFailedException {
+        FileStore fileStore = 
FileStoreBuilder.fileStoreBuilder(temporaryFolder.getRoot()).withMaxFileSize(256)
+            .withSegmentCacheSize(64).build();
+
+        SegmentNodeStore nodeStore = 
SegmentNodeStoreBuilders.builder(fileStore).build();
+        NodeBuilder builder = nodeStore.getRoot().builder();
+
+        // add a new property value to existing child "b"
+        addChildWithBlobProperties(nodeStore, builder, "y", 5);
+        nodeStore.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+        fileStore.close();
+    }
+
+    private static boolean hasAnyHeadRevision(ConsistencyCheckResult result) {
+        return result.getHeadRevisions()
+            .values()
+            .stream()
+            .anyMatch(Objects::nonNull);
+    }
+
+    private static boolean hasAnyCheckpointRevision(ConsistencyCheckResult 
result) {
+        return result.getCheckpointRevisions()
+            .values()
+            .stream()
+            .flatMap(m -> m.values().stream())
+            .anyMatch(Objects::nonNull);
+    }
+
+    private int check(Consumer<Check.Builder> builderConsumer) {
+        Check.Builder builder = Check.builder()
+            .withPath(new File(temporaryFolder.getRoot().getAbsolutePath()))
             .withDebugInterval(Long.MAX_VALUE)
             .withCheckBinaries(true)
             .withCheckHead(true)
-            .withFilterPaths(ImmutableSet.of("/"))
             .withCheckpoints(checkpoints)
-            .withOutWriter(outWriter)
-            .withErrWriter(errWriter)
-            .build()
-            .run();
-
-        outWriter.close();
-        errWriter.close();
+            .withOutWriter(log.outWriter)
+            .withErrWriter(log.errWriter);
+        builderConsumer.accept(builder);
+        return builder.build().run();
+    }
+    
+    private static void assertCheckFailed(int checkResult) {
+        assertEquals("Check should have failed", 1, checkResult);
+    }
 
-        assertExpectedOutput(strOut.toString(), Lists.newArrayList("No good 
revision found"));
+    private static void assertCheckSucceeded(int checkResult) {
+        assertEquals("Check should have succeeded", 0, checkResult);
     }
+    
+    private static class Output {
+        private final StringWriter strOut;
+        private final StringWriter strErr;
+        private final PrintWriter outWriter;
+        private final PrintWriter errWriter;
+        
+        public Output() {
+            strOut = new StringWriter();
+            strErr = new StringWriter();
+            outWriter = new PrintWriter(strOut, true);
+            errWriter = new PrintWriter(strErr, true);
+        }
 
+        public void close() {
+            outWriter.close();
+            errWriter.close();
+        }
+
+        public String outString() {
+            return strOut.toString();
+        }
+
+        public String errString() {
+            return strErr.toString();
+        }
+    }
 }

Reply via email to