fuse/runtests: add overlapping write tests
authorrobk-tahoe <robk-tahoe@allmydata.com>
Fri, 3 Oct 2008 22:48:33 +0000 (15:48 -0700)
committerrobk-tahoe <robk-tahoe@allmydata.com>
Fri, 3 Oct 2008 22:48:33 +0000 (15:48 -0700)
using both small and large blocksizes for writes, write a 1Mb file to fuse
where every write overlaps another.

This serves a useful purpose - in manual testing of blackmatch some time ago
most operations e.g. bulk copies, worked fine, but using rsync caused data
corruption on most files.  it turned out to be that rsync writes in 64K blocks,
but rather than making the last block short, the last block instead overlaps
the preceding (already written) block.  This revealed a problem where cache
files were being opened 'append' rather than 'write' and hence the overlapping
write to the fuse layer caused the overlapping portion of the file to be
duplicated in cache, leading to oversized and corrupt files being uploaded.

contrib/fuse/runtests.py

index 54c12a2e22aa5883d11f7d5b35a90767ebed9632..cf0097057295dee7cb84a0dddf4124274cdb016f 100644 (file)
@@ -464,6 +464,34 @@ class SystemTest (object):
             tmpl = 'Expected file contents %r but found %r'
             raise TestFailure(tmpl, expected_body, uploaded_body)
 
+    def test_write_overlapping_small_writes(self, testcap, testdir):
+        self._write_test_overlap(testcap, testdir, name='large_overlap', bs=2**9, sz=2**20)
+
+    def test_write_overlapping_large_writes(self, testcap, testdir):
+        self._write_test_overlap(testcap, testdir, name='small_overlap', bs=2**18, sz=2**20)
+
+    def _write_test_overlap(self, testcap, testdir, name, bs, sz):
+        body = os.urandom(sz)
+        try:
+            path = os.path.join(testdir, name)
+            f = file(path, 'w')
+        except Exception, err:
+            tmpl = 'Could not open file for write at %r: %r'
+            raise TestFailure(tmpl, path, err)
+        try:
+            for posn in range(0,sz,bs):
+                start = max(0, posn-bs)
+                end = min(sz, posn+bs)
+                f.seek(start)
+                f.write(body[start:end])
+            f.close()
+        except Exception, err:
+            tmpl = 'Could not write to file %r: %r'
+            raise TestFailure(tmpl, path, err)
+
+        self._check_write(testcap, name, body)
+
+
     # Utilities:
     def run_tahoe(self, *args):
         realargs = ('tahoe',) + args