]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/test/test_immutable.py
hush pyflakes by removing unused imports
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / test / test_immutable.py
1 from allmydata.test import common
2 from allmydata.interfaces import NotEnoughSharesError
3 from twisted.internet import defer
4 from twisted.trial import unittest
5 import random
6
7 class Test(common.ShareManglingMixin, unittest.TestCase):
8     def test_test_code(self):
9         # The following process of stashing the shares, running
10         # replace_shares, and asserting that the new set of shares equals the
11         # old is more to test this test code than to test the Tahoe code...
12         d = defer.succeed(None)
13         d.addCallback(self.find_shares)
14         stash = [None]
15         def _stash_it(res):
16             stash[0] = res
17             return res
18         d.addCallback(_stash_it)
19
20         # The following process of deleting 8 of the shares and asserting that you can't
21         # download it is more to test this test code than to test the Tahoe code...
22         def _then_delete_8(unused=None):
23             self.replace_shares(stash[0], storage_index=self.uri.storage_index)
24             for i in range(8):
25                 self._delete_a_share()
26         d.addCallback(_then_delete_8)
27
28         def _then_download(unused=None):
29             self.downloader = self.clients[1].getServiceNamed("downloader")
30             d2 = self.downloader.download_to_data(self.uri)
31
32             def _after_download_callb(result):
33                 self.fail() # should have gotten an errback instead
34                 return result
35             def _after_download_errb(failure):
36                 failure.trap(NotEnoughSharesError)
37                 return None # success!
38             d2.addCallbacks(_after_download_callb, _after_download_errb)
39             return d2
40         d.addCallback(_then_download)
41
42         return d
43
44     def test_download(self):
45         """ Basic download.  (This functionality is more or less already tested by test code in
46         other modules, but this module is also going to test some more specific things about
47         immutable download.)
48         """
49         d = defer.succeed(None)
50         before_download_reads = self._count_reads()
51         def _after_download(unused=None):
52             after_download_reads = self._count_reads()
53             self.failIf(after_download_reads-before_download_reads > 27, (after_download_reads, before_download_reads))
54         d.addCallback(self._download_and_check_plaintext)
55         d.addCallback(_after_download)
56         return d
57
58     def test_download_from_only_3_remaining_shares(self):
59         """ Test download after 7 random shares (of the 10) have been removed. """
60         d = defer.succeed(None)
61         def _then_delete_7(unused=None):
62             for i in range(7):
63                 self._delete_a_share()
64         before_download_reads = self._count_reads()
65         d.addCallback(_then_delete_7)
66         def _after_download(unused=None):
67             after_download_reads = self._count_reads()
68             self.failIf(after_download_reads-before_download_reads > 27, (after_download_reads, before_download_reads))
69         d.addCallback(self._download_and_check_plaintext)
70         d.addCallback(_after_download)
71         return d
72
73     def test_download_from_only_3_shares_with_good_crypttext_hash(self):
74         """ Test download after 7 random shares (of the 10) have had their crypttext hash tree corrupted. """
75         d = defer.succeed(None)
76         def _then_corrupt_7(unused=None):
77             shnums = range(10)
78             random.shuffle(shnums)
79             for i in shnums[:7]:
80                 self._corrupt_a_share(None, common._corrupt_offset_of_block_hashes_to_truncate_crypttext_hashes, i)
81         before_download_reads = self._count_reads()
82         d.addCallback(_then_corrupt_7)
83         d.addCallback(self._download_and_check_plaintext)
84         return d
85
86     def test_download_abort_if_too_many_missing_shares(self):
87         """ Test that download gives up quickly when it realizes there aren't enough shares out
88         there."""
89         d = defer.succeed(None)
90         def _then_delete_8(unused=None):
91             for i in range(8):
92                 self._delete_a_share()
93         d.addCallback(_then_delete_8)
94
95         before_download_reads = self._count_reads()
96         def _attempt_to_download(unused=None):
97             downloader = self.clients[1].getServiceNamed("downloader")
98             d2 = downloader.download_to_data(self.uri)
99
100             def _callb(res):
101                 self.fail("Should have gotten an error from attempt to download, not %r" % (res,))
102             def _errb(f):
103                 self.failUnless(f.check(NotEnoughSharesError))
104             d2.addCallbacks(_callb, _errb)
105             return d2
106
107         d.addCallback(_attempt_to_download)
108
109         def _after_attempt(unused=None):
110             after_download_reads = self._count_reads()
111             # To pass this test, you are required to give up before actually trying to read any
112             # share data.
113             self.failIf(after_download_reads-before_download_reads > 0, (after_download_reads, before_download_reads))
114         d.addCallback(_after_attempt)
115         return d
116
117     def test_download_abort_if_too_many_corrupted_shares(self):
118         """ Test that download gives up quickly when it realizes there aren't enough uncorrupted
119         shares out there. It should be able to tell because the corruption occurs in the
120         sharedata version number, which it checks first."""
121         d = defer.succeed(None)
122         def _then_corrupt_8(unused=None):
123             shnums = range(10)
124             random.shuffle(shnums)
125             for shnum in shnums[:8]:
126                 self._corrupt_a_share(None, common._corrupt_sharedata_version_number, shnum)
127         d.addCallback(_then_corrupt_8)
128
129         before_download_reads = self._count_reads()
130         def _attempt_to_download(unused=None):
131             downloader = self.clients[1].getServiceNamed("downloader")
132             d2 = downloader.download_to_data(self.uri)
133
134             def _callb(res):
135                 self.fail("Should have gotten an error from attempt to download, not %r" % (res,))
136             def _errb(f):
137                 self.failUnless(f.check(NotEnoughSharesError))
138             d2.addCallbacks(_callb, _errb)
139             return d2
140
141         d.addCallback(_attempt_to_download)
142
143         def _after_attempt(unused=None):
144             after_download_reads = self._count_reads()
145             # To pass this test, you are required to give up before reading all of the share
146             # data.  Actually, we could give up sooner than 45 reads, but currently our download
147             # code does 45 reads.  This test then serves as a "performance regression detector"
148             # -- if you change download code so that it takes *more* reads, then this test will
149             # fail.
150             self.failIf(after_download_reads-before_download_reads > 45, (after_download_reads, before_download_reads))
151         d.addCallback(_after_attempt)
152         return d
153
154
155 # XXX extend these tests to show bad behavior of various kinds from servers: raising exception from each remove_foo() method, for example
156
157 # XXX test disconnect DeadReferenceError from get_buckets and get_block_whatsit
158