Author: adulceanu
Date: Wed Jan 31 11:09:50 2018
New Revision: 1822791
URL: http://svn.apache.org/viewvc?rev=1822791&view=rev
Log:
OAK-6373 - oak-run check should also check checkpoints
Added new tests for checking valid and invalid revisions
Corrected and improved code for corrupting records
Modified:
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tooling/ConsistencyChecker.java
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/tooling/CheckInvalidRepositoryTest.java
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/tooling/CheckRepositoryTestBase.java
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/tooling/CheckValidRepositoryTest.java
Modified:
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tooling/ConsistencyChecker.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tooling/ConsistencyChecker.java?rev=1822791&r1=1822790&r2=1822791&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tooling/ConsistencyChecker.java
(original)
+++
jackrabbit/oak/trunk/oak-segment-tar/src/main/java/org/apache/jackrabbit/oak/segment/file/tooling/ConsistencyChecker.java
Wed Jan 31 11:09:50 2018
@@ -216,7 +216,7 @@ public class ConsistencyChecker implemen
NodeState root = sns.retrieve(checkpoint);
if (root == null) {
- checker.print("Checkpoint {0} not
found in this revision!", checkpoint);
+ checker.printError("Checkpoint {0} not
found in this revision!", checkpoint);
overallValid = false;
} else {
overallValid = overallValid &&
checker.checkPathsAtRoot(pathList, root,
Modified:
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/tooling/CheckInvalidRepositoryTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/tooling/CheckInvalidRepositoryTest.java?rev=1822791&r1=1822790&r2=1822791&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/tooling/CheckInvalidRepositoryTest.java
(original)
+++
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/tooling/CheckInvalidRepositoryTest.java
Wed Jan 31 11:09:50 2018
@@ -25,12 +25,11 @@ import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
+import com.google.common.collect.Lists;
import org.apache.jackrabbit.oak.segment.tool.Check;
import org.junit.Before;
import org.junit.Test;
-import com.google.common.collect.Lists;
-
/**
* Tests for {@link CheckCommand} assuming an invalid repository.
*/
@@ -58,7 +57,7 @@ public class CheckInvalidRepositoryTest
.withJournal("journal.log")
.withDebugInterval(Long.MAX_VALUE)
.withCheckHead(true)
- .withCheckpoints(new HashSet<String>())
+ .withCheckpoints(checkpoints)
.withCheckBinaries(true)
.withFilterPaths(filterPaths)
.withOutWriter(outWriter)
@@ -93,7 +92,7 @@ public class CheckInvalidRepositoryTest
.withDebugInterval(Long.MAX_VALUE)
.withCheckBinaries(true)
.withCheckHead(true)
- .withCheckpoints(new HashSet<String>())
+ .withCheckpoints(checkpoints)
.withFilterPaths(filterPaths)
.withOutWriter(outWriter)
.withErrWriter(errWriter)
@@ -103,7 +102,7 @@ public class CheckInvalidRepositoryTest
outWriter.close();
errWriter.close();
- assertExpectedOutput(strOut.toString(), Lists.newArrayList("No good
revision found"));
+ assertExpectedOutput(strOut.toString(), Lists.newArrayList("Checking
head", "Checking checkpoints", "No good revision found"));
assertExpectedOutput(strErr.toString(),
Lists.newArrayList(
"Error while traversing /z:
java.lang.IllegalArgumentException: Segment reference out of bounds",
@@ -142,4 +141,73 @@ public class CheckInvalidRepositoryTest
assertExpectedOutput(strErr.toString(), 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()))
+ .withJournal("journal.log")
+ .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",
+ "Checked 7 nodes and 21 properties", "Path / is consistent",
"Searched through 2 revisions and 2 checkpoints"));
+ assertExpectedOutput(strErr.toString(), Lists.newArrayList(
+ "Error while traversing /a:
java.lang.IllegalArgumentException: Segment reference out of bounds"));
+ }
+
+ @Test
+ 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);
+
+ 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()))
+ .withJournal("journal.log")
+ .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(
+ "Error while traversing /b:
java.lang.IllegalArgumentException: Segment reference out of bounds"));
+ }
}
Modified:
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/tooling/CheckRepositoryTestBase.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/tooling/CheckRepositoryTestBase.java?rev=1822791&r1=1822790&r2=1822791&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/tooling/CheckRepositoryTestBase.java
(original)
+++
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/tooling/CheckRepositoryTestBase.java
Wed Jan 31 11:09:50 2018
@@ -18,6 +18,8 @@
*/
package org.apache.jackrabbit.oak.segment.file.tooling;
+import static com.google.common.base.Charsets.UTF_8;
+
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
@@ -26,10 +28,13 @@ import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Random;
+import java.util.Set;
import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.segment.RecordId;
import org.apache.jackrabbit.oak.segment.RecordType;
import org.apache.jackrabbit.oak.segment.SegmentNodeState;
import org.apache.jackrabbit.oak.segment.SegmentNodeStore;
@@ -57,6 +62,8 @@ public class CheckRepositoryTestBase {
@Rule
public final TemporaryFolder temporaryFolder = new TemporaryFolder(new
File("target"));
+
+ protected Set<String> checkpoints = new LinkedHashSet<>();
@Before
public void setup() throws Exception {
@@ -66,7 +73,7 @@ public class CheckRepositoryTestBase {
protected void addValidRevision() 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();
@@ -79,6 +86,13 @@ public class CheckRepositoryTestBase {
addChildWithProperties(nodeStore, builder, "f", 6);
nodeStore.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY);
+
+ // add checkpoints
+ String cp1 = nodeStore.checkpoint(10_000);
+ String cp2 = nodeStore.checkpoint(10_000);
+ checkpoints.add(cp1);
+ checkpoints.add(cp2);
+
fileStore.close();
}
@@ -99,59 +113,88 @@ public class CheckRepositoryTestBase {
// get record number to corrupt (NODE record for "z")
SegmentNodeState child = (SegmentNodeState) after.getChildNode("z");
- int zRecordNumber = child.getRecordId().getRecordNumber();
+ RecordId zRecordId = child.getRecordId();
// get record number to corrupt (NODE record for "a")
child = (SegmentNodeState) after.getChildNode("a");
- int aRecordNumber = child.getRecordId().getRecordNumber();
+ RecordId aRecordId = child.getRecordId();
fileStore.close();
- corruptRecord(zRecordNumber);
- corruptRecord(aRecordNumber);
+ corruptRecord(zRecordId, "data00001a.tar");
+ corruptRecord(aRecordId, "data00001a.tar");
}
+
+ protected void corruptPathFromCheckpoint() throws
InvalidFileStoreVersionException, IOException {
+ FileStore fileStore =
FileStoreBuilder.fileStoreBuilder(temporaryFolder.getRoot()).withMaxFileSize(256)
+ .withSegmentCacheSize(64).build();
- private void corruptRecord(int recordNumber) throws FileNotFoundException,
IOException {
- //since the filestore was closed after writing the first revision,
we're always dealing with the 2nd tar file
- RandomAccessFile file = new RandomAccessFile(new
File(temporaryFolder.getRoot(),"data00001a.tar"), "rw");
-
- // read segment header
- ByteBuffer header = ByteBuffer.allocate(HEADER_SIZE);
- file.readFully(header.array());
-
- // read segment size from header
- byte[] segmentSizeBytes = new byte[11];
- System.arraycopy(header.array(), 124, segmentSizeBytes, 0, 11);
- int size = Integer.parseInt(new String(segmentSizeBytes,
Charset.forName("UTF-8")), 8);
-
+ SegmentNodeStore nodeStore =
SegmentNodeStoreBuilders.builder(fileStore).build();
+ SegmentNodeState cp1 = (SegmentNodeState)
nodeStore.retrieve(checkpoints.iterator().next());
+ RecordId bRecordId = ((SegmentNodeState)
cp1.getChildNode("b")).getRecordId();
+ fileStore.close();
+
+ corruptRecord(bRecordId, "data00000a.tar");
+ }
+
+ private void corruptRecord(RecordId recordId, String tarFileName) throws
FileNotFoundException, IOException {
+ RandomAccessFile file = new RandomAccessFile(new
File(temporaryFolder.getRoot(), tarFileName), "rw");
+
+ String segmentName = recordId.getSegmentId().toString();
+ String crtEntryName = "";
+ int entrySize = 0;
+ long filePointer = 0;
+
+ while(!crtEntryName.equals(segmentName)) {
+ filePointer = file.getFilePointer();
+ // read entry header
+ ByteBuffer entryHeader = ByteBuffer.allocate(HEADER_SIZE);
+ file.readFully(entryHeader.array());
+
+ // read entry size from header
+ byte[] crtEntryNameBytes = new byte[100];
+ System.arraycopy(entryHeader.array(), 0, crtEntryNameBytes, 0,
100);
+ crtEntryName = new String(crtEntryNameBytes, 0, 100, UTF_8);
+ crtEntryName = crtEntryName.substring(0,
crtEntryName.indexOf('.'));
+
+ byte[] entrySizeBytes = new byte[11];
+ System.arraycopy(entryHeader.array(), 124, entrySizeBytes, 0, 11);
+ entrySize = Integer.parseInt(new String(entrySizeBytes,
Charset.forName("UTF-8")), 8);
+
+ if (!crtEntryName.equals(segmentName)) {
+ file.skipBytes(entrySize);
+ file.skipBytes(HEADER_SIZE - (entrySize % HEADER_SIZE));
+ }
+ };
+
// read actual segment
- ByteBuffer segmentBytes = ByteBuffer.allocate(size);
+ ByteBuffer segmentBytes = ByteBuffer.allocate(entrySize);
file.readFully(segmentBytes.array());
int segmentRefs = segmentBytes.getInt(14);
// read the header for our record
- int skip = 32 + segmentRefs * 16 + recordNumber * 9;
+ int skip = 32 + segmentRefs * 16 + recordId.getRecordNumber() * 9;
int number = segmentBytes.getInt(skip);
byte type = segmentBytes.get(skip + 4);
int offset = segmentBytes.getInt(skip + 4 + 1);
- Assert.assertEquals(recordNumber, number);
+ Assert.assertEquals(recordId.getRecordNumber(), number);
Assert.assertEquals(RecordType.NODE.ordinal(), type);
// read the offset of previous record to derive length of our record
- int prevSkip = 32 + segmentRefs * 16 + (recordNumber - 1) * 9;
+ int prevSkip = 32 + segmentRefs * 16 + (recordId.getRecordNumber() -
1) * 9;
int prevOffset = segmentBytes.getInt(prevSkip + 4 + 1);
int length = prevOffset - offset;
- int realOffset = size - (MAX_SEGMENT_SIZE - offset);
+ int realOffset = entrySize - (MAX_SEGMENT_SIZE - offset);
// write random bytes inside the NODE record to corrupt it
Random r = new Random(10);
byte[] bogusData = new byte[length];
r.nextBytes(bogusData);
- file.seek(HEADER_SIZE + realOffset);
+ file.seek(filePointer + HEADER_SIZE + realOffset);
file.write(bogusData);
file.close();
Modified:
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/tooling/CheckValidRepositoryTest.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/tooling/CheckValidRepositoryTest.java?rev=1822791&r1=1822790&r2=1822791&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/tooling/CheckValidRepositoryTest.java
(original)
+++
jackrabbit/oak/trunk/oak-segment-tar/src/test/java/org/apache/jackrabbit/oak/segment/file/tooling/CheckValidRepositoryTest.java
Wed Jan 31 11:09:50 2018
@@ -62,8 +62,8 @@ public class CheckValidRepositoryTest ex
outWriter.close();
errWriter.close();
- assertExpectedOutput(strOut.toString(), Lists.newArrayList("Searched
through 1 revisions and 0 checkpoints", "Checked 7 nodes and 21 properties",
- "Path / is consistent"));
+ assertExpectedOutput(strOut.toString(), Lists.newArrayList("Checking
head", "Searched through 1 revisions and 0 checkpoints",
+ "Checked 7 nodes and 21 properties", "Path / is consistent"));
assertExpectedOutput(strErr.toString(), Lists.newArrayList(""));
}
@@ -100,7 +100,7 @@ public class CheckValidRepositoryTest ex
outWriter.close();
errWriter.close();
- assertExpectedOutput(strOut.toString(), Lists.newArrayList("Searched
through 1 revisions",
+ assertExpectedOutput(strOut.toString(), Lists.newArrayList("Checking
head", "Searched through 1 revisions and 0 checkpoints",
"Checked 1 nodes and 1 properties", "Checked 1 nodes and 2
properties", "Checked 1 nodes and 3 properties",
"Path /a is consistent", "Path /b is consistent", "Path /c is
consistent", "Path /d is consistent", "Path /e is consistent",
"Path /f is consistent"));
@@ -134,8 +134,8 @@ public class CheckValidRepositoryTest ex
outWriter.close();
errWriter.close();
- assertExpectedOutput(strOut.toString(), Lists.newArrayList("Searched
through 1 revisions", "Checked 7 nodes and 15 properties",
- "Path / is consistent"));
+ assertExpectedOutput(strOut.toString(), Lists.newArrayList("Checking
head", "Searched through 1 revisions and 0 checkpoints",
+ "Checked 7 nodes and 15 properties", "Path / is consistent"));
assertExpectedOutput(strErr.toString(), Lists.newArrayList(""));
}
@@ -169,7 +169,7 @@ public class CheckValidRepositoryTest ex
outWriter.close();
errWriter.close();
- assertExpectedOutput(strOut.toString(), Lists.newArrayList("Searched
through 1 revisions", "Checked 1 nodes and 0 properties",
+ assertExpectedOutput(strOut.toString(), Lists.newArrayList("Checking
head", "Searched through 1 revisions and 0 checkpoints",
"Checked 1 nodes and 0 properties", "Checked 1 nodes and 4
properties", "Checked 1 nodes and 5 properties",
"Path /a is consistent", "Path /b is consistent", "Path /d is
consistent", "Path /e is consistent"));
assertExpectedOutput(strErr.toString(), Lists.newArrayList(""));
@@ -202,7 +202,8 @@ public class CheckValidRepositoryTest ex
outWriter.close();
errWriter.close();
- assertExpectedOutput(strOut.toString(), Lists.newArrayList("Searched
through 1 revisions", "No good revision found"));
+ assertExpectedOutput(strOut.toString(), Lists.newArrayList("Checking
head", "Searched through 1 revisions and 0 checkpoints",
+ "No good revision found"));
assertExpectedOutput(strErr.toString(), Lists.newArrayList("Path /g
not found"));
}
@@ -238,9 +239,111 @@ public class CheckValidRepositoryTest ex
outWriter.close();
errWriter.close();
- assertExpectedOutput(strOut.toString(), Lists.newArrayList("Searched
through 1 revisions", "Checked 1 nodes and 1 properties",
- "Checked 1 nodes and 6 properties", "Checked 1 nodes and 4
properties", "Checked 1 nodes and 5 properties",
+ assertExpectedOutput(strOut.toString(), Lists.newArrayList("Checking
head", "Searched through 1 revisions and 0 checkpoints",
+ "Checked 1 nodes and 1 properties", "Checked 1 nodes and 6
properties", "Checked 1 nodes and 4 properties",
+ "Checked 1 nodes and 5 properties",
"Path /a is consistent", "Path /f is consistent", "Path /d is
consistent", "Path /e is consistent"));
assertExpectedOutput(strErr.toString(), Lists.newArrayList("Path /g
not found"));
}
+
+ @Test
+ public void testSuccessfulCheckOfHeadAndCheckpointsWithoutFilterPaths()
throws Exception {
+ 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()))
+ .withJournal("journal.log")
+ .withDebugInterval(Long.MAX_VALUE)
+ .withFilterPaths(filterPaths)
+ .withCheckBinaries(true)
+ .withCheckHead(true)
+ .withCheckpoints(checkpoints)
+ .withIOStatistics(true)
+ .withOutWriter(outWriter)
+ .withErrWriter(errWriter)
+ .build()
+ .run();
+
+ outWriter.close();
+ errWriter.close();
+
+ assertExpectedOutput(strOut.toString(), Lists.newArrayList("Checking
head", "Checking checkpoints",
+ "Searched through 1 revisions and 2 checkpoints", "Checked 7
nodes and 21 properties", "Path / is consistent"));
+ assertExpectedOutput(strErr.toString(), Lists.newArrayList(""));
+ }
+
+ @Test
+ public void testSuccessfulCheckOfHeadAndCheckpointsWithFilterPaths()
throws Exception {
+ 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("/f");
+
+ Check.builder()
+ .withPath(new File(temporaryFolder.getRoot().getAbsolutePath()))
+ .withJournal("journal.log")
+ .withDebugInterval(Long.MAX_VALUE)
+ .withFilterPaths(filterPaths)
+ .withCheckBinaries(true)
+ .withCheckHead(true)
+ .withCheckpoints(checkpoints)
+ .withIOStatistics(true)
+ .withOutWriter(outWriter)
+ .withErrWriter(errWriter)
+ .build()
+ .run();
+
+ outWriter.close();
+ errWriter.close();
+
+ assertExpectedOutput(strOut.toString(), Lists.newArrayList("Checking
head", "Checking checkpoints",
+ "Searched through 1 revisions and 2 checkpoints", "Checked 1
nodes and 6 properties", "Path /f is consistent"));
+ assertExpectedOutput(strErr.toString(), Lists.newArrayList(""));
+ }
+
+ @Test
+ public void testMissingCheckpointCheck() throws Exception {
+ 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("/");
+
+ HashSet<String> checkpoints = new HashSet<String>();
+ checkpoints.add("bogus-checkpoint");
+
+ Check.builder()
+ .withPath(new File(temporaryFolder.getRoot().getAbsolutePath()))
+ .withJournal("journal.log")
+ .withDebugInterval(Long.MAX_VALUE)
+ .withFilterPaths(filterPaths)
+ .withCheckBinaries(true)
+ .withCheckpoints(checkpoints)
+ .withIOStatistics(true)
+ .withOutWriter(outWriter)
+ .withErrWriter(errWriter)
+ .build()
+ .run();
+
+ outWriter.close();
+ errWriter.close();
+
+ assertExpectedOutput(strOut.toString(), Lists.newArrayList("Checking
checkpoints", "Searched through 1 revisions and 1 checkpoints",
+ "No good revision found"));
+ assertExpectedOutput(strErr.toString(), Lists.newArrayList("Checkpoint
bogus-checkpoint not found in this revision!"));
+ }
}