From 6cf4096156594724406fa370f2ebd4fd3d0b80bf Mon Sep 17 00:00:00 2001
From: Brian Warner <warner@allmydata.com>
Date: Tue, 24 Feb 2009 20:00:10 -0700
Subject: [PATCH] test_deepcheck: convert MutableChecker to no-network GridTest

---
 src/allmydata/test/common.py         |  17 ++++-
 src/allmydata/test/test_deepcheck.py | 108 ++++++++++-----------------
 2 files changed, 55 insertions(+), 70 deletions(-)

diff --git a/src/allmydata/test/common.py b/src/allmydata/test/common.py
index fd9cb1bb..be0834d0 100644
--- a/src/allmydata/test/common.py
+++ b/src/allmydata/test/common.py
@@ -13,7 +13,9 @@ from allmydata.interfaces import IURI, IMutableFileNode, IFileNode, \
 from allmydata.check_results import CheckResults, CheckAndRepairResults, \
      DeepCheckResults, DeepCheckAndRepairResults
 from allmydata.mutable.common import CorruptShareError
+from allmydata.mutable.layout import unpack_header
 from allmydata.storage.server import storage_index_to_dir
+from allmydata.storage.mutable import MutableShareFile
 from allmydata.util import hashutil, log, fileutil, pollmixin
 from allmydata.util.assertutil import precondition
 from allmydata.stats import StatsGathererService
@@ -1255,11 +1257,24 @@ def _corrupt_offset_of_uri_extension_to_force_short_read(data, debug=False):
             log.msg("testing: corrupting offset %d, size %d, changing %d to %d (len(data) == %d)" % (0x48, 8, struct.unpack(">Q", data[0x48:0x48+8])[0], len(data)-0x0c-3, len(data)))
         return data[:0x48] + struct.pack(">Q", len(data)-0x0c-3) + data[0x48+8:]
 
+def _corrupt_mutable_share_data(data):
+    prefix = data[:32]
+    assert prefix == MutableShareFile.MAGIC, "This function is designed to corrupt mutable shares of v1, and the magic number doesn't look right: %r vs %r" % (prefix, MutableShareFile.MAGIC)
+    data_offset = MutableShareFile.DATA_OFFSET
+    sharetype = data[data_offset:data_offset+1]
+    assert sharetype == "\x00", "non-SDMF mutable shares not supported"
+    (version, ig_seqnum, ig_roothash, ig_IV, ig_k, ig_N, ig_segsize,
+     ig_datalen, offsets) = unpack_header(data[data_offset:])
+    assert version == 0, "this function only handles v0 SDMF files"
+    start = data_offset + offsets["share_data"]
+    length = data_offset + offsets["enc_privkey"] - start
+    return corrupt_field(data, start, length)
+
 def _corrupt_share_data(data):
     """ Scramble the file data -- the field containing the share data itself will have one
     bit flipped or else will be changed to a random value. """
     sharevernum = struct.unpack(">L", data[0x0c:0x0c+4])[0]
-    assert sharevernum in (1, 2), "This test is designed to corrupt immutable shares of v1 or v2 in specific ways."
+    assert sharevernum in (1, 2), "This test is designed to corrupt immutable shares of v1 or v2 in specific ways, not v%d." % sharevernum
     if sharevernum == 1:
         sharedatasize = struct.unpack(">L", data[0x0c+0x08:0x0c+0x08+4])[0]
 
diff --git a/src/allmydata/test/test_deepcheck.py b/src/allmydata/test/test_deepcheck.py
index f8d4cfc4..7ec1ed26 100644
--- a/src/allmydata/test/test_deepcheck.py
+++ b/src/allmydata/test/test_deepcheck.py
@@ -13,9 +13,11 @@ from allmydata.interfaces import ICheckResults, ICheckAndRepairResults, \
 from allmydata.monitor import Monitor, OperationCancelledError
 from twisted.web.client import getPage
 
-from allmydata.test.common import SystemTestMixin, ErrorMixin
+from allmydata.test.common import SystemTestMixin, ErrorMixin, \
+     _corrupt_mutable_share_data
+from allmydata.test.no_network import GridTestMixin
 
-class MutableChecker(SystemTestMixin, unittest.TestCase, ErrorMixin):
+class MutableChecker(GridTestMixin, unittest.TestCase, ErrorMixin):
 
     def _run_cli(self, argv):
         stdout, stderr = StringIO(), StringIO()
@@ -25,21 +27,18 @@ class MutableChecker(SystemTestMixin, unittest.TestCase, ErrorMixin):
         return stdout.getvalue()
 
     def test_good(self):
-        self.basedir = self.mktemp()
-        d = self.set_up_nodes()
+        self.basedir = "deepcheck/MutableChecker/good"
+        self.set_up_grid()
         CONTENTS = "a little bit of data"
-        d.addCallback(lambda res: self.clients[0].create_mutable_file(CONTENTS))
+        d = self.g.clients[0].create_mutable_file(CONTENTS)
         def _created(node):
             self.node = node
+            self.fileurl = "uri/" + urllib.quote(node.get_uri())
             si = self.node.get_storage_index()
         d.addCallback(_created)
         # now make sure the webapi verifier sees no problems
-        def _do_check(res):
-            url = (self.webish_url +
-                   "uri/%s" % urllib.quote(self.node.get_uri()) +
-                   "?t=check&verify=true")
-            return getPage(url, method="POST")
-        d.addCallback(_do_check)
+        d.addCallback(lambda ign: self.GET(self.fileurl+"?t=check&verify=true",
+                                           method="POST"))
         def _got_results(out):
             self.failUnless("<span>Healthy : Healthy</span>" in out, out)
             self.failUnless("Recoverable Versions: 10*seq1-" in out, out)
@@ -51,31 +50,19 @@ class MutableChecker(SystemTestMixin, unittest.TestCase, ErrorMixin):
         return d
 
     def test_corrupt(self):
-        self.basedir = self.mktemp()
-        d = self.set_up_nodes()
+        self.basedir = "deepcheck/MutableChecker/corrupt"
+        self.set_up_grid()
         CONTENTS = "a little bit of data"
-        d.addCallback(lambda res: self.clients[0].create_mutable_file(CONTENTS))
-        def _created(node):
+        d = self.g.clients[0].create_mutable_file(CONTENTS)
+        def _stash_and_corrupt(node):
             self.node = node
-            si = self.node.get_storage_index()
-            out = self._run_cli(["debug", "find-shares", base32.b2a(si),
-                                self.clients[1].basedir])
-            files = out.split("\n")
-            # corrupt one of them, using the CLI debug command
-            f = files[0]
-            shnum = os.path.basename(f)
-            nodeid = self.clients[1].nodeid
-            nodeid_prefix = idlib.shortnodeid_b2a(nodeid)
-            self.corrupt_shareid = "%s-sh%s" % (nodeid_prefix, shnum)
-            out = self._run_cli(["debug", "corrupt-share", files[0]])
-        d.addCallback(_created)
+            self.fileurl = "uri/" + urllib.quote(node.get_uri())
+            self.corrupt_shares_numbered(node.get_uri(), [0],
+                                         _corrupt_mutable_share_data)
+        d.addCallback(_stash_and_corrupt)
         # now make sure the webapi verifier notices it
-        def _do_check(res):
-            url = (self.webish_url +
-                   "uri/%s" % urllib.quote(self.node.get_uri()) +
-                   "?t=check&verify=true")
-            return getPage(url, method="POST")
-        d.addCallback(_do_check)
+        d.addCallback(lambda ign: self.GET(self.fileurl+"?t=check&verify=true",
+                                           method="POST"))
         def _got_results(out):
             self.failUnless("Not Healthy!" in out, out)
             self.failUnless("Unhealthy: best version has only 9 shares (encoding is 3-of-10)" in out, out)
@@ -83,16 +70,14 @@ class MutableChecker(SystemTestMixin, unittest.TestCase, ErrorMixin):
         d.addCallback(_got_results)
 
         # now make sure the webapi repairer can fix it
-        def _do_repair(res):
-            url = (self.webish_url +
-                   "uri/%s" % urllib.quote(self.node.get_uri()) +
-                   "?t=check&verify=true&repair=true")
-            return getPage(url, method="POST")
-        d.addCallback(_do_repair)
+        d.addCallback(lambda ign:
+                      self.GET(self.fileurl+"?t=check&verify=true&repair=true",
+                               method="POST"))
         def _got_repair_results(out):
             self.failUnless("<div>Repair successful</div>" in out, out)
         d.addCallback(_got_repair_results)
-        d.addCallback(_do_check)
+        d.addCallback(lambda ign: self.GET(self.fileurl+"?t=check&verify=true",
+                                           method="POST"))
         def _got_postrepair_results(out):
             self.failIf("Not Healthy!" in out, out)
             self.failUnless("Recoverable Versions: 10*seq" in out, out)
@@ -102,31 +87,18 @@ class MutableChecker(SystemTestMixin, unittest.TestCase, ErrorMixin):
         return d
 
     def test_delete_share(self):
-        self.basedir = self.mktemp()
-        d = self.set_up_nodes()
+        self.basedir = "deepcheck/MutableChecker/delete_share"
+        self.set_up_grid()
         CONTENTS = "a little bit of data"
-        d.addCallback(lambda res: self.clients[0].create_mutable_file(CONTENTS))
-        def _created(node):
+        d = self.g.clients[0].create_mutable_file(CONTENTS)
+        def _stash_and_delete(node):
             self.node = node
-            si = self.node.get_storage_index()
-            out = self._run_cli(["debug", "find-shares", base32.b2a(si),
-                                self.clients[1].basedir])
-            files = out.split("\n")
-            # corrupt one of them, using the CLI debug command
-            f = files[0]
-            shnum = os.path.basename(f)
-            nodeid = self.clients[1].nodeid
-            nodeid_prefix = idlib.shortnodeid_b2a(nodeid)
-            self.corrupt_shareid = "%s-sh%s" % (nodeid_prefix, shnum)
-            os.unlink(files[0])
-        d.addCallback(_created)
+            self.fileurl = "uri/" + urllib.quote(node.get_uri())
+            self.delete_shares_numbered(node.get_uri(), [0])
+        d.addCallback(_stash_and_delete)
         # now make sure the webapi checker notices it
-        def _do_check(res):
-            url = (self.webish_url +
-                   "uri/%s" % urllib.quote(self.node.get_uri()) +
-                   "?t=check&verify=false")
-            return getPage(url, method="POST")
-        d.addCallback(_do_check)
+        d.addCallback(lambda ign: self.GET(self.fileurl+"?t=check&verify=false",
+                                           method="POST"))
         def _got_results(out):
             self.failUnless("Not Healthy!" in out, out)
             self.failUnless("Unhealthy: best version has only 9 shares (encoding is 3-of-10)" in out, out)
@@ -134,16 +106,14 @@ class MutableChecker(SystemTestMixin, unittest.TestCase, ErrorMixin):
         d.addCallback(_got_results)
 
         # now make sure the webapi repairer can fix it
-        def _do_repair(res):
-            url = (self.webish_url +
-                   "uri/%s" % urllib.quote(self.node.get_uri()) +
-                   "?t=check&verify=false&repair=true")
-            return getPage(url, method="POST")
-        d.addCallback(_do_repair)
+        d.addCallback(lambda ign:
+                      self.GET(self.fileurl+"?t=check&verify=false&repair=true",
+                               method="POST"))
         def _got_repair_results(out):
             self.failUnless("Repair successful" in out)
         d.addCallback(_got_repair_results)
-        d.addCallback(_do_check)
+        d.addCallback(lambda ign: self.GET(self.fileurl+"?t=check&verify=false",
+                                           method="POST"))
         def _got_postrepair_results(out):
             self.failIf("Not Healthy!" in out, out)
             self.failUnless("Recoverable Versions: 10*seq" in out)
-- 
2.45.2