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
10 from pycryptopp.hash.sha256 import SHA256 as _hash
12 from allmydata.util import base32, idlib, humanreadable, mathutil, hashutil
13 from allmydata.util import assertutil, fileutil, deferredutil, abbreviate
14 from allmydata.util import limiter, time_format, pollmixin, cachedir
15 from allmydata.util import statistics, dictutil, pipeline
16 from allmydata.util import log as tahoe_log
17 from allmydata.util.spans import Spans, overlap, DataSpans
18 from allmydata.test.common_util import ReallyEqualMixin
21 class Base32(unittest.TestCase):
22 def test_b2a_matches_Pythons(self):
24 y = "\x12\x34\x45\x67\x89\x0a\xbc\xde\xf0"
25 x = base64.b32encode(y)
26 while x and x[-1] == '=':
29 self.failUnlessEqual(base32.b2a(y), x)
31 self.failUnlessEqual(base32.b2a("\x12\x34"), "ci2a")
32 def test_b2a_or_none(self):
33 self.failUnlessEqual(base32.b2a_or_none(None), None)
34 self.failUnlessEqual(base32.b2a_or_none("\x12\x34"), "ci2a")
36 self.failUnlessEqual(base32.a2b("ci2a"), "\x12\x34")
37 self.failUnlessRaises(AssertionError, base32.a2b, "b0gus")
39 class IDLib(unittest.TestCase):
40 def test_nodeid_b2a(self):
41 self.failUnlessEqual(idlib.nodeid_b2a("\x00"*20), "a"*32)
43 class NoArgumentException(Exception):
47 class HumanReadable(unittest.TestCase):
50 self.failUnlessEqual(hr(foo), "<foo() at test_util.py:2>")
51 self.failUnlessEqual(hr(self.test_repr),
52 "<bound method HumanReadable.test_repr of <allmydata.test.test_util.HumanReadable testMethod=test_repr>>")
53 self.failUnlessEqual(hr(1L), "1")
54 self.failUnlessEqual(hr(10**40),
55 "100000000000000000...000000000000000000")
56 self.failUnlessEqual(hr(self), "<allmydata.test.test_util.HumanReadable testMethod=test_repr>")
57 self.failUnlessEqual(hr([1,2]), "[1, 2]")
58 self.failUnlessEqual(hr({1:2}), "{1:2}")
63 hr(e) == "<ValueError: ()>" # python-2.4
64 or hr(e) == "ValueError()") # python-2.5
66 raise ValueError("oops")
69 hr(e) == "<ValueError: 'oops'>" # python-2.4
70 or hr(e) == "ValueError('oops',)") # python-2.5
72 raise NoArgumentException
75 hr(e) == "<NoArgumentException>" # python-2.4
76 or hr(e) == "NoArgumentException()") # python-2.5
82 class Math(unittest.TestCase):
83 def test_div_ceil(self):
85 self.failUnlessEqual(f(0, 1), 0)
86 self.failUnlessEqual(f(0, 2), 0)
87 self.failUnlessEqual(f(0, 3), 0)
88 self.failUnlessEqual(f(1, 3), 1)
89 self.failUnlessEqual(f(2, 3), 1)
90 self.failUnlessEqual(f(3, 3), 1)
91 self.failUnlessEqual(f(4, 3), 2)
92 self.failUnlessEqual(f(5, 3), 2)
93 self.failUnlessEqual(f(6, 3), 2)
94 self.failUnlessEqual(f(7, 3), 3)
96 def test_next_multiple(self):
97 f = mathutil.next_multiple
98 self.failUnlessEqual(f(5, 1), 5)
99 self.failUnlessEqual(f(5, 2), 6)
100 self.failUnlessEqual(f(5, 3), 6)
101 self.failUnlessEqual(f(5, 4), 8)
102 self.failUnlessEqual(f(5, 5), 5)
103 self.failUnlessEqual(f(5, 6), 6)
104 self.failUnlessEqual(f(32, 1), 32)
105 self.failUnlessEqual(f(32, 2), 32)
106 self.failUnlessEqual(f(32, 3), 33)
107 self.failUnlessEqual(f(32, 4), 32)
108 self.failUnlessEqual(f(32, 5), 35)
109 self.failUnlessEqual(f(32, 6), 36)
110 self.failUnlessEqual(f(32, 7), 35)
111 self.failUnlessEqual(f(32, 8), 32)
112 self.failUnlessEqual(f(32, 9), 36)
113 self.failUnlessEqual(f(32, 10), 40)
114 self.failUnlessEqual(f(32, 11), 33)
115 self.failUnlessEqual(f(32, 12), 36)
116 self.failUnlessEqual(f(32, 13), 39)
117 self.failUnlessEqual(f(32, 14), 42)
118 self.failUnlessEqual(f(32, 15), 45)
119 self.failUnlessEqual(f(32, 16), 32)
120 self.failUnlessEqual(f(32, 17), 34)
121 self.failUnlessEqual(f(32, 18), 36)
122 self.failUnlessEqual(f(32, 589), 589)
124 def test_pad_size(self):
125 f = mathutil.pad_size
126 self.failUnlessEqual(f(0, 4), 0)
127 self.failUnlessEqual(f(1, 4), 3)
128 self.failUnlessEqual(f(2, 4), 2)
129 self.failUnlessEqual(f(3, 4), 1)
130 self.failUnlessEqual(f(4, 4), 0)
131 self.failUnlessEqual(f(5, 4), 3)
133 def test_is_power_of_k(self):
134 f = mathutil.is_power_of_k
135 for i in range(1, 100):
136 if i in (1, 2, 4, 8, 16, 32, 64):
137 self.failUnless(f(i, 2), "but %d *is* a power of 2" % i)
139 self.failIf(f(i, 2), "but %d is *not* a power of 2" % i)
140 for i in range(1, 100):
141 if i in (1, 3, 9, 27, 81):
142 self.failUnless(f(i, 3), "but %d *is* a power of 3" % i)
144 self.failIf(f(i, 3), "but %d is *not* a power of 3" % i)
146 def test_next_power_of_k(self):
147 f = mathutil.next_power_of_k
148 self.failUnlessEqual(f(0,2), 1)
149 self.failUnlessEqual(f(1,2), 1)
150 self.failUnlessEqual(f(2,2), 2)
151 self.failUnlessEqual(f(3,2), 4)
152 self.failUnlessEqual(f(4,2), 4)
153 for i in range(5, 8): self.failUnlessEqual(f(i,2), 8, "%d" % i)
154 for i in range(9, 16): self.failUnlessEqual(f(i,2), 16, "%d" % i)
155 for i in range(17, 32): self.failUnlessEqual(f(i,2), 32, "%d" % i)
156 for i in range(33, 64): self.failUnlessEqual(f(i,2), 64, "%d" % i)
157 for i in range(65, 100): self.failUnlessEqual(f(i,2), 128, "%d" % i)
159 self.failUnlessEqual(f(0,3), 1)
160 self.failUnlessEqual(f(1,3), 1)
161 self.failUnlessEqual(f(2,3), 3)
162 self.failUnlessEqual(f(3,3), 3)
163 for i in range(4, 9): self.failUnlessEqual(f(i,3), 9, "%d" % i)
164 for i in range(10, 27): self.failUnlessEqual(f(i,3), 27, "%d" % i)
165 for i in range(28, 81): self.failUnlessEqual(f(i,3), 81, "%d" % i)
166 for i in range(82, 200): self.failUnlessEqual(f(i,3), 243, "%d" % i)
170 self.failUnlessEqual(f([1,2,3]), 2)
171 self.failUnlessEqual(f([0,0,0,4]), 1)
172 self.failUnlessAlmostEqual(f([0.0, 1.0, 1.0]), .666666666666)
174 def test_round_sigfigs(self):
175 f = mathutil.round_sigfigs
176 self.failUnlessEqual(f(22.0/3, 4), 7.3330000000000002)
178 class Statistics(unittest.TestCase):
179 def should_assert(self, msg, func, *args, **kwargs):
181 func(*args, **kwargs)
183 except AssertionError:
186 def failUnlessListEqual(self, a, b, msg = None):
187 self.failUnlessEqual(len(a), len(b))
188 for i in range(len(a)):
189 self.failUnlessEqual(a[i], b[i], msg)
191 def failUnlessListAlmostEqual(self, a, b, places = 7, msg = None):
192 self.failUnlessEqual(len(a), len(b))
193 for i in range(len(a)):
194 self.failUnlessAlmostEqual(a[i], b[i], places, msg)
196 def test_binomial_coeff(self):
197 f = statistics.binomial_coeff
198 self.failUnlessEqual(f(20, 0), 1)
199 self.failUnlessEqual(f(20, 1), 20)
200 self.failUnlessEqual(f(20, 2), 190)
201 self.failUnlessEqual(f(20, 8), f(20, 12))
202 self.should_assert("Should assert if n < k", f, 2, 3)
204 def test_binomial_distribution_pmf(self):
205 f = statistics.binomial_distribution_pmf
208 pmf_stat = [0.81, 0.18, 0.01]
209 self.failUnlessListAlmostEqual(pmf_comp, pmf_stat)
211 # Summing across a PMF should give the total probability 1
212 self.failUnlessAlmostEqual(sum(pmf_comp), 1)
213 self.should_assert("Should assert if not 0<=p<=1", f, 1, -1)
214 self.should_assert("Should assert if n < 1", f, 0, .1)
217 statistics.print_pmf(pmf_comp, out=out)
218 lines = out.getvalue().splitlines()
219 self.failUnlessEqual(lines[0], "i=0: 0.81")
220 self.failUnlessEqual(lines[1], "i=1: 0.18")
221 self.failUnlessEqual(lines[2], "i=2: 0.01")
223 def test_survival_pmf(self):
224 f = statistics.survival_pmf
225 # Cross-check binomial-distribution method against convolution
227 p_list = [.9999] * 100 + [.99] * 50 + [.8] * 20
228 pmf1 = statistics.survival_pmf_via_conv(p_list)
229 pmf2 = statistics.survival_pmf_via_bd(p_list)
230 self.failUnlessListAlmostEqual(pmf1, pmf2)
231 self.failUnlessTrue(statistics.valid_pmf(pmf1))
232 self.should_assert("Should assert if p_i > 1", f, [1.1]);
233 self.should_assert("Should assert if p_i < 0", f, [-.1]);
235 def test_repair_count_pmf(self):
236 survival_pmf = statistics.binomial_distribution_pmf(5, .9)
237 repair_pmf = statistics.repair_count_pmf(survival_pmf, 3)
238 # repair_pmf[0] == sum(survival_pmf[0,1,2,5])
239 # repair_pmf[1] == survival_pmf[4]
240 # repair_pmf[2] = survival_pmf[3]
241 self.failUnlessListAlmostEqual(repair_pmf,
242 [0.00001 + 0.00045 + 0.0081 + 0.59049,
247 def test_repair_cost(self):
248 survival_pmf = statistics.binomial_distribution_pmf(5, .9)
249 bwcost = statistics.bandwidth_cost_function
250 cost = statistics.mean_repair_cost(bwcost, 1000,
251 survival_pmf, 3, ul_dl_ratio=1.0)
252 self.failUnlessAlmostEqual(cost, 558.90)
253 cost = statistics.mean_repair_cost(bwcost, 1000,
254 survival_pmf, 3, ul_dl_ratio=8.0)
255 self.failUnlessAlmostEqual(cost, 1664.55)
257 # I haven't manually checked the math beyond here -warner
258 cost = statistics.eternal_repair_cost(bwcost, 1000,
260 discount_rate=0, ul_dl_ratio=1.0)
261 self.failUnlessAlmostEqual(cost, 65292.056074766246)
262 cost = statistics.eternal_repair_cost(bwcost, 1000,
266 self.failUnlessAlmostEqual(cost, 9133.6097158191551)
268 def test_convolve(self):
269 f = statistics.convolve
273 v1v2result = [ 4, 13, 28, 27, 18 ]
274 # Convolution is commutative
277 self.failUnlessListEqual(r1, r2, "Convolution should be commutative")
278 self.failUnlessListEqual(r1, v1v2result, "Didn't match known result")
279 # Convolution is associative
280 r1 = f(f(v1, v2), v3)
281 r2 = f(v1, f(v2, v3))
282 self.failUnlessListEqual(r1, r2, "Convolution should be associative")
283 # Convolution is distributive
284 r1 = f(v3, [ a + b for a, b in zip(v1, v2) ])
287 r2 = [ a + b for a, b in zip(tmp1, tmp2) ]
288 self.failUnlessListEqual(r1, r2, "Convolution should be distributive")
289 # Convolution is scalar multiplication associative
291 r1 = [ a * 4 for a in tmp1 ]
292 tmp2 = [ a * 4 for a in v1 ]
294 self.failUnlessListEqual(r1, r2, "Convolution should be scalar multiplication associative")
296 def test_find_k(self):
297 f = statistics.find_k
298 g = statistics.pr_file_loss
299 plist = [.9] * 10 + [.8] * 10 # N=20
302 self.failUnlessEqual(k, 10)
303 self.failUnless(g(plist, k) < t)
305 def test_pr_file_loss(self):
306 f = statistics.pr_file_loss
308 self.failUnlessEqual(f(plist, 3), .0546875)
310 def test_pr_backup_file_loss(self):
311 f = statistics.pr_backup_file_loss
313 self.failUnlessEqual(f(plist, .5, 3), .02734375)
316 class Asserts(unittest.TestCase):
317 def should_assert(self, func, *args, **kwargs):
319 func(*args, **kwargs)
320 except AssertionError, e:
323 self.fail("assert failed with non-AssertionError: %s" % e)
324 self.fail("assert was not caught")
326 def should_not_assert(self, func, *args, **kwargs):
328 func(*args, **kwargs)
329 except AssertionError, e:
330 self.fail("assertion fired when it should not have: %s" % e)
332 self.fail("assertion (which shouldn't have failed) failed with non-AssertionError: %s" % e)
336 def test_assert(self):
337 f = assertutil._assert
338 self.should_assert(f)
339 self.should_assert(f, False)
340 self.should_not_assert(f, True)
342 m = self.should_assert(f, False, "message")
343 self.failUnlessEqual(m, "'message' <type 'str'>", m)
344 m = self.should_assert(f, False, "message1", othermsg=12)
345 self.failUnlessEqual("'message1' <type 'str'>, othermsg: 12 <type 'int'>", m)
346 m = self.should_assert(f, False, othermsg="message2")
347 self.failUnlessEqual("othermsg: 'message2' <type 'str'>", m)
349 def test_precondition(self):
350 f = assertutil.precondition
351 self.should_assert(f)
352 self.should_assert(f, False)
353 self.should_not_assert(f, True)
355 m = self.should_assert(f, False, "message")
356 self.failUnlessEqual("precondition: 'message' <type 'str'>", m)
357 m = self.should_assert(f, False, "message1", othermsg=12)
358 self.failUnlessEqual("precondition: 'message1' <type 'str'>, othermsg: 12 <type 'int'>", m)
359 m = self.should_assert(f, False, othermsg="message2")
360 self.failUnlessEqual("precondition: othermsg: 'message2' <type 'str'>", m)
362 def test_postcondition(self):
363 f = assertutil.postcondition
364 self.should_assert(f)
365 self.should_assert(f, False)
366 self.should_not_assert(f, True)
368 m = self.should_assert(f, False, "message")
369 self.failUnlessEqual("postcondition: 'message' <type 'str'>", m)
370 m = self.should_assert(f, False, "message1", othermsg=12)
371 self.failUnlessEqual("postcondition: 'message1' <type 'str'>, othermsg: 12 <type 'int'>", m)
372 m = self.should_assert(f, False, othermsg="message2")
373 self.failUnlessEqual("postcondition: othermsg: 'message2' <type 'str'>", m)
375 class FileUtil(ReallyEqualMixin, unittest.TestCase):
376 def mkdir(self, basedir, path, mode=0777):
377 fn = os.path.join(basedir, path)
378 fileutil.make_dirs(fn, mode)
380 def touch(self, basedir, path, mode=None, data="touch\n"):
381 fn = os.path.join(basedir, path)
388 def test_rm_dir(self):
389 basedir = "util/FileUtil/test_rm_dir"
390 fileutil.make_dirs(basedir)
391 # create it again to test idempotency
392 fileutil.make_dirs(basedir)
393 d = os.path.join(basedir, "doomed")
395 self.touch(d, "a/b/1.txt")
396 self.touch(d, "a/b/2.txt", 0444)
397 self.touch(d, "a/b/3.txt", 0)
399 self.touch(d, "a/c/1.txt")
400 self.touch(d, "a/c/2.txt", 0444)
401 self.touch(d, "a/c/3.txt", 0)
402 os.chmod(os.path.join(d, "a/c"), 0444)
404 self.touch(d, "a/d/1.txt")
405 self.touch(d, "a/d/2.txt", 0444)
406 self.touch(d, "a/d/3.txt", 0)
407 os.chmod(os.path.join(d, "a/d"), 0)
410 self.failIf(os.path.exists(d))
411 # remove it again to test idempotency
414 def test_remove_if_possible(self):
415 basedir = "util/FileUtil/test_remove_if_possible"
416 fileutil.make_dirs(basedir)
417 self.touch(basedir, "here")
418 fn = os.path.join(basedir, "here")
419 fileutil.remove_if_possible(fn)
420 self.failIf(os.path.exists(fn))
421 fileutil.remove_if_possible(fn) # should be idempotent
422 fileutil.rm_dir(basedir)
423 fileutil.remove_if_possible(fn) # should survive errors
425 def test_write_atomically(self):
426 basedir = "util/FileUtil/test_write_atomically"
427 fileutil.make_dirs(basedir)
428 fn = os.path.join(basedir, "here")
429 fileutil.write_atomically(fn, "one")
430 self.failUnlessEqual(fileutil.read(fn), "one")
431 fileutil.write_atomically(fn, "two", mode="") # non-binary
432 self.failUnlessEqual(fileutil.read(fn), "two")
434 def test_rename(self):
435 basedir = "util/FileUtil/test_rename"
436 fileutil.make_dirs(basedir)
437 self.touch(basedir, "here")
438 fn = os.path.join(basedir, "here")
439 fn2 = os.path.join(basedir, "there")
440 fileutil.rename(fn, fn2)
441 self.failIf(os.path.exists(fn))
442 self.failUnless(os.path.exists(fn2))
444 def test_rename_no_overwrite(self):
445 workdir = fileutil.abspath_expanduser_unicode(u"test_rename_no_overwrite")
446 fileutil.make_dirs(workdir)
448 source_path = os.path.join(workdir, "source")
449 dest_path = os.path.join(workdir, "dest")
451 # when neither file exists
452 self.failUnlessRaises(OSError, fileutil.rename_no_overwrite, source_path, dest_path)
454 # when only dest exists
455 fileutil.write(dest_path, "dest")
456 self.failUnlessRaises(OSError, fileutil.rename_no_overwrite, source_path, dest_path)
457 self.failUnlessEqual(fileutil.read(dest_path), "dest")
460 fileutil.write(source_path, "source")
461 self.failUnlessRaises(OSError, fileutil.rename_no_overwrite, source_path, dest_path)
462 self.failUnlessEqual(fileutil.read(source_path), "source")
463 self.failUnlessEqual(fileutil.read(dest_path), "dest")
465 # when only source exists
467 fileutil.rename_no_overwrite(source_path, dest_path)
468 self.failUnlessEqual(fileutil.read(dest_path), "source")
469 self.failIf(os.path.exists(source_path))
471 def test_replace_file(self):
472 workdir = fileutil.abspath_expanduser_unicode(u"test_replace_file")
473 fileutil.make_dirs(workdir)
475 backup_path = os.path.join(workdir, "backup")
476 replaced_path = os.path.join(workdir, "replaced")
477 replacement_path = os.path.join(workdir, "replacement")
479 # when none of the files exist
480 self.failUnlessRaises(fileutil.ConflictError, fileutil.replace_file, replaced_path, replacement_path, backup_path)
482 # when only replaced exists
483 fileutil.write(replaced_path, "foo")
484 self.failUnlessRaises(fileutil.ConflictError, fileutil.replace_file, replaced_path, replacement_path, backup_path)
485 self.failUnlessEqual(fileutil.read(replaced_path), "foo")
487 # when both replaced and replacement exist, but not backup
488 fileutil.write(replacement_path, "bar")
489 fileutil.replace_file(replaced_path, replacement_path, backup_path)
490 self.failUnlessEqual(fileutil.read(backup_path), "foo")
491 self.failUnlessEqual(fileutil.read(replaced_path), "bar")
492 self.failIf(os.path.exists(replacement_path))
494 # when only replacement exists
495 os.remove(backup_path)
496 os.remove(replaced_path)
497 fileutil.write(replacement_path, "bar")
498 fileutil.replace_file(replaced_path, replacement_path, backup_path)
499 self.failUnlessEqual(fileutil.read(replaced_path), "bar")
500 self.failIf(os.path.exists(replacement_path))
501 self.failIf(os.path.exists(backup_path))
503 # when replaced, replacement and backup all exist
504 fileutil.write(replaced_path, "foo")
505 fileutil.write(replacement_path, "bar")
506 fileutil.write(backup_path, "bak")
507 fileutil.replace_file(replaced_path, replacement_path, backup_path)
508 self.failUnlessEqual(fileutil.read(backup_path), "foo")
509 self.failUnlessEqual(fileutil.read(replaced_path), "bar")
510 self.failIf(os.path.exists(replacement_path))
513 basedir = "util/FileUtil/test_du"
514 fileutil.make_dirs(basedir)
515 d = os.path.join(basedir, "space-consuming")
517 self.touch(d, "a/b/1.txt", data="a"*10)
518 self.touch(d, "a/b/2.txt", data="b"*11)
520 self.touch(d, "a/c/1.txt", data="c"*12)
521 self.touch(d, "a/c/2.txt", data="d"*13)
523 used = fileutil.du(basedir)
524 self.failUnlessEqual(10+11+12+13, used)
526 def test_abspath_expanduser_unicode(self):
527 self.failUnlessRaises(AssertionError, fileutil.abspath_expanduser_unicode, "bytestring")
529 saved_cwd = os.path.normpath(os.getcwdu())
530 abspath_cwd = fileutil.abspath_expanduser_unicode(u".")
531 self.failUnless(isinstance(saved_cwd, unicode), saved_cwd)
532 self.failUnless(isinstance(abspath_cwd, unicode), abspath_cwd)
533 if sys.platform == "win32":
534 self.failUnlessReallyEqual(abspath_cwd, fileutil.to_windows_long_path(saved_cwd))
536 self.failUnlessReallyEqual(abspath_cwd, saved_cwd)
538 self.failUnlessReallyEqual(fileutil.to_windows_long_path(u"\\\\?\\foo"), u"\\\\?\\foo")
539 self.failUnlessReallyEqual(fileutil.to_windows_long_path(u"\\\\.\\foo"), u"\\\\.\\foo")
540 self.failUnlessReallyEqual(fileutil.to_windows_long_path(u"\\\\server\\foo"), u"\\\\?\\UNC\\server\\foo")
541 self.failUnlessReallyEqual(fileutil.to_windows_long_path(u"C:\\foo"), u"\\\\?\\C:\\foo")
542 self.failUnlessReallyEqual(fileutil.to_windows_long_path(u"C:\\foo/bar"), u"\\\\?\\C:\\foo\\bar")
544 # adapted from <http://svn.python.org/view/python/branches/release26-maint/Lib/test/test_posixpath.py?view=markup&pathrev=78279#test_abspath>
546 foo = fileutil.abspath_expanduser_unicode(u"foo")
547 self.failUnless(foo.endswith(u"%sfoo" % (os.path.sep,)), foo)
549 foobar = fileutil.abspath_expanduser_unicode(u"bar", base=foo)
550 self.failUnless(foobar.endswith(u"%sfoo%sbar" % (os.path.sep, os.path.sep)), foobar)
552 if sys.platform == "win32":
553 # This is checking that a drive letter is added for a path without one.
554 baz = fileutil.abspath_expanduser_unicode(u"\\baz")
555 self.failUnless(baz.startswith(u"\\\\?\\"), baz)
556 self.failUnlessReallyEqual(baz[5 :], u":\\baz")
558 bar = fileutil.abspath_expanduser_unicode(u"\\bar", base=baz)
559 self.failUnless(bar.startswith(u"\\\\?\\"), bar)
560 self.failUnlessReallyEqual(bar[5 :], u":\\bar")
561 # not u":\\baz\\bar", because \bar is absolute on the current drive.
563 self.failUnlessReallyEqual(baz[4], bar[4]) # same drive
565 self.failIfIn(u"~", fileutil.abspath_expanduser_unicode(u"~"))
569 cwds.append(u'\xe7w\xf0'.encode(sys.getfilesystemencoding()
571 except UnicodeEncodeError:
572 pass # the cwd can't be encoded -- test with ascii cwd only
578 for upath in (u'', u'fuu', u'f\xf9\xf9', u'/fuu', u'U:\\', u'~'):
579 uabspath = fileutil.abspath_expanduser_unicode(upath)
580 self.failUnless(isinstance(uabspath, unicode), uabspath)
584 def test_create_long_path(self):
585 workdir = u"test_create_long_path"
586 fileutil.make_dirs(workdir)
587 long_path = fileutil.abspath_expanduser_unicode(os.path.join(workdir, u'x'*255))
589 fileutil.remove(long_path)
590 self.addCleanup(_cleanup)
592 fileutil.write(long_path, "test")
593 self.failUnless(os.path.exists(long_path))
594 self.failUnlessEqual(fileutil.read(long_path), "test")
596 self.failIf(os.path.exists(long_path))
598 def _test_windows_expanduser(self, userprofile=None, homedrive=None, homepath=None):
599 def call_windows_getenv(name):
600 if name == u"USERPROFILE": return userprofile
601 if name == u"HOMEDRIVE": return homedrive
602 if name == u"HOMEPATH": return homepath
603 self.fail("unexpected argument to call_windows_getenv")
604 self.patch(fileutil, 'windows_getenv', call_windows_getenv)
606 self.failUnlessReallyEqual(fileutil.windows_expanduser(u"~"), os.path.join(u"C:", u"\\Documents and Settings\\\u0100"))
607 self.failUnlessReallyEqual(fileutil.windows_expanduser(u"~\\foo"), os.path.join(u"C:", u"\\Documents and Settings\\\u0100", u"foo"))
608 self.failUnlessReallyEqual(fileutil.windows_expanduser(u"~/foo"), os.path.join(u"C:", u"\\Documents and Settings\\\u0100", u"foo"))
609 self.failUnlessReallyEqual(fileutil.windows_expanduser(u"a"), u"a")
610 self.failUnlessReallyEqual(fileutil.windows_expanduser(u"a~"), u"a~")
611 self.failUnlessReallyEqual(fileutil.windows_expanduser(u"a\\~\\foo"), u"a\\~\\foo")
613 def test_windows_expanduser_xp(self):
614 return self._test_windows_expanduser(homedrive=u"C:", homepath=u"\\Documents and Settings\\\u0100")
616 def test_windows_expanduser_win7(self):
617 return self._test_windows_expanduser(userprofile=os.path.join(u"C:", u"\\Documents and Settings\\\u0100"))
619 def test_disk_stats(self):
620 avail = fileutil.get_available_space('.', 2**14)
622 raise unittest.SkipTest("This test will spuriously fail there is no disk space left.")
624 disk = fileutil.get_disk_stats('.', 2**13)
625 self.failUnless(disk['total'] > 0, disk['total'])
626 # we tolerate used==0 for a Travis-CI bug, see #2290
627 self.failUnless(disk['used'] >= 0, disk['used'])
628 self.failUnless(disk['free_for_root'] > 0, disk['free_for_root'])
629 self.failUnless(disk['free_for_nonroot'] > 0, disk['free_for_nonroot'])
630 self.failUnless(disk['avail'] > 0, disk['avail'])
632 def test_disk_stats_avail_nonnegative(self):
633 # This test will spuriously fail if you have more than 2^128
634 # bytes of available space on your filesystem.
635 disk = fileutil.get_disk_stats('.', 2**128)
636 self.failUnlessEqual(disk['avail'], 0)
638 def test_get_pathinfo(self):
639 basedir = "util/FileUtil/test_get_pathinfo"
640 fileutil.make_dirs(basedir)
643 self.mkdir(basedir, "a")
644 dirinfo = fileutil.get_pathinfo(basedir)
645 self.failUnlessTrue(dirinfo.isdir)
646 self.failUnlessTrue(dirinfo.exists)
647 self.failUnlessFalse(dirinfo.isfile)
648 self.failUnlessFalse(dirinfo.islink)
650 # create a file under the directory
651 f = os.path.join(basedir, "a", "1.txt")
652 self.touch(basedir, "a/1.txt", data="a"*10)
653 fileinfo = fileutil.get_pathinfo(f)
654 self.failUnlessTrue(fileinfo.isfile)
655 self.failUnlessTrue(fileinfo.exists)
656 self.failUnlessFalse(fileinfo.isdir)
657 self.failUnlessFalse(fileinfo.islink)
658 self.failUnlessEqual(fileinfo.size, 10)
660 # create a symlink under the directory a pointing to 1.txt
661 slname = os.path.join(basedir, "a", "linkto1.txt")
662 os.symlink(f, slname)
663 symlinkinfo = fileutil.get_pathinfo(slname)
664 self.failUnlessTrue(symlinkinfo.islink)
665 self.failUnlessTrue(symlinkinfo.exists)
666 self.failUnlessFalse(symlinkinfo.isfile)
667 self.failUnlessFalse(symlinkinfo.isdir)
669 # path at which nothing exists
670 dnename = os.path.join(basedir, "a", "doesnotexist")
672 dneinfo = fileutil.get_pathinfo(dnename, now=now)
673 self.failUnlessFalse(dneinfo.exists)
674 self.failUnlessFalse(dneinfo.isfile)
675 self.failUnlessFalse(dneinfo.isdir)
676 self.failUnlessFalse(dneinfo.islink)
677 self.failUnlessEqual(dneinfo.size, None)
678 self.failUnlessEqual(dneinfo.mtime, now)
679 self.failUnlessEqual(dneinfo.ctime, now)
682 class PollMixinTests(unittest.TestCase):
684 self.pm = pollmixin.PollMixin()
686 def test_PollMixin_True(self):
687 d = self.pm.poll(check_f=lambda : True,
691 def test_PollMixin_False_then_True(self):
692 i = iter([False, True])
693 d = self.pm.poll(check_f=i.next,
697 def test_timeout(self):
698 d = self.pm.poll(check_f=lambda: False,
702 self.fail("poll should have failed, not returned %s" % (res,))
704 f.trap(pollmixin.TimeoutError)
705 return None # success
706 d.addCallbacks(_suc, _err)
709 class DeferredUtilTests(unittest.TestCase, deferredutil.WaitForDelayedCallsMixin):
710 def test_gather_results(self):
711 d1 = defer.Deferred()
712 d2 = defer.Deferred()
713 res = deferredutil.gatherResults([d1, d2])
714 d1.errback(ValueError("BAD"))
716 self.fail("Should have errbacked, not resulted in %s" % (res,))
718 thef.trap(ValueError)
719 res.addCallbacks(_callb, _errb)
722 def test_success(self):
723 d1, d2 = defer.Deferred(), defer.Deferred()
726 dlss = deferredutil.DeferredListShouldSucceed([d1,d2])
727 dlss.addCallbacks(good.append, bad.append)
730 self.failUnlessEqual(good, [[1,2]])
731 self.failUnlessEqual(bad, [])
733 def test_failure(self):
734 d1, d2 = defer.Deferred(), defer.Deferred()
737 dlss = deferredutil.DeferredListShouldSucceed([d1,d2])
738 dlss.addCallbacks(good.append, bad.append)
739 d1.addErrback(lambda _ignore: None)
740 d2.addErrback(lambda _ignore: None)
742 d2.errback(ValueError())
743 self.failUnlessEqual(good, [])
744 self.failUnlessEqual(len(bad), 1)
746 self.failUnless(isinstance(f, Failure))
747 self.failUnless(f.check(ValueError))
749 def test_wait_for_delayed_calls(self):
751 This tests that 'wait_for_delayed_calls' does in fact wait for a
752 delayed call that is active when the test returns. If it didn't,
753 Trial would report an unclean reactor error for this test.
758 reactor.callLater(0.1, _trigger)
760 d = defer.succeed(None)
761 d.addBoth(self.wait_for_delayed_calls)
764 class HashUtilTests(unittest.TestCase):
766 def test_random_key(self):
767 k = hashutil.random_key()
768 self.failUnlessEqual(len(k), hashutil.KEYLEN)
770 def test_sha256d(self):
771 h1 = hashutil.tagged_hash("tag1", "value")
772 h2 = hashutil.tagged_hasher("tag1")
776 self.failUnlessEqual(h1, h2a)
777 self.failUnlessEqual(h2a, h2b)
779 def test_sha256d_truncated(self):
780 h1 = hashutil.tagged_hash("tag1", "value", 16)
781 h2 = hashutil.tagged_hasher("tag1", 16)
784 self.failUnlessEqual(len(h1), 16)
785 self.failUnlessEqual(len(h2), 16)
786 self.failUnlessEqual(h1, h2)
789 h1 = hashutil.convergence_hash(3, 10, 1000, "data", "secret")
790 h2 = hashutil.convergence_hasher(3, 10, 1000, "secret")
793 self.failUnlessEqual(h1, h2)
795 def test_hashers(self):
796 h1 = hashutil.block_hash("foo")
797 h2 = hashutil.block_hasher()
799 self.failUnlessEqual(h1, h2.digest())
801 h1 = hashutil.uri_extension_hash("foo")
802 h2 = hashutil.uri_extension_hasher()
804 self.failUnlessEqual(h1, h2.digest())
806 h1 = hashutil.plaintext_hash("foo")
807 h2 = hashutil.plaintext_hasher()
809 self.failUnlessEqual(h1, h2.digest())
811 h1 = hashutil.crypttext_hash("foo")
812 h2 = hashutil.crypttext_hasher()
814 self.failUnlessEqual(h1, h2.digest())
816 h1 = hashutil.crypttext_segment_hash("foo")
817 h2 = hashutil.crypttext_segment_hasher()
819 self.failUnlessEqual(h1, h2.digest())
821 h1 = hashutil.plaintext_segment_hash("foo")
822 h2 = hashutil.plaintext_segment_hasher()
824 self.failUnlessEqual(h1, h2.digest())
826 def test_timing_safe_compare(self):
827 self.failUnless(hashutil.timing_safe_compare("a", "a"))
828 self.failUnless(hashutil.timing_safe_compare("ab", "ab"))
829 self.failIf(hashutil.timing_safe_compare("a", "b"))
830 self.failIf(hashutil.timing_safe_compare("a", "aa"))
832 def _testknown(self, hashf, expected_a, *args):
834 got_a = base32.b2a(got)
835 self.failUnlessEqual(got_a, expected_a)
837 def test_known_answers(self):
838 # assert backwards compatibility
839 self._testknown(hashutil.storage_index_hash, "qb5igbhcc5esa6lwqorsy7e6am", "")
840 self._testknown(hashutil.block_hash, "msjr5bh4evuh7fa3zw7uovixfbvlnstr5b65mrerwfnvjxig2jvq", "")
841 self._testknown(hashutil.uri_extension_hash, "wthsu45q7zewac2mnivoaa4ulh5xvbzdmsbuyztq2a5fzxdrnkka", "")
842 self._testknown(hashutil.plaintext_hash, "5lz5hwz3qj3af7n6e3arblw7xzutvnd3p3fjsngqjcb7utf3x3da", "")
843 self._testknown(hashutil.crypttext_hash, "itdj6e4njtkoiavlrmxkvpreosscssklunhwtvxn6ggho4rkqwga", "")
844 self._testknown(hashutil.crypttext_segment_hash, "aovy5aa7jej6ym5ikgwyoi4pxawnoj3wtaludjz7e2nb5xijb7aa", "")
845 self._testknown(hashutil.plaintext_segment_hash, "4fdgf6qruaisyukhqcmoth4t3li6bkolbxvjy4awwcpprdtva7za", "")
846 self._testknown(hashutil.convergence_hash, "3mo6ni7xweplycin6nowynw2we", 3, 10, 100, "", "converge")
847 self._testknown(hashutil.my_renewal_secret_hash, "ujhr5k5f7ypkp67jkpx6jl4p47pyta7hu5m527cpcgvkafsefm6q", "")
848 self._testknown(hashutil.my_cancel_secret_hash, "rjwzmafe2duixvqy6h47f5wfrokdziry6zhx4smew4cj6iocsfaa", "")
849 self._testknown(hashutil.file_renewal_secret_hash, "hzshk2kf33gzbd5n3a6eszkf6q6o6kixmnag25pniusyaulqjnia", "", "si")
850 self._testknown(hashutil.file_cancel_secret_hash, "bfciwvr6w7wcavsngxzxsxxaszj72dej54n4tu2idzp6b74g255q", "", "si")
851 self._testknown(hashutil.bucket_renewal_secret_hash, "e7imrzgzaoashsncacvy3oysdd2m5yvtooo4gmj4mjlopsazmvuq", "", "\x00"*20)
852 self._testknown(hashutil.bucket_cancel_secret_hash, "dvdujeyxeirj6uux6g7xcf4lvesk632aulwkzjar7srildvtqwma", "", "\x00"*20)
853 self._testknown(hashutil.hmac, "c54ypfi6pevb3nvo6ba42jtglpkry2kbdopqsi7dgrm4r7tw5sra", "tag", "")
854 self._testknown(hashutil.mutable_rwcap_key_hash, "6rvn2iqrghii5n4jbbwwqqsnqu", "iv", "wk")
855 self._testknown(hashutil.ssk_writekey_hash, "ykpgmdbpgbb6yqz5oluw2q26ye", "")
856 self._testknown(hashutil.ssk_write_enabler_master_hash, "izbfbfkoait4dummruol3gy2bnixrrrslgye6ycmkuyujnenzpia", "")
857 self._testknown(hashutil.ssk_write_enabler_hash, "fuu2dvx7g6gqu5x22vfhtyed7p4pd47y5hgxbqzgrlyvxoev62tq", "wk", "\x00"*20)
858 self._testknown(hashutil.ssk_pubkey_fingerprint_hash, "3opzw4hhm2sgncjx224qmt5ipqgagn7h5zivnfzqycvgqgmgz35q", "")
859 self._testknown(hashutil.ssk_readkey_hash, "vugid4as6qbqgeq2xczvvcedai", "")
860 self._testknown(hashutil.ssk_readkey_data_hash, "73wsaldnvdzqaf7v4pzbr2ae5a", "iv", "rk")
861 self._testknown(hashutil.ssk_storage_index_hash, "j7icz6kigb6hxrej3tv4z7ayym", "")
864 class Abbreviate(unittest.TestCase):
866 a = abbreviate.abbreviate_time
867 self.failUnlessEqual(a(None), "unknown")
868 self.failUnlessEqual(a(0), "0 seconds")
869 self.failUnlessEqual(a(1), "1 second")
870 self.failUnlessEqual(a(2), "2 seconds")
871 self.failUnlessEqual(a(119), "119 seconds")
873 self.failUnlessEqual(a(2*MIN), "2 minutes")
874 self.failUnlessEqual(a(60*MIN), "60 minutes")
875 self.failUnlessEqual(a(179*MIN), "179 minutes")
877 self.failUnlessEqual(a(180*MIN), "3 hours")
878 self.failUnlessEqual(a(4*HOUR), "4 hours")
881 self.failUnlessEqual(a(2*DAY), "2 days")
882 self.failUnlessEqual(a(2*MONTH), "2 months")
884 self.failUnlessEqual(a(5*YEAR), "5 years")
886 def test_space(self):
887 tests_si = [(None, "unknown"),
894 (20*1000, "20.00 kB"),
895 (1024*1024, "1.05 MB"),
896 (1000*1000, "1.00 MB"),
897 (1000*1000*1000, "1.00 GB"),
898 (1000*1000*1000*1000, "1.00 TB"),
899 (1000*1000*1000*1000*1000, "1.00 PB"),
900 (1000*1000*1000*1000*1000*1000, "1.00 EB"),
901 (1234567890123456789, "1.23 EB"),
903 for (x, expected) in tests_si:
904 got = abbreviate.abbreviate_space(x, SI=True)
905 self.failUnlessEqual(got, expected)
907 tests_base1024 = [(None, "unknown"),
914 (20*1024, "20.00 kiB"),
915 (1000*1000, "976.56 kiB"),
916 (1024*1024, "1.00 MiB"),
917 (1024*1024*1024, "1.00 GiB"),
918 (1024*1024*1024*1024, "1.00 TiB"),
919 (1000*1000*1000*1000*1000, "909.49 TiB"),
920 (1024*1024*1024*1024*1024, "1.00 PiB"),
921 (1024*1024*1024*1024*1024*1024, "1.00 EiB"),
922 (1234567890123456789, "1.07 EiB"),
924 for (x, expected) in tests_base1024:
925 got = abbreviate.abbreviate_space(x, SI=False)
926 self.failUnlessEqual(got, expected)
928 self.failUnlessEqual(abbreviate.abbreviate_space_both(1234567),
929 "(1.23 MB, 1.18 MiB)")
931 def test_parse_space(self):
932 p = abbreviate.parse_abbreviated_size
933 self.failUnlessEqual(p(""), None)
934 self.failUnlessEqual(p(None), None)
935 self.failUnlessEqual(p("123"), 123)
936 self.failUnlessEqual(p("123B"), 123)
937 self.failUnlessEqual(p("2K"), 2000)
938 self.failUnlessEqual(p("2kb"), 2000)
939 self.failUnlessEqual(p("2KiB"), 2048)
940 self.failUnlessEqual(p("10MB"), 10*1000*1000)
941 self.failUnlessEqual(p("10MiB"), 10*1024*1024)
942 self.failUnlessEqual(p("5G"), 5*1000*1000*1000)
943 self.failUnlessEqual(p("4GiB"), 4*1024*1024*1024)
944 self.failUnlessEqual(p("3TB"), 3*1000*1000*1000*1000)
945 self.failUnlessEqual(p("3TiB"), 3*1024*1024*1024*1024)
946 self.failUnlessEqual(p("6PB"), 6*1000*1000*1000*1000*1000)
947 self.failUnlessEqual(p("6PiB"), 6*1024*1024*1024*1024*1024)
948 self.failUnlessEqual(p("9EB"), 9*1000*1000*1000*1000*1000*1000)
949 self.failUnlessEqual(p("9EiB"), 9*1024*1024*1024*1024*1024*1024)
951 e = self.failUnlessRaises(ValueError, p, "12 cubits")
952 self.failUnlessIn("12 cubits", str(e))
953 e = self.failUnlessRaises(ValueError, p, "1 BB")
954 self.failUnlessIn("1 BB", str(e))
955 e = self.failUnlessRaises(ValueError, p, "fhtagn")
956 self.failUnlessIn("fhtagn", str(e))
958 class Limiter(unittest.TestCase):
959 timeout = 480 # This takes longer than 240 seconds on Francois's arm box.
961 def job(self, i, foo):
962 self.calls.append( (i, foo) )
963 self.simultaneous += 1
964 self.peak_simultaneous = max(self.simultaneous, self.peak_simultaneous)
967 self.simultaneous -= 1
968 d.callback("done %d" % i)
969 reactor.callLater(1.0, _done)
972 def bad_job(self, i, foo):
973 raise ValueError("bad_job %d" % i)
975 def test_limiter(self):
977 self.simultaneous = 0
978 self.peak_simultaneous = 0
979 l = limiter.ConcurrencyLimiter()
982 dl.append(l.add(self.job, i, foo=str(i)))
983 d = defer.DeferredList(dl, fireOnOneErrback=True)
985 self.failUnlessEqual(self.simultaneous, 0)
986 self.failUnless(self.peak_simultaneous <= 10)
987 self.failUnlessEqual(len(self.calls), 20)
989 self.failUnless( (i, str(i)) in self.calls)
993 def test_errors(self):
995 self.simultaneous = 0
996 self.peak_simultaneous = 0
997 l = limiter.ConcurrencyLimiter()
1000 dl.append(l.add(self.job, i, foo=str(i)))
1001 d2 = l.add(self.bad_job, 21, "21")
1002 d = defer.DeferredList(dl, fireOnOneErrback=True)
1003 def _most_done(res):
1005 for (success, result) in res:
1006 self.failUnlessEqual(success, True)
1007 results.append(result)
1009 expected_results = ["done %d" % i for i in range(20)]
1010 expected_results.sort()
1011 self.failUnlessEqual(results, expected_results)
1012 self.failUnless(self.peak_simultaneous <= 10)
1013 self.failUnlessEqual(len(self.calls), 20)
1015 self.failUnless( (i, str(i)) in self.calls)
1017 self.fail("should have failed, not got %s" % (res,))
1020 self.failUnless("bad_job 21" in str(f))
1021 d2.addCallbacks(_good, _err)
1023 d.addCallback(_most_done)
1025 self.failUnlessEqual(self.simultaneous, 0)
1026 self.failUnless(self.peak_simultaneous <= 10)
1027 self.failUnlessEqual(len(self.calls), 20)
1029 self.failUnless( (i, str(i)) in self.calls)
1030 d.addCallback(_all_done)
1033 class TimeFormat(unittest.TestCase):
1034 def test_epoch(self):
1035 return self._help_test_epoch()
1037 def test_epoch_in_London(self):
1038 # Europe/London is a particularly troublesome timezone. Nowadays, its
1039 # offset from GMT is 0. But in 1970, its offset from GMT was 1.
1040 # (Apparently in 1970 Britain had redefined standard time to be GMT+1
1041 # and stayed in standard time all year round, whereas today
1042 # Europe/London standard time is GMT and Europe/London Daylight
1043 # Savings Time is GMT+1.) The current implementation of
1044 # time_format.iso_utc_time_to_localseconds() breaks if the timezone is
1045 # Europe/London. (As soon as this unit test is done then I'll change
1046 # that implementation to something that works even in this case...)
1047 origtz = os.environ.get('TZ')
1048 os.environ['TZ'] = "Europe/London"
1049 if hasattr(time, 'tzset'):
1052 return self._help_test_epoch()
1055 del os.environ['TZ']
1057 os.environ['TZ'] = origtz
1058 if hasattr(time, 'tzset'):
1061 def _help_test_epoch(self):
1062 origtzname = time.tzname
1063 s = time_format.iso_utc_time_to_seconds("1970-01-01T00:00:01")
1064 self.failUnlessEqual(s, 1.0)
1065 s = time_format.iso_utc_time_to_seconds("1970-01-01_00:00:01")
1066 self.failUnlessEqual(s, 1.0)
1067 s = time_format.iso_utc_time_to_seconds("1970-01-01 00:00:01")
1068 self.failUnlessEqual(s, 1.0)
1070 self.failUnlessEqual(time_format.iso_utc(1.0), "1970-01-01_00:00:01")
1071 self.failUnlessEqual(time_format.iso_utc(1.0, sep=" "),
1072 "1970-01-01 00:00:01")
1075 isostr = time_format.iso_utc(now)
1076 timestamp = time_format.iso_utc_time_to_seconds(isostr)
1077 self.failUnlessEqual(int(timestamp), int(now))
1081 self.failUnlessEqual(time_format.iso_utc(t=my_time),
1082 "1970-01-01_00:00:01")
1083 e = self.failUnlessRaises(ValueError,
1084 time_format.iso_utc_time_to_seconds,
1085 "invalid timestring")
1086 self.failUnless("not a complete ISO8601 timestamp" in str(e))
1087 s = time_format.iso_utc_time_to_seconds("1970-01-01_00:00:01.500")
1088 self.failUnlessEqual(s, 1.5)
1090 # Look for daylight-savings-related errors.
1091 thatmomentinmarch = time_format.iso_utc_time_to_seconds("2009-03-20 21:49:02.226536")
1092 self.failUnlessEqual(thatmomentinmarch, 1237585742.226536)
1093 self.failUnlessEqual(origtzname, time.tzname)
1095 def test_iso_utc(self):
1096 when = 1266760143.7841301
1097 out = time_format.iso_utc_date(when)
1098 self.failUnlessEqual(out, "2010-02-21")
1099 out = time_format.iso_utc_date(t=lambda: when)
1100 self.failUnlessEqual(out, "2010-02-21")
1101 out = time_format.iso_utc(when)
1102 self.failUnlessEqual(out, "2010-02-21_13:49:03.784130")
1103 out = time_format.iso_utc(when, sep="-")
1104 self.failUnlessEqual(out, "2010-02-21-13:49:03.784130")
1106 def test_parse_duration(self):
1107 p = time_format.parse_duration
1109 self.failUnlessEqual(p("1 day"), DAY)
1110 self.failUnlessEqual(p("2 days"), 2*DAY)
1111 self.failUnlessEqual(p("3 months"), 3*31*DAY)
1112 self.failUnlessEqual(p("4 mo"), 4*31*DAY)
1113 self.failUnlessEqual(p("5 years"), 5*365*DAY)
1114 e = self.failUnlessRaises(ValueError, p, "123")
1115 self.failUnlessIn("no unit (like day, month, or year) in '123'",
1118 def test_parse_date(self):
1119 self.failUnlessEqual(time_format.parse_date("2010-02-21"), 1266710400)
1121 def test_format_time(self):
1122 self.failUnlessEqual(time_format.format_time(time.gmtime(0)), '1970-01-01 00:00:00')
1123 self.failUnlessEqual(time_format.format_time(time.gmtime(60)), '1970-01-01 00:01:00')
1124 self.failUnlessEqual(time_format.format_time(time.gmtime(60*60)), '1970-01-01 01:00:00')
1125 seconds_per_day = 60*60*24
1126 leap_years_1970_to_2014_inclusive = ((2012 - 1968) // 4)
1127 self.failUnlessEqual(time_format.format_time(time.gmtime(seconds_per_day*((2015 - 1970)*365+leap_years_1970_to_2014_inclusive))), '2015-01-01 00:00:00')
1129 def test_format_time_y2038(self):
1130 seconds_per_day = 60*60*24
1131 leap_years_1970_to_2047_inclusive = ((2044 - 1968) // 4)
1132 self.failUnlessEqual(time_format.format_time(time.gmtime(seconds_per_day*((2048 - 1970)*365+leap_years_1970_to_2047_inclusive))), '2048-01-01 00:00:00')
1134 test_format_time_y2038.todo = "This test is known to fail on systems with 32-bit time_t."
1136 def test_format_delta(self):
1138 time_5s_delta = 1389812728
1139 time_28m7s_delta = 1389814410
1140 time_1h_delta = 1389816323
1141 time_1d21h46m49s_delta = 1389977532
1143 self.failUnlessEqual(
1144 time_format.format_delta(time_1, time_1), '0s')
1146 self.failUnlessEqual(
1147 time_format.format_delta(time_1, time_5s_delta), '5s')
1148 self.failUnlessEqual(
1149 time_format.format_delta(time_1, time_28m7s_delta), '28m 7s')
1150 self.failUnlessEqual(
1151 time_format.format_delta(time_1, time_1h_delta), '1h 0m 0s')
1152 self.failUnlessEqual(
1153 time_format.format_delta(time_1, time_1d21h46m49s_delta), '1d 21h 46m 49s')
1155 self.failUnlessEqual(
1156 time_format.format_delta(time_1d21h46m49s_delta, time_1), '-')
1158 # time_1 with a decimal fraction will make the delta 1s less
1159 time_1decimal = 1389812723.383963
1161 self.failUnlessEqual(
1162 time_format.format_delta(time_1decimal, time_5s_delta), '4s')
1163 self.failUnlessEqual(
1164 time_format.format_delta(time_1decimal, time_28m7s_delta), '28m 6s')
1165 self.failUnlessEqual(
1166 time_format.format_delta(time_1decimal, time_1h_delta), '59m 59s')
1167 self.failUnlessEqual(
1168 time_format.format_delta(time_1decimal, time_1d21h46m49s_delta), '1d 21h 46m 48s')
1170 class CacheDir(unittest.TestCase):
1171 def test_basic(self):
1172 basedir = "test_util/CacheDir/test_basic"
1174 def _failIfExists(name):
1175 absfn = os.path.join(basedir, name)
1176 self.failIf(os.path.exists(absfn),
1177 "%s exists but it shouldn't" % absfn)
1179 def _failUnlessExists(name):
1180 absfn = os.path.join(basedir, name)
1181 self.failUnless(os.path.exists(absfn),
1182 "%s doesn't exist but it should" % absfn)
1184 cdm = cachedir.CacheDirectoryManager(basedir)
1185 a = cdm.get_file("a")
1186 b = cdm.get_file("b")
1187 c = cdm.get_file("c")
1188 f = open(a.get_filename(), "wb"); f.write("hi"); f.close(); del f
1189 f = open(b.get_filename(), "wb"); f.write("hi"); f.close(); del f
1190 f = open(c.get_filename(), "wb"); f.write("hi"); f.close(); del f
1192 _failUnlessExists("a")
1193 _failUnlessExists("b")
1194 _failUnlessExists("c")
1198 _failUnlessExists("a")
1199 _failUnlessExists("b")
1200 _failUnlessExists("c")
1203 # this file won't be deleted yet, because it isn't old enough
1205 _failUnlessExists("a")
1206 _failUnlessExists("b")
1207 _failUnlessExists("c")
1209 # we change the definition of "old" to make everything old
1214 _failUnlessExists("b")
1215 _failUnlessExists("c")
1223 _failUnlessExists("b")
1224 _failUnlessExists("c")
1226 b2 = cdm.get_file("b")
1230 _failUnlessExists("b")
1231 _failUnlessExists("c")
1236 def __init__(self, x):
1241 return "<%s %s>" % (self.__class__.__name__, self.x,)
1244 def __le__(self, other):
1245 return self.x <= other
1246 def __lt__(self, other):
1247 return self.x < other
1248 def __ge__(self, other):
1249 return self.x >= other
1250 def __gt__(self, other):
1251 return self.x > other
1252 def __ne__(self, other):
1253 return self.x != other
1254 def __eq__(self, other):
1255 return self.x == other
1257 class DictUtil(unittest.TestCase):
1258 def _help_test_empty_dict(self, klass):
1262 self.failUnless(d1 == d2, "d1: %r, d2: %r" % (d1, d2,))
1263 self.failUnless(len(d1) == 0)
1264 self.failUnless(len(d2) == 0)
1266 def _help_test_nonempty_dict(self, klass):
1267 d1 = klass({'a': 1, 'b': "eggs", 3: "spam",})
1268 d2 = klass({'a': 1, 'b': "eggs", 3: "spam",})
1270 self.failUnless(d1 == d2)
1271 self.failUnless(len(d1) == 3, "%s, %s" % (len(d1), d1,))
1272 self.failUnless(len(d2) == 3)
1274 def _help_test_eq_but_notis(self, klass):
1275 d = klass({'a': 3, 'b': EqButNotIs(3), 'c': 3})
1280 d['b'] = EqButNotIs(3)
1285 d['b'] = EqButNotIs(3)
1291 d['a'] = EqButNotIs(3)
1296 fake3 = EqButNotIs(3)
1297 fake7 = EqButNotIs(7)
1301 self.failUnless(filter(lambda x: x is 8, d.itervalues()))
1302 self.failUnless(filter(lambda x: x is fake7, d.itervalues()))
1303 # The real 7 should have been ejected by the d[3] = 8.
1304 self.failUnless(not filter(lambda x: x is 7, d.itervalues()))
1305 self.failUnless(filter(lambda x: x is fake3, d.iterkeys()))
1306 self.failUnless(filter(lambda x: x is 3, d.iterkeys()))
1311 fake3 = EqButNotIs(3)
1312 fake7 = EqButNotIs(7)
1315 self.failUnless(filter(lambda x: x is 8, d.itervalues()))
1316 self.failUnless(filter(lambda x: x is fake7, d.itervalues()))
1317 # The real 7 should have been ejected by the d[3] = 8.
1318 self.failUnless(not filter(lambda x: x is 7, d.itervalues()))
1319 self.failUnless(filter(lambda x: x is fake3, d.iterkeys()))
1320 self.failUnless(filter(lambda x: x is 3, d.iterkeys()))
1324 self._help_test_eq_but_notis(dictutil.UtilDict)
1325 self._help_test_eq_but_notis(dictutil.NumDict)
1326 self._help_test_eq_but_notis(dictutil.ValueOrderedDict)
1327 self._help_test_nonempty_dict(dictutil.UtilDict)
1328 self._help_test_nonempty_dict(dictutil.NumDict)
1329 self._help_test_nonempty_dict(dictutil.ValueOrderedDict)
1330 self._help_test_eq_but_notis(dictutil.UtilDict)
1331 self._help_test_eq_but_notis(dictutil.NumDict)
1332 self._help_test_eq_but_notis(dictutil.ValueOrderedDict)
1334 def test_dict_of_sets(self):
1335 ds = dictutil.DictOfSets()
1340 self.failUnlessEqual(ds[1], set(["a"]))
1341 self.failUnlessEqual(ds[2], set(["b", "c"]))
1342 ds.discard(3, "d") # should not raise an exception
1344 self.failUnlessEqual(ds[2], set(["c"]))
1346 self.failIf(2 in ds)
1349 ds2 = dictutil.DictOfSets()
1354 self.failUnlessEqual(ds[1], set(["a"]))
1355 self.failUnlessEqual(ds[3], set(["f", "g"]))
1356 self.failUnlessEqual(ds[4], set(["h"]))
1358 def test_move(self):
1359 d1 = {1: "a", 2: "b"}
1360 d2 = {2: "c", 3: "d"}
1361 dictutil.move(1, d1, d2)
1362 self.failUnlessEqual(d1, {2: "b"})
1363 self.failUnlessEqual(d2, {1: "a", 2: "c", 3: "d"})
1365 d1 = {1: "a", 2: "b"}
1366 d2 = {2: "c", 3: "d"}
1367 dictutil.move(2, d1, d2)
1368 self.failUnlessEqual(d1, {1: "a"})
1369 self.failUnlessEqual(d2, {2: "b", 3: "d"})
1371 d1 = {1: "a", 2: "b"}
1372 d2 = {2: "c", 3: "d"}
1373 self.failUnlessRaises(KeyError, dictutil.move, 5, d1, d2, strict=True)
1375 def test_subtract(self):
1376 d1 = {1: "a", 2: "b"}
1377 d2 = {2: "c", 3: "d"}
1378 d3 = dictutil.subtract(d1, d2)
1379 self.failUnlessEqual(d3, {1: "a"})
1381 d1 = {1: "a", 2: "b"}
1383 d3 = dictutil.subtract(d1, d2)
1384 self.failUnlessEqual(d3, {1: "a"})
1386 def test_utildict(self):
1387 d = dictutil.UtilDict({1: "a", 2: "b"})
1390 self.failUnlessEqual(d, {2: "b"})
1393 self.failUnlessRaises(TypeError, eq, d, "not a dict")
1395 d = dictutil.UtilDict({1: "b", 2: "a"})
1396 self.failUnlessEqual(d.items_sorted_by_value(),
1397 [(2, "a"), (1, "b")])
1398 self.failUnlessEqual(d.items_sorted_by_key(),
1399 [(1, "b"), (2, "a")])
1400 self.failUnlessEqual(repr(d), "{1: 'b', 2: 'a'}")
1401 self.failUnless(1 in d)
1403 d2 = dictutil.UtilDict({3: "c", 4: "d"})
1404 self.failUnless(d != d2)
1405 self.failUnless(d2 > d)
1406 self.failUnless(d2 >= d)
1407 self.failUnless(d <= d2)
1408 self.failUnless(d < d2)
1409 self.failUnlessEqual(d[1], "b")
1410 self.failUnlessEqual(sorted(list([k for k in d])), [1,2])
1413 self.failUnlessEqual(d, d3)
1414 self.failUnless(isinstance(d3, dictutil.UtilDict))
1416 d4 = d.fromkeys([3,4], "e")
1417 self.failUnlessEqual(d4, {3: "e", 4: "e"})
1419 self.failUnlessEqual(d.get(1), "b")
1420 self.failUnlessEqual(d.get(3), None)
1421 self.failUnlessEqual(d.get(3, "default"), "default")
1422 self.failUnlessEqual(sorted(list(d.items())),
1423 [(1, "b"), (2, "a")])
1424 self.failUnlessEqual(sorted(list(d.iteritems())),
1425 [(1, "b"), (2, "a")])
1426 self.failUnlessEqual(sorted(d.keys()), [1, 2])
1427 self.failUnlessEqual(sorted(d.values()), ["a", "b"])
1428 x = d.setdefault(1, "new")
1429 self.failUnlessEqual(x, "b")
1430 self.failUnlessEqual(d[1], "b")
1431 x = d.setdefault(3, "new")
1432 self.failUnlessEqual(x, "new")
1433 self.failUnlessEqual(d[3], "new")
1437 self.failUnless(x in [(1, "b"), (2, "a")])
1439 self.failUnless(x in [(1, "b"), (2, "a")])
1440 self.failUnlessRaises(KeyError, d.popitem)
1442 def test_numdict(self):
1443 d = dictutil.NumDict({"a": 1, "b": 2})
1445 d.add_num("a", 10, 5)
1446 d.add_num("c", 20, 5)
1448 self.failUnlessEqual(d, {"a": 11, "b": 2, "c": 25, "d": 30})
1450 d.subtract_num("a", 10)
1451 d.subtract_num("e", 10)
1452 d.subtract_num("f", 10, 15)
1453 self.failUnlessEqual(d, {"a": 1, "b": 2, "c": 25, "d": 30,
1456 self.failUnlessEqual(d.sum(), sum([1, 2, 25, 30, -10, 5]))
1458 d = dictutil.NumDict()
1462 self.failUnlessEqual(d, {"a": 2, "b": 6})
1466 self.failUnlessEqual(d, {"a": 1, "b": 6, "c": -1, "d": 4})
1467 self.failUnlessEqual(d.items_sorted_by_key(),
1468 [("a", 1), ("b", 6), ("c", -1), ("d", 4)])
1469 self.failUnlessEqual(d.items_sorted_by_value(),
1470 [("c", -1), ("a", 1), ("d", 4), ("b", 6)])
1471 self.failUnlessEqual(d.item_with_largest_value(), ("b", 6))
1473 d = dictutil.NumDict({"a": 1, "b": 2})
1474 self.failUnlessEqual(repr(d), "{'a': 1, 'b': 2}")
1475 self.failUnless("a" in d)
1477 d2 = dictutil.NumDict({"c": 3, "d": 4})
1478 self.failUnless(d != d2)
1479 self.failUnless(d2 > d)
1480 self.failUnless(d2 >= d)
1481 self.failUnless(d <= d2)
1482 self.failUnless(d < d2)
1483 self.failUnlessEqual(d["a"], 1)
1484 self.failUnlessEqual(sorted(list([k for k in d])), ["a","b"])
1487 self.failUnlessRaises(TypeError, eq, d, "not a dict")
1490 self.failUnlessEqual(d, d3)
1491 self.failUnless(isinstance(d3, dictutil.NumDict))
1493 d4 = d.fromkeys(["a","b"], 5)
1494 self.failUnlessEqual(d4, {"a": 5, "b": 5})
1496 self.failUnlessEqual(d.get("a"), 1)
1497 self.failUnlessEqual(d.get("c"), 0)
1498 self.failUnlessEqual(d.get("c", 5), 5)
1499 self.failUnlessEqual(sorted(list(d.items())),
1500 [("a", 1), ("b", 2)])
1501 self.failUnlessEqual(sorted(list(d.iteritems())),
1502 [("a", 1), ("b", 2)])
1503 self.failUnlessEqual(sorted(d.keys()), ["a", "b"])
1504 self.failUnlessEqual(sorted(d.values()), [1, 2])
1505 self.failUnless(d.has_key("a"))
1506 self.failIf(d.has_key("c"))
1508 x = d.setdefault("c", 3)
1509 self.failUnlessEqual(x, 3)
1510 self.failUnlessEqual(d["c"], 3)
1511 x = d.setdefault("c", 5)
1512 self.failUnlessEqual(x, 3)
1513 self.failUnlessEqual(d["c"], 3)
1517 self.failUnless(x in [("a", 1), ("b", 2)])
1519 self.failUnless(x in [("a", 1), ("b", 2)])
1520 self.failUnlessRaises(KeyError, d.popitem)
1523 d.update({"c": 4, "d": 5})
1524 self.failUnlessEqual(d, {"c": 4, "d": 5})
1526 def test_del_if_present(self):
1527 d = {1: "a", 2: "b"}
1528 dictutil.del_if_present(d, 1)
1529 dictutil.del_if_present(d, 3)
1530 self.failUnlessEqual(d, {2: "b"})
1532 def test_valueordereddict(self):
1533 d = dictutil.ValueOrderedDict()
1538 self.failUnlessEqual(d, {"a": 3, "b": 2, "c": 1})
1539 self.failUnlessEqual(d.items(), [("c", 1), ("b", 2), ("a", 3)])
1540 self.failUnlessEqual(d.values(), [1, 2, 3])
1541 self.failUnlessEqual(d.keys(), ["c", "b", "a"])
1542 self.failUnlessEqual(repr(d), "<ValueOrderedDict {c: 1, b: 2, a: 3}>")
1545 self.failIf(d == {"a": 4})
1546 self.failUnless(d != {"a": 4})
1548 x = d.setdefault("d", 0)
1549 self.failUnlessEqual(x, 0)
1550 self.failUnlessEqual(d["d"], 0)
1551 x = d.setdefault("d", -1)
1552 self.failUnlessEqual(x, 0)
1553 self.failUnlessEqual(d["d"], 0)
1555 x = d.remove("e", "default", False)
1556 self.failUnlessEqual(x, "default")
1557 self.failUnlessRaises(KeyError, d.remove, "e", "default", True)
1558 x = d.remove("d", 5)
1559 self.failUnlessEqual(x, 0)
1561 x = d.__getitem__("c")
1562 self.failUnlessEqual(x, 1)
1563 x = d.__getitem__("e", "default", False)
1564 self.failUnlessEqual(x, "default")
1565 self.failUnlessRaises(KeyError, d.__getitem__, "e", "default", True)
1567 self.failUnlessEqual(d.popitem(), ("c", 1))
1568 self.failUnlessEqual(d.popitem(), ("b", 2))
1569 self.failUnlessEqual(d.popitem(), ("a", 3))
1570 self.failUnlessRaises(KeyError, d.popitem)
1572 d = dictutil.ValueOrderedDict({"a": 3, "b": 2, "c": 1})
1573 x = d.pop("d", "default", False)
1574 self.failUnlessEqual(x, "default")
1575 self.failUnlessRaises(KeyError, d.pop, "d", "default", True)
1577 self.failUnlessEqual(x, 2)
1578 self.failUnlessEqual(d.items(), [("c", 1), ("a", 3)])
1580 d = dictutil.ValueOrderedDict({"a": 3, "b": 2, "c": 1})
1581 x = d.pop_from_list(1) # pop the second item, b/2
1582 self.failUnlessEqual(x, "b")
1583 self.failUnlessEqual(d.items(), [("c", 1), ("a", 3)])
1585 def test_auxdict(self):
1586 d = dictutil.AuxValueDict()
1587 # we put the serialized form in the auxdata
1588 d.set_with_aux("key", ("filecap", "metadata"), "serialized")
1590 self.failUnlessEqual(d.keys(), ["key"])
1591 self.failUnlessEqual(d["key"], ("filecap", "metadata"))
1592 self.failUnlessEqual(d.get_aux("key"), "serialized")
1593 def _get_missing(key):
1595 self.failUnlessRaises(KeyError, _get_missing, "nonkey")
1596 self.failUnlessEqual(d.get("nonkey"), None)
1597 self.failUnlessEqual(d.get("nonkey", "nonvalue"), "nonvalue")
1598 self.failUnlessEqual(d.get_aux("nonkey"), None)
1599 self.failUnlessEqual(d.get_aux("nonkey", "nonvalue"), "nonvalue")
1601 d["key"] = ("filecap2", "metadata2")
1602 self.failUnlessEqual(d["key"], ("filecap2", "metadata2"))
1603 self.failUnlessEqual(d.get_aux("key"), None)
1605 d.set_with_aux("key2", "value2", "aux2")
1606 self.failUnlessEqual(sorted(d.keys()), ["key", "key2"])
1608 self.failUnlessEqual(d.keys(), ["key"])
1609 self.failIf("key2" in d)
1610 self.failUnlessRaises(KeyError, _get_missing, "key2")
1611 self.failUnlessEqual(d.get("key2"), None)
1612 self.failUnlessEqual(d.get_aux("key2"), None)
1613 d["key2"] = "newvalue2"
1614 self.failUnlessEqual(d.get("key2"), "newvalue2")
1615 self.failUnlessEqual(d.get_aux("key2"), None)
1617 d = dictutil.AuxValueDict({1:2,3:4})
1618 self.failUnlessEqual(sorted(d.keys()), [1,3])
1619 self.failUnlessEqual(d[1], 2)
1620 self.failUnlessEqual(d.get_aux(1), None)
1622 d = dictutil.AuxValueDict([ (1,2), (3,4) ])
1623 self.failUnlessEqual(sorted(d.keys()), [1,3])
1624 self.failUnlessEqual(d[1], 2)
1625 self.failUnlessEqual(d.get_aux(1), None)
1627 d = dictutil.AuxValueDict(one=1, two=2)
1628 self.failUnlessEqual(sorted(d.keys()), ["one","two"])
1629 self.failUnlessEqual(d["one"], 1)
1630 self.failUnlessEqual(d.get_aux("one"), None)
1632 class Pipeline(unittest.TestCase):
1633 def pause(self, *args, **kwargs):
1634 d = defer.Deferred()
1635 self.calls.append( (d, args, kwargs) )
1638 def failUnlessCallsAre(self, expected):
1641 self.failUnlessEqual(len(self.calls), len(expected), self.calls)
1642 for i,c in enumerate(self.calls):
1643 self.failUnlessEqual(c[1:], expected[i], str(i))
1645 def test_basic(self):
1648 p = pipeline.Pipeline(100)
1650 d = p.flush() # fires immediately
1651 d.addCallbacks(finished.append, log.err)
1652 self.failUnlessEqual(len(finished), 1)
1655 d = p.add(10, self.pause, "one")
1656 # the call should start right away, and our return Deferred should
1658 d.addCallbacks(finished.append, log.err)
1659 self.failUnlessEqual(len(finished), 1)
1660 self.failUnlessEqual(finished[0], None)
1661 self.failUnlessCallsAre([ ( ("one",) , {} ) ])
1662 self.failUnlessEqual(p.gauge, 10)
1667 d = p.add(20, self.pause, "two", kw=2)
1668 # pipeline: [one, two]
1670 # the call and the Deferred should fire right away
1671 d.addCallbacks(finished.append, log.err)
1672 self.failUnlessEqual(len(finished), 1)
1673 self.failUnlessEqual(finished[0], None)
1674 self.failUnlessCallsAre([ ( ("one",) , {} ),
1675 ( ("two",) , {"kw": 2} ),
1677 self.failUnlessEqual(p.gauge, 30)
1679 self.calls[0][0].callback("one-result")
1681 self.failUnlessEqual(p.gauge, 20)
1684 d = p.add(90, self.pause, "three", "posarg1")
1685 # pipeline: [two, three]
1688 fd.addCallbacks(flushed.append, log.err)
1689 self.failUnlessEqual(flushed, [])
1691 # the call will be made right away, but the return Deferred will not,
1692 # because the pipeline is now full.
1693 d.addCallbacks(finished.append, log.err)
1694 self.failUnlessEqual(len(finished), 0)
1695 self.failUnlessCallsAre([ ( ("one",) , {} ),
1696 ( ("two",) , {"kw": 2} ),
1697 ( ("three", "posarg1"), {} ),
1699 self.failUnlessEqual(p.gauge, 110)
1701 self.failUnlessRaises(pipeline.SingleFileError, p.add, 10, self.pause)
1703 # retiring either call will unblock the pipeline, causing the #3
1705 self.calls[2][0].callback("three-result")
1708 self.failUnlessEqual(len(finished), 1)
1709 self.failUnlessEqual(finished[0], None)
1710 self.failUnlessEqual(flushed, [])
1712 # retiring call#2 will finally allow the flush() Deferred to fire
1713 self.calls[1][0].callback("two-result")
1714 self.failUnlessEqual(len(flushed), 1)
1716 def test_errors(self):
1718 p = pipeline.Pipeline(100)
1720 d1 = p.add(200, self.pause, "one")
1724 d1.addBoth(finished.append)
1725 self.failUnlessEqual(finished, [])
1728 d2.addBoth(flushed.append)
1729 self.failUnlessEqual(flushed, [])
1731 self.calls[0][0].errback(ValueError("oops"))
1733 self.failUnlessEqual(len(finished), 1)
1735 self.failUnless(isinstance(f, Failure))
1736 self.failUnless(f.check(pipeline.PipelineError))
1737 self.failUnlessIn("PipelineError", str(f.value))
1738 self.failUnlessIn("ValueError", str(f.value))
1740 self.failUnless("ValueError" in r, r)
1742 self.failUnless(f2.check(ValueError))
1744 self.failUnlessEqual(len(flushed), 1)
1746 self.failUnless(isinstance(f, Failure))
1747 self.failUnless(f.check(pipeline.PipelineError))
1749 self.failUnless(f2.check(ValueError))
1751 # now that the pipeline is in the failed state, any new calls will
1754 d3 = p.add(20, self.pause, "two")
1757 d3.addBoth(finished.append)
1758 self.failUnlessEqual(len(finished), 1)
1760 self.failUnless(isinstance(f, Failure))
1761 self.failUnless(f.check(pipeline.PipelineError))
1763 self.failUnless("ValueError" in r, r)
1765 self.failUnless(f2.check(ValueError))
1769 d4.addBoth(flushed.append)
1770 self.failUnlessEqual(len(flushed), 1)
1772 self.failUnless(isinstance(f, Failure))
1773 self.failUnless(f.check(pipeline.PipelineError))
1775 self.failUnless(f2.check(ValueError))
1777 def test_errors2(self):
1779 p = pipeline.Pipeline(100)
1781 d1 = p.add(10, self.pause, "one")
1782 d2 = p.add(20, self.pause, "two")
1783 d3 = p.add(30, self.pause, "three")
1786 # one call fails, then the second one succeeds: make sure
1787 # ExpandableDeferredList tolerates the second one
1790 d4.addBoth(flushed.append)
1791 self.failUnlessEqual(flushed, [])
1793 self.calls[0][0].errback(ValueError("oops"))
1794 self.failUnlessEqual(len(flushed), 1)
1796 self.failUnless(isinstance(f, Failure))
1797 self.failUnless(f.check(pipeline.PipelineError))
1799 self.failUnless(f2.check(ValueError))
1801 self.calls[1][0].callback("two-result")
1802 self.calls[2][0].errback(ValueError("three-error"))
1806 class SampleError(Exception):
1809 class Log(unittest.TestCase):
1811 if not hasattr(self, "flushLoggedErrors"):
1812 # without flushLoggedErrors, we can't get rid of the
1813 # twisted.log.err that tahoe_log records, so we can't keep this
1814 # test from [ERROR]ing
1815 raise unittest.SkipTest("needs flushLoggedErrors from Twisted-2.5.0")
1817 raise SampleError("simple sample")
1820 tahoe_log.err(format="intentional sample error",
1821 failure=f, level=tahoe_log.OPERATIONAL, umid="wO9UoQ")
1822 self.flushLoggedErrors(SampleError)
1826 # this is a simple+inefficient form of util.spans.Spans . We compare the
1827 # behavior of this reference model against the real (efficient) form.
1829 def __init__(self, _span_or_start=None, length=None):
1831 if length is not None:
1832 for i in range(_span_or_start, _span_or_start+length):
1834 elif _span_or_start:
1835 for (start,length) in _span_or_start:
1836 self.add(start, length)
1838 def add(self, start, length):
1839 for i in range(start, start+length):
1843 def remove(self, start, length):
1844 for i in range(start, start+length):
1845 self._have.discard(i)
1849 return sorted(self._have)
1852 items = sorted(self._have)
1856 if prevstart is None:
1857 prevstart = prevend = i
1862 yield (prevstart, prevend-prevstart+1)
1863 prevstart = prevend = i
1864 if prevstart is not None:
1865 yield (prevstart, prevend-prevstart+1)
1867 def __nonzero__(self): # this gets us bool()
1871 return len(self._have)
1873 def __add__(self, other):
1874 s = self.__class__(self)
1875 for (start, length) in other:
1876 s.add(start, length)
1879 def __sub__(self, other):
1880 s = self.__class__(self)
1881 for (start, length) in other:
1882 s.remove(start, length)
1885 def __iadd__(self, other):
1886 for (start, length) in other:
1887 self.add(start, length)
1890 def __isub__(self, other):
1891 for (start, length) in other:
1892 self.remove(start, length)
1895 def __and__(self, other):
1896 s = self.__class__()
1897 for i in other.each():
1902 def __contains__(self, (start,length)):
1903 for i in range(start, start+length):
1904 if i not in self._have:
1908 class ByteSpans(unittest.TestCase):
1909 def test_basic(self):
1911 self.failUnlessEqual(list(s), [])
1913 self.failIf((0,1) in s)
1914 self.failUnlessEqual(s.len(), 0)
1916 s1 = Spans(3, 4) # 3,4,5,6
1919 s1 = Spans(3L, 4L) # 3,4,5,6
1925 s2.add(10,2) # 10,11
1927 self.failUnless((10,1) in s2)
1928 self.failIf((10,1) in s1)
1929 self.failUnlessEqual(list(s2.each()), [3,4,5,6,10,11])
1930 self.failUnlessEqual(s2.len(), 6)
1932 s2.add(15,2).add(20,2)
1933 self.failUnlessEqual(list(s2.each()), [3,4,5,6,10,11,15,16,20,21])
1934 self.failUnlessEqual(s2.len(), 10)
1936 s2.remove(4,3).remove(15,1)
1937 self.failUnlessEqual(list(s2.each()), [3,10,11,16,20,21])
1938 self.failUnlessEqual(s2.len(), 6)
1940 s1 = SimpleSpans(3, 4) # 3 4 5 6
1941 s2 = SimpleSpans(5, 4) # 5 6 7 8
1943 self.failUnlessEqual(list(i.each()), [5, 6])
1945 def _check1(self, s):
1946 self.failUnlessEqual(list(s), [(3,4)])
1948 self.failUnlessEqual(s.len(), 4)
1949 self.failIf((0,1) in s)
1950 self.failUnless((3,4) in s)
1951 self.failUnless((3,1) in s)
1952 self.failUnless((5,2) in s)
1953 self.failUnless((6,1) in s)
1954 self.failIf((6,2) in s)
1955 self.failIf((7,1) in s)
1956 self.failUnlessEqual(list(s.each()), [3,4,5,6])
1958 def test_large(self):
1959 s = Spans(4, 2**65) # don't do this with a SimpleSpans
1960 self.failUnlessEqual(list(s), [(4, 2**65)])
1962 self.failUnlessEqual(s.len(), 2**65)
1963 self.failIf((0,1) in s)
1964 self.failUnless((4,2) in s)
1965 self.failUnless((2**65,2) in s)
1967 def test_math(self):
1968 s1 = Spans(0, 10) # 0,1,2,3,4,5,6,7,8,9
1969 s2 = Spans(5, 3) # 5,6,7
1970 s3 = Spans(8, 4) # 8,9,10,11
1973 self.failUnlessEqual(list(s.each()), [0,1,2,3,4,8,9])
1975 self.failUnlessEqual(list(s.each()), [0,1,2,3,4,5,6,7])
1977 self.failUnlessEqual(list(s.each()), [5,6,7])
1979 self.failUnlessEqual(list(s.each()), [5,6,7])
1981 self.failUnlessEqual(list(s.each()), [5,6,7])
1983 self.failUnlessEqual(list(s.each()), [8,9])
1985 self.failUnlessEqual(list(s.each()), [8,9])
1987 self.failUnlessEqual(list(s.each()), [])
1989 self.failUnlessEqual(list(s.each()), [])
1991 self.failUnlessEqual(list(s.each()), [])
1993 self.failUnlessEqual(list(s.each()), [])
1996 self.failUnlessEqual(list(s.each()), [0,1,2,3,4,5,6,7,8,9])
1998 self.failUnlessEqual(list(s.each()), [0,1,2,3,4,5,6,7,8,9,10,11])
2000 self.failUnlessEqual(list(s.each()), [5,6,7,8,9,10,11])
2004 self.failUnlessEqual(list(s.each()), [0,1,2,3,4,8,9])
2007 self.failUnlessEqual(list(s.each()), [0,1,2,3,4,5,6,7])
2010 self.failUnlessEqual(list(s.each()), [5,6,7])
2014 self.failUnlessEqual(list(s.each()), [0,1,2,3,4,5,6,7,8,9])
2017 self.failUnlessEqual(list(s.each()), [0,1,2,3,4,5,6,7,8,9,10,11])
2020 self.failUnlessEqual(list(s.each()), [5,6,7,8,9,10,11])
2022 def test_random(self):
2023 # attempt to increase coverage of corner cases by comparing behavior
2024 # of a simple-but-slow model implementation against the
2025 # complex-but-fast actual implementation, in a large number of random
2029 s1 = S1(); s2 = S2()
2031 def _create(subseed):
2032 ns1 = S1(); ns2 = S2()
2034 what = _hash(subseed+str(i)).hexdigest()
2035 start = int(what[2:4], 16)
2036 length = max(1,int(what[5:6], 16))
2037 ns1.add(start, length); ns2.add(start, length)
2041 for i in range(1000):
2042 what = _hash(seed+str(i)).hexdigest()
2045 start = int(what[2:4], 16)
2046 length = max(1,int(what[5:6], 16))
2049 if subop in "01234":
2050 s1 = S1(); s2 = S2()
2051 elif subop in "5678":
2052 s1 = S1(start, length); s2 = S2(start, length)
2054 s1 = S1(s1); s2 = S2(s2)
2055 #print "s2 = %s" % s2.dump()
2057 #print "s2.add(%d,%d)" % (start, length)
2058 s1.add(start, length); s2.add(start, length)
2060 #print "s2.remove(%d,%d)" % (start, length)
2061 s1.remove(start, length); s2.remove(start, length)
2063 ns1, ns2 = _create(what[7:11])
2064 #print "s2 + %s" % ns2.dump()
2065 s1 = s1 + ns1; s2 = s2 + ns2
2067 ns1, ns2 = _create(what[7:11])
2068 #print "%s - %s" % (s2.dump(), ns2.dump())
2069 s1 = s1 - ns1; s2 = s2 - ns2
2071 ns1, ns2 = _create(what[7:11])
2072 #print "s2 += %s" % ns2.dump()
2073 s1 += ns1; s2 += ns2
2075 ns1, ns2 = _create(what[7:11])
2076 #print "%s -= %s" % (s2.dump(), ns2.dump())
2077 s1 -= ns1; s2 -= ns2
2079 ns1, ns2 = _create(what[7:11])
2080 #print "%s &= %s" % (s2.dump(), ns2.dump())
2081 s1 = s1 & ns1; s2 = s2 & ns2
2082 #print "s2 now %s" % s2.dump()
2083 self.failUnlessEqual(list(s1.each()), list(s2.each()))
2084 self.failUnlessEqual(s1.len(), s2.len())
2085 self.failUnlessEqual(bool(s1), bool(s2))
2086 self.failUnlessEqual(list(s1), list(s2))
2088 what = _hash(what[12:14]+str(j)).hexdigest()
2089 start = int(what[2:4], 16)
2090 length = max(1, int(what[5:6], 16))
2091 span = (start, length)
2092 self.failUnlessEqual(bool(span in s1), bool(span in s2))
2098 # s.add(start,length) : returns s
2099 # s.remove(start,length)
2100 # s.each() -> list of byte offsets, mostly for testing
2101 # list(s) -> list of (start,length) tuples, one per span
2102 # (start,length) in s -> True if (start..start+length-1) are all members
2103 # NOT equivalent to x in list(s)
2104 # s.len() -> number of bytes, for testing, bool(), and accounting/limiting
2105 # bool(s) (__nonzeron__)
2106 # s = s1+s2, s1-s2, +=s1, -=s1
2108 def test_overlap(self):
2113 self._test_overlap(a,b,c,d)
2115 def _test_overlap(self, a, b, c, d):
2116 s1 = set(range(a,a+b))
2117 s2 = set(range(c,c+d))
2119 #self._show_overlap(s1, "1")
2120 #self._show_overlap(s2, "2")
2121 o = overlap(a,b,c,d)
2122 expected = s1.intersection(s2)
2124 self.failUnlessEqual(o, None)
2127 so = set(range(start,start+length))
2128 #self._show(so, "o")
2129 self.failUnlessEqual(so, expected)
2131 def _show_overlap(self, s, c):
2135 for i in range(max(s)):
2142 def extend(s, start, length, fill):
2143 if len(s) >= start+length:
2145 assert len(fill) == 1
2146 return s + fill*(start+length-len(s))
2148 def replace(s, start, data):
2149 assert len(s) >= start+len(data)
2150 return s[:start] + data + s[start+len(data):]
2152 class SimpleDataSpans:
2153 def __init__(self, other=None):
2154 self.missing = "" # "1" where missing, "0" where found
2157 for (start, data) in other.get_chunks():
2158 self.add(start, data)
2160 def __nonzero__(self): # this gets us bool()
2163 return len(self.missing.replace("1", ""))
2165 return [i for (i,c) in enumerate(self.missing) if c == "0"]
2166 def _have(self, start, length):
2167 m = self.missing[start:start+length]
2168 if not m or len(m)<length or int(m):
2171 def get_chunks(self):
2172 for i in self._dump():
2173 yield (i, self.data[i])
2174 def get_spans(self):
2175 return SimpleSpans([(start,len(data))
2176 for (start,data) in self.get_chunks()])
2177 def get(self, start, length):
2178 if self._have(start, length):
2179 return self.data[start:start+length]
2181 def pop(self, start, length):
2182 data = self.get(start, length)
2184 self.remove(start, length)
2186 def remove(self, start, length):
2187 self.missing = replace(extend(self.missing, start, length, "1"),
2189 def add(self, start, data):
2190 self.missing = replace(extend(self.missing, start, len(data), "1"),
2191 start, "0"*len(data))
2192 self.data = replace(extend(self.data, start, len(data), " "),
2196 class StringSpans(unittest.TestCase):
2197 def do_basic(self, klass):
2199 self.failUnlessEqual(ds.len(), 0)
2200 self.failUnlessEqual(list(ds._dump()), [])
2201 self.failUnlessEqual(sum([len(d) for (s,d) in ds.get_chunks()]), 0)
2203 self.failUnlessEqual(ds.get(0, 4), None)
2204 self.failUnlessEqual(ds.pop(0, 4), None)
2208 self.failUnlessEqual(ds.len(), 4)
2209 self.failUnlessEqual(list(ds._dump()), [2,3,4,5])
2210 self.failUnlessEqual(sum([len(d) for (s,d) in ds.get_chunks()]), 4)
2212 self.failUnless((2,2) in s1)
2213 self.failUnlessEqual(ds.get(0, 4), None)
2214 self.failUnlessEqual(ds.pop(0, 4), None)
2215 self.failUnlessEqual(ds.get(4, 4), None)
2218 self.failUnlessEqual(ds2.len(), 4)
2219 self.failUnlessEqual(list(ds2._dump()), [2,3,4,5])
2220 self.failUnlessEqual(sum([len(d) for (s,d) in ds2.get_chunks()]), 4)
2221 self.failUnlessEqual(ds2.get(0, 4), None)
2222 self.failUnlessEqual(ds2.pop(0, 4), None)
2223 self.failUnlessEqual(ds2.pop(2, 3), "fou")
2224 self.failUnlessEqual(sum([len(d) for (s,d) in ds2.get_chunks()]), 1)
2225 self.failUnlessEqual(ds2.get(2, 3), None)
2226 self.failUnlessEqual(ds2.get(5, 1), "r")
2227 self.failUnlessEqual(ds.get(2, 3), "fou")
2228 self.failUnlessEqual(sum([len(d) for (s,d) in ds.get_chunks()]), 4)
2231 self.failUnlessEqual(ds.len(), 6)
2232 self.failUnlessEqual(list(ds._dump()), [0,1,2,3,4,5])
2233 self.failUnlessEqual(sum([len(d) for (s,d) in ds.get_chunks()]), 6)
2234 self.failUnlessEqual(ds.get(0, 4), "23fo")
2235 self.failUnlessEqual(ds.pop(0, 4), "23fo")
2236 self.failUnlessEqual(sum([len(d) for (s,d) in ds.get_chunks()]), 2)
2237 self.failUnlessEqual(ds.get(0, 4), None)
2238 self.failUnlessEqual(ds.pop(0, 4), None)
2243 self.failUnlessEqual(ds.get(2, 4), "fear")
2248 self.failUnlessEqual(ds.get(2L, 4L), "fear")
2251 def do_scan(self, klass):
2252 # do a test with gaps and spans of size 1 and 2
2253 # left=(1,11) * right=(1,11) * gapsize=(1,2)
2254 # 111, 112, 121, 122, 211, 212, 221, 222
2263 # 11 1 1 11 11 11 1 1 111
2264 # 0123456789012345678901234567
2265 # abcdefghijklmnopqrstuvwxyz-=
2266 pieces = [(1, "bc"),
2276 p_elements = set([1,2,4,7,9,10,12,13,16,17,20,22,25,26,27])
2277 S = "abcdefghijklmnopqrstuvwxyz-="
2278 # TODO: when adding data, add capital letters, to make sure we aren't
2279 # just leaving the old data in place
2283 for start, data in pieces:
2288 d = "".join([((i not in p) and " " or S[i]) for i in range(l)])
2292 for start in range(0, l):
2293 for end in range(start+1, l):
2294 # add [start-end) to the baseline
2295 which = "%d-%d" % (start, end-1)
2296 p_added = set(range(start, end))
2300 print dump(b), which
2301 add = klass(); add.add(start, S[start:end])
2303 b.add(start, S[start:end])
2306 # check that the new span is there
2307 d = b.get(start, end-start)
2308 self.failUnlessEqual(d, S[start:end], which)
2309 # check that all the original pieces are still there
2310 for t_start, t_data in pieces:
2312 self.failUnlessEqual(b.get(t_start, t_len),
2313 S[t_start:t_start+t_len],
2314 "%s %d+%d" % (which, t_start, t_len))
2315 # check that a lot of subspans are mostly correct
2316 for t_start in range(l):
2317 for t_len in range(1,4):
2318 d = b.get(t_start, t_len)
2320 which2 = "%s+(%d-%d)" % (which, t_start,
2322 self.failUnlessEqual(d, S[t_start:t_start+t_len],
2324 # check that removing a subspan gives the right value
2326 b2.remove(t_start, t_len)
2327 removed = set(range(t_start, t_start+t_len))
2329 exp = (((i in p_elements) or (i in p_added))
2330 and (i not in removed))
2331 which2 = "%s-(%d-%d)" % (which, t_start,
2333 self.failUnlessEqual(bool(b2.get(i, 1)), exp,
2336 def test_test(self):
2337 self.do_basic(SimpleDataSpans)
2338 self.do_scan(SimpleDataSpans)
2340 def test_basic(self):
2341 self.do_basic(DataSpans)
2342 self.do_scan(DataSpans)
2344 def test_random(self):
2345 # attempt to increase coverage of corner cases by comparing behavior
2346 # of a simple-but-slow model implementation against the
2347 # complex-but-fast actual implementation, in a large number of random
2349 S1 = SimpleDataSpans
2351 s1 = S1(); s2 = S2()
2353 def _randstr(length, seed):
2356 while created < length:
2357 piece = _hash(seed + str(created)).hexdigest()
2358 pieces.append(piece)
2359 created += len(piece)
2360 return "".join(pieces)[:length]
2361 def _create(subseed):
2362 ns1 = S1(); ns2 = S2()
2364 what = _hash(subseed+str(i)).hexdigest()
2365 start = int(what[2:4], 16)
2366 length = max(1,int(what[5:6], 16))
2367 ns1.add(start, _randstr(length, what[7:9]));
2368 ns2.add(start, _randstr(length, what[7:9]))
2372 for i in range(1000):
2373 what = _hash(seed+str(i)).hexdigest()
2376 start = int(what[2:4], 16)
2377 length = max(1,int(what[5:6], 16))
2380 if subop in "0123456":
2381 s1 = S1(); s2 = S2()
2383 s1, s2 = _create(what[7:11])
2384 #print "s2 = %s" % list(s2._dump())
2385 elif op in "123456":
2386 #print "s2.add(%d,%d)" % (start, length)
2387 s1.add(start, _randstr(length, what[7:9]));
2388 s2.add(start, _randstr(length, what[7:9]))
2389 elif op in "789abc":
2390 #print "s2.remove(%d,%d)" % (start, length)
2391 s1.remove(start, length); s2.remove(start, length)
2393 #print "s2.pop(%d,%d)" % (start, length)
2394 d1 = s1.pop(start, length); d2 = s2.pop(start, length)
2395 self.failUnlessEqual(d1, d2)
2396 #print "s1 now %s" % list(s1._dump())
2397 #print "s2 now %s" % list(s2._dump())
2398 self.failUnlessEqual(s1.len(), s2.len())
2399 self.failUnlessEqual(list(s1._dump()), list(s2._dump()))
2400 for j in range(100):
2401 what = _hash(what[12:14]+str(j)).hexdigest()
2402 start = int(what[2:4], 16)
2403 length = max(1, int(what[5:6], 16))
2404 d1 = s1.get(start, length); d2 = s2.get(start, length)
2405 self.failUnlessEqual(d1, d2, "%d+%d" % (start, length))