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
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]
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()
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)
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)
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)
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)
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)