From a9272522d5aff5342d08892992bf669b047c17fe Mon Sep 17 00:00:00 2001
From: David-Sarah Hopwood <david-sarah@jacaranda.org>
Date: Thu, 3 Jan 2013 22:16:20 +0000
Subject: [PATCH] tahoe_check.py: tolerate missing fields in check results for
 LIT files/dirs. fixes #1758 Also test this case and improve some existing
 tests of 'tahoe check'.

Signed-off-by: David-Sarah Hopwood <david-sarah@jacaranda.org>
---
 src/allmydata/scripts/tahoe_check.py | 23 +++++++++-----
 src/allmydata/test/test_cli.py       | 45 ++++++++++++++++++++++++++++
 2 files changed, 61 insertions(+), 7 deletions(-)

diff --git a/src/allmydata/scripts/tahoe_check.py b/src/allmydata/scripts/tahoe_check.py
index adb0ccc4..23064359 100644
--- a/src/allmydata/scripts/tahoe_check.py
+++ b/src/allmydata/scripts/tahoe_check.py
@@ -77,19 +77,26 @@ def check(options):
             else:
                 stdout.write(" repair failed\n")
     else:
-        stdout.write("Summary: %s\n" % quote_output(data["summary"], quotemarks=False))
+        # LIT files and directories do not have a "summary" field.
+        summary = data.get("summary", "Healthy (LIT)")
+        stdout.write("Summary: %s\n" % quote_output(summary, quotemarks=False))
         cr = data["results"]
         stdout.write(" storage index: %s\n" % quote_output(data["storage-index"], quotemarks=False))
-        stdout.write(" good-shares: %r (encoding is %r-of-%r)\n"
-                     % (cr["count-shares-good"],
-                        cr["count-shares-needed"],
-                        cr["count-shares-expected"]))
-        stdout.write(" wrong-shares: %r\n" % cr["count-wrong-shares"])
-        corrupt = cr["list-corrupt-shares"]
+
+        if all([field in cr for field in ("count-shares-good", "count-shares-needed",
+                                          "count-shares-expected", "count-wrong-shares")]):
+            stdout.write(" good-shares: %r (encoding is %r-of-%r)\n"
+                         % (cr["count-shares-good"],
+                            cr["count-shares-needed"],
+                            cr["count-shares-expected"]))
+            stdout.write(" wrong-shares: %r\n" % cr["count-wrong-shares"])
+
+        corrupt = cr.get("list-corrupt-shares", [])
         if corrupt:
             stdout.write(" corrupt shares:\n")
             for (serverid, storage_index, sharenum) in corrupt:
                 stdout.write("  %s\n" % _quote_serverid_index_share(serverid, storage_index, sharenum))
+
     return 0
 
 
@@ -138,6 +145,8 @@ class DeepCheckOutput(LineOnlyReceiver):
             path = d["path"]
             if not path:
                 path = ["<root>"]
+
+            # LIT files and directories do not have a "summary" field.
             summary = cr.get("summary", "Healthy (LIT)")
             print >>stdout, "%s: %s" % (quote_path(path), quote_output(summary, quotemarks=False))
 
diff --git a/src/allmydata/test/test_cli.py b/src/allmydata/test/test_cli.py
index 0edcd78a..b6a592e9 100644
--- a/src/allmydata/test/test_cli.py
+++ b/src/allmydata/test/test_cli.py
@@ -2953,8 +2953,41 @@ class Check(GridTestMixin, CLITestMixin, unittest.TestCase):
             self.failUnlessReallyEqual(rc, 0)
             data = simplejson.loads(out)
             self.failUnlessReallyEqual(to_str(data["summary"]), "Healthy")
+            self.failUnlessReallyEqual(data["results"]["healthy"], True)
         d.addCallback(_check2)
 
+        d.addCallback(lambda ign: c0.upload(upload.Data("literal", convergence="")))
+        def _stash_lit_uri(n):
+            self.lit_uri = n.get_uri()
+        d.addCallback(_stash_lit_uri)
+
+        d.addCallback(lambda ign: self.do_cli("check", self.lit_uri))
+        def _check_lit((rc, out, err)):
+            self.failUnlessReallyEqual(err, "")
+            self.failUnlessReallyEqual(rc, 0)
+            lines = out.splitlines()
+            self.failUnless("Summary: Healthy (LIT)" in lines, out)
+        d.addCallback(_check_lit)
+
+        d.addCallback(lambda ign: self.do_cli("check", "--raw", self.lit_uri))
+        def _check_lit_raw((rc, out, err)):
+            self.failUnlessReallyEqual(err, "")
+            self.failUnlessReallyEqual(rc, 0)
+            data = simplejson.loads(out)
+            self.failUnlessReallyEqual(data["results"]["healthy"], True)
+        d.addCallback(_check_lit_raw)
+
+        d.addCallback(lambda ign: c0.create_immutable_dirnode({}, convergence=""))
+        def _stash_lit_dir_uri(n):
+            self.lit_dir_uri = n.get_uri()
+        d.addCallback(_stash_lit_dir_uri)
+
+        d.addCallback(lambda ign: self.do_cli("check", self.lit_dir_uri))
+        d.addCallback(_check_lit)
+
+        d.addCallback(lambda ign: self.do_cli("check", "--raw", self.lit_uri))
+        d.addCallback(_check_lit_raw)
+
         def _clobber_shares(ignored):
             # delete one, corrupt a second
             shares = self.find_uri_shares(self.uri)
@@ -2984,6 +3017,18 @@ class Check(GridTestMixin, CLITestMixin, unittest.TestCase):
             self.failUnless(self._corrupt_share_line in lines, out)
         d.addCallback(_check3)
 
+        d.addCallback(lambda ign: self.do_cli("check", "--verify", "--raw", self.uri))
+        def _check3_raw((rc, out, err)):
+            self.failUnlessReallyEqual(err, "")
+            self.failUnlessReallyEqual(rc, 0)
+            data = simplejson.loads(out)
+            self.failUnlessReallyEqual(data["results"]["healthy"], False)
+            self.failUnlessIn("Unhealthy: 8 shares (enc 3-of-10)", data["summary"])
+            self.failUnlessReallyEqual(data["results"]["count-shares-good"], 8)
+            self.failUnlessReallyEqual(data["results"]["count-corrupt-shares"], 1)
+            self.failUnlessIn("list-corrupt-shares", data["results"])
+        d.addCallback(_check3_raw)
+
         d.addCallback(lambda ign:
                       self.do_cli("check", "--verify", "--repair", self.uri))
         def _check4((rc, out, err)):
-- 
2.45.2