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")
923 def __init__(self, x):
928 return "<%s %s>" % (self.__class__.__name__, self.x,)
931 def __le__(self, other):
932 return self.x <= other
933 def __lt__(self, other):
934 return self.x < other
935 def __ge__(self, other):
936 return self.x >= other
937 def __gt__(self, other):
938 return self.x > other
939 def __ne__(self, other):
940 return self.x != other
941 def __eq__(self, other):
942 return self.x == other
944 class DictUtil(unittest.TestCase):
945 def _help_test_empty_dict(self, klass):
949 self.failUnless(d1 == d2, "d1: %r, d2: %r" % (d1, d2,))
950 self.failUnless(len(d1) == 0)
951 self.failUnless(len(d2) == 0)
953 def _help_test_nonempty_dict(self, klass):
954 d1 = klass({'a': 1, 'b': "eggs", 3: "spam",})
955 d2 = klass({'a': 1, 'b': "eggs", 3: "spam",})
957 self.failUnless(d1 == d2)
958 self.failUnless(len(d1) == 3, "%s, %s" % (len(d1), d1,))
959 self.failUnless(len(d2) == 3)
961 def _help_test_eq_but_notis(self, klass):
962 d = klass({'a': 3, 'b': EqButNotIs(3), 'c': 3})
967 d['b'] = EqButNotIs(3)
972 d['b'] = EqButNotIs(3)
978 d['a'] = EqButNotIs(3)
983 fake3 = EqButNotIs(3)
984 fake7 = EqButNotIs(7)
988 self.failUnless(filter(lambda x: x is 8, d.itervalues()))
989 self.failUnless(filter(lambda x: x is fake7, d.itervalues()))
990 # The real 7 should have been ejected by the d[3] = 8.
991 self.failUnless(not filter(lambda x: x is 7, d.itervalues()))
992 self.failUnless(filter(lambda x: x is fake3, d.iterkeys()))
993 self.failUnless(filter(lambda x: x is 3, d.iterkeys()))
998 fake3 = EqButNotIs(3)
999 fake7 = EqButNotIs(7)
1002 self.failUnless(filter(lambda x: x is 8, d.itervalues()))
1003 self.failUnless(filter(lambda x: x is fake7, d.itervalues()))
1004 # The real 7 should have been ejected by the d[3] = 8.
1005 self.failUnless(not filter(lambda x: x is 7, d.itervalues()))
1006 self.failUnless(filter(lambda x: x is fake3, d.iterkeys()))
1007 self.failUnless(filter(lambda x: x is 3, d.iterkeys()))
1011 self._help_test_eq_but_notis(dictutil.UtilDict)
1012 self._help_test_eq_but_notis(dictutil.NumDict)
1013 self._help_test_eq_but_notis(dictutil.ValueOrderedDict)
1014 self._help_test_nonempty_dict(dictutil.UtilDict)
1015 self._help_test_nonempty_dict(dictutil.NumDict)
1016 self._help_test_nonempty_dict(dictutil.ValueOrderedDict)
1017 self._help_test_eq_but_notis(dictutil.UtilDict)
1018 self._help_test_eq_but_notis(dictutil.NumDict)
1019 self._help_test_eq_but_notis(dictutil.ValueOrderedDict)
1021 def test_dict_of_sets(self):
1022 ds = dictutil.DictOfSets()
1027 self.failUnlessEqual(ds[1], set(["a"]))
1028 self.failUnlessEqual(ds[2], set(["b", "c"]))
1029 ds.discard(3, "d") # should not raise an exception
1031 self.failUnlessEqual(ds[2], set(["c"]))
1033 self.failIf(2 in ds)
1035 ds.union(1, ["a", "e"])
1037 self.failUnlessEqual(ds[1], set(["a","e"]))
1038 self.failUnlessEqual(ds[3], set(["f"]))
1039 ds2 = dictutil.DictOfSets()
1044 self.failUnlessEqual(ds[1], set(["a","e"]))
1045 self.failUnlessEqual(ds[3], set(["f", "g"]))
1046 self.failUnlessEqual(ds[4], set(["h"]))
1048 def test_move(self):
1049 d1 = {1: "a", 2: "b"}
1050 d2 = {2: "c", 3: "d"}
1051 dictutil.move(1, d1, d2)
1052 self.failUnlessEqual(d1, {2: "b"})
1053 self.failUnlessEqual(d2, {1: "a", 2: "c", 3: "d"})
1055 d1 = {1: "a", 2: "b"}
1056 d2 = {2: "c", 3: "d"}
1057 dictutil.move(2, d1, d2)
1058 self.failUnlessEqual(d1, {1: "a"})
1059 self.failUnlessEqual(d2, {2: "b", 3: "d"})
1061 d1 = {1: "a", 2: "b"}
1062 d2 = {2: "c", 3: "d"}
1063 self.failUnlessRaises(KeyError, dictutil.move, 5, d1, d2, strict=True)
1065 def test_subtract(self):
1066 d1 = {1: "a", 2: "b"}
1067 d2 = {2: "c", 3: "d"}
1068 d3 = dictutil.subtract(d1, d2)
1069 self.failUnlessEqual(d3, {1: "a"})
1071 d1 = {1: "a", 2: "b"}
1073 d3 = dictutil.subtract(d1, d2)
1074 self.failUnlessEqual(d3, {1: "a"})
1076 def test_utildict(self):
1077 d = dictutil.UtilDict({1: "a", 2: "b"})
1080 self.failUnlessEqual(d, {2: "b"})
1083 self.failUnlessRaises(TypeError, eq, d, "not a dict")
1085 d = dictutil.UtilDict({1: "b", 2: "a"})
1086 self.failUnlessEqual(d.items_sorted_by_value(),
1087 [(2, "a"), (1, "b")])
1088 self.failUnlessEqual(d.items_sorted_by_key(),
1089 [(1, "b"), (2, "a")])
1090 self.failUnlessEqual(repr(d), "{1: 'b', 2: 'a'}")
1091 self.failUnless(1 in d)
1093 d2 = dictutil.UtilDict({3: "c", 4: "d"})
1094 self.failUnless(d != d2)
1095 self.failUnless(d2 > d)
1096 self.failUnless(d2 >= d)
1097 self.failUnless(d <= d2)
1098 self.failUnless(d < d2)
1099 self.failUnlessEqual(d[1], "b")
1100 self.failUnlessEqual(sorted(list([k for k in d])), [1,2])
1103 self.failUnlessEqual(d, d3)
1104 self.failUnless(isinstance(d3, dictutil.UtilDict))
1106 d4 = d.fromkeys([3,4], "e")
1107 self.failUnlessEqual(d4, {3: "e", 4: "e"})
1109 self.failUnlessEqual(d.get(1), "b")
1110 self.failUnlessEqual(d.get(3), None)
1111 self.failUnlessEqual(d.get(3, "default"), "default")
1112 self.failUnlessEqual(sorted(list(d.items())),
1113 [(1, "b"), (2, "a")])
1114 self.failUnlessEqual(sorted(list(d.iteritems())),
1115 [(1, "b"), (2, "a")])
1116 self.failUnlessEqual(sorted(d.keys()), [1, 2])
1117 self.failUnlessEqual(sorted(d.values()), ["a", "b"])
1118 x = d.setdefault(1, "new")
1119 self.failUnlessEqual(x, "b")
1120 self.failUnlessEqual(d[1], "b")
1121 x = d.setdefault(3, "new")
1122 self.failUnlessEqual(x, "new")
1123 self.failUnlessEqual(d[3], "new")
1127 self.failUnless(x in [(1, "b"), (2, "a")])
1129 self.failUnless(x in [(1, "b"), (2, "a")])
1130 self.failUnlessRaises(KeyError, d.popitem)
1132 def test_numdict(self):
1133 d = dictutil.NumDict({"a": 1, "b": 2})
1135 d.add_num("a", 10, 5)
1136 d.add_num("c", 20, 5)
1138 self.failUnlessEqual(d, {"a": 11, "b": 2, "c": 25, "d": 30})
1140 d.subtract_num("a", 10)
1141 d.subtract_num("e", 10)
1142 d.subtract_num("f", 10, 15)
1143 self.failUnlessEqual(d, {"a": 1, "b": 2, "c": 25, "d": 30,
1146 self.failUnlessEqual(d.sum(), sum([1, 2, 25, 30, -10, 5]))
1148 d = dictutil.NumDict()
1152 self.failUnlessEqual(d, {"a": 2, "b": 6})
1156 self.failUnlessEqual(d, {"a": 1, "b": 6, "c": -1, "d": 4})
1157 self.failUnlessEqual(d.items_sorted_by_key(),
1158 [("a", 1), ("b", 6), ("c", -1), ("d", 4)])
1159 self.failUnlessEqual(d.items_sorted_by_value(),
1160 [("c", -1), ("a", 1), ("d", 4), ("b", 6)])
1161 self.failUnlessEqual(d.item_with_largest_value(), ("b", 6))
1163 d = dictutil.NumDict({"a": 1, "b": 2})
1164 self.failUnlessEqual(repr(d), "{'a': 1, 'b': 2}")
1165 self.failUnless("a" in d)
1167 d2 = dictutil.NumDict({"c": 3, "d": 4})
1168 self.failUnless(d != d2)
1169 self.failUnless(d2 > d)
1170 self.failUnless(d2 >= d)
1171 self.failUnless(d <= d2)
1172 self.failUnless(d < d2)
1173 self.failUnlessEqual(d["a"], 1)
1174 self.failUnlessEqual(sorted(list([k for k in d])), ["a","b"])
1177 self.failUnlessRaises(TypeError, eq, d, "not a dict")
1180 self.failUnlessEqual(d, d3)
1181 self.failUnless(isinstance(d3, dictutil.NumDict))
1183 d4 = d.fromkeys(["a","b"], 5)
1184 self.failUnlessEqual(d4, {"a": 5, "b": 5})
1186 self.failUnlessEqual(d.get("a"), 1)
1187 self.failUnlessEqual(d.get("c"), 0)
1188 self.failUnlessEqual(d.get("c", 5), 5)
1189 self.failUnlessEqual(sorted(list(d.items())),
1190 [("a", 1), ("b", 2)])
1191 self.failUnlessEqual(sorted(list(d.iteritems())),
1192 [("a", 1), ("b", 2)])
1193 self.failUnlessEqual(sorted(d.keys()), ["a", "b"])
1194 self.failUnlessEqual(sorted(d.values()), [1, 2])
1195 self.failUnless(d.has_key("a"))
1196 self.failIf(d.has_key("c"))
1198 x = d.setdefault("c", 3)
1199 self.failUnlessEqual(x, 3)
1200 self.failUnlessEqual(d["c"], 3)
1201 x = d.setdefault("c", 5)
1202 self.failUnlessEqual(x, 3)
1203 self.failUnlessEqual(d["c"], 3)
1207 self.failUnless(x in [("a", 1), ("b", 2)])
1209 self.failUnless(x in [("a", 1), ("b", 2)])
1210 self.failUnlessRaises(KeyError, d.popitem)
1213 d.update({"c": 4, "d": 5})
1214 self.failUnlessEqual(d, {"c": 4, "d": 5})
1216 def test_del_if_present(self):
1217 d = {1: "a", 2: "b"}
1218 dictutil.del_if_present(d, 1)
1219 dictutil.del_if_present(d, 3)
1220 self.failUnlessEqual(d, {2: "b"})
1222 def test_valueordereddict(self):
1223 d = dictutil.ValueOrderedDict()
1228 self.failUnlessEqual(d, {"a": 3, "b": 2, "c": 1})
1229 self.failUnlessEqual(d.items(), [("c", 1), ("b", 2), ("a", 3)])
1230 self.failUnlessEqual(d.values(), [1, 2, 3])
1231 self.failUnlessEqual(d.keys(), ["c", "b", "a"])
1232 self.failUnlessEqual(repr(d), "<ValueOrderedDict {c: 1, b: 2, a: 3}>")
1235 self.failIf(d == {"a": 4})
1236 self.failUnless(d != {"a": 4})
1238 x = d.setdefault("d", 0)
1239 self.failUnlessEqual(x, 0)
1240 self.failUnlessEqual(d["d"], 0)
1241 x = d.setdefault("d", -1)
1242 self.failUnlessEqual(x, 0)
1243 self.failUnlessEqual(d["d"], 0)
1245 x = d.remove("e", "default", False)
1246 self.failUnlessEqual(x, "default")
1247 self.failUnlessRaises(KeyError, d.remove, "e", "default", True)
1248 x = d.remove("d", 5)
1249 self.failUnlessEqual(x, 0)
1251 x = d.__getitem__("c")
1252 self.failUnlessEqual(x, 1)
1253 x = d.__getitem__("e", "default", False)
1254 self.failUnlessEqual(x, "default")
1255 self.failUnlessRaises(KeyError, d.__getitem__, "e", "default", True)
1257 self.failUnlessEqual(d.popitem(), ("c", 1))
1258 self.failUnlessEqual(d.popitem(), ("b", 2))
1259 self.failUnlessEqual(d.popitem(), ("a", 3))
1260 self.failUnlessRaises(KeyError, d.popitem)
1262 d = dictutil.ValueOrderedDict({"a": 3, "b": 2, "c": 1})
1263 x = d.pop("d", "default", False)
1264 self.failUnlessEqual(x, "default")
1265 self.failUnlessRaises(KeyError, d.pop, "d", "default", True)
1267 self.failUnlessEqual(x, 2)
1268 self.failUnlessEqual(d.items(), [("c", 1), ("a", 3)])
1270 d = dictutil.ValueOrderedDict({"a": 3, "b": 2, "c": 1})
1271 x = d.pop_from_list(1) # pop the second item, b/2
1272 self.failUnlessEqual(x, "b")
1273 self.failUnlessEqual(d.items(), [("c", 1), ("a", 3)])
1275 def test_auxdict(self):
1276 d = dictutil.AuxValueDict()
1277 # we put the serialized form in the auxdata
1278 d.set_with_aux("key", ("filecap", "metadata"), "serialized")
1280 self.failUnlessEqual(d.keys(), ["key"])
1281 self.failUnlessEqual(d["key"], ("filecap", "metadata"))
1282 self.failUnlessEqual(d.get_aux("key"), "serialized")
1283 def _get_missing(key):
1285 self.failUnlessRaises(KeyError, _get_missing, "nonkey")
1286 self.failUnlessEqual(d.get("nonkey"), None)
1287 self.failUnlessEqual(d.get("nonkey", "nonvalue"), "nonvalue")
1288 self.failUnlessEqual(d.get_aux("nonkey"), None)
1289 self.failUnlessEqual(d.get_aux("nonkey", "nonvalue"), "nonvalue")
1291 d["key"] = ("filecap2", "metadata2")
1292 self.failUnlessEqual(d["key"], ("filecap2", "metadata2"))
1293 self.failUnlessEqual(d.get_aux("key"), None)
1295 d.set_with_aux("key2", "value2", "aux2")
1296 self.failUnlessEqual(sorted(d.keys()), ["key", "key2"])
1298 self.failUnlessEqual(d.keys(), ["key"])
1299 self.failIf("key2" in d)
1300 self.failUnlessRaises(KeyError, _get_missing, "key2")
1301 self.failUnlessEqual(d.get("key2"), None)
1302 self.failUnlessEqual(d.get_aux("key2"), None)
1303 d["key2"] = "newvalue2"
1304 self.failUnlessEqual(d.get("key2"), "newvalue2")
1305 self.failUnlessEqual(d.get_aux("key2"), None)
1307 d = dictutil.AuxValueDict({1:2,3:4})
1308 self.failUnlessEqual(sorted(d.keys()), [1,3])
1309 self.failUnlessEqual(d[1], 2)
1310 self.failUnlessEqual(d.get_aux(1), None)
1312 d = dictutil.AuxValueDict([ (1,2), (3,4) ])
1313 self.failUnlessEqual(sorted(d.keys()), [1,3])
1314 self.failUnlessEqual(d[1], 2)
1315 self.failUnlessEqual(d.get_aux(1), None)
1317 d = dictutil.AuxValueDict(one=1, two=2)
1318 self.failUnlessEqual(sorted(d.keys()), ["one","two"])
1319 self.failUnlessEqual(d["one"], 1)
1320 self.failUnlessEqual(d.get_aux("one"), None)
1322 class Pipeline(unittest.TestCase):
1323 def pause(self, *args, **kwargs):
1324 d = defer.Deferred()
1325 self.calls.append( (d, args, kwargs) )
1328 def failUnlessCallsAre(self, expected):
1331 self.failUnlessEqual(len(self.calls), len(expected), self.calls)
1332 for i,c in enumerate(self.calls):
1333 self.failUnlessEqual(c[1:], expected[i], str(i))
1335 def test_basic(self):
1338 p = pipeline.Pipeline(100)
1340 d = p.flush() # fires immediately
1341 d.addCallbacks(finished.append, log.err)
1342 self.failUnlessEqual(len(finished), 1)
1345 d = p.add(10, self.pause, "one")
1346 # the call should start right away, and our return Deferred should
1348 d.addCallbacks(finished.append, log.err)
1349 self.failUnlessEqual(len(finished), 1)
1350 self.failUnlessEqual(finished[0], None)
1351 self.failUnlessCallsAre([ ( ("one",) , {} ) ])
1352 self.failUnlessEqual(p.gauge, 10)
1357 d = p.add(20, self.pause, "two", kw=2)
1358 # pipeline: [one, two]
1360 # the call and the Deferred should fire right away
1361 d.addCallbacks(finished.append, log.err)
1362 self.failUnlessEqual(len(finished), 1)
1363 self.failUnlessEqual(finished[0], None)
1364 self.failUnlessCallsAre([ ( ("one",) , {} ),
1365 ( ("two",) , {"kw": 2} ),
1367 self.failUnlessEqual(p.gauge, 30)
1369 self.calls[0][0].callback("one-result")
1371 self.failUnlessEqual(p.gauge, 20)
1374 d = p.add(90, self.pause, "three", "posarg1")
1375 # pipeline: [two, three]
1378 fd.addCallbacks(flushed.append, log.err)
1379 self.failUnlessEqual(flushed, [])
1381 # the call will be made right away, but the return Deferred will not,
1382 # because the pipeline is now full.
1383 d.addCallbacks(finished.append, log.err)
1384 self.failUnlessEqual(len(finished), 0)
1385 self.failUnlessCallsAre([ ( ("one",) , {} ),
1386 ( ("two",) , {"kw": 2} ),
1387 ( ("three", "posarg1"), {} ),
1389 self.failUnlessEqual(p.gauge, 110)
1391 self.failUnlessRaises(pipeline.SingleFileError, p.add, 10, self.pause)
1393 # retiring either call will unblock the pipeline, causing the #3
1395 self.calls[2][0].callback("three-result")
1398 self.failUnlessEqual(len(finished), 1)
1399 self.failUnlessEqual(finished[0], None)
1400 self.failUnlessEqual(flushed, [])
1402 # retiring call#2 will finally allow the flush() Deferred to fire
1403 self.calls[1][0].callback("two-result")
1404 self.failUnlessEqual(len(flushed), 1)
1406 def test_errors(self):
1408 p = pipeline.Pipeline(100)
1410 d1 = p.add(200, self.pause, "one")
1414 d1.addBoth(finished.append)
1415 self.failUnlessEqual(finished, [])
1418 d2.addBoth(flushed.append)
1419 self.failUnlessEqual(flushed, [])
1421 self.calls[0][0].errback(ValueError("oops"))
1423 self.failUnlessEqual(len(finished), 1)
1425 self.failUnless(isinstance(f, Failure))
1426 self.failUnless(f.check(pipeline.PipelineError))
1427 self.failUnlessIn("PipelineError", str(f.value))
1428 self.failUnlessIn("ValueError", str(f.value))
1430 self.failUnless("ValueError" in r, r)
1432 self.failUnless(f2.check(ValueError))
1434 self.failUnlessEqual(len(flushed), 1)
1436 self.failUnless(isinstance(f, Failure))
1437 self.failUnless(f.check(pipeline.PipelineError))
1439 self.failUnless(f2.check(ValueError))
1441 # now that the pipeline is in the failed state, any new calls will
1444 d3 = p.add(20, self.pause, "two")
1447 d3.addBoth(finished.append)
1448 self.failUnlessEqual(len(finished), 1)
1450 self.failUnless(isinstance(f, Failure))
1451 self.failUnless(f.check(pipeline.PipelineError))
1453 self.failUnless("ValueError" in r, r)
1455 self.failUnless(f2.check(ValueError))
1459 d4.addBoth(flushed.append)
1460 self.failUnlessEqual(len(flushed), 1)
1462 self.failUnless(isinstance(f, Failure))
1463 self.failUnless(f.check(pipeline.PipelineError))
1465 self.failUnless(f2.check(ValueError))
1467 def test_errors2(self):
1469 p = pipeline.Pipeline(100)
1471 d1 = p.add(10, self.pause, "one")
1472 d2 = p.add(20, self.pause, "two")
1473 d3 = p.add(30, self.pause, "three")
1476 # one call fails, then the second one succeeds: make sure
1477 # ExpandableDeferredList tolerates the second one
1480 d4.addBoth(flushed.append)
1481 self.failUnlessEqual(flushed, [])
1483 self.calls[0][0].errback(ValueError("oops"))
1484 self.failUnlessEqual(len(flushed), 1)
1486 self.failUnless(isinstance(f, Failure))
1487 self.failUnless(f.check(pipeline.PipelineError))
1489 self.failUnless(f2.check(ValueError))
1491 self.calls[1][0].callback("two-result")
1492 self.calls[2][0].errback(ValueError("three-error"))
1494 class SampleError(Exception):
1497 class Log(unittest.TestCase):
1499 if not hasattr(self, "flushLoggedErrors"):
1500 # without flushLoggedErrors, we can't get rid of the
1501 # twisted.log.err that tahoe_log records, so we can't keep this
1502 # test from [ERROR]ing
1503 raise unittest.SkipTest("needs flushLoggedErrors from Twisted-2.5.0")
1505 raise SampleError("simple sample")
1508 tahoe_log.err(format="intentional sample error",
1509 failure=f, level=tahoe_log.OPERATIONAL, umid="wO9UoQ")
1510 self.flushLoggedErrors(SampleError)