2 def foo(): pass # keep the line number constant
5 from StringIO import StringIO
6 from twisted.trial import unittest
7 from twisted.internet import defer, reactor
8 from twisted.python.failure import Failure
9 from twisted.python import log
11 from allmydata.util import base32, idlib, humanreadable, mathutil, hashutil
12 from allmydata.util import assertutil, fileutil, deferredutil, abbreviate
13 from allmydata.util import limiter, time_format, pollmixin, cachedir
14 from allmydata.util import statistics, dictutil, pipeline
15 from allmydata.util import log as tahoe_log
17 class Base32(unittest.TestCase):
18 def test_b2a_matches_Pythons(self):
20 y = "\x12\x34\x45\x67\x89\x0a\xbc\xde\xf0"
21 x = base64.b32encode(y)
22 while x and x[-1] == '=':
25 self.failUnlessEqual(base32.b2a(y), x)
27 self.failUnlessEqual(base32.b2a("\x12\x34"), "ci2a")
28 def test_b2a_or_none(self):
29 self.failUnlessEqual(base32.b2a_or_none(None), None)
30 self.failUnlessEqual(base32.b2a_or_none("\x12\x34"), "ci2a")
32 self.failUnlessEqual(base32.a2b("ci2a"), "\x12\x34")
33 self.failUnlessRaises(AssertionError, base32.a2b, "b0gus")
35 class IDLib(unittest.TestCase):
36 def test_nodeid_b2a(self):
37 self.failUnlessEqual(idlib.nodeid_b2a("\x00"*20), "a"*32)
39 class NoArgumentException(Exception):
43 class HumanReadable(unittest.TestCase):
46 self.failUnlessEqual(hr(foo), "<foo() at test_util.py:2>")
47 self.failUnlessEqual(hr(self.test_repr),
48 "<bound method HumanReadable.test_repr of <allmydata.test.test_util.HumanReadable testMethod=test_repr>>")
49 self.failUnlessEqual(hr(1L), "1")
50 self.failUnlessEqual(hr(10**40),
51 "100000000000000000...000000000000000000")
52 self.failUnlessEqual(hr(self), "<allmydata.test.test_util.HumanReadable testMethod=test_repr>")
53 self.failUnlessEqual(hr([1,2]), "[1, 2]")
54 self.failUnlessEqual(hr({1:2}), "{1:2}")
59 hr(e) == "<ValueError: ()>" # python-2.4
60 or hr(e) == "ValueError()") # python-2.5
62 raise ValueError("oops")
65 hr(e) == "<ValueError: 'oops'>" # python-2.4
66 or hr(e) == "ValueError('oops',)") # python-2.5
68 raise NoArgumentException
71 hr(e) == "<NoArgumentException>" # python-2.4
72 or hr(e) == "NoArgumentException()") # python-2.5
78 class Math(unittest.TestCase):
79 def test_div_ceil(self):
81 self.failUnlessEqual(f(0, 1), 0)
82 self.failUnlessEqual(f(0, 2), 0)
83 self.failUnlessEqual(f(0, 3), 0)
84 self.failUnlessEqual(f(1, 3), 1)
85 self.failUnlessEqual(f(2, 3), 1)
86 self.failUnlessEqual(f(3, 3), 1)
87 self.failUnlessEqual(f(4, 3), 2)
88 self.failUnlessEqual(f(5, 3), 2)
89 self.failUnlessEqual(f(6, 3), 2)
90 self.failUnlessEqual(f(7, 3), 3)
92 def test_next_multiple(self):
93 f = mathutil.next_multiple
94 self.failUnlessEqual(f(5, 1), 5)
95 self.failUnlessEqual(f(5, 2), 6)
96 self.failUnlessEqual(f(5, 3), 6)
97 self.failUnlessEqual(f(5, 4), 8)
98 self.failUnlessEqual(f(5, 5), 5)
99 self.failUnlessEqual(f(5, 6), 6)
100 self.failUnlessEqual(f(32, 1), 32)
101 self.failUnlessEqual(f(32, 2), 32)
102 self.failUnlessEqual(f(32, 3), 33)
103 self.failUnlessEqual(f(32, 4), 32)
104 self.failUnlessEqual(f(32, 5), 35)
105 self.failUnlessEqual(f(32, 6), 36)
106 self.failUnlessEqual(f(32, 7), 35)
107 self.failUnlessEqual(f(32, 8), 32)
108 self.failUnlessEqual(f(32, 9), 36)
109 self.failUnlessEqual(f(32, 10), 40)
110 self.failUnlessEqual(f(32, 11), 33)
111 self.failUnlessEqual(f(32, 12), 36)
112 self.failUnlessEqual(f(32, 13), 39)
113 self.failUnlessEqual(f(32, 14), 42)
114 self.failUnlessEqual(f(32, 15), 45)
115 self.failUnlessEqual(f(32, 16), 32)
116 self.failUnlessEqual(f(32, 17), 34)
117 self.failUnlessEqual(f(32, 18), 36)
118 self.failUnlessEqual(f(32, 589), 589)
120 def test_pad_size(self):
121 f = mathutil.pad_size
122 self.failUnlessEqual(f(0, 4), 0)
123 self.failUnlessEqual(f(1, 4), 3)
124 self.failUnlessEqual(f(2, 4), 2)
125 self.failUnlessEqual(f(3, 4), 1)
126 self.failUnlessEqual(f(4, 4), 0)
127 self.failUnlessEqual(f(5, 4), 3)
129 def test_is_power_of_k(self):
130 f = mathutil.is_power_of_k
131 for i in range(1, 100):
132 if i in (1, 2, 4, 8, 16, 32, 64):
133 self.failUnless(f(i, 2), "but %d *is* a power of 2" % i)
135 self.failIf(f(i, 2), "but %d is *not* a power of 2" % i)
136 for i in range(1, 100):
137 if i in (1, 3, 9, 27, 81):
138 self.failUnless(f(i, 3), "but %d *is* a power of 3" % i)
140 self.failIf(f(i, 3), "but %d is *not* a power of 3" % i)
142 def test_next_power_of_k(self):
143 f = mathutil.next_power_of_k
144 self.failUnlessEqual(f(0,2), 1)
145 self.failUnlessEqual(f(1,2), 1)
146 self.failUnlessEqual(f(2,2), 2)
147 self.failUnlessEqual(f(3,2), 4)
148 self.failUnlessEqual(f(4,2), 4)
149 for i in range(5, 8): self.failUnlessEqual(f(i,2), 8, "%d" % i)
150 for i in range(9, 16): self.failUnlessEqual(f(i,2), 16, "%d" % i)
151 for i in range(17, 32): self.failUnlessEqual(f(i,2), 32, "%d" % i)
152 for i in range(33, 64): self.failUnlessEqual(f(i,2), 64, "%d" % i)
153 for i in range(65, 100): self.failUnlessEqual(f(i,2), 128, "%d" % i)
155 self.failUnlessEqual(f(0,3), 1)
156 self.failUnlessEqual(f(1,3), 1)
157 self.failUnlessEqual(f(2,3), 3)
158 self.failUnlessEqual(f(3,3), 3)
159 for i in range(4, 9): self.failUnlessEqual(f(i,3), 9, "%d" % i)
160 for i in range(10, 27): self.failUnlessEqual(f(i,3), 27, "%d" % i)
161 for i in range(28, 81): self.failUnlessEqual(f(i,3), 81, "%d" % i)
162 for i in range(82, 200): self.failUnlessEqual(f(i,3), 243, "%d" % i)
166 self.failUnlessEqual(f([1,2,3]), 2)
167 self.failUnlessEqual(f([0,0,0,4]), 1)
168 self.failUnlessAlmostEqual(f([0.0, 1.0, 1.0]), .666666666666)
170 def test_round_sigfigs(self):
171 f = mathutil.round_sigfigs
172 self.failUnlessEqual(f(22.0/3, 4), 7.3330000000000002)
174 class Statistics(unittest.TestCase):
175 def should_assert(self, msg, func, *args, **kwargs):
177 func(*args, **kwargs)
179 except AssertionError:
182 def failUnlessListEqual(self, a, b, msg = None):
183 self.failUnlessEqual(len(a), len(b))
184 for i in range(len(a)):
185 self.failUnlessEqual(a[i], b[i], msg)
187 def failUnlessListAlmostEqual(self, a, b, places = 7, msg = None):
188 self.failUnlessEqual(len(a), len(b))
189 for i in range(len(a)):
190 self.failUnlessAlmostEqual(a[i], b[i], places, msg)
192 def test_binomial_coeff(self):
193 f = statistics.binomial_coeff
194 self.failUnlessEqual(f(20, 0), 1)
195 self.failUnlessEqual(f(20, 1), 20)
196 self.failUnlessEqual(f(20, 2), 190)
197 self.failUnlessEqual(f(20, 8), f(20, 12))
198 self.should_assert("Should assert if n < k", f, 2, 3)
200 def test_binomial_distribution_pmf(self):
201 f = statistics.binomial_distribution_pmf
204 pmf_stat = [0.81, 0.18, 0.01]
205 self.failUnlessListAlmostEqual(pmf_comp, pmf_stat)
207 # Summing across a PMF should give the total probability 1
208 self.failUnlessAlmostEqual(sum(pmf_comp), 1)
209 self.should_assert("Should assert if not 0<=p<=1", f, 1, -1)
210 self.should_assert("Should assert if n < 1", f, 0, .1)
213 statistics.print_pmf(pmf_comp, out=out)
214 lines = out.getvalue().splitlines()
215 self.failUnlessEqual(lines[0], "i=0: 0.81")
216 self.failUnlessEqual(lines[1], "i=1: 0.18")
217 self.failUnlessEqual(lines[2], "i=2: 0.01")
219 def test_survival_pmf(self):
220 f = statistics.survival_pmf
221 # Cross-check binomial-distribution method against convolution
223 p_list = [.9999] * 100 + [.99] * 50 + [.8] * 20
224 pmf1 = statistics.survival_pmf_via_conv(p_list)
225 pmf2 = statistics.survival_pmf_via_bd(p_list)
226 self.failUnlessListAlmostEqual(pmf1, pmf2)
227 self.failUnlessTrue(statistics.valid_pmf(pmf1))
228 self.should_assert("Should assert if p_i > 1", f, [1.1]);
229 self.should_assert("Should assert if p_i < 0", f, [-.1]);
231 def test_repair_count_pmf(self):
232 survival_pmf = statistics.binomial_distribution_pmf(5, .9)
233 repair_pmf = statistics.repair_count_pmf(survival_pmf, 3)
234 # repair_pmf[0] == sum(survival_pmf[0,1,2,5])
235 # repair_pmf[1] == survival_pmf[4]
236 # repair_pmf[2] = survival_pmf[3]
237 self.failUnlessListAlmostEqual(repair_pmf,
238 [0.00001 + 0.00045 + 0.0081 + 0.59049,
243 def test_repair_cost(self):
244 survival_pmf = statistics.binomial_distribution_pmf(5, .9)
245 bwcost = statistics.bandwidth_cost_function
246 cost = statistics.mean_repair_cost(bwcost, 1000,
247 survival_pmf, 3, ul_dl_ratio=1.0)
248 self.failUnlessAlmostEqual(cost, 558.90)
249 cost = statistics.mean_repair_cost(bwcost, 1000,
250 survival_pmf, 3, ul_dl_ratio=8.0)
251 self.failUnlessAlmostEqual(cost, 1664.55)
253 # I haven't manually checked the math beyond here -warner
254 cost = statistics.eternal_repair_cost(bwcost, 1000,
256 discount_rate=0, ul_dl_ratio=1.0)
257 self.failUnlessAlmostEqual(cost, 65292.056074766246)
258 cost = statistics.eternal_repair_cost(bwcost, 1000,
262 self.failUnlessAlmostEqual(cost, 9133.6097158191551)
264 def test_convolve(self):
265 f = statistics.convolve
269 v1v2result = [ 4, 13, 28, 27, 18 ]
270 # Convolution is commutative
273 self.failUnlessListEqual(r1, r2, "Convolution should be commutative")
274 self.failUnlessListEqual(r1, v1v2result, "Didn't match known result")
275 # Convolution is associative
276 r1 = f(f(v1, v2), v3)
277 r2 = f(v1, f(v2, v3))
278 self.failUnlessListEqual(r1, r2, "Convolution should be associative")
279 # Convolution is distributive
280 r1 = f(v3, [ a + b for a, b in zip(v1, v2) ])
283 r2 = [ a + b for a, b in zip(tmp1, tmp2) ]
284 self.failUnlessListEqual(r1, r2, "Convolution should be distributive")
285 # Convolution is scalar multiplication associative
287 r1 = [ a * 4 for a in tmp1 ]
288 tmp2 = [ a * 4 for a in v1 ]
290 self.failUnlessListEqual(r1, r2, "Convolution should be scalar multiplication associative")
292 def test_find_k(self):
293 f = statistics.find_k
294 g = statistics.pr_file_loss
295 plist = [.9] * 10 + [.8] * 10 # N=20
298 self.failUnlessEqual(k, 10)
299 self.failUnless(g(plist, k) < t)
301 def test_pr_file_loss(self):
302 f = statistics.pr_file_loss
304 self.failUnlessEqual(f(plist, 3), .0546875)
306 def test_pr_backup_file_loss(self):
307 f = statistics.pr_backup_file_loss
309 self.failUnlessEqual(f(plist, .5, 3), .02734375)
312 class Asserts(unittest.TestCase):
313 def should_assert(self, func, *args, **kwargs):
315 func(*args, **kwargs)
316 except AssertionError, e:
319 self.fail("assert failed with non-AssertionError: %s" % e)
320 self.fail("assert was not caught")
322 def should_not_assert(self, func, *args, **kwargs):
324 func(*args, **kwargs)
325 except AssertionError, e:
326 self.fail("assertion fired when it should not have: %s" % e)
328 self.fail("assertion (which shouldn't have failed) failed with non-AssertionError: %s" % e)
332 def test_assert(self):
333 f = assertutil._assert
334 self.should_assert(f)
335 self.should_assert(f, False)
336 self.should_not_assert(f, True)
338 m = self.should_assert(f, False, "message")
339 self.failUnlessEqual(m, "'message' <type 'str'>", m)
340 m = self.should_assert(f, False, "message1", othermsg=12)
341 self.failUnlessEqual("'message1' <type 'str'>, othermsg: 12 <type 'int'>", m)
342 m = self.should_assert(f, False, othermsg="message2")
343 self.failUnlessEqual("othermsg: 'message2' <type 'str'>", m)
345 def test_precondition(self):
346 f = assertutil.precondition
347 self.should_assert(f)
348 self.should_assert(f, False)
349 self.should_not_assert(f, True)
351 m = self.should_assert(f, False, "message")
352 self.failUnlessEqual("precondition: 'message' <type 'str'>", m)
353 m = self.should_assert(f, False, "message1", othermsg=12)
354 self.failUnlessEqual("precondition: 'message1' <type 'str'>, othermsg: 12 <type 'int'>", m)
355 m = self.should_assert(f, False, othermsg="message2")
356 self.failUnlessEqual("precondition: othermsg: 'message2' <type 'str'>", m)
358 def test_postcondition(self):
359 f = assertutil.postcondition
360 self.should_assert(f)
361 self.should_assert(f, False)
362 self.should_not_assert(f, True)
364 m = self.should_assert(f, False, "message")
365 self.failUnlessEqual("postcondition: 'message' <type 'str'>", m)
366 m = self.should_assert(f, False, "message1", othermsg=12)
367 self.failUnlessEqual("postcondition: 'message1' <type 'str'>, othermsg: 12 <type 'int'>", m)
368 m = self.should_assert(f, False, othermsg="message2")
369 self.failUnlessEqual("postcondition: othermsg: 'message2' <type 'str'>", m)
371 class FileUtil(unittest.TestCase):
372 def mkdir(self, basedir, path, mode=0777):
373 fn = os.path.join(basedir, path)
374 fileutil.make_dirs(fn, mode)
376 def touch(self, basedir, path, mode=None, data="touch\n"):
377 fn = os.path.join(basedir, path)
384 def test_rm_dir(self):
385 basedir = "util/FileUtil/test_rm_dir"
386 fileutil.make_dirs(basedir)
387 # create it again to test idempotency
388 fileutil.make_dirs(basedir)
389 d = os.path.join(basedir, "doomed")
391 self.touch(d, "a/b/1.txt")
392 self.touch(d, "a/b/2.txt", 0444)
393 self.touch(d, "a/b/3.txt", 0)
395 self.touch(d, "a/c/1.txt")
396 self.touch(d, "a/c/2.txt", 0444)
397 self.touch(d, "a/c/3.txt", 0)
398 os.chmod(os.path.join(d, "a/c"), 0444)
400 self.touch(d, "a/d/1.txt")
401 self.touch(d, "a/d/2.txt", 0444)
402 self.touch(d, "a/d/3.txt", 0)
403 os.chmod(os.path.join(d, "a/d"), 0)
406 self.failIf(os.path.exists(d))
407 # remove it again to test idempotency
410 def test_remove_if_possible(self):
411 basedir = "util/FileUtil/test_remove_if_possible"
412 fileutil.make_dirs(basedir)
413 self.touch(basedir, "here")
414 fn = os.path.join(basedir, "here")
415 fileutil.remove_if_possible(fn)
416 self.failIf(os.path.exists(fn))
417 fileutil.remove_if_possible(fn) # should be idempotent
418 fileutil.rm_dir(basedir)
419 fileutil.remove_if_possible(fn) # should survive errors
421 def test_open_or_create(self):
422 basedir = "util/FileUtil/test_open_or_create"
423 fileutil.make_dirs(basedir)
424 fn = os.path.join(basedir, "here")
425 f = fileutil.open_or_create(fn)
428 f = fileutil.open_or_create(fn)
435 self.failUnlessEqual(data, "stuff.more.")
437 def test_NamedTemporaryDirectory(self):
438 basedir = "util/FileUtil/test_NamedTemporaryDirectory"
439 fileutil.make_dirs(basedir)
440 td = fileutil.NamedTemporaryDirectory(dir=basedir)
442 self.failUnless(basedir in name)
443 self.failUnless(basedir in repr(td))
444 self.failUnless(os.path.isdir(name))
446 # it is conceivable that we need to force gc here, but I'm not sure
447 self.failIf(os.path.isdir(name))
449 def test_rename(self):
450 basedir = "util/FileUtil/test_rename"
451 fileutil.make_dirs(basedir)
452 self.touch(basedir, "here")
453 fn = os.path.join(basedir, "here")
454 fn2 = os.path.join(basedir, "there")
455 fileutil.rename(fn, fn2)
456 self.failIf(os.path.exists(fn))
457 self.failUnless(os.path.exists(fn2))
460 basedir = "util/FileUtil/test_du"
461 fileutil.make_dirs(basedir)
462 d = os.path.join(basedir, "space-consuming")
464 self.touch(d, "a/b/1.txt", data="a"*10)
465 self.touch(d, "a/b/2.txt", data="b"*11)
467 self.touch(d, "a/c/1.txt", data="c"*12)
468 self.touch(d, "a/c/2.txt", data="d"*13)
470 used = fileutil.du(basedir)
471 self.failUnlessEqual(10+11+12+13, used)
473 class PollMixinTests(unittest.TestCase):
475 self.pm = pollmixin.PollMixin()
477 def test_PollMixin_True(self):
478 d = self.pm.poll(check_f=lambda : True,
482 def test_PollMixin_False_then_True(self):
483 i = iter([False, True])
484 d = self.pm.poll(check_f=i.next,
488 def test_timeout(self):
489 d = self.pm.poll(check_f=lambda: False,
493 self.fail("poll should have failed, not returned %s" % (res,))
495 f.trap(pollmixin.TimeoutError)
496 return None # success
497 d.addCallbacks(_suc, _err)
500 class DeferredUtilTests(unittest.TestCase):
501 def test_gather_results(self):
502 d1 = defer.Deferred()
503 d2 = defer.Deferred()
504 res = deferredutil.gatherResults([d1, d2])
505 d1.errback(ValueError("BAD"))
507 self.fail("Should have errbacked, not resulted in %s" % (res,))
509 thef.trap(ValueError)
510 res.addCallbacks(_callb, _errb)
513 def test_success(self):
514 d1, d2 = defer.Deferred(), defer.Deferred()
517 dlss = deferredutil.DeferredListShouldSucceed([d1,d2])
518 dlss.addCallbacks(good.append, bad.append)
521 self.failUnlessEqual(good, [[1,2]])
522 self.failUnlessEqual(bad, [])
524 def test_failure(self):
525 d1, d2 = defer.Deferred(), defer.Deferred()
528 dlss = deferredutil.DeferredListShouldSucceed([d1,d2])
529 dlss.addCallbacks(good.append, bad.append)
530 d1.addErrback(lambda _ignore: None)
531 d2.addErrback(lambda _ignore: None)
533 d2.errback(ValueError())
534 self.failUnlessEqual(good, [])
535 self.failUnlessEqual(len(bad), 1)
537 self.failUnless(isinstance(f, Failure))
538 self.failUnless(f.check(ValueError))
540 class HashUtilTests(unittest.TestCase):
542 def test_random_key(self):
543 k = hashutil.random_key()
544 self.failUnlessEqual(len(k), hashutil.KEYLEN)
546 def test_sha256d(self):
547 h1 = hashutil.tagged_hash("tag1", "value")
548 h2 = hashutil.tagged_hasher("tag1")
552 self.failUnlessEqual(h1, h2a)
553 self.failUnlessEqual(h2a, h2b)
555 def test_sha256d_truncated(self):
556 h1 = hashutil.tagged_hash("tag1", "value", 16)
557 h2 = hashutil.tagged_hasher("tag1", 16)
560 self.failUnlessEqual(len(h1), 16)
561 self.failUnlessEqual(len(h2), 16)
562 self.failUnlessEqual(h1, h2)
565 h1 = hashutil.convergence_hash(3, 10, 1000, "data", "secret")
566 h2 = hashutil.convergence_hasher(3, 10, 1000, "secret")
569 self.failUnlessEqual(h1, h2)
571 def test_hashers(self):
572 h1 = hashutil.block_hash("foo")
573 h2 = hashutil.block_hasher()
575 self.failUnlessEqual(h1, h2.digest())
577 h1 = hashutil.uri_extension_hash("foo")
578 h2 = hashutil.uri_extension_hasher()
580 self.failUnlessEqual(h1, h2.digest())
582 h1 = hashutil.plaintext_hash("foo")
583 h2 = hashutil.plaintext_hasher()
585 self.failUnlessEqual(h1, h2.digest())
587 h1 = hashutil.crypttext_hash("foo")
588 h2 = hashutil.crypttext_hasher()
590 self.failUnlessEqual(h1, h2.digest())
592 h1 = hashutil.crypttext_segment_hash("foo")
593 h2 = hashutil.crypttext_segment_hasher()
595 self.failUnlessEqual(h1, h2.digest())
597 h1 = hashutil.plaintext_segment_hash("foo")
598 h2 = hashutil.plaintext_segment_hasher()
600 self.failUnlessEqual(h1, h2.digest())
602 def test_constant_time_compare(self):
603 self.failUnless(hashutil.constant_time_compare("a", "a"))
604 self.failUnless(hashutil.constant_time_compare("ab", "ab"))
605 self.failIf(hashutil.constant_time_compare("a", "b"))
606 self.failIf(hashutil.constant_time_compare("a", "aa"))
608 def _testknown(self, hashf, expected_a, *args):
610 got_a = base32.b2a(got)
611 self.failUnlessEqual(got_a, expected_a)
613 def test_known_answers(self):
614 # assert backwards compatibility
615 self._testknown(hashutil.storage_index_hash, "qb5igbhcc5esa6lwqorsy7e6am", "")
616 self._testknown(hashutil.block_hash, "msjr5bh4evuh7fa3zw7uovixfbvlnstr5b65mrerwfnvjxig2jvq", "")
617 self._testknown(hashutil.uri_extension_hash, "wthsu45q7zewac2mnivoaa4ulh5xvbzdmsbuyztq2a5fzxdrnkka", "")
618 self._testknown(hashutil.plaintext_hash, "5lz5hwz3qj3af7n6e3arblw7xzutvnd3p3fjsngqjcb7utf3x3da", "")
619 self._testknown(hashutil.crypttext_hash, "itdj6e4njtkoiavlrmxkvpreosscssklunhwtvxn6ggho4rkqwga", "")
620 self._testknown(hashutil.crypttext_segment_hash, "aovy5aa7jej6ym5ikgwyoi4pxawnoj3wtaludjz7e2nb5xijb7aa", "")
621 self._testknown(hashutil.plaintext_segment_hash, "4fdgf6qruaisyukhqcmoth4t3li6bkolbxvjy4awwcpprdtva7za", "")
622 self._testknown(hashutil.convergence_hash, "3mo6ni7xweplycin6nowynw2we", 3, 10, 100, "", "converge")
623 self._testknown(hashutil.my_renewal_secret_hash, "ujhr5k5f7ypkp67jkpx6jl4p47pyta7hu5m527cpcgvkafsefm6q", "")
624 self._testknown(hashutil.my_cancel_secret_hash, "rjwzmafe2duixvqy6h47f5wfrokdziry6zhx4smew4cj6iocsfaa", "")
625 self._testknown(hashutil.file_renewal_secret_hash, "hzshk2kf33gzbd5n3a6eszkf6q6o6kixmnag25pniusyaulqjnia", "", "si")
626 self._testknown(hashutil.file_cancel_secret_hash, "bfciwvr6w7wcavsngxzxsxxaszj72dej54n4tu2idzp6b74g255q", "", "si")
627 self._testknown(hashutil.bucket_renewal_secret_hash, "e7imrzgzaoashsncacvy3oysdd2m5yvtooo4gmj4mjlopsazmvuq", "", "\x00"*20)
628 self._testknown(hashutil.bucket_cancel_secret_hash, "dvdujeyxeirj6uux6g7xcf4lvesk632aulwkzjar7srildvtqwma", "", "\x00"*20)
629 self._testknown(hashutil.hmac, "c54ypfi6pevb3nvo6ba42jtglpkry2kbdopqsi7dgrm4r7tw5sra", "tag", "")
630 self._testknown(hashutil.mutable_rwcap_key_hash, "6rvn2iqrghii5n4jbbwwqqsnqu", "iv", "wk")
631 self._testknown(hashutil.ssk_writekey_hash, "ykpgmdbpgbb6yqz5oluw2q26ye", "")
632 self._testknown(hashutil.ssk_write_enabler_master_hash, "izbfbfkoait4dummruol3gy2bnixrrrslgye6ycmkuyujnenzpia", "")
633 self._testknown(hashutil.ssk_write_enabler_hash, "fuu2dvx7g6gqu5x22vfhtyed7p4pd47y5hgxbqzgrlyvxoev62tq", "wk", "\x00"*20)
634 self._testknown(hashutil.ssk_pubkey_fingerprint_hash, "3opzw4hhm2sgncjx224qmt5ipqgagn7h5zivnfzqycvgqgmgz35q", "")
635 self._testknown(hashutil.ssk_readkey_hash, "vugid4as6qbqgeq2xczvvcedai", "")
636 self._testknown(hashutil.ssk_readkey_data_hash, "73wsaldnvdzqaf7v4pzbr2ae5a", "iv", "rk")
637 self._testknown(hashutil.ssk_storage_index_hash, "j7icz6kigb6hxrej3tv4z7ayym", "")
640 class Abbreviate(unittest.TestCase):
642 a = abbreviate.abbreviate_time
643 self.failUnlessEqual(a(None), "unknown")
644 self.failUnlessEqual(a(0), "0 seconds")
645 self.failUnlessEqual(a(1), "1 second")
646 self.failUnlessEqual(a(2), "2 seconds")
647 self.failUnlessEqual(a(119), "119 seconds")
649 self.failUnlessEqual(a(2*MIN), "2 minutes")
650 self.failUnlessEqual(a(60*MIN), "60 minutes")
651 self.failUnlessEqual(a(179*MIN), "179 minutes")
653 self.failUnlessEqual(a(180*MIN), "3 hours")
654 self.failUnlessEqual(a(4*HOUR), "4 hours")
657 self.failUnlessEqual(a(2*DAY), "2 days")
658 self.failUnlessEqual(a(2*MONTH), "2 months")
660 self.failUnlessEqual(a(5*YEAR), "5 years")
662 def test_space(self):
663 tests_si = [(None, "unknown"),
670 (20*1000, "20.00 kB"),
671 (1024*1024, "1.05 MB"),
672 (1000*1000, "1.00 MB"),
673 (1000*1000*1000, "1.00 GB"),
674 (1000*1000*1000*1000, "1.00 TB"),
675 (1000*1000*1000*1000*1000, "1.00 PB"),
676 (1234567890123456, "1.23 PB"),
678 for (x, expected) in tests_si:
679 got = abbreviate.abbreviate_space(x, SI=True)
680 self.failUnlessEqual(got, expected)
682 tests_base1024 = [(None, "unknown"),
689 (20*1024, "20.00 kiB"),
690 (1000*1000, "976.56 kiB"),
691 (1024*1024, "1.00 MiB"),
692 (1024*1024*1024, "1.00 GiB"),
693 (1024*1024*1024*1024, "1.00 TiB"),
694 (1000*1000*1000*1000*1000, "909.49 TiB"),
695 (1024*1024*1024*1024*1024, "1.00 PiB"),
696 (1234567890123456, "1.10 PiB"),
698 for (x, expected) in tests_base1024:
699 got = abbreviate.abbreviate_space(x, SI=False)
700 self.failUnlessEqual(got, expected)
702 self.failUnlessEqual(abbreviate.abbreviate_space_both(1234567),
703 "(1.23 MB, 1.18 MiB)")
705 def test_parse_space(self):
706 p = abbreviate.parse_abbreviated_size
707 self.failUnlessEqual(p(""), None)
708 self.failUnlessEqual(p(None), None)
709 self.failUnlessEqual(p("123"), 123)
710 self.failUnlessEqual(p("123B"), 123)
711 self.failUnlessEqual(p("2K"), 2000)
712 self.failUnlessEqual(p("2kb"), 2000)
713 self.failUnlessEqual(p("2KiB"), 2048)
714 self.failUnlessEqual(p("10MB"), 10*1000*1000)
715 self.failUnlessEqual(p("10MiB"), 10*1024*1024)
716 self.failUnlessEqual(p("5G"), 5*1000*1000*1000)
717 self.failUnlessEqual(p("4GiB"), 4*1024*1024*1024)
718 e = self.failUnlessRaises(ValueError, p, "12 cubits")
719 self.failUnless("12 cubits" in str(e))
721 class Limiter(unittest.TestCase):
722 timeout = 480 # This takes longer than 240 seconds on Francois's arm box.
724 def job(self, i, foo):
725 self.calls.append( (i, foo) )
726 self.simultaneous += 1
727 self.peak_simultaneous = max(self.simultaneous, self.peak_simultaneous)
730 self.simultaneous -= 1
731 d.callback("done %d" % i)
732 reactor.callLater(1.0, _done)
735 def bad_job(self, i, foo):
736 raise ValueError("bad_job %d" % i)
738 def test_limiter(self):
740 self.simultaneous = 0
741 self.peak_simultaneous = 0
742 l = limiter.ConcurrencyLimiter()
745 dl.append(l.add(self.job, i, foo=str(i)))
746 d = defer.DeferredList(dl, fireOnOneErrback=True)
748 self.failUnlessEqual(self.simultaneous, 0)
749 self.failUnless(self.peak_simultaneous <= 10)
750 self.failUnlessEqual(len(self.calls), 20)
752 self.failUnless( (i, str(i)) in self.calls)
756 def test_errors(self):
758 self.simultaneous = 0
759 self.peak_simultaneous = 0
760 l = limiter.ConcurrencyLimiter()
763 dl.append(l.add(self.job, i, foo=str(i)))
764 d2 = l.add(self.bad_job, 21, "21")
765 d = defer.DeferredList(dl, fireOnOneErrback=True)
768 for (success, result) in res:
769 self.failUnlessEqual(success, True)
770 results.append(result)
772 expected_results = ["done %d" % i for i in range(20)]
773 expected_results.sort()
774 self.failUnlessEqual(results, expected_results)
775 self.failUnless(self.peak_simultaneous <= 10)
776 self.failUnlessEqual(len(self.calls), 20)
778 self.failUnless( (i, str(i)) in self.calls)
780 self.fail("should have failed, not got %s" % (res,))
783 self.failUnless("bad_job 21" in str(f))
784 d2.addCallbacks(_good, _err)
786 d.addCallback(_most_done)
788 self.failUnlessEqual(self.simultaneous, 0)
789 self.failUnless(self.peak_simultaneous <= 10)
790 self.failUnlessEqual(len(self.calls), 20)
792 self.failUnless( (i, str(i)) in self.calls)
793 d.addCallback(_all_done)
796 class TimeFormat(unittest.TestCase):
797 def test_epoch(self):
798 return self._help_test_epoch()
800 def test_epoch_in_London(self):
801 # Europe/London is a particularly troublesome timezone. Nowadays, its
802 # offset from GMT is 0. But in 1970, its offset from GMT was 1.
803 # (Apparently in 1970 Britain had redefined standard time to be GMT+1
804 # and stayed in standard time all year round, whereas today
805 # Europe/London standard time is GMT and Europe/London Daylight
806 # Savings Time is GMT+1.) The current implementation of
807 # time_format.iso_utc_time_to_localseconds() breaks if the timezone is
808 # Europe/London. (As soon as this unit test is done then I'll change
809 # that implementation to something that works even in this case...)
810 origtz = os.environ.get('TZ')
811 os.environ['TZ'] = "Europe/London"
812 if hasattr(time, 'tzset'):
815 return self._help_test_epoch()
820 os.environ['TZ'] = origtz
821 if hasattr(time, 'tzset'):
824 def _help_test_epoch(self):
825 origtzname = time.tzname
826 s = time_format.iso_utc_time_to_seconds("1970-01-01T00:00:01")
827 self.failUnlessEqual(s, 1.0)
828 s = time_format.iso_utc_time_to_seconds("1970-01-01_00:00:01")
829 self.failUnlessEqual(s, 1.0)
830 s = time_format.iso_utc_time_to_seconds("1970-01-01 00:00:01")
831 self.failUnlessEqual(s, 1.0)
833 self.failUnlessEqual(time_format.iso_utc(1.0), "1970-01-01_00:00:01")
834 self.failUnlessEqual(time_format.iso_utc(1.0, sep=" "),
835 "1970-01-01 00:00:01")
838 isostr = time_format.iso_utc(now)
839 timestamp = time_format.iso_utc_time_to_seconds(isostr)
840 self.failUnlessEqual(int(timestamp), int(now))
844 self.failUnlessEqual(time_format.iso_utc(t=my_time),
845 "1970-01-01_00:00:01")
846 e = self.failUnlessRaises(ValueError,
847 time_format.iso_utc_time_to_seconds,
848 "invalid timestring")
849 self.failUnless("not a complete ISO8601 timestamp" in str(e))
850 s = time_format.iso_utc_time_to_seconds("1970-01-01_00:00:01.500")
851 self.failUnlessEqual(s, 1.5)
853 # Look for daylight-savings-related errors.
854 thatmomentinmarch = time_format.iso_utc_time_to_seconds("2009-03-20 21:49:02.226536")
855 self.failUnlessEqual(thatmomentinmarch, 1237585742.226536)
856 self.failUnlessEqual(origtzname, time.tzname)
858 class CacheDir(unittest.TestCase):
859 def test_basic(self):
860 basedir = "test_util/CacheDir/test_basic"
862 def _failIfExists(name):
863 absfn = os.path.join(basedir, name)
864 self.failIf(os.path.exists(absfn),
865 "%s exists but it shouldn't" % absfn)
867 def _failUnlessExists(name):
868 absfn = os.path.join(basedir, name)
869 self.failUnless(os.path.exists(absfn),
870 "%s doesn't exist but it should" % absfn)
872 cdm = cachedir.CacheDirectoryManager(basedir)
873 a = cdm.get_file("a")
874 b = cdm.get_file("b")
875 c = cdm.get_file("c")
876 f = open(a.get_filename(), "wb"); f.write("hi"); f.close(); del f
877 f = open(b.get_filename(), "wb"); f.write("hi"); f.close(); del f
878 f = open(c.get_filename(), "wb"); f.write("hi"); f.close(); del f
880 _failUnlessExists("a")
881 _failUnlessExists("b")
882 _failUnlessExists("c")
886 _failUnlessExists("a")
887 _failUnlessExists("b")
888 _failUnlessExists("c")
891 # this file won't be deleted yet, because it isn't old enough
893 _failUnlessExists("a")
894 _failUnlessExists("b")
895 _failUnlessExists("c")
897 # we change the definition of "old" to make everything old
902 _failUnlessExists("b")
903 _failUnlessExists("c")
911 _failUnlessExists("b")
912 _failUnlessExists("c")
914 b2 = cdm.get_file("b")
918 _failUnlessExists("b")
919 _failUnlessExists("c")
924 def __init__(self, x):
929 return "<%s %s>" % (self.__class__.__name__, self.x,)
932 def __le__(self, other):
933 return self.x <= other
934 def __lt__(self, other):
935 return self.x < other
936 def __ge__(self, other):
937 return self.x >= other
938 def __gt__(self, other):
939 return self.x > other
940 def __ne__(self, other):
941 return self.x != other
942 def __eq__(self, other):
943 return self.x == other
945 class DictUtil(unittest.TestCase):
946 def _help_test_empty_dict(self, klass):
950 self.failUnless(d1 == d2, "d1: %r, d2: %r" % (d1, d2,))
951 self.failUnless(len(d1) == 0)
952 self.failUnless(len(d2) == 0)
954 def _help_test_nonempty_dict(self, klass):
955 d1 = klass({'a': 1, 'b': "eggs", 3: "spam",})
956 d2 = klass({'a': 1, 'b': "eggs", 3: "spam",})
958 self.failUnless(d1 == d2)
959 self.failUnless(len(d1) == 3, "%s, %s" % (len(d1), d1,))
960 self.failUnless(len(d2) == 3)
962 def _help_test_eq_but_notis(self, klass):
963 d = klass({'a': 3, 'b': EqButNotIs(3), 'c': 3})
968 d['b'] = EqButNotIs(3)
973 d['b'] = EqButNotIs(3)
979 d['a'] = EqButNotIs(3)
984 fake3 = EqButNotIs(3)
985 fake7 = EqButNotIs(7)
989 self.failUnless(filter(lambda x: x is 8, d.itervalues()))
990 self.failUnless(filter(lambda x: x is fake7, d.itervalues()))
991 # The real 7 should have been ejected by the d[3] = 8.
992 self.failUnless(not filter(lambda x: x is 7, d.itervalues()))
993 self.failUnless(filter(lambda x: x is fake3, d.iterkeys()))
994 self.failUnless(filter(lambda x: x is 3, d.iterkeys()))
999 fake3 = EqButNotIs(3)
1000 fake7 = EqButNotIs(7)
1003 self.failUnless(filter(lambda x: x is 8, d.itervalues()))
1004 self.failUnless(filter(lambda x: x is fake7, d.itervalues()))
1005 # The real 7 should have been ejected by the d[3] = 8.
1006 self.failUnless(not filter(lambda x: x is 7, d.itervalues()))
1007 self.failUnless(filter(lambda x: x is fake3, d.iterkeys()))
1008 self.failUnless(filter(lambda x: x is 3, d.iterkeys()))
1012 self._help_test_eq_but_notis(dictutil.UtilDict)
1013 self._help_test_eq_but_notis(dictutil.NumDict)
1014 self._help_test_eq_but_notis(dictutil.ValueOrderedDict)
1015 self._help_test_nonempty_dict(dictutil.UtilDict)
1016 self._help_test_nonempty_dict(dictutil.NumDict)
1017 self._help_test_nonempty_dict(dictutil.ValueOrderedDict)
1018 self._help_test_eq_but_notis(dictutil.UtilDict)
1019 self._help_test_eq_but_notis(dictutil.NumDict)
1020 self._help_test_eq_but_notis(dictutil.ValueOrderedDict)
1022 def test_dict_of_sets(self):
1023 ds = dictutil.DictOfSets()
1028 self.failUnlessEqual(ds[1], set(["a"]))
1029 self.failUnlessEqual(ds[2], set(["b", "c"]))
1030 ds.discard(3, "d") # should not raise an exception
1032 self.failUnlessEqual(ds[2], set(["c"]))
1034 self.failIf(2 in ds)
1036 ds.union(1, ["a", "e"])
1038 self.failUnlessEqual(ds[1], set(["a","e"]))
1039 self.failUnlessEqual(ds[3], set(["f"]))
1040 ds2 = dictutil.DictOfSets()
1045 self.failUnlessEqual(ds[1], set(["a","e"]))
1046 self.failUnlessEqual(ds[3], set(["f", "g"]))
1047 self.failUnlessEqual(ds[4], set(["h"]))
1049 def test_move(self):
1050 d1 = {1: "a", 2: "b"}
1051 d2 = {2: "c", 3: "d"}
1052 dictutil.move(1, d1, d2)
1053 self.failUnlessEqual(d1, {2: "b"})
1054 self.failUnlessEqual(d2, {1: "a", 2: "c", 3: "d"})
1056 d1 = {1: "a", 2: "b"}
1057 d2 = {2: "c", 3: "d"}
1058 dictutil.move(2, d1, d2)
1059 self.failUnlessEqual(d1, {1: "a"})
1060 self.failUnlessEqual(d2, {2: "b", 3: "d"})
1062 d1 = {1: "a", 2: "b"}
1063 d2 = {2: "c", 3: "d"}
1064 self.failUnlessRaises(KeyError, dictutil.move, 5, d1, d2, strict=True)
1066 def test_subtract(self):
1067 d1 = {1: "a", 2: "b"}
1068 d2 = {2: "c", 3: "d"}
1069 d3 = dictutil.subtract(d1, d2)
1070 self.failUnlessEqual(d3, {1: "a"})
1072 d1 = {1: "a", 2: "b"}
1074 d3 = dictutil.subtract(d1, d2)
1075 self.failUnlessEqual(d3, {1: "a"})
1077 def test_utildict(self):
1078 d = dictutil.UtilDict({1: "a", 2: "b"})
1081 self.failUnlessEqual(d, {2: "b"})
1084 self.failUnlessRaises(TypeError, eq, d, "not a dict")
1086 d = dictutil.UtilDict({1: "b", 2: "a"})
1087 self.failUnlessEqual(d.items_sorted_by_value(),
1088 [(2, "a"), (1, "b")])
1089 self.failUnlessEqual(d.items_sorted_by_key(),
1090 [(1, "b"), (2, "a")])
1091 self.failUnlessEqual(repr(d), "{1: 'b', 2: 'a'}")
1092 self.failUnless(1 in d)
1094 d2 = dictutil.UtilDict({3: "c", 4: "d"})
1095 self.failUnless(d != d2)
1096 self.failUnless(d2 > d)
1097 self.failUnless(d2 >= d)
1098 self.failUnless(d <= d2)
1099 self.failUnless(d < d2)
1100 self.failUnlessEqual(d[1], "b")
1101 self.failUnlessEqual(sorted(list([k for k in d])), [1,2])
1104 self.failUnlessEqual(d, d3)
1105 self.failUnless(isinstance(d3, dictutil.UtilDict))
1107 d4 = d.fromkeys([3,4], "e")
1108 self.failUnlessEqual(d4, {3: "e", 4: "e"})
1110 self.failUnlessEqual(d.get(1), "b")
1111 self.failUnlessEqual(d.get(3), None)
1112 self.failUnlessEqual(d.get(3, "default"), "default")
1113 self.failUnlessEqual(sorted(list(d.items())),
1114 [(1, "b"), (2, "a")])
1115 self.failUnlessEqual(sorted(list(d.iteritems())),
1116 [(1, "b"), (2, "a")])
1117 self.failUnlessEqual(sorted(d.keys()), [1, 2])
1118 self.failUnlessEqual(sorted(d.values()), ["a", "b"])
1119 x = d.setdefault(1, "new")
1120 self.failUnlessEqual(x, "b")
1121 self.failUnlessEqual(d[1], "b")
1122 x = d.setdefault(3, "new")
1123 self.failUnlessEqual(x, "new")
1124 self.failUnlessEqual(d[3], "new")
1128 self.failUnless(x in [(1, "b"), (2, "a")])
1130 self.failUnless(x in [(1, "b"), (2, "a")])
1131 self.failUnlessRaises(KeyError, d.popitem)
1133 def test_numdict(self):
1134 d = dictutil.NumDict({"a": 1, "b": 2})
1136 d.add_num("a", 10, 5)
1137 d.add_num("c", 20, 5)
1139 self.failUnlessEqual(d, {"a": 11, "b": 2, "c": 25, "d": 30})
1141 d.subtract_num("a", 10)
1142 d.subtract_num("e", 10)
1143 d.subtract_num("f", 10, 15)
1144 self.failUnlessEqual(d, {"a": 1, "b": 2, "c": 25, "d": 30,
1147 self.failUnlessEqual(d.sum(), sum([1, 2, 25, 30, -10, 5]))
1149 d = dictutil.NumDict()
1153 self.failUnlessEqual(d, {"a": 2, "b": 6})
1157 self.failUnlessEqual(d, {"a": 1, "b": 6, "c": -1, "d": 4})
1158 self.failUnlessEqual(d.items_sorted_by_key(),
1159 [("a", 1), ("b", 6), ("c", -1), ("d", 4)])
1160 self.failUnlessEqual(d.items_sorted_by_value(),
1161 [("c", -1), ("a", 1), ("d", 4), ("b", 6)])
1162 self.failUnlessEqual(d.item_with_largest_value(), ("b", 6))
1164 d = dictutil.NumDict({"a": 1, "b": 2})
1165 self.failUnlessEqual(repr(d), "{'a': 1, 'b': 2}")
1166 self.failUnless("a" in d)
1168 d2 = dictutil.NumDict({"c": 3, "d": 4})
1169 self.failUnless(d != d2)
1170 self.failUnless(d2 > d)
1171 self.failUnless(d2 >= d)
1172 self.failUnless(d <= d2)
1173 self.failUnless(d < d2)
1174 self.failUnlessEqual(d["a"], 1)
1175 self.failUnlessEqual(sorted(list([k for k in d])), ["a","b"])
1178 self.failUnlessRaises(TypeError, eq, d, "not a dict")
1181 self.failUnlessEqual(d, d3)
1182 self.failUnless(isinstance(d3, dictutil.NumDict))
1184 d4 = d.fromkeys(["a","b"], 5)
1185 self.failUnlessEqual(d4, {"a": 5, "b": 5})
1187 self.failUnlessEqual(d.get("a"), 1)
1188 self.failUnlessEqual(d.get("c"), 0)
1189 self.failUnlessEqual(d.get("c", 5), 5)
1190 self.failUnlessEqual(sorted(list(d.items())),
1191 [("a", 1), ("b", 2)])
1192 self.failUnlessEqual(sorted(list(d.iteritems())),
1193 [("a", 1), ("b", 2)])
1194 self.failUnlessEqual(sorted(d.keys()), ["a", "b"])
1195 self.failUnlessEqual(sorted(d.values()), [1, 2])
1196 self.failUnless(d.has_key("a"))
1197 self.failIf(d.has_key("c"))
1199 x = d.setdefault("c", 3)
1200 self.failUnlessEqual(x, 3)
1201 self.failUnlessEqual(d["c"], 3)
1202 x = d.setdefault("c", 5)
1203 self.failUnlessEqual(x, 3)
1204 self.failUnlessEqual(d["c"], 3)
1208 self.failUnless(x in [("a", 1), ("b", 2)])
1210 self.failUnless(x in [("a", 1), ("b", 2)])
1211 self.failUnlessRaises(KeyError, d.popitem)
1214 d.update({"c": 4, "d": 5})
1215 self.failUnlessEqual(d, {"c": 4, "d": 5})
1217 def test_del_if_present(self):
1218 d = {1: "a", 2: "b"}
1219 dictutil.del_if_present(d, 1)
1220 dictutil.del_if_present(d, 3)
1221 self.failUnlessEqual(d, {2: "b"})
1223 def test_valueordereddict(self):
1224 d = dictutil.ValueOrderedDict()
1229 self.failUnlessEqual(d, {"a": 3, "b": 2, "c": 1})
1230 self.failUnlessEqual(d.items(), [("c", 1), ("b", 2), ("a", 3)])
1231 self.failUnlessEqual(d.values(), [1, 2, 3])
1232 self.failUnlessEqual(d.keys(), ["c", "b", "a"])
1233 self.failUnlessEqual(repr(d), "<ValueOrderedDict {c: 1, b: 2, a: 3}>")
1236 self.failIf(d == {"a": 4})
1237 self.failUnless(d != {"a": 4})
1239 x = d.setdefault("d", 0)
1240 self.failUnlessEqual(x, 0)
1241 self.failUnlessEqual(d["d"], 0)
1242 x = d.setdefault("d", -1)
1243 self.failUnlessEqual(x, 0)
1244 self.failUnlessEqual(d["d"], 0)
1246 x = d.remove("e", "default", False)
1247 self.failUnlessEqual(x, "default")
1248 self.failUnlessRaises(KeyError, d.remove, "e", "default", True)
1249 x = d.remove("d", 5)
1250 self.failUnlessEqual(x, 0)
1252 x = d.__getitem__("c")
1253 self.failUnlessEqual(x, 1)
1254 x = d.__getitem__("e", "default", False)
1255 self.failUnlessEqual(x, "default")
1256 self.failUnlessRaises(KeyError, d.__getitem__, "e", "default", True)
1258 self.failUnlessEqual(d.popitem(), ("c", 1))
1259 self.failUnlessEqual(d.popitem(), ("b", 2))
1260 self.failUnlessEqual(d.popitem(), ("a", 3))
1261 self.failUnlessRaises(KeyError, d.popitem)
1263 d = dictutil.ValueOrderedDict({"a": 3, "b": 2, "c": 1})
1264 x = d.pop("d", "default", False)
1265 self.failUnlessEqual(x, "default")
1266 self.failUnlessRaises(KeyError, d.pop, "d", "default", True)
1268 self.failUnlessEqual(x, 2)
1269 self.failUnlessEqual(d.items(), [("c", 1), ("a", 3)])
1271 d = dictutil.ValueOrderedDict({"a": 3, "b": 2, "c": 1})
1272 x = d.pop_from_list(1) # pop the second item, b/2
1273 self.failUnlessEqual(x, "b")
1274 self.failUnlessEqual(d.items(), [("c", 1), ("a", 3)])
1276 def test_auxdict(self):
1277 d = dictutil.AuxValueDict()
1278 # we put the serialized form in the auxdata
1279 d.set_with_aux("key", ("filecap", "metadata"), "serialized")
1281 self.failUnlessEqual(d.keys(), ["key"])
1282 self.failUnlessEqual(d["key"], ("filecap", "metadata"))
1283 self.failUnlessEqual(d.get_aux("key"), "serialized")
1284 def _get_missing(key):
1286 self.failUnlessRaises(KeyError, _get_missing, "nonkey")
1287 self.failUnlessEqual(d.get("nonkey"), None)
1288 self.failUnlessEqual(d.get("nonkey", "nonvalue"), "nonvalue")
1289 self.failUnlessEqual(d.get_aux("nonkey"), None)
1290 self.failUnlessEqual(d.get_aux("nonkey", "nonvalue"), "nonvalue")
1292 d["key"] = ("filecap2", "metadata2")
1293 self.failUnlessEqual(d["key"], ("filecap2", "metadata2"))
1294 self.failUnlessEqual(d.get_aux("key"), None)
1296 d.set_with_aux("key2", "value2", "aux2")
1297 self.failUnlessEqual(sorted(d.keys()), ["key", "key2"])
1299 self.failUnlessEqual(d.keys(), ["key"])
1300 self.failIf("key2" in d)
1301 self.failUnlessRaises(KeyError, _get_missing, "key2")
1302 self.failUnlessEqual(d.get("key2"), None)
1303 self.failUnlessEqual(d.get_aux("key2"), None)
1304 d["key2"] = "newvalue2"
1305 self.failUnlessEqual(d.get("key2"), "newvalue2")
1306 self.failUnlessEqual(d.get_aux("key2"), None)
1308 d = dictutil.AuxValueDict({1:2,3:4})
1309 self.failUnlessEqual(sorted(d.keys()), [1,3])
1310 self.failUnlessEqual(d[1], 2)
1311 self.failUnlessEqual(d.get_aux(1), None)
1313 d = dictutil.AuxValueDict([ (1,2), (3,4) ])
1314 self.failUnlessEqual(sorted(d.keys()), [1,3])
1315 self.failUnlessEqual(d[1], 2)
1316 self.failUnlessEqual(d.get_aux(1), None)
1318 d = dictutil.AuxValueDict(one=1, two=2)
1319 self.failUnlessEqual(sorted(d.keys()), ["one","two"])
1320 self.failUnlessEqual(d["one"], 1)
1321 self.failUnlessEqual(d.get_aux("one"), None)
1323 class Pipeline(unittest.TestCase):
1324 def pause(self, *args, **kwargs):
1325 d = defer.Deferred()
1326 self.calls.append( (d, args, kwargs) )
1329 def failUnlessCallsAre(self, expected):
1332 self.failUnlessEqual(len(self.calls), len(expected), self.calls)
1333 for i,c in enumerate(self.calls):
1334 self.failUnlessEqual(c[1:], expected[i], str(i))
1336 def test_basic(self):
1339 p = pipeline.Pipeline(100)
1341 d = p.flush() # fires immediately
1342 d.addCallbacks(finished.append, log.err)
1343 self.failUnlessEqual(len(finished), 1)
1346 d = p.add(10, self.pause, "one")
1347 # the call should start right away, and our return Deferred should
1349 d.addCallbacks(finished.append, log.err)
1350 self.failUnlessEqual(len(finished), 1)
1351 self.failUnlessEqual(finished[0], None)
1352 self.failUnlessCallsAre([ ( ("one",) , {} ) ])
1353 self.failUnlessEqual(p.gauge, 10)
1358 d = p.add(20, self.pause, "two", kw=2)
1359 # pipeline: [one, two]
1361 # the call and the Deferred should fire right away
1362 d.addCallbacks(finished.append, log.err)
1363 self.failUnlessEqual(len(finished), 1)
1364 self.failUnlessEqual(finished[0], None)
1365 self.failUnlessCallsAre([ ( ("one",) , {} ),
1366 ( ("two",) , {"kw": 2} ),
1368 self.failUnlessEqual(p.gauge, 30)
1370 self.calls[0][0].callback("one-result")
1372 self.failUnlessEqual(p.gauge, 20)
1375 d = p.add(90, self.pause, "three", "posarg1")
1376 # pipeline: [two, three]
1379 fd.addCallbacks(flushed.append, log.err)
1380 self.failUnlessEqual(flushed, [])
1382 # the call will be made right away, but the return Deferred will not,
1383 # because the pipeline is now full.
1384 d.addCallbacks(finished.append, log.err)
1385 self.failUnlessEqual(len(finished), 0)
1386 self.failUnlessCallsAre([ ( ("one",) , {} ),
1387 ( ("two",) , {"kw": 2} ),
1388 ( ("three", "posarg1"), {} ),
1390 self.failUnlessEqual(p.gauge, 110)
1392 self.failUnlessRaises(pipeline.SingleFileError, p.add, 10, self.pause)
1394 # retiring either call will unblock the pipeline, causing the #3
1396 self.calls[2][0].callback("three-result")
1399 self.failUnlessEqual(len(finished), 1)
1400 self.failUnlessEqual(finished[0], None)
1401 self.failUnlessEqual(flushed, [])
1403 # retiring call#2 will finally allow the flush() Deferred to fire
1404 self.calls[1][0].callback("two-result")
1405 self.failUnlessEqual(len(flushed), 1)
1407 def test_errors(self):
1409 p = pipeline.Pipeline(100)
1411 d1 = p.add(200, self.pause, "one")
1415 d1.addBoth(finished.append)
1416 self.failUnlessEqual(finished, [])
1419 d2.addBoth(flushed.append)
1420 self.failUnlessEqual(flushed, [])
1422 self.calls[0][0].errback(ValueError("oops"))
1424 self.failUnlessEqual(len(finished), 1)
1426 self.failUnless(isinstance(f, Failure))
1427 self.failUnless(f.check(pipeline.PipelineError))
1428 self.failUnlessIn("PipelineError", str(f.value))
1429 self.failUnlessIn("ValueError", str(f.value))
1431 self.failUnless("ValueError" in r, r)
1433 self.failUnless(f2.check(ValueError))
1435 self.failUnlessEqual(len(flushed), 1)
1437 self.failUnless(isinstance(f, Failure))
1438 self.failUnless(f.check(pipeline.PipelineError))
1440 self.failUnless(f2.check(ValueError))
1442 # now that the pipeline is in the failed state, any new calls will
1445 d3 = p.add(20, self.pause, "two")
1448 d3.addBoth(finished.append)
1449 self.failUnlessEqual(len(finished), 1)
1451 self.failUnless(isinstance(f, Failure))
1452 self.failUnless(f.check(pipeline.PipelineError))
1454 self.failUnless("ValueError" in r, r)
1456 self.failUnless(f2.check(ValueError))
1460 d4.addBoth(flushed.append)
1461 self.failUnlessEqual(len(flushed), 1)
1463 self.failUnless(isinstance(f, Failure))
1464 self.failUnless(f.check(pipeline.PipelineError))
1466 self.failUnless(f2.check(ValueError))
1468 def test_errors2(self):
1470 p = pipeline.Pipeline(100)
1472 d1 = p.add(10, self.pause, "one")
1473 d2 = p.add(20, self.pause, "two")
1474 d3 = p.add(30, self.pause, "three")
1477 # one call fails, then the second one succeeds: make sure
1478 # ExpandableDeferredList tolerates the second one
1481 d4.addBoth(flushed.append)
1482 self.failUnlessEqual(flushed, [])
1484 self.calls[0][0].errback(ValueError("oops"))
1485 self.failUnlessEqual(len(flushed), 1)
1487 self.failUnless(isinstance(f, Failure))
1488 self.failUnless(f.check(pipeline.PipelineError))
1490 self.failUnless(f2.check(ValueError))
1492 self.calls[1][0].callback("two-result")
1493 self.calls[2][0].errback(ValueError("three-error"))
1497 class SampleError(Exception):
1500 class Log(unittest.TestCase):
1502 if not hasattr(self, "flushLoggedErrors"):
1503 # without flushLoggedErrors, we can't get rid of the
1504 # twisted.log.err that tahoe_log records, so we can't keep this
1505 # test from [ERROR]ing
1506 raise unittest.SkipTest("needs flushLoggedErrors from Twisted-2.5.0")
1508 raise SampleError("simple sample")
1511 tahoe_log.err(format="intentional sample error",
1512 failure=f, level=tahoe_log.OPERATIONAL, umid="wO9UoQ")
1513 self.flushLoggedErrors(SampleError)