mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-04-07 10:56:49 +00:00
Merge pull request #677 from tahoe-lafs/2266.remove-repeatable-random
Remove repeatable random test helper Fixes: ticket:2266
This commit is contained in:
commit
5e1c3df336
0
newsfragments/2266.minor
Normal file
0
newsfragments/2266.minor
Normal file
@ -173,26 +173,10 @@ class ShouldFailMixin(object):
|
||||
|
||||
|
||||
class TestMixin(SignalMixin):
|
||||
def setUp(self, repeatable=False):
|
||||
"""
|
||||
@param repeatable: install the repeatable_randomness hacks to attempt
|
||||
to without access to real randomness and real time.time from the
|
||||
code under test
|
||||
"""
|
||||
self.repeatable = repeatable
|
||||
if self.repeatable:
|
||||
import repeatable_random
|
||||
repeatable_random.force_repeatability()
|
||||
if hasattr(time, 'realtime'):
|
||||
self.teststarttime = time.realtime()
|
||||
else:
|
||||
self.teststarttime = time.time()
|
||||
def setUp(self):
|
||||
return super(TestMixin, self).setUp()
|
||||
|
||||
def tearDown(self):
|
||||
if self.repeatable:
|
||||
import repeatable_random
|
||||
repeatable_random.restore_non_repeatability()
|
||||
self.clean_pending(required_to_quiesce=True)
|
||||
return super(TestMixin, self).tearDown()
|
||||
|
||||
|
@ -1,90 +0,0 @@
|
||||
"""
|
||||
If you execute force_repeatability() then the following things are changed in the runtime:
|
||||
|
||||
1. random.random() and its sibling functions, and random.Random.seed() in the random module are seeded with a known seed so that they will return the same sequence on each run.
|
||||
2. os.urandom() is replaced by a fake urandom that returns a pseudorandom sequence.
|
||||
3. time.time() is replaced by a fake time that returns an incrementing number. (Original time.time is available as time.realtime.)
|
||||
|
||||
Which seed will be used?
|
||||
|
||||
If the environment variable REPEATABLE_RANDOMNESS_SEED is set, then it will use that. Else, it will use the current real time. In either case it logs the seed that it used.
|
||||
|
||||
Caveats:
|
||||
|
||||
1. If some code has acquired a random.Random object before force_repeatability() is executed, then that Random object will produce non-reproducible results. For example, the tempfile module in the Python Standard Library does this.
|
||||
2. Likewise if some code called time.time() before force_repeatability() was called, then it will have gotten a real time stamp. For example, trial does this. (Then it later subtracts that real timestamp from a faketime timestamp to calculate elapsed time, resulting in a large negative elapsed time.)
|
||||
3. The output from the fake urandom has weird distribution for performance reasons-- every byte after the first 20 bytes resulting from a single call to os.urandom() is zero. In practice this hasn't caused any problems.
|
||||
"""
|
||||
|
||||
import os, random, time
|
||||
if not hasattr(time, "realtime"):
|
||||
time.realtime = time.time
|
||||
if not hasattr(os, "realurandom"):
|
||||
os.realurandom = os.urandom
|
||||
if not hasattr(random, "realseed"):
|
||||
random.realseed = random.seed
|
||||
|
||||
tdelta = 0
|
||||
seeded = False
|
||||
def force_repeatability():
|
||||
now = 1043659734.0
|
||||
def faketime():
|
||||
global tdelta
|
||||
tdelta += 1
|
||||
return now + tdelta
|
||||
time.faketime = faketime
|
||||
time.time = faketime
|
||||
|
||||
from allmydata.util.idlib import i2b
|
||||
def fakeurandom(n):
|
||||
if n > 20:
|
||||
z = i2b(random.getrandbits(20*8))
|
||||
elif n == 0:
|
||||
return ''
|
||||
else:
|
||||
z = i2b(random.getrandbits(n*8))
|
||||
x = z + "0" * (n-len(z))
|
||||
assert len(x) == n
|
||||
return x
|
||||
os.fakeurandom = fakeurandom
|
||||
os.urandom = fakeurandom
|
||||
|
||||
global seeded
|
||||
if not seeded:
|
||||
SEED = os.environ.get('REPEATABLE_RANDOMNESS_SEED', None)
|
||||
|
||||
if SEED is None:
|
||||
# Generate a seed which is integral and fairly short (to ease cut-and-paste, writing it down, etc.).
|
||||
t = time.realtime()
|
||||
subsec = t % 1
|
||||
t += (subsec * 1000000)
|
||||
t %= 1000000
|
||||
SEED = long(t)
|
||||
import sys
|
||||
sys.stdout.write("REPEATABLE_RANDOMNESS_SEED: %s\n" % SEED) ; sys.stdout.flush()
|
||||
sys.stdout.write("In order to reproduce this run of the code, set the environment variable \"REPEATABLE_RANDOMNESS_SEED\" to %s before executing.\n" % SEED) ; sys.stdout.flush()
|
||||
random.seed(SEED)
|
||||
|
||||
def seed_which_refuses(a):
|
||||
sys.stdout.write("I refuse to reseed to %s. Go away!\n" % (a,)) ; sys.stdout.flush()
|
||||
return
|
||||
random.realseed = random.seed
|
||||
random.seed = seed_which_refuses
|
||||
seeded = True
|
||||
|
||||
import setutil
|
||||
setutil.RandomSet.DETERMINISTIC = True
|
||||
|
||||
def restore_real_clock():
|
||||
time.time = time.realtime
|
||||
|
||||
def restore_real_urandom():
|
||||
os.urandom = os.realurandom
|
||||
|
||||
def restore_real_seed():
|
||||
random.seed = random.realseed
|
||||
|
||||
def restore_non_repeatability():
|
||||
restore_real_seed()
|
||||
restore_real_urandom()
|
||||
restore_real_clock()
|
Loading…
x
Reference in New Issue
Block a user