2 from twisted.internet import defer
3 from twisted.trial import unittest
4 from twisted.application import service
6 from foolscap.api import Tub, fireEventually, flushEventualQueue
8 from allmydata.storage.server import si_b2a
9 from allmydata.storage_client import StorageFarmBroker
10 from allmydata.immutable import offloaded, upload
11 from allmydata import uri, client
12 from allmydata.util import hashutil, fileutil, mathutil
13 from pycryptopp.cipher.aes import AES
17 DATA = "I need help\n" * 1000
19 class CHKUploadHelper_fake(offloaded.CHKUploadHelper):
20 def start_encrypted(self, eu):
23 d2 = eu.get_all_encoding_parameters()
24 def _got_parms(parms):
25 # just pretend we did the upload
26 needed_shares, happy, total_shares, segsize = parms
27 ueb_data = {"needed_shares": needed_shares,
28 "total_shares": total_shares,
29 "segment_size": segsize,
33 v = uri.CHKFileVerifierURI(self._storage_index, "x"*32,
34 needed_shares, total_shares, size)
35 _UR = upload.UploadResults
36 ur = _UR(file_size=size,
39 pushed_shares=total_shares,
43 uri_extension_data=ueb_data,
44 uri_extension_hash=ueb_hash,
45 verifycapstr=v.to_string())
46 self._upload_status.set_results(ur)
48 d2.addCallback(_got_parms)
50 d.addCallback(_got_size)
53 class Helper_fake_upload(offloaded.Helper):
54 def _make_chk_upload_helper(self, storage_index, lp):
55 si_s = si_b2a(storage_index)
56 incoming_file = os.path.join(self._chk_incoming, si_s)
57 encoding_file = os.path.join(self._chk_encoding, si_s)
58 uh = CHKUploadHelper_fake(storage_index, self,
61 incoming_file, encoding_file,
65 class Helper_already_uploaded(Helper_fake_upload):
66 def _check_chk(self, storage_index, lp):
67 res = upload.HelperUploadResults()
68 res.uri_extension_hash = hashutil.uri_extension_hash("")
70 # we're pretending that the file they're trying to upload was already
71 # present in the grid. We return some information about the file, so
72 # the client can decide if they like the way it looks. The parameters
73 # used here are chosen to match the defaults.
74 PARAMS = FakeClient.DEFAULT_ENCODING_PARAMETERS
75 ueb_data = {"needed_shares": PARAMS["k"],
76 "total_shares": PARAMS["n"],
77 "segment_size": min(PARAMS["max_segment_size"], len(DATA)),
80 res.uri_extension_data = ueb_data
81 return defer.succeed(res)
83 class FakeClient(service.MultiService):
84 DEFAULT_ENCODING_PARAMETERS = {"k":25,
87 "max_segment_size": 1*MiB,
90 def get_encoding_parameters(self):
91 return self.DEFAULT_ENCODING_PARAMETERS
92 def get_storage_broker(self):
93 return self.storage_broker
95 def flush_but_dont_ignore(res):
96 d = flushEventualQueue()
102 def wait_a_few_turns(ignored=None):
104 d.addCallback(fireEventually)
105 d.addCallback(fireEventually)
106 d.addCallback(fireEventually)
107 d.addCallback(fireEventually)
108 d.addCallback(fireEventually)
111 def upload_data(uploader, data, convergence):
112 u = upload.Data(data, convergence=convergence)
113 return uploader.upload(u)
115 class AssistedUpload(unittest.TestCase):
116 timeout = 240 # It takes longer than 120 seconds on Francois's arm box.
118 self.s = FakeClient()
119 self.s.storage_broker = StorageFarmBroker(None, True, 0, None)
120 self.s.secret_holder = client.SecretHolder("lease secret", "converge")
121 self.s.startService()
124 t.setOption("expose-remote-exception-types", False)
125 t.setServiceParent(self.s)
127 # we never actually use this for network traffic, so it can use a
129 t.setLocation("bogus:1234")
131 def setUpHelper(self, basedir, helper_class=Helper_fake_upload):
132 fileutil.make_dirs(basedir)
133 self.helper = h = helper_class(basedir,
134 self.s.storage_broker,
135 self.s.secret_holder,
137 self.helper_furl = self.tub.registerReference(h)
140 d = self.s.stopService()
141 d.addCallback(fireEventually)
142 d.addBoth(flush_but_dont_ignore)
147 self.basedir = "helper/AssistedUpload/test_one"
148 self.setUpHelper(self.basedir)
149 u = upload.Uploader(self.helper_furl)
150 u.setServiceParent(self.s)
152 d = wait_a_few_turns()
157 return upload_data(u, DATA, convergence="some convergence string")
158 d.addCallback(_ready)
159 def _uploaded(results):
160 the_uri = results.get_uri()
161 assert "CHK" in the_uri
162 d.addCallback(_uploaded)
164 def _check_empty(res):
165 files = os.listdir(os.path.join(self.basedir, "CHK_encoding"))
166 self.failUnlessEqual(files, [])
167 files = os.listdir(os.path.join(self.basedir, "CHK_incoming"))
168 self.failUnlessEqual(files, [])
169 d.addCallback(_check_empty)
173 def test_previous_upload_failed(self):
174 self.basedir = "helper/AssistedUpload/test_previous_upload_failed"
175 self.setUpHelper(self.basedir)
177 # we want to make sure that an upload which fails (leaving the
178 # ciphertext in the CHK_encoding/ directory) does not prevent a later
179 # attempt to upload that file from working. We simulate this by
180 # populating the directory manually. The hardest part is guessing the
183 k = FakeClient.DEFAULT_ENCODING_PARAMETERS["k"]
184 n = FakeClient.DEFAULT_ENCODING_PARAMETERS["n"]
185 max_segsize = FakeClient.DEFAULT_ENCODING_PARAMETERS["max_segment_size"]
186 segsize = min(max_segsize, len(DATA))
187 # this must be a multiple of 'required_shares'==k
188 segsize = mathutil.next_multiple(segsize, k)
190 key = hashutil.convergence_hash(k, n, segsize, DATA, "test convergence string")
191 assert len(key) == 16
193 SI = hashutil.storage_index_hash(key)
195 encfile = os.path.join(self.basedir, "CHK_encoding", SI_s)
196 f = open(encfile, "wb")
197 f.write(encryptor.process(DATA))
200 u = upload.Uploader(self.helper_furl)
201 u.setServiceParent(self.s)
203 d = wait_a_few_turns()
207 return upload_data(u, DATA, convergence="test convergence string")
208 d.addCallback(_ready)
209 def _uploaded(results):
210 the_uri = results.get_uri()
211 assert "CHK" in the_uri
212 d.addCallback(_uploaded)
214 def _check_empty(res):
215 files = os.listdir(os.path.join(self.basedir, "CHK_encoding"))
216 self.failUnlessEqual(files, [])
217 files = os.listdir(os.path.join(self.basedir, "CHK_incoming"))
218 self.failUnlessEqual(files, [])
219 d.addCallback(_check_empty)
223 def test_already_uploaded(self):
224 self.basedir = "helper/AssistedUpload/test_already_uploaded"
225 self.setUpHelper(self.basedir, helper_class=Helper_already_uploaded)
226 u = upload.Uploader(self.helper_furl)
227 u.setServiceParent(self.s)
229 d = wait_a_few_turns()
234 return upload_data(u, DATA, convergence="some convergence string")
235 d.addCallback(_ready)
236 def _uploaded(results):
237 the_uri = results.get_uri()
238 assert "CHK" in the_uri
239 d.addCallback(_uploaded)
241 def _check_empty(res):
242 files = os.listdir(os.path.join(self.basedir, "CHK_encoding"))
243 self.failUnlessEqual(files, [])
244 files = os.listdir(os.path.join(self.basedir, "CHK_incoming"))
245 self.failUnlessEqual(files, [])
246 d.addCallback(_check_empty)