3 from twisted.trial import unittest
4 from allmydata import check_results, uri
5 from allmydata.web import check_results as web_check_results
6 from allmydata.storage_client import StorageFarmBroker, NativeStorageClient
7 from common_web import WebRenderingMixin
10 def get_storage_broker(self):
11 return self.storage_broker
13 class WebResultsRendering(unittest.TestCase, WebRenderingMixin):
15 def create_fake_client(self):
16 sb = StorageFarmBroker()
17 for (peerid, nickname) in [("\x00"*20, "peer-0"),
18 ("\xff"*20, "peer-f"),
19 ("\x11"*20, "peer-11")] :
20 n = NativeStorageClient(peerid, None, nickname)
21 sb.add_server(peerid, n)
26 def render_json(self, page):
27 d = self.render1(page, args={"output": ["json"]})
30 def test_literal(self):
31 c = self.create_fake_client()
32 lcr = web_check_results.LiteralCheckResults(c)
36 s = self.remove_tags(html)
37 self.failUnlessIn("Literal files are always healthy", s)
39 d.addCallback(lambda ignored:
40 self.render1(lcr, args={"return_to": ["FOOURL"]}))
41 def _check_return_to(html):
42 s = self.remove_tags(html)
43 self.failUnlessIn("Literal files are always healthy", s)
44 self.failUnlessIn('<a href="FOOURL">Return to file.</a>',
46 d.addCallback(_check_return_to)
47 d.addCallback(lambda ignored: self.render_json(lcr))
48 def _check_json(json):
49 j = simplejson.loads(json)
50 self.failUnlessEqual(j["storage-index"], "")
51 self.failUnlessEqual(j["results"]["healthy"], True)
52 d.addCallback(_check_json)
56 c = self.create_fake_client()
57 serverid_1 = "\x00"*20
58 serverid_f = "\xff"*20
59 u = uri.CHKFileURI("\x00"*16, "\x00"*32, 3, 10, 1234)
60 cr = check_results.CheckResults(u, u.storage_index)
62 cr.set_needs_rebalancing(False)
63 cr.set_summary("groovy")
64 data = { "count-shares-needed": 3,
65 "count-shares-expected": 9,
66 "count-shares-good": 10,
67 "count-good-share-hosts": 11,
68 "list-corrupt-shares": [],
69 "count-wrong-shares": 0,
70 "sharemap": {"shareid1": [serverid_1, serverid_f]},
71 "count-recoverable-versions": 1,
72 "count-unrecoverable-versions": 0,
73 "servers-responding": [],
77 w = web_check_results.CheckResults(c, cr)
78 html = self.render2(w)
79 s = self.remove_tags(html)
80 self.failUnlessIn("File Check Results for SI=2k6avp", s) # abbreviated
81 self.failUnlessIn("Healthy : groovy", s)
82 self.failUnlessIn("Share Counts: need 3-of-9, have 10", s)
83 self.failUnlessIn("Hosts with good shares: 11", s)
84 self.failUnlessIn("Corrupt shares: none", s)
85 self.failUnlessIn("Wrong Shares: 0", s)
86 self.failUnlessIn("Recoverable Versions: 1", s)
87 self.failUnlessIn("Unrecoverable Versions: 0", s)
90 cr.set_recoverable(True)
91 cr.set_summary("ungroovy")
92 html = self.render2(w)
93 s = self.remove_tags(html)
94 self.failUnlessIn("File Check Results for SI=2k6avp", s) # abbreviated
95 self.failUnlessIn("Not Healthy! : ungroovy", s)
98 cr.set_recoverable(False)
99 cr.set_summary("rather dead")
100 data["list-corrupt-shares"] = [(serverid_1, u.storage_index, 2)]
102 html = self.render2(w)
103 s = self.remove_tags(html)
104 self.failUnlessIn("File Check Results for SI=2k6avp", s) # abbreviated
105 self.failUnlessIn("Not Recoverable! : rather dead", s)
106 self.failUnlessIn("Corrupt shares: Share ID Nickname Node ID sh#2 peer-0 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", s)
108 html = self.render2(w)
109 s = self.remove_tags(html)
110 self.failUnlessIn("File Check Results for SI=2k6avp", s) # abbreviated
111 self.failUnlessIn("Not Recoverable! : rather dead", s)
113 html = self.render2(w, args={"return_to": ["FOOURL"]})
114 self.failUnlessIn('<a href="FOOURL">Return to file/directory.</a>',
117 d = self.render_json(w)
118 def _check_json(jdata):
119 j = simplejson.loads(jdata)
120 self.failUnlessEqual(j["summary"], "rather dead")
121 self.failUnlessEqual(j["storage-index"],
122 "2k6avpjga3dho3zsjo6nnkt7n4")
123 expected = {'needs-rebalancing': False,
124 'count-shares-expected': 9,
126 'count-unrecoverable-versions': 0,
127 'count-shares-needed': 3,
128 'sharemap': {"shareid1":
129 ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
130 "77777777777777777777777777777777"]},
131 'count-recoverable-versions': 1,
132 'list-corrupt-shares':
133 [["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
134 "2k6avpjga3dho3zsjo6nnkt7n4", 2]],
135 'count-good-share-hosts': 11,
136 'count-wrong-shares': 0,
137 'count-shares-good': 10,
138 'count-corrupt-shares': 0,
139 'servers-responding': [],
140 'recoverable': False,
142 self.failUnlessEqual(j["results"], expected)
143 d.addCallback(_check_json)
144 d.addCallback(lambda ignored: self.render1(w))
146 s = self.remove_tags(html)
147 self.failUnlessIn("File Check Results for SI=2k6avp", s)
148 self.failUnlessIn("Not Recoverable! : rather dead", s)
149 d.addCallback(_check)
153 def test_check_and_repair(self):
154 c = self.create_fake_client()
155 serverid_1 = "\x00"*20
156 serverid_f = "\xff"*20
157 u = uri.CHKFileURI("\x00"*16, "\x00"*32, 3, 10, 1234)
159 pre_cr = check_results.CheckResults(u, u.storage_index)
160 pre_cr.set_healthy(False)
161 pre_cr.set_recoverable(True)
162 pre_cr.set_needs_rebalancing(False)
163 pre_cr.set_summary("illing")
164 data = { "count-shares-needed": 3,
165 "count-shares-expected": 10,
166 "count-shares-good": 6,
167 "count-good-share-hosts": 7,
168 "list-corrupt-shares": [],
169 "count-wrong-shares": 0,
170 "sharemap": {"shareid1": [serverid_1, serverid_f]},
171 "count-recoverable-versions": 1,
172 "count-unrecoverable-versions": 0,
173 "servers-responding": [],
175 pre_cr.set_data(data)
177 post_cr = check_results.CheckResults(u, u.storage_index)
178 post_cr.set_healthy(True)
179 post_cr.set_recoverable(True)
180 post_cr.set_needs_rebalancing(False)
181 post_cr.set_summary("groovy")
182 data = { "count-shares-needed": 3,
183 "count-shares-expected": 10,
184 "count-shares-good": 10,
185 "count-good-share-hosts": 11,
186 "list-corrupt-shares": [],
187 "count-wrong-shares": 0,
188 "sharemap": {"shareid1": [serverid_1, serverid_f]},
189 "count-recoverable-versions": 1,
190 "count-unrecoverable-versions": 0,
191 "servers-responding": [],
193 post_cr.set_data(data)
195 crr = check_results.CheckAndRepairResults(u.storage_index)
196 crr.pre_repair_results = pre_cr
197 crr.post_repair_results = post_cr
198 crr.repair_attempted = False
200 w = web_check_results.CheckAndRepairResults(c, crr)
201 html = self.render2(w)
202 s = self.remove_tags(html)
204 self.failUnlessIn("File Check-And-Repair Results for SI=2k6avp", s)
205 self.failUnlessIn("Healthy : groovy", s)
206 self.failUnlessIn("No repair necessary", s)
207 self.failUnlessIn("Post-Repair Checker Results:", s)
208 self.failUnlessIn("Share Counts: need 3-of-10, have 10", s)
210 crr.repair_attempted = True
211 crr.repair_successful = True
212 html = self.render2(w)
213 s = self.remove_tags(html)
215 self.failUnlessIn("File Check-And-Repair Results for SI=2k6avp", s)
216 self.failUnlessIn("Healthy : groovy", s)
217 self.failUnlessIn("Repair successful", s)
218 self.failUnlessIn("Post-Repair Checker Results:", s)
220 crr.repair_attempted = True
221 crr.repair_successful = False
222 post_cr.set_healthy(False)
223 post_cr.set_summary("better")
224 html = self.render2(w)
225 s = self.remove_tags(html)
227 self.failUnlessIn("File Check-And-Repair Results for SI=2k6avp", s)
228 self.failUnlessIn("Not Healthy! : better", s)
229 self.failUnlessIn("Repair unsuccessful", s)
230 self.failUnlessIn("Post-Repair Checker Results:", s)
232 crr.repair_attempted = True
233 crr.repair_successful = False
234 post_cr.set_healthy(False)
235 post_cr.set_recoverable(False)
236 post_cr.set_summary("worse")
237 html = self.render2(w)
238 s = self.remove_tags(html)
240 self.failUnlessIn("File Check-And-Repair Results for SI=2k6avp", s)
241 self.failUnlessIn("Not Recoverable! : worse", s)
242 self.failUnlessIn("Repair unsuccessful", s)
243 self.failUnlessIn("Post-Repair Checker Results:", s)
245 d = self.render_json(w)
247 j = simplejson.loads(data)
248 self.failUnlessEqual(j["repair-attempted"], True)
249 self.failUnlessEqual(j["storage-index"],
250 "2k6avpjga3dho3zsjo6nnkt7n4")
251 self.failUnlessEqual(j["pre-repair-results"]["summary"], "illing")
252 self.failUnlessEqual(j["post-repair-results"]["summary"], "worse")
253 d.addCallback(_got_json)
255 w2 = web_check_results.CheckAndRepairResults(c, None)
256 d.addCallback(lambda ignored: self.render_json(w2))
257 def _got_lit_results(data):
258 j = simplejson.loads(data)
259 self.failUnlessEqual(j["repair-attempted"], False)
260 self.failUnlessEqual(j["storage-index"], "")
261 d.addCallback(_got_lit_results)