1 import os, signal, time
2 from random import randrange
4 from twisted.internet import reactor, defer
5 from twisted.python import failure
7 def insecurerandstr(n):
8 return ''.join(map(chr, map(randrange, [0]*n, [256]*n)))
10 def flip_bit(good, which):
11 # flip the low-order bit of good[which]
13 pieces = good[:which], good[-1:], ""
15 pieces = good[:which], good[which:which+1], good[which+1:]
16 return pieces[0] + chr(ord(pieces[1]) ^ 0x01) + pieces[2]
18 def flip_one_bit(s, offset=0, size=None):
19 """ flip one random bit of the string s, in a byte greater than or equal to offset and less
23 i = randrange(offset, offset+size)
24 result = s[:i] + chr(ord(s[i])^(0x01<<randrange(0, 8))) + s[i+1:]
25 assert result != s, "Internal error -- flip_one_bit() produced the same string as its input: %s == %s" % (result, s)
29 # This class is necessary for any code which wants to use Processes
30 # outside the usual reactor.run() environment. It is copied from
31 # Twisted's twisted.test.test_process . Note that Twisted-8.2.0 uses
32 # something rather different.
36 # make sure SIGCHLD handler is installed, as it should be on
37 # reactor.run(). problem is reactor may not have been run when this
39 if hasattr(reactor, "_handleSigchld") and hasattr(signal, "SIGCHLD"):
40 self.sigchldHandler = signal.signal(signal.SIGCHLD,
41 reactor._handleSigchld)
44 if self.sigchldHandler:
45 signal.signal(signal.SIGCHLD, self.sigchldHandler)
48 def stall(self, res=None, delay=1):
50 reactor.callLater(delay, d.callback, res)
53 class ShouldFailMixin:
55 def shouldFail(self, expected_failure, which, substring,
56 callable, *args, **kwargs):
57 assert substring is None or isinstance(substring, str)
58 d = defer.maybeDeferred(callable, *args, **kwargs)
60 if isinstance(res, failure.Failure):
61 res.trap(expected_failure)
63 self.failUnless(substring in str(res),
64 "%s: substring '%s' not in '%s'"
65 % (which, substring, str(res)))
66 # return the Failure for further analysis, but in a form that
67 # doesn't make the Deferred chain think that we failed.
70 self.fail("%s was supposed to raise %s, not get '%s'" %
71 (which, expected_failure, res))
76 class TestMixin(SignalMixin):
77 def setUp(self, repeatable=False):
79 @param repeatable: install the repeatable_randomness hacks to attempt
80 to without access to real randomness and real time.time from the
83 SignalMixin.setUp(self)
84 self.repeatable = repeatable
86 import repeatable_random
87 repeatable_random.force_repeatability()
88 if hasattr(time, 'realtime'):
89 self.teststarttime = time.realtime()
91 self.teststarttime = time.time()
94 SignalMixin.tearDown(self)
96 import repeatable_random
97 repeatable_random.restore_non_repeatability()
98 self.clean_pending(required_to_quiesce=True)
100 def clean_pending(self, dummy=None, required_to_quiesce=True):
102 This handy method cleans all pending tasks from the reactor.
104 When writing a unit test, consider the following question:
106 Is the code that you are testing required to release control once it
107 has done its job, so that it is impossible for it to later come around
108 (with a delayed reactor task) and do anything further?
110 If so, then trial will usefully test that for you -- if the code under
111 test leaves any pending tasks on the reactor then trial will fail it.
113 On the other hand, some code is *not* required to release control -- some
114 code is allowed to continuously maintain control by rescheduling reactor
115 tasks in order to do ongoing work. Trial will incorrectly require that
116 code to clean up all its tasks from the reactor.
118 Most people think that such code should be amended to have an optional
119 "shutdown" operation that releases all control, but on the contrary it is
120 good design for some code to *not* have a shutdown operation, but instead
121 to have a "crash-only" design in which it recovers from crash on startup.
123 If the code under test is of the "long-running" kind, which is *not*
124 required to shutdown cleanly in order to pass tests, then you can simply
125 call testutil.clean_pending() at the end of the unit test, and trial will
128 pending = reactor.getDelayedCalls()
129 active = bool(pending)
134 print "WEIRNESS! pending timed call not active+!"
135 if required_to_quiesce and active:
136 self.fail("Reactor was still active when it was required to be quiescent.")
141 def make_readonly(path):
142 win32file.SetFileAttributes(path, win32con.FILE_ATTRIBUTE_READONLY)
143 def make_accessible(path):
144 win32file.SetFileAttributes(path, win32con.FILE_ATTRIBUTE_NORMAL)
147 def _make_readonly(path):
148 os.chmod(path, stat.S_IREAD)
149 os.chmod(os.path.dirname(path), stat.S_IREAD)
150 def _make_accessible(path):
151 os.chmod(os.path.dirname(path), stat.S_IWRITE | stat.S_IEXEC | stat.S_IREAD)
152 os.chmod(path, stat.S_IWRITE | stat.S_IEXEC | stat.S_IREAD)
153 make_readonly = _make_readonly
154 make_accessible = _make_accessible