Ticket #562: tests.darcspatch.txt

File tests.darcspatch.txt, 20.4 KB (added by kevan, at 2010-05-01T23:49:22Z)

tests for 'tahoe censor'

Line 
1Sun Apr 25 13:11:21 PDT 2010  kevan@isnotajoke.com
2  * Add tests for 'tahoe censor'
3
4Sun Apr 25 13:11:50 PDT 2010  kevan@isnotajoke.com
5  * Make it so that CLI tests work without actually making a node directory
6 
7  It is not necessary to have a node directory for 'tahoe censor', because
8  its operations are all local -- it processes a log file. So I made its
9  CensorOptions class subclass something other than VDriveOptions. The
10  result of that is that CensorOptions doesn't know how to process a
11  node-directory parameter, which this code would send. So, now it looks
12  for a 'no_node' kwarg; if this is present and set to True, the
13  node-directory option is not sent, and everything works.
14
15New patches:
16
17[Add tests for 'tahoe censor'
18kevan@isnotajoke.com**20100425201121
19 Ignore-this: 9fe8849052cc261e5d4c40051686bd9b
20] {
21hunk ./src/allmydata/test/test_cli.py 9
22 import urllib
23 import re
24 import simplejson
25+import pickle
26+import platform
27+import stat
28+import bz2
29 
30 from allmydata.util import fileutil, hashutil, base32
31 from allmydata import uri
32hunk ./src/allmydata/test/test_cli.py 453
33         help = str(cli.AddAliasOptions())
34         self.failUnless("add-alias ALIAS DIRCAP" in help, help)
35 
36+    def test_censor(self):
37+        help = str(cli.CensorOptions())
38+        self.failUnless("censor SOURCE-LOG DEST-LOG" in help, help)
39+
40+
41 class CLITestMixin:
42     def do_cli(self, verb, *args, **kwargs):
43         nodeargs = [
44hunk ./src/allmydata/test/test_cli.py 2228
45             self.failUnlessIn("error:", err)
46         d.addCallback(_check)
47         return d
48+
49+
50+class Censor(GridTestMixin, CLITestMixin, unittest.TestCase):
51+    def write_test_log_to_file(self, f):
52+        e1 = {}
53+        e1['d'] = {"message": "Tub location set to 62.220.0.0:49628,127.0.0.1:49628"}
54+        ips_to_look_for = ["62.220.0.0", "127.0.0.1"]
55+        pickle.dump(e1, f)
56+        e2 = {}
57+        e2['d'] = {"message": "connectTCP to ('134.71.255.255', 44785)"}
58+        ips_to_look_for.append("134.71.255.255")
59+        pickle.dump(e2, f)
60+        e3 = {}
61+        e3['d'] = {"message": "pb://todjw7qkb4dgq4fkeo7cqydcu5vneioh@tahoecs2.allmydata.com:52106/introducer"}
62+        furls_to_look_for = ["pb://todjw7qkb4dgq4fkeo7cqydcu5vneioh@tahoecs2.allmydata.com:52106/introducer"]
63+        pickle.dump(e3, f)
64+        e4 = {}
65+        e4['d'] = {"message": "<si>dkalsdkjaslkjd</si>"}
66+        sis_to_look_for = ["dkalsdkjaslkjd"]
67+        pickle.dump(e4, f)
68+        e5 = {}
69+        e5['d'] = {"message": "<SI>dasdasdsadsads</SI>"}
70+        sis_to_look_for.append("dasdasdsadsads")
71+        pickle.dump(e5, f)
72+        # ([ips], [furls], [sis], # of log messages)
73+        return (ips_to_look_for, furls_to_look_for, sis_to_look_for, 5)
74+
75+
76+    def test_censor_with_nonexistent_source(self):
77+        # When asked to censor a file that doesn't exist, 'tahoe censor'
78+        # should print something useful as an error message.
79+        self.basedir = os.path.join("cli",
80+                                    "Censor",
81+                                    "test_censor_with_nonexistent_source")
82+        self.set_up_grid()
83+        d = self.do_cli("censor", "does_not_exist", no_node=True)
84+        def _check((rc, out, err)):
85+            self.failUnlessEqual(rc, 1)
86+            self.failUnlessIn("Error", err)
87+            self.failUnlessIn("doesn't exist", err)
88+        d.addCallback(_check)
89+        return d
90+
91+
92+    def test_censor_with_nonsensical_source(self):
93+        # 'tahoe censor' works on logs that are actually pickled
94+        # dictionaries, as output by foolscap. If asked to censor
95+        # something else, it should print something useful as an error
96+        # message.
97+        self.basedir = os.path.join("cli",
98+                                    "Censor",
99+                                    "test_censor_with_nonsensical_source")
100+        self.set_up_grid()
101+        test_file = os.path.join(self.basedir, "input")
102+        f = open(test_file, "wb")
103+        f.write("blahblahblah")
104+        f.close()
105+        d = self.do_cli("censor", test_file, no_node=True)
106+        def _check((rc, out, err)):
107+            self.failUnlessEqual(rc, 1)
108+            self.failUnlessIn("Error", err)
109+            self.failUnlessIn("invalid format", err)
110+        d.addCallback(_check)
111+        def _then(ign):
112+            self.test_file = os.path.join(self.basedir, "input2")
113+            f = open(self.test_file, "wb")
114+            f.write("For some reason, the file contents above result in "
115+                    "an IndexError, while these result in an EOFError. In "
116+                    "either case, the program should output something useful")
117+            f.close()
118+        d.addCallback(_then)
119+        d.addCallback(lambda ign: self.do_cli("censor", self.test_file,
120+                                              no_node=True))
121+        d.addCallback(_check)
122+        return d
123+
124+
125+    def test_censor_with_empty_source(self):
126+        # 'tahoe censor' should complain when presented with an empty
127+        # log file to censor.
128+        self.basedir = os.path.join("cli",
129+                                    "Censor",
130+                                    "test_censor_with_empty_source")
131+        self.set_up_grid()
132+        test_file = os.path.join(self.basedir, "input")
133+        f = open(test_file, "wb").close()
134+        d = self.do_cli("censor", test_file, no_node=True)
135+        def _check((rc, out, err)):
136+            self.failUnlessEqual(rc, 1)
137+            self.failUnlessIn("Error", err)
138+            self.failUnlessIn("empty", err)
139+        d.addCallback(_check)
140+        return d
141+
142+
143+    def test_censor_with_unreadable_source(self):
144+        # 'tahoe censor' should complain when presented with a file that
145+        # OS-level access controls prevent it from reading.
146+        if platform.system() == "Windows":
147+            raise unittest.SkipTest("os.chmod() can't make a file that this "
148+                                    "test can't read on Windows.")
149+        self.basedir = os.path.join("cli",
150+                                    "Censor",
151+                                    "test_censor_with_unreadable_source")
152+        self.set_up_grid()
153+        test_file = os.path.join(self.basedir, "input")
154+        f = open(test_file, "wb")
155+        self.write_test_log_to_file(f)
156+        f.close()
157+        os.chmod(test_file, stat.S_IWRITE)
158+        d = self.do_cli("censor", test_file, no_node=True)
159+        def _check((rc, out, err)):
160+            self.failUnlessEqual(rc, 1)
161+            self.failUnlessIn("Error", err)
162+            self.failUnlessIn("read", err)
163+        d.addCallback(_check)
164+        return d
165+
166+
167+    def test_censor_with_unwritable_destination(self):
168+        # 'tahoe censor' should complain when presented with a
169+        # destination file that it can't write to.
170+        self.basedir = os.path.join("cli",
171+                                    "Censor",
172+                                    "test_censor_with_unwritable_destination")
173+        self.set_up_grid()
174+        test_file = os.path.join(self.basedir, "input")
175+        f = open(test_file, "wb")
176+        self.write_test_log_to_file(f)
177+        f.close()
178+        test_out = os.path.join(self.basedir, "output")
179+        open(test_out, "wb").close()
180+        # should make test_out readonly on both Windows and *nixes.
181+        os.chmod(test_out, stat.S_IREAD)
182+        d = self.do_cli("censor", test_file, test_out, no_node=True)
183+        def _check((rc, out, err)):
184+            self.failUnlessEqual(rc, 1)
185+            self.failUnlessIn("Error:", err)
186+            self.failUnlessIn("writable", err)
187+        d.addCallback(_check)
188+        # In the case where the source file is also the destination file
189+        # (i.e.: we're censoring in-place), 'tahoe censor' should also
190+        # complain if it can't write to the source file.
191+        def _then(ign):
192+            self.second_test_file = os.path.join(self.basedir, "input2")
193+            f = open(self.second_test_file, "wb")
194+            self.write_test_log_to_file(f)
195+            f.close()
196+            os.chmod(self.second_test_file, stat.S_IREAD)
197+        d.addCallback(_then)
198+        d.addCallback(lambda ign: self.do_cli("censor", self.second_test_file,
199+                                              no_node=True))
200+        d.addCallback(_check)
201+        return d
202+
203+
204+    def test_censor_should_censor_IP_addresses(self):
205+        # 'tahoe censor' should successfully remove IP addresses from
206+        # valid log files.
207+        self.basedir = os.path.join("cli",
208+                                    "Censor",
209+                                    "test_censor_should_censor_IP_addresses")
210+        self.set_up_grid()
211+        test_file = os.path.join(self.basedir, "input")
212+        f = open(test_file, "wb")
213+        ips, furls, sis, total = self.write_test_log_to_file(f)
214+        f.close()
215+        d = self.do_cli("censor", test_file, no_node=True)
216+        def _check((rc, out, err)):
217+            self.failUnlessEqual(rc, 0)
218+            f = open(test_file, "rb")
219+            while True:
220+                try:
221+                    e = pickle.load(f)
222+                    for ip in ips:
223+                        self.failIfIn(ip, e['d']["message"])
224+                except EOFError:
225+                    break
226+            f.close()
227+        d.addCallback(_check)
228+        return d
229+
230+
231+    def test_censor_should_censor_storage_indices(self):
232+        # 'tahoe censor' should successfully remove storage indices
233+        # from valid log files if they are of the form <si>SI</si> or
234+        # <SI>SI</SI>
235+        self.basedir = os.path.join("cli",
236+                                    "Censor",
237+                                    "test_censor_should_censor_storage_indices")
238+        self.set_up_grid()
239+        test_file = os.path.join(self.basedir, "input")
240+        f = open(test_file, "wb")
241+        ips, furls, sis, total = self.write_test_log_to_file(f)
242+        f.close()
243+        d = self.do_cli("censor", test_file, no_node=True)
244+        def _check((rc, out, err)):
245+            self.failUnlessEqual(rc, 0)
246+            f = open(test_file, "rb")
247+            while True:
248+                try:
249+                    e = pickle.load(f)
250+                    for si in sis:
251+                        self.failIfIn(si, e['d']["message"])
252+                except EOFError:
253+                    break
254+            f.close()
255+        d.addCallback(_check)
256+        return d
257+
258+
259+    def test_censor_should_censor_furls(self):
260+        # 'tahoe censor' should successfully remove furls from valid log
261+        # files.
262+        self.basedir = os.path.join("cli",
263+                                    "Censor",
264+                                    "test_censor_should_censor_furls")
265+        self.set_up_grid()
266+        test_file = os.path.join(self.basedir, "input")
267+        f = open(test_file, "wb")
268+        ips, furls, sis, total = self.write_test_log_to_file(f)
269+        f.close()
270+        d = self.do_cli("censor", test_file, no_node=True)
271+        def _check((rc, out, err)):
272+            self.failUnlessEqual(rc, 0)
273+            f = open(test_file, "rb")
274+            while True:
275+                try:
276+                    e = pickle.load(f)
277+                    for furl in furls:
278+                        self.failIfIn(furl, e['d']["message"])
279+                except EOFError:
280+                    break
281+            f.close()
282+        d.addCallback(_check)
283+        return d
284+
285+
286+    def test_censor_verbose_mode(self):
287+        # When run in verbose mode (with the -v or --verbose flags),
288+        # 'tahoe censor' should output messages telling the user what it
289+        # is doing.
290+        self.basedir = os.path.join("cli",
291+                                    "Censor",
292+                                    "test_censor_verbose_mode")
293+        self.set_up_grid()
294+        test_file = os.path.join(self.basedir, "input")
295+        f = open(test_file, "wb")
296+        ips, furls, sis, total = self.write_test_log_to_file(f)
297+        f.close()
298+        d = self.do_cli("censor", "-v", test_file, no_node=True)
299+        def _check((rc, out, err)):
300+            self.failUnlessEqual(rc, 0)
301+            for item in ips + furls + sis:
302+                self.failUnlessIn(item, out)
303+        d.addCallback(_check)
304+        return d
305+
306+
307+    def test_censor_quiet_mode(self):
308+        # When run in quiet mode (with the -q or --quiet flags), 'tahoe
309+        # censor' should not output anything other than error messages.
310+        self.basedir = os.path.join("cli",
311+                                    "Censor",
312+                                    "test_censor_quiet_mode")
313+        self.set_up_grid()
314+        test_file = os.path.join(self.basedir, "input")
315+        f = open(test_file, "wb")
316+        self.write_test_log_to_file(f)
317+        f.close()
318+        d = self.do_cli("censor", "-q", test_file, no_node=True)
319+        def _check((rc, out, err)):
320+            self.failUnlessEqual(rc, 0)
321+            self.failUnlessEqual(out, "")
322+        d.addCallback(_check)
323+        def _then(ign):
324+            self.second_test_file = os.path.join(self.basedir, "input2")
325+            f = open(self.second_test_file, "wb")
326+            self.write_test_log_to_file(f)
327+            f.close()
328+            os.chmod(self.second_test_file, stat.S_IREAD)
329+        d.addCallback(_then)
330+        d.addCallback(lambda ign: self.do_cli("censor",
331+                                              "-q",
332+                                              self.second_test_file,
333+                                              no_node=True))
334+        def _check2((rc, out, err)):
335+            self.failUnlessEqual(rc, 1)
336+            self.failUnlessEqual(out, "")
337+            self.failUnlessIn("Error:", err)
338+            self.failUnlessIn("write", err)
339+        d.addCallback(_check2)
340+        return d
341+
342+
343+    def test_censor_bz2(self):
344+        # 'tahoe censor' should be capable of censoring both
345+        # uncompressed log files and bzipped log files.
346+        self.basedir = os.path.join("cli",
347+                                    "Censor",
348+                                    "test_censor_bz2")
349+        self.set_up_grid()
350+        test_file = os.path.join(self.basedir, "input.bz2")
351+        f = bz2.BZ2File(test_file, "wb")
352+        ips, furls, sis, total = self.write_test_log_to_file(f)
353+        self.items = ips + furls + sis
354+        f.close()
355+        # First, check to see that we can read from a bz2 file and
356+        # write to a bz2 file.
357+        d = self.do_cli("censor", test_file, no_node=True)
358+        def _check((rc, out, err)):
359+            self.failUnlessEqual(rc, 0)
360+            f = bz2.BZ2File(test_file, "rb")
361+            while True:
362+                try:
363+                    e = pickle.load(f)
364+                    for item in self.items:
365+                        self.failIfIn(item, e['d']["message"])
366+                except EOFError:
367+                    break
368+            f.close()
369+        d.addCallback(_check)
370+        # Now, check to see that we can write to a bz2 logfile
371+        # from a plain logfile
372+        def _then(ign):
373+            self.second_source = os.path.join(self.basedir, "input2")
374+            self.second_dest = os.path.join(self.basedir, "output2.bz2")
375+            f = open(self.second_source, "wb")
376+            self.write_test_log_to_file(f)
377+            f.close()
378+        d.addCallback(_then)
379+        d.addCallback(lambda ign: self.do_cli("censor",
380+                                              self.second_source,
381+                                              self.second_dest,
382+                                              no_node=True))
383+        def _check2((rc, out, err)):
384+            self.failUnlessEqual(rc, 0)
385+            f = bz2.BZ2File(self.second_dest, "rb")
386+            while True:
387+                try:
388+                    e = pickle.load(f)
389+                    for item in self.items:
390+                        self.failIfIn(item, e['d']["message"])
391+                except EOFError:
392+                    break
393+            f.close()
394+        d.addCallback(_check2)
395+        # Finally, check to see that we can write from a bz2 logfile
396+        # to a plain logfile.
397+        def _later(ign):
398+            self.third_source = os.path.join(self.basedir, "input3.bz2")
399+            self.third_dest = os.path.join(self.basedir, "output3")
400+            f = bz2.BZ2File(self.third_source, "wb")
401+            self.write_test_log_to_file(f)
402+            f.close()
403+        d.addCallback(_later)
404+        d.addCallback(lambda ign: self.do_cli("censor",
405+                                              self.third_source,
406+                                              self.third_dest,
407+                                              no_node=True))
408+        def _check3((rc, out, err)):
409+            self.failUnlessEqual(rc, 0)
410+            f = open(self.third_dest, "rb")
411+            while True:
412+                try:
413+                    e = pickle.load(f)
414+                    for item in self.items:
415+                        self.failIfIn(item, e['d']["message"])
416+                except EOFError:
417+                    break
418+            f.close()
419+        d.addCallback(_check3)
420+        return d
421+
422+
423+    def test_censor_log_counting(self):
424+        # When not run in quiet mode, 'tahoe censor' should output a
425+        # useful concluding message, including:
426+        #  - The total number of logs processed
427+        #  - The total number of SIs censored
428+        #  - The total number of IP addresses censored.
429+        #  - The total number of furls censored.
430+        self.basedir = os.path.join("cli",
431+                                    "Censor",
432+                                    "test_censor_log_counting")
433+        self.set_up_grid()
434+        test_file = os.path.join(self.basedir, "input")
435+        f = open(test_file, "wb")
436+        ips, furls, sis, total = self.write_test_log_to_file(f)
437+        f.close()
438+        d = self.do_cli("censor", test_file, no_node=True)
439+        def _check((rc, out, err)):
440+            self.failUnlessEqual(rc, 0)
441+            self.failUnlessIn("total of %d" % total, out)
442+            self.failUnlessIn("Storage Indices: %d" % len(sis), out)
443+            self.failUnlessIn("IP Addresses: %d" % len(ips), out)
444+            self.failUnlessIn("Node URLs: %d" % len(furls), out)
445+        d.addCallback(_check)
446+        return d
447}
448[Make it so that CLI tests work without actually making a node directory
449kevan@isnotajoke.com**20100425201150
450 Ignore-this: ca5467176c9ce15b17dfa27cf6b2885d
451 
452 It is not necessary to have a node directory for 'tahoe censor', because
453 its operations are all local -- it processes a log file. So I made its
454 CensorOptions class subclass something other than VDriveOptions. The
455 result of that is that CensorOptions doesn't know how to process a
456 node-directory parameter, which this code would send. So, now it looks
457 for a 'no_node' kwarg; if this is present and set to True, the
458 node-directory option is not sent, and everything works.
459] hunk ./src/allmydata/test/test_cli.py 460
460 
461 class CLITestMixin:
462     def do_cli(self, verb, *args, **kwargs):
463-        nodeargs = [
464-            "--node-directory", self.get_clientdir(),
465-            ]
466+        if "no_node" not in kwargs:
467+            nodeargs = [
468+                "--node-directory", self.get_clientdir(),
469+                ]
470+        else:
471+            del(kwargs['no_node'])
472+            nodeargs = []
473         argv = [verb] + nodeargs + list(args)
474         stdin = kwargs.get("stdin", "")
475         stdout, stderr = StringIO(), StringIO()
476
477Context:
478
479[setup: add licensing declaration for setuptools (noticed by the FSF compliance folks)
480zooko@zooko.com**20100309184415
481 Ignore-this: 2dfa7d812d65fec7c72ddbf0de609ccb
482]
483[setup: fix error in licensing declaration from Shawn Willden, as noted by the FSF compliance division
484zooko@zooko.com**20100309163736
485 Ignore-this: c0623d27e469799d86cabf67921a13f8
486]
487[CREDITS to Jacob Appelbaum
488zooko@zooko.com**20100304015616
489 Ignore-this: 70db493abbc23968fcc8db93f386ea54
490]
491[desert-island-build-with-proper-versions
492jacob@appelbaum.net**20100304013858]
493[docs: a few small edits to try to guide newcomers through the docs
494zooko@zooko.com**20100303231902
495 Ignore-this: a6aab44f5bf5ad97ea73e6976bc4042d
496 These edits were suggested by my watching over Jake Appelbaum's shoulder as he completely ignored/skipped/missed install.html and also as he decided that debian.txt wouldn't help him with basic installation. Then I threw in a few docs edits that have been sitting around in my sandbox asking to be committed for months.
497]
498[TAG allmydata-tahoe-1.6.1
499david-sarah@jacaranda.org**20100228062314
500 Ignore-this: eb5f03ada8ea953ee7780e7fe068539
501]
502Patch bundle hash:
5037e2f8933bb23af7dc504dab74325f01cfbbea2ec