]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/test/test_helper.py
b45811a8331ad4be77be0bd61142bd142cd7e912
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / test / test_helper.py
1
2 import os
3 from twisted.trial import unittest
4 from twisted.application import service
5
6 from foolscap import Tub, eventual
7 from foolscap.logging import log
8
9 from allmydata import upload, offloaded
10 from allmydata.util import hashutil, fileutil, idlib
11 from pycryptopp.cipher.aes import AES
12
13 MiB = 1024*1024
14
15 DATA = "I need help\n" * 1000
16
17 class CHKUploadHelper_fake(offloaded.CHKUploadHelper):
18     def start_encrypted(self, eu):
19         d = eu.get_size()
20         def _got_size(size):
21             d2 = eu.get_all_encoding_parameters()
22             def _got_parms(parms):
23                 needed_shares, happy, total_shares, segsize = parms
24                 ueb_data = {"needed_shares": needed_shares,
25                             "total_shares": total_shares,
26                             "segment_size": segsize,
27                             "size": size,
28                             }
29                 self._results.uri_extension_data = ueb_data
30                 return (hashutil.uri_extension_hash(""),
31                         needed_shares, total_shares, size)
32             d2.addCallback(_got_parms)
33             return d2
34         d.addCallback(_got_size)
35         return d
36
37 class CHKUploadHelper_already_uploaded(offloaded.CHKUploadHelper):
38     def start(self):
39         res = upload.UploadResults()
40         res.uri_extension_hash = hashutil.uri_extension_hash("")
41
42         # we're pretending that the file they're trying to upload was already
43         # present in the grid. We return some information about the file, so
44         # the client can decide if they like the way it looks. The parameters
45         # used here are chosen to match the defaults.
46         PARAMS = FakeClient.DEFAULT_ENCODING_PARAMETERS
47         ueb_data = {"needed_shares": PARAMS["k"],
48                     "total_shares": PARAMS["n"],
49                     "segment_size": min(PARAMS["max_segment_size"], len(DATA)),
50                     "size": len(DATA),
51                     }
52         res.uri_extension_data = ueb_data
53         return (res, None)
54
55 class FakeClient(service.MultiService):
56     DEFAULT_ENCODING_PARAMETERS = {"k":25,
57                                    "happy": 75,
58                                    "n": 100,
59                                    "max_segment_size": 1*MiB,
60                                    }
61     def log(self, *args, **kwargs):
62         return log.msg(*args, **kwargs)
63     def get_encoding_parameters(self):
64         return self.DEFAULT_ENCODING_PARAMETERS
65     def get_permuted_peers(self, service_name, storage_index):
66         return []
67
68 def flush_but_dont_ignore(res):
69     d = eventual.flushEventualQueue()
70     def _done(ignored):
71         return res
72     d.addCallback(_done)
73     return d
74
75 def upload_data(uploader, data):
76     u = upload.Data(data)
77     return uploader.upload(u)
78
79 class AssistedUpload(unittest.TestCase):
80     def setUp(self):
81         self.s = FakeClient()
82         self.s.startService()
83
84         self.tub = t = Tub()
85         t.setServiceParent(self.s)
86         self.s.tub = t
87         # we never actually use this for network traffic, so it can use a
88         # bogus host/port
89         t.setLocation("bogus:1234")
90
91     def setUpHelper(self, basedir):
92         fileutil.make_dirs(basedir)
93         self.helper = h = offloaded.Helper(basedir)
94         h.chk_upload_helper_class = CHKUploadHelper_fake
95         h.setServiceParent(self.s)
96         self.helper_furl = self.tub.registerReference(h)
97
98     def tearDown(self):
99         d = self.s.stopService()
100         d.addCallback(eventual.fireEventually)
101         d.addBoth(flush_but_dont_ignore)
102         return d
103
104
105     def test_one(self):
106         self.basedir = "helper/AssistedUpload/test_one"
107         self.setUpHelper(self.basedir)
108         u = upload.Uploader(self.helper_furl)
109         u.setServiceParent(self.s)
110
111         # wait a few turns
112         d = eventual.fireEventually()
113         d.addCallback(eventual.fireEventually)
114         d.addCallback(eventual.fireEventually)
115
116         def _ready(res):
117             assert u._helper
118
119             return upload_data(u, DATA)
120         d.addCallback(_ready)
121         def _uploaded(results):
122             uri = results.uri
123             assert "CHK" in uri
124         d.addCallback(_uploaded)
125
126         def _check_empty(res):
127             files = os.listdir(os.path.join(self.basedir, "CHK_encoding"))
128             self.failUnlessEqual(files, [])
129             files = os.listdir(os.path.join(self.basedir, "CHK_incoming"))
130             self.failUnlessEqual(files, [])
131         d.addCallback(_check_empty)
132
133         return d
134
135     def test_previous_upload_failed(self):
136         self.basedir = "helper/AssistedUpload/test_previous_upload_failed"
137         self.setUpHelper(self.basedir)
138
139         # we want to make sure that an upload which fails (leaving the
140         # ciphertext in the CHK_encoding/ directory) does not prevent a later
141         # attempt to upload that file from working. We simulate this by
142         # populating the directory manually.
143         key = hashutil.key_hash(DATA)[:16]
144         encryptor = AES(key)
145         SI = hashutil.storage_index_hash(key)
146         SI_s = idlib.b2a(SI)
147         encfile = os.path.join(self.basedir, "CHK_encoding", SI_s)
148         f = open(encfile, "wb")
149         f.write(encryptor.process(DATA))
150         f.close()
151
152         u = upload.Uploader(self.helper_furl)
153         u.setServiceParent(self.s)
154
155         # wait a few turns
156         d = eventual.fireEventually()
157         d.addCallback(eventual.fireEventually)
158         d.addCallback(eventual.fireEventually)
159
160         def _ready(res):
161             assert u._helper
162             return upload_data(u, DATA)
163         d.addCallback(_ready)
164         def _uploaded(results):
165             uri = results.uri
166             assert "CHK" in uri
167         d.addCallback(_uploaded)
168
169         def _check_empty(res):
170             files = os.listdir(os.path.join(self.basedir, "CHK_encoding"))
171             self.failUnlessEqual(files, [])
172             files = os.listdir(os.path.join(self.basedir, "CHK_incoming"))
173             self.failUnlessEqual(files, [])
174         d.addCallback(_check_empty)
175
176         return d
177
178     def test_already_uploaded(self):
179         self.basedir = "helper/AssistedUpload/test_already_uploaded"
180         self.setUpHelper(self.basedir)
181         self.helper.chk_upload_helper_class = CHKUploadHelper_already_uploaded
182         u = upload.Uploader(self.helper_furl)
183         u.setServiceParent(self.s)
184
185         # wait a few turns
186         d = eventual.fireEventually()
187         d.addCallback(eventual.fireEventually)
188         d.addCallback(eventual.fireEventually)
189
190         def _ready(res):
191             assert u._helper
192
193             return upload_data(u, DATA)
194         d.addCallback(_ready)
195         def _uploaded(results):
196             uri = results.uri
197             assert "CHK" in uri
198         d.addCallback(_uploaded)
199
200         def _check_empty(res):
201             files = os.listdir(os.path.join(self.basedir, "CHK_encoding"))
202             self.failUnlessEqual(files, [])
203             files = os.listdir(os.path.join(self.basedir, "CHK_incoming"))
204             self.failUnlessEqual(files, [])
205         d.addCallback(_check_empty)
206
207         return d