]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blobdiff - src/allmydata/test/test_repairer.py
tests: add more diagnostics when code-under-test fails
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / test / test_repairer.py
index 7efb4a82a41ea34c04b409d53b6fdcc179a706e9..0feaacb12162c369eb2f205da44c6dee34f74d1e 100644 (file)
@@ -62,9 +62,9 @@ class RepairTestMixin:
         c0.DEFAULT_ENCODING_PARAMETERS['max_segment_size'] = 12
         d = c0.upload(upload.Data(common.TEST_DATA, convergence=""))
         def _stash_uri(ur):
-            self.uri = ur.uri
-            self.c0_filenode = c0.create_node_from_uri(ur.uri)
-            self.c1_filenode = c1.create_node_from_uri(ur.uri)
+            self.uri = ur.get_uri()
+            self.c0_filenode = c0.create_node_from_uri(ur.get_uri())
+            self.c1_filenode = c1.create_node_from_uri(ur.get_uri())
         d.addCallback(_stash_uri)
         return d
 
@@ -117,7 +117,7 @@ class Verifier(GridTestMixin, unittest.TestCase, RepairTestMixin):
                 judgement(vr)
             except unittest.FailTest, e:
                 # FailTest just uses e.args[0] == str
-                new_arg = str(e.args[0]) + "\nvr.data is: " + str(vr.get_data())
+                new_arg = str(e.args[0]) + "\nvr.data is: " + str(vr.as_dict())
                 e.args = (new_arg,)
                 raise
         d.addCallback(_check)
@@ -127,15 +127,14 @@ class Verifier(GridTestMixin, unittest.TestCase, RepairTestMixin):
         """ Verify says the file is healthy when none of the shares have been
         touched in a way that matters. It doesn't use more than seven times
         as many reads as it needs."""
-        self.failUnless(vr.is_healthy(), (vr, vr.is_healthy(), vr.get_data()))
-        data = vr.get_data()
-        self.failUnless(data['count-shares-good'] == 10, data)
-        self.failUnless(len(data['sharemap']) == 10, data)
-        self.failUnless(data['count-shares-needed'] == 3, data)
-        self.failUnless(data['count-shares-expected'] == 10, data)
-        self.failUnless(data['count-good-share-hosts'] == 10, data)
-        self.failUnless(len(data['servers-responding']) == 10, data)
-        self.failUnless(len(data['list-corrupt-shares']) == 0, data)
+        self.failUnless(vr.is_healthy(), (vr, vr.is_healthy(), vr.as_dict()))
+        self.failUnlessEqual(vr.get_share_counter_good(), 10)
+        self.failUnlessEqual(len(vr.get_sharemap()), 10)
+        self.failUnlessEqual(vr.get_encoding_needed(), 3)
+        self.failUnlessEqual(vr.get_encoding_expected(), 10)
+        self.failUnlessEqual(vr.get_host_counter_good_shares(), 10)
+        self.failUnlessEqual(len(vr.get_servers_responding()), 10)
+        self.failUnlessEqual(len(vr.get_corrupt_shares()), 0)
 
     def test_ok_no_corruption(self):
         self.basedir = "repairer/Verifier/ok_no_corruption"
@@ -163,15 +162,14 @@ class Verifier(GridTestMixin, unittest.TestCase, RepairTestMixin):
         giving you the share data. Test that verifier handles these answers
         correctly. It doesn't use more than seven times as many reads as it
         needs."""
-        self.failIf(vr.is_healthy(), (vr, vr.is_healthy(), vr.get_data()))
-        data = vr.get_data()
-        self.failUnless(data['count-shares-good'] == 9, data)
-        self.failUnless(len(data['sharemap']) == 9, data)
-        self.failUnless(data['count-shares-needed'] == 3, data)
-        self.failUnless(data['count-shares-expected'] == 10, data)
-        self.failUnless(data['count-good-share-hosts'] == 9, data)
-        self.failUnless(len(data['servers-responding']) == 10, data)
-        self.failUnless(len(data['list-corrupt-shares']) == 0, data)
+        self.failIf(vr.is_healthy(), (vr, vr.is_healthy(), vr.as_dict()))
+        self.failUnlessEqual(vr.get_share_counter_good(), 9)
+        self.failUnlessEqual(len(vr.get_sharemap()), 9)
+        self.failUnlessEqual(vr.get_encoding_needed(), 3)
+        self.failUnlessEqual(vr.get_encoding_expected(), 10)
+        self.failUnlessEqual(vr.get_host_counter_good_shares(), 9)
+        self.failUnlessEqual(len(vr.get_servers_responding()), 9)
+        self.failUnlessEqual(len(vr.get_corrupt_shares()), 0)
 
     def test_corrupt_file_verno(self):
         self.basedir = "repairer/Verifier/corrupt_file_verno"
@@ -184,18 +182,15 @@ class Verifier(GridTestMixin, unittest.TestCase, RepairTestMixin):
         # offsets) to something larger than 2 will trigger a
         # ShareVersionIncompatible exception, which should be counted in
         # list-incompatible-shares, rather than list-corrupt-shares.
-        self.failIf(vr.is_healthy(), (vr, vr.is_healthy(), vr.get_data()))
-        data = vr.get_data()
-        self.failUnlessEqual(data['count-shares-good'], 9)
-        self.failUnlessEqual(len(data['sharemap']), 9)
-        self.failUnlessEqual(data['count-shares-needed'], 3)
-        self.failUnlessEqual(data['count-shares-expected'], 10)
-        self.failUnlessEqual(data['count-good-share-hosts'], 9)
-        self.failUnlessEqual(len(data['servers-responding']), 10)
-        self.failUnlessEqual(len(data['list-corrupt-shares']), 0)
-        self.failUnlessEqual(data['count-corrupt-shares'], 0)
-        self.failUnlessEqual(len(data['list-incompatible-shares']), 1)
-        self.failUnlessEqual(data['count-incompatible-shares'], 1)
+        self.failIf(vr.is_healthy(), (vr, vr.is_healthy(), vr.as_dict()))
+        self.failUnlessEqual(vr.get_share_counter_good(), 9)
+        self.failUnlessEqual(len(vr.get_sharemap()), 9)
+        self.failUnlessEqual(vr.get_encoding_needed(), 3)
+        self.failUnlessEqual(vr.get_encoding_expected(), 10)
+        self.failUnlessEqual(vr.get_host_counter_good_shares(), 9)
+        self.failUnlessEqual(len(vr.get_servers_responding()), 10)
+        self.failUnlessEqual(len(vr.get_corrupt_shares()), 0)
+        self.failUnlessEqual(len(vr.get_incompatible_shares()), 1)
 
     def test_corrupt_share_verno(self):
         self.basedir = "repairer/Verifier/corrupt_share_verno"
@@ -206,18 +201,15 @@ class Verifier(GridTestMixin, unittest.TestCase, RepairTestMixin):
         # corruption of fields that the server does not check (which is most
         # of them), which will be detected by the client as it downloads
         # those shares.
-        self.failIf(vr.is_healthy(), (vr, vr.is_healthy(), vr.get_data()))
-        data = vr.get_data()
-        self.failUnlessEqual(data['count-shares-good'], 9)
-        self.failUnlessEqual(data['count-shares-needed'], 3)
-        self.failUnlessEqual(data['count-shares-expected'], 10)
-        self.failUnlessEqual(data['count-good-share-hosts'], 9)
-        self.failUnlessEqual(data['count-corrupt-shares'], 1)
-        self.failUnlessEqual(len(data['list-corrupt-shares']), 1)
-        self.failUnlessEqual(data['count-incompatible-shares'], 0)
-        self.failUnlessEqual(len(data['list-incompatible-shares']), 0)
-        self.failUnlessEqual(len(data['servers-responding']), 10)
-        self.failUnlessEqual(len(data['sharemap']), 9)
+        self.failIf(vr.is_healthy(), (vr, vr.is_healthy(), vr.as_dict()))
+        self.failUnlessEqual(vr.get_share_counter_good(), 9)
+        self.failUnlessEqual(vr.get_encoding_needed(), 3)
+        self.failUnlessEqual(vr.get_encoding_expected(), 10)
+        self.failUnlessEqual(vr.get_host_counter_good_shares(), 9)
+        self.failUnlessEqual(len(vr.get_corrupt_shares()), 1)
+        self.failUnlessEqual(len(vr.get_incompatible_shares()), 0)
+        self.failUnlessEqual(len(vr.get_servers_responding()), 10)
+        self.failUnlessEqual(len(vr.get_sharemap()), 9)
 
     def test_corrupt_sharedata_offset(self):
         self.basedir = "repairer/Verifier/corrupt_sharedata_offset"
@@ -239,6 +231,11 @@ class Verifier(GridTestMixin, unittest.TestCase, RepairTestMixin):
         return self._help_test_verify(common._corrupt_share_data,
                                       self.judge_invisible_corruption)
 
+    def test_corrupt_sharedata_last_byte(self):
+        self.basedir = "repairer/Verifier/corrupt_sharedata_last_byte"
+        return self._help_test_verify(common._corrupt_share_data_last_byte,
+                                      self.judge_invisible_corruption)
+
     def test_corrupt_ueb_length(self):
         self.basedir = "repairer/Verifier/corrupt_ueb_length"
         return self._help_test_verify(common._corrupt_length_of_uri_extension,
@@ -493,7 +490,7 @@ class Repairer(GridTestMixin, unittest.TestCase, RepairTestMixin,
             self.failIfBigger(delta_reads, MAX_DELTA_READS)
             self.failIfBigger(delta_allocates, (DELTA_WRITES_PER_SHARE * 7))
             self.failIf(pre.is_healthy())
-            self.failUnless(post.is_healthy(), post.data)
+            self.failUnless(post.is_healthy(), post.as_dict())
 
             # Make sure we really have 10 shares.
             shares = self.find_uri_shares(self.uri)
@@ -685,9 +682,9 @@ class Repairer(GridTestMixin, unittest.TestCase, RepairTestMixin,
         c0.DEFAULT_ENCODING_PARAMETERS['n'] = 66
         d = c0.upload(upload.Data(DATA, convergence=""))
         def _then(ur):
-            self.uri = ur.uri
+            self.uri = ur.get_uri()
             self.delete_shares_numbered(self.uri, [0])
-            self.c0_filenode = c0.create_node_from_uri(ur.uri)
+            self.c0_filenode = c0.create_node_from_uri(ur.get_uri())
             self._stash_counts()
             return self.c0_filenode.check_and_repair(Monitor())
         d.addCallback(_then)
@@ -701,6 +698,32 @@ class Repairer(GridTestMixin, unittest.TestCase, RepairTestMixin,
         d.addCallback(_check)
         return d
 
+    def test_servers_responding(self):
+        self.basedir = "repairer/Repairer/servers_responding"
+        self.set_up_grid(num_clients=2)
+        d = self.upload_and_stash()
+        # now cause one of the servers to not respond during the pre-repair
+        # filecheck, but then *do* respond to the post-repair filecheck
+        def _then(ign):
+            ss = self.g.servers_by_number[0]
+            self.g.break_server(ss.my_nodeid, count=1)
+            self.delete_shares_numbered(self.uri, [9])
+            return self.c0_filenode.check_and_repair(Monitor())
+        d.addCallback(_then)
+        def _check(rr):
+            # this exercises a bug in which the servers-responding list did
+            # not include servers that responded to the Repair, but which did
+            # not respond to the pre-repair filecheck
+            prr = rr.get_post_repair_results()
+            expected = set(self.g.get_all_serverids())
+            responding_set = frozenset([s.get_serverid() for s in prr.get_servers_responding()])
+            self.failIf(expected - responding_set, expected - responding_set)
+            self.failIf(responding_set - expected, responding_set - expected)
+            self.failUnlessEqual(expected,
+                                 set([s.get_serverid()
+                                      for s in prr.get_servers_responding()]))
+        d.addCallback(_check)
+        return d
 
 # XXX extend these tests to show that the checker detects which specific
 # share on which specific server is broken -- this is necessary so that the