Skip to content
Snippets Groups Projects
Commit a98f91f5 authored by jakubs's avatar jakubs
Browse files

SP-155 BIS-38 make checksum verification optional in rsync archiver

SVN: 26273
parent 13c122ec
No related branches found
No related tags found
No related merge requests found
...@@ -56,6 +56,9 @@ public class RsyncArchiver extends AbstractArchiverProcessingPlugin ...@@ -56,6 +56,9 @@ public class RsyncArchiver extends AbstractArchiverProcessingPlugin
@Private @Private
static final String STAGING_FOLDER = "archive-staging"; static final String STAGING_FOLDER = "archive-staging";
@Private
static final String VERIFY_CHECKSUMS_KEY = "verify-checksums";
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Comparator<IHierarchicalContentNode> NODE_COMPARATOR = private static final Comparator<IHierarchicalContentNode> NODE_COMPARATOR =
...@@ -106,6 +109,8 @@ public class RsyncArchiver extends AbstractArchiverProcessingPlugin ...@@ -106,6 +109,8 @@ public class RsyncArchiver extends AbstractArchiverProcessingPlugin
private final DeleteAction deleteAction; private final DeleteAction deleteAction;
private final boolean verifyChecksums;
public RsyncArchiver(Properties properties, File storeRoot) public RsyncArchiver(Properties properties, File storeRoot)
{ {
this(properties, storeRoot, new DataSetFileOperationsManager(properties, this(properties, storeRoot, new DataSetFileOperationsManager(properties,
...@@ -125,6 +130,9 @@ public class RsyncArchiver extends AbstractArchiverProcessingPlugin ...@@ -125,6 +130,9 @@ public class RsyncArchiver extends AbstractArchiverProcessingPlugin
{ {
deleteAction = DeleteAction.DELETE; deleteAction = DeleteAction.DELETE;
} }
verifyChecksums = PropertyUtils.getBoolean(properties, VERIFY_CHECKSUMS_KEY, true);
} }
@Override @Override
...@@ -170,7 +178,7 @@ public class RsyncArchiver extends AbstractArchiverProcessingPlugin ...@@ -170,7 +178,7 @@ public class RsyncArchiver extends AbstractArchiverProcessingPlugin
IHierarchicalContentNode root = content.getRootNode(); IHierarchicalContentNode root = content.getRootNode();
IHierarchicalContentNode archivedRoot = archivedContent.getRootNode(); IHierarchicalContentNode archivedRoot = archivedContent.getRootNode();
status = checkHierarchySizeAndChecksums(root, archivedRoot); status = checkHierarchySizeAndChecksums(root, archivedRoot, verifyChecksums);
} finally } finally
{ {
FileUtils.deleteQuietly(temp); FileUtils.deleteQuietly(temp);
...@@ -184,7 +192,7 @@ public class RsyncArchiver extends AbstractArchiverProcessingPlugin ...@@ -184,7 +192,7 @@ public class RsyncArchiver extends AbstractArchiverProcessingPlugin
@Private @Private
static Status checkHierarchySizeAndChecksums(IHierarchicalContentNode node, static Status checkHierarchySizeAndChecksums(IHierarchicalContentNode node,
IHierarchicalContentNode retrievedNode) IHierarchicalContentNode retrievedNode, boolean verifyChecksums)
{ {
String relativePath = node.getRelativePath(); String relativePath = node.getRelativePath();
String relativePathOfRetrieved = retrievedNode.getRelativePath(); String relativePathOfRetrieved = retrievedNode.getRelativePath();
...@@ -218,7 +226,7 @@ public class RsyncArchiver extends AbstractArchiverProcessingPlugin ...@@ -218,7 +226,7 @@ public class RsyncArchiver extends AbstractArchiverProcessingPlugin
{ {
Status status = Status status =
checkHierarchySizeAndChecksums(childNodes.get(i), checkHierarchySizeAndChecksums(childNodes.get(i),
childNodesOfRetrieved.get(i)); childNodesOfRetrieved.get(i), verifyChecksums);
if (status.isError()) if (status.isError())
{ {
return status; return status;
...@@ -233,14 +241,16 @@ public class RsyncArchiver extends AbstractArchiverProcessingPlugin ...@@ -233,14 +241,16 @@ public class RsyncArchiver extends AbstractArchiverProcessingPlugin
return Status.createError("The file '" + relativePath + "' has in the store " return Status.createError("The file '" + relativePath + "' has in the store "
+ fileLength + " bytes but " + fileLengthOfRetrieved + " in the archive."); + fileLength + " bytes but " + fileLengthOfRetrieved + " in the archive.");
} }
// TODO: check the configuration if should allow checksum checking for archiver if (verifyChecksums)
long checksum = node.getChecksumCRC32();
long checksumOfRetrieved = retrievedNode.getChecksumCRC32();
if (checksum != checksumOfRetrieved)
{ {
return Status.createError("The file '" + relativePath long checksum = node.getChecksumCRC32();
+ "' has in the store the checksum " + renderChecksum(checksum) + " but " long checksumOfRetrieved = retrievedNode.getChecksumCRC32();
+ renderChecksum(checksumOfRetrieved) + " in the archive."); if (checksum != checksumOfRetrieved)
{
return Status.createError("The file '" + relativePath
+ "' has in the store the checksum " + renderChecksum(checksum)
+ " but " + renderChecksum(checksumOfRetrieved) + " in the archive.");
}
} }
} }
return Status.OK; return Status.OK;
......
...@@ -199,7 +199,7 @@ public class RsyncArchiverTest extends AbstractFileSystemTestCase ...@@ -199,7 +199,7 @@ public class RsyncArchiverTest extends AbstractFileSystemTestCase
{ {
// ignored // ignored
} }
allowing(dataSetDirectoryProvider).getStoreRoot(); allowing(dataSetDirectoryProvider).getStoreRoot();
will(returnValue(store)); will(returnValue(store));
} }
...@@ -299,15 +299,17 @@ public class RsyncArchiverTest extends AbstractFileSystemTestCase ...@@ -299,15 +299,17 @@ public class RsyncArchiverTest extends AbstractFileSystemTestCase
one(fileOperationsManager).copyToDestination(file, ds1); one(fileOperationsManager).copyToDestination(file, ds1);
will(returnValue(Status.OK)); will(returnValue(Status.OK));
one(fileOperationsManager).isHosted();
will(returnValue(true));
one(statusUpdater).update(Arrays.asList("ds1"), one(statusUpdater).update(Arrays.asList("ds1"),
DataSetArchivingStatus.AVAILABLE, true); DataSetArchivingStatus.AVAILABLE, true);
one(contentProvider).asContent("ds1"); one(contentProvider).asContent("ds1");
will(returnValue(new MockContent(":0:0", "f.txt:9:8DA988AF"))); will(returnValue(new MockContent(":0:0", "f.txt:9:8DA988AF")));
FileUtilities.writeToFile(new File(retrievedDataSet, "f.txt"), "abcdefghi"); FileUtilities.writeToFile(new File(retrievedDataSet, "f.txt"), "abcdefghi");
one(fileOperationsManager).retrieveFromDestination( one(fileOperationsManager).retrieveFromDestination(retrievedDataSet, ds1);
retrievedDataSet, ds1);
will(returnValue(Status.OK)); will(returnValue(Status.OK));
} }
}); });
...@@ -504,14 +506,15 @@ public class RsyncArchiverTest extends AbstractFileSystemTestCase ...@@ -504,14 +506,15 @@ public class RsyncArchiverTest extends AbstractFileSystemTestCase
public void testCheckHierarchySizeAndChecksumsHappyCase() public void testCheckHierarchySizeAndChecksumsHappyCase()
{ {
IHierarchicalContentNode root1 = IHierarchicalContentNode root1 =
new MockContent(":0:0", "a/:0:0", "a/f1.txt:5:-3", "a/f2.txt:15:13", new MockContent(":0:0", "a/:0:0", "a/f1.txt:5:-3", "a/f2.txt:15:13", "r.txt:7:17")
"r.txt:7:17").getRootNode(); .getRootNode();
IHierarchicalContentNode root2 = IHierarchicalContentNode root2 =
new MockContent(":0:0", "a/:0:0", "a/f2.txt:15:13", "a/f1.txt:5:-3", new MockContent(":0:0", "a/:0:0", "a/f2.txt:15:13", "a/f1.txt:5:-3", "r.txt:7:17")
"r.txt:7:17").getRootNode(); .getRootNode();
assertEquals("OK", RsyncArchiver.checkHierarchySizeAndChecksums(root1, root2).toString()); assertEquals("OK", RsyncArchiver.checkHierarchySizeAndChecksums(root1, root2, true)
.toString());
} }
@Test @Test
public void testCheckHierarchySizeAndChecksumsWrongPaths() public void testCheckHierarchySizeAndChecksumsWrongPaths()
{ {
...@@ -521,9 +524,9 @@ public class RsyncArchiverTest extends AbstractFileSystemTestCase ...@@ -521,9 +524,9 @@ public class RsyncArchiverTest extends AbstractFileSystemTestCase
new MockContent(":0:0", "a/:0:0", "a/f3.txt:15:13").getRootNode(); new MockContent(":0:0", "a/:0:0", "a/f3.txt:15:13").getRootNode();
assertEquals("ERROR: \"Different paths: Path in the store is 'a/f1.txt' " assertEquals("ERROR: \"Different paths: Path in the store is 'a/f1.txt' "
+ "and in the archive 'a/f3.txt'.\"", + "and in the archive 'a/f3.txt'.\"",
RsyncArchiver.checkHierarchySizeAndChecksums(root1, root2).toString()); RsyncArchiver.checkHierarchySizeAndChecksums(root1, root2, true).toString());
} }
@Test @Test
public void testCheckHierarchySizeAndChecksumsFileInsteadOfDirectory() public void testCheckHierarchySizeAndChecksumsFileInsteadOfDirectory()
{ {
...@@ -532,7 +535,7 @@ public class RsyncArchiverTest extends AbstractFileSystemTestCase ...@@ -532,7 +535,7 @@ public class RsyncArchiverTest extends AbstractFileSystemTestCase
assertEquals("ERROR: \"The path 'a' should be in store and archive either " assertEquals("ERROR: \"The path 'a' should be in store and archive either "
+ "both directories or files but not mixed: In the store it is a directory " + "both directories or files but not mixed: In the store it is a directory "
+ "but in the archive it is a file.\"", RsyncArchiver + "but in the archive it is a file.\"", RsyncArchiver
.checkHierarchySizeAndChecksums(root1, root2).toString()); .checkHierarchySizeAndChecksums(root1, root2, true).toString());
} }
@Test @Test
...@@ -543,16 +546,16 @@ public class RsyncArchiverTest extends AbstractFileSystemTestCase ...@@ -543,16 +546,16 @@ public class RsyncArchiverTest extends AbstractFileSystemTestCase
IHierarchicalContentNode root2 = IHierarchicalContentNode root2 =
new MockContent(":0:0", "a/:0:0", "a/f2.txt:15:13").getRootNode(); new MockContent(":0:0", "a/:0:0", "a/f2.txt:15:13").getRootNode();
assertEquals("ERROR: \"The directory 'a' has in the store 2 files but 1 in the archive.\"", assertEquals("ERROR: \"The directory 'a' has in the store 2 files but 1 in the archive.\"",
RsyncArchiver.checkHierarchySizeAndChecksums(root1, root2).toString()); RsyncArchiver.checkHierarchySizeAndChecksums(root1, root2, true).toString());
} }
@Test @Test
public void testCheckHierarchySizeAndChecksumsWrongSize() public void testCheckHierarchySizeAndChecksumsWrongSize()
{ {
IHierarchicalContentNode root1 = new MockContent(":0:0", "r.txt:7:17").getRootNode(); IHierarchicalContentNode root1 = new MockContent(":0:0", "r.txt:7:17").getRootNode();
IHierarchicalContentNode root2 = new MockContent(":0:0", "r.txt:9:17").getRootNode(); IHierarchicalContentNode root2 = new MockContent(":0:0", "r.txt:9:17").getRootNode();
assertEquals("ERROR: \"The file 'r.txt' has in the store 7 bytes but 9 in the archive.\"", assertEquals("ERROR: \"The file 'r.txt' has in the store 7 bytes but 9 in the archive.\"",
RsyncArchiver.checkHierarchySizeAndChecksums(root1, root2).toString()); RsyncArchiver.checkHierarchySizeAndChecksums(root1, root2, true).toString());
} }
@Test @Test
...@@ -562,20 +565,34 @@ public class RsyncArchiverTest extends AbstractFileSystemTestCase ...@@ -562,20 +565,34 @@ public class RsyncArchiverTest extends AbstractFileSystemTestCase
IHierarchicalContentNode root2 = new MockContent(":0:0", "r.txt:7:18").getRootNode(); IHierarchicalContentNode root2 = new MockContent(":0:0", "r.txt:7:18").getRootNode();
assertEquals("ERROR: \"The file 'r.txt' has in the store the checksum 00000017 " assertEquals("ERROR: \"The file 'r.txt' has in the store the checksum 00000017 "
+ "but 00000018 in the archive.\"", + "but 00000018 in the archive.\"",
RsyncArchiver.checkHierarchySizeAndChecksums(root1, root2).toString()); RsyncArchiver.checkHierarchySizeAndChecksums(root1, root2, true).toString());
} }
public void testCheckHierarchySizeAndChecksumsWrongChecksumAreNotChecked()
{
IHierarchicalContentNode root1 = new MockContent(":0:0", "r.txt:7:17").getRootNode();
IHierarchicalContentNode root2 = new MockContent(":0:0", "r.txt:7:18").getRootNode();
assertEquals("OK", RsyncArchiver.checkHierarchySizeAndChecksums(root1, root2, false)
.toString());
}
private static final class MockNode implements IHierarchicalContentNode private static final class MockNode implements IHierarchicalContentNode
{ {
private final List<IHierarchicalContentNode> children = new ArrayList<IHierarchicalContentNode>(); private final List<IHierarchicalContentNode> children =
new ArrayList<IHierarchicalContentNode>();
private String name; private String name;
private String relativePath; private String relativePath;
private IHierarchicalContentNode parent; private IHierarchicalContentNode parent;
private boolean directory; private boolean directory;
private long size; private long size;
private int checksum; private int checksum;
void addNode(MockNode node) void addNode(MockNode node)
{ {
node.parent = this; node.parent = this;
...@@ -653,7 +670,7 @@ public class RsyncArchiverTest extends AbstractFileSystemTestCase ...@@ -653,7 +670,7 @@ public class RsyncArchiverTest extends AbstractFileSystemTestCase
{ {
return true; return true;
} }
@Override @Override
public IRandomAccessFile getFileContent() throws UnsupportedOperationException, public IRandomAccessFile getFileContent() throws UnsupportedOperationException,
IOExceptionUnchecked IOExceptionUnchecked
...@@ -669,12 +686,13 @@ public class RsyncArchiverTest extends AbstractFileSystemTestCase ...@@ -669,12 +686,13 @@ public class RsyncArchiverTest extends AbstractFileSystemTestCase
} }
} }
private static final class MockContent implements IHierarchicalContent private static final class MockContent implements IHierarchicalContent
{ {
private MockNode root; private MockNode root;
private final Map<String, MockNode> nodes = new HashMap<String, MockNode>(); private final Map<String, MockNode> nodes = new HashMap<String, MockNode>();
MockContent(String... contentDescriptions) MockContent(String... contentDescriptions)
{ {
for (String contentDescription : contentDescriptions) for (String contentDescription : contentDescriptions)
...@@ -745,6 +763,6 @@ public class RsyncArchiverTest extends AbstractFileSystemTestCase ...@@ -745,6 +763,6 @@ public class RsyncArchiverTest extends AbstractFileSystemTestCase
public void close() public void close()
{ {
} }
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment