test corruption by tearing a hole in a volume
authorPhilipp Gesang <philipp.gesang@intra2net.com>
Tue, 15 Aug 2017 14:54:30 +0000 (16:54 +0200)
committerThomas Jarosch <thomas.jarosch@intra2net.com>
Mon, 2 Apr 2018 11:34:09 +0000 (13:34 +0200)
runtests.py
testing/test_recover.py

index eb81a83..c03a7df 100755 (executable)
@@ -49,7 +49,10 @@ from testing.test_recover import \
     , RecoverCorruptTrailingDataGZAESMultiTest \
     , RecoverCorruptVolumeTest \
     , RecoverCorruptVolumeGZTest \
-    , RecoverCorruptVolumeGZAESTest
+    , RecoverCorruptVolumeGZAESTest \
+    , RecoverCorruptHoleTest \
+    , RecoverCorruptHoleGZTest \
+    , RecoverCorruptHoleGZAESTest
 from testing.test_rescue_tar import RescueTarTest
 from testing.test_encryption import EncryptionTest
 from testing.test_deltatar import (DeltaTarTest, DeltaTar2Test,
@@ -111,6 +114,9 @@ if __name__ == "__main__":
                          , RecoverCorruptVolumeTest
                          , RecoverCorruptVolumeGZTest
                          , RecoverCorruptVolumeGZAESTest
+                         , RecoverCorruptHoleTest
+                         , RecoverCorruptHoleGZTest
+                         , RecoverCorruptHoleGZAESTest
                          ]:
                 try:
                     t = group (n)
index e936e89..91b10f7 100644 (file)
@@ -1,6 +1,7 @@
 import logging
 import os
 import shutil
+import stat
 
 import deltatar.deltatar as deltatar
 import deltatar.crypto   as crypto
@@ -77,6 +78,10 @@ def is_pdt_encrypted (fname):
     return True
 
 
+###############################################################################
+## corruption simulators                                                     ##
+###############################################################################
+
 def corrupt_header (_, fname, compress, encrypt):
     """
     Modify a significant byte in the object header of the format.
@@ -148,6 +153,36 @@ def corrupt_volume (_, fname, compress, encrypt):
     os.close (fd)
 
 
+def corrupt_hole (_, fname, compress, encrypt):
+    """
+    Cut file in three pieces, reassemble without the middle one.
+    """
+    aname = os.path.abspath (fname)
+    infd = os.open (fname, os.O_RDONLY)
+    size = os.lseek (infd, 0, os.SEEK_END)
+    assert os.lseek (infd, 0, os.SEEK_SET) == 0
+    assert size > 3 * TEST_BLOCKSIZE
+    hole = (size / 3, size * 2 / 3)
+    outfd = os.open (os.path.dirname (aname), os.O_WRONLY | os.O_TMPFILE,
+                     stat.S_IRUSR | stat.S_IWUSR)
+    
+    zeros = bytes (b'\x00' * TEST_BLOCKSIZE)
+    done = 0
+    while done < size:
+        data = os.read (infd, TEST_BLOCKSIZE)
+        if done < hole [0] or hole [1] < done:
+            # only copy from outside hole
+            os.write (outfd, data)
+        done += len (data)
+
+    os.close (infd)
+    os.unlink (fname)
+
+    path = "/proc/self/fd/%d" % outfd
+    os.link (path, aname, src_dir_fd=0, follow_symlinks=True)
+    os.close (outfd)
+
+
 ###############################################################################
 ## tests                                                                     ##
 ###############################################################################
@@ -503,17 +538,36 @@ class RecoverCorruptVolumeBaseTest (RecoverTest):
 class RecoverCorruptVolumeTest (RecoverCorruptVolumeBaseTest):
     pass
 
-class RecoverCorruptVolumeGZTest (RecoverTest):
+class RecoverCorruptVolumeGZTest (RecoverCorruptVolumeBaseTest):
+    COMPRESSION = "#gz"
+
+class RecoverCorruptVolumeGZAESTest (RecoverCorruptVolumeBaseTest):
     COMPRESSION = "#gz"
+    PASSWORD    = TEST_PASSWORD
+
+
+class RecoverCorruptHoleBaseTest (RecoverTest):
+    """
+    Cut bytes from the middle of a volume.
+
+    Index-based recovery works only up to the hole.
+    """
+    COMPRESSION = None
     PASSWORD    = None
-    FAILURES    = 8
-    CORRUPT     = corrupt_volume
-    VOLUMES     = 3
+    FAILURES    = 3
+    CORRUPT     = corrupt_hole
+    VOLUMES     = 2 # request two vols to swell up the first one
+    MISMATCHES  = 1
+
+class RecoverCorruptHoleTest (RecoverCorruptHoleBaseTest):
+    FAILURES    = 2
+
+class RecoverCorruptHoleGZTest (RecoverCorruptHoleBaseTest):
+    COMPRESSION = "#gz"
+    MISSING     = 2
 
-class RecoverCorruptVolumeGZAESTest (RecoverTest):
+class RecoverCorruptHoleGZAESTest (RecoverCorruptHoleBaseTest):
     COMPRESSION = "#gz"
     PASSWORD    = TEST_PASSWORD
-    FAILURES    = 8
-    CORRUPT     = corrupt_volume
-    VOLUMES     = 3
+    MISSING     = 2