Kaydet (Commit) abd08884 authored tarafından Thomas Wouters's avatar Thomas Wouters

The result of SF patch #1471578: big-memory tests for strings, lists and

tuples. Lots to be added, still, but this will give big-memory people
something to play with in 2.5 alpha 2, and hopefully get more people to
write these tests.
üst 98189244
......@@ -25,6 +25,7 @@ Command line options:
-N: nocoverdir -- Put coverage files alongside modules
-L: runleaks -- run the leaks(1) command just before exit
-R: huntrleaks -- search for reference leaks (needs debug build, v. slow)
-M: memlimit -- run very large memory-consuming tests
If non-option arguments are present, they are names for tests to run,
unless -x is given, in which case they are names for tests not to run.
......@@ -63,6 +64,19 @@ of times further it is run and 'fname' is the name of the file the
reports are written to. These parameters all have defaults (5, 4 and
"reflog.txt" respectively), so the minimal invocation is '-R ::'.
-M runs tests that require an exorbitant amount of memory. These tests
typically try to ascertain containers keep working when containing more than
2 bilion objects, and only work on 64-bit systems. The passed-in memlimit,
which is a string in the form of '2.5Gb', determines howmuch memory the
tests will limit themselves to (but they may go slightly over.) The number
shouldn't be more memory than the machine has (including swap memory). You
should also keep in mind that swap memory is generally much, much slower
than RAM, and setting memlimit to all available RAM or higher will heavily
tax the machine. On the other hand, it is no use running these tests with a
limit of less than 2.5Gb, and many require more than 20Gb. Tests that expect
to use more than memlimit memory will be skipped. The big-memory tests
generally run very, very long.
-u is used to specify which special resource intensive tests to run,
such as those requiring large file support or network connectivity.
The argument is a comma-separated list of words indicating the
......@@ -180,12 +194,12 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, generate=False,
test_support.record_original_stdout(sys.stdout)
try:
opts, args = getopt.getopt(sys.argv[1:], 'hvgqxsrf:lu:t:TD:NLR:w',
opts, args = getopt.getopt(sys.argv[1:], 'hvgqxsrf:lu:t:TD:NLR:wM:',
['help', 'verbose', 'quiet', 'generate',
'exclude', 'single', 'random', 'fromfile',
'findleaks', 'use=', 'threshold=', 'trace',
'coverdir=', 'nocoverdir', 'runleaks',
'huntrleaks=', 'verbose2',
'huntrleaks=', 'verbose2', 'memlimit=',
])
except getopt.error, msg:
usage(2, msg)
......@@ -241,6 +255,8 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, generate=False,
huntrleaks[1] = int(huntrleaks[1])
if len(huntrleaks[2]) == 0:
huntrleaks[2] = "reflog.txt"
elif o in ('-M', '--memlimit'):
test_support.set_memlimit(a)
elif o in ('-u', '--use'):
u = [x.lower() for x in a.split(',')]
for r in u:
......
from test import test_support
from test.test_support import bigmemtest, _1G, _2G
import unittest
import operator
import string
import sys
# Bigmem testing houserules:
#
# - Try not to allocate too many large objects. It's okay to rely on
# refcounting semantics, but don't forget that 's = create_largestring()'
# doesn't release the old 's' (if it exists) until well after its new
# value has been created. Use 'del s' before the create_largestring call.
#
# - Do *not* compare large objects using assertEquals or similar. It's a
# lengty operation and the errormessage will be utterly useless due to
# its size. To make sure whether a result has the right contents, better
# to use the strip or count methods, or compare meaningful slices.
#
# - Don't forget to test for large indices, offsets and results and such,
# in addition to large sizes.
#
# - When repeating an object (say, a substring, or a small list) to create
# a large object, make the subobject of a length that is not a power of
# 2. That way, int-wrapping problems are more easily detected.
#
# - While the bigmemtest decorator speaks of 'minsize', all tests will
# actually be called with a much smaller number too, in the normal
# test run (5Kb currently.) This is so the tests themselves get frequent
# testing Consequently, always make all large allocations based on the
# passed-in 'size', and don't rely on the size being very large. Also,
# memuse-per-size should remain sane (less than a few thousand); if your
# test uses more, adjust 'size' upward, instead.
class StrTest(unittest.TestCase):
@bigmemtest(minsize=_2G, memuse=2)
def test_capitalize(self, size):
SUBSTR = ' abc def ghi'
s = '-' * size + SUBSTR
caps = s.capitalize()
self.assertEquals(caps[-len(SUBSTR):],
SUBSTR.capitalize())
self.assertEquals(caps.lstrip('-'), SUBSTR)
@bigmemtest(minsize=_2G + 10, memuse=1)
def test_center(self, size):
SUBSTR = ' abc def ghi'
s = SUBSTR.center(size)
self.assertEquals(len(s), size)
lpadsize = rpadsize = (len(s) - len(SUBSTR)) // 2
if len(s) % 2:
lpadsize += 1
self.assertEquals(s[lpadsize:-rpadsize], SUBSTR)
self.assertEquals(s.strip(), SUBSTR.strip())
@bigmemtest(minsize=_2G, memuse=2)
def test_count(self, size):
SUBSTR = ' abc def ghi'
s = '.' * size + SUBSTR
self.assertEquals(s.count('.'), size)
s += '.'
self.assertEquals(s.count('.'), size + 1)
self.assertEquals(s.count(' '), 3)
self.assertEquals(s.count('i'), 1)
self.assertEquals(s.count('j'), 0)
@bigmemtest(minsize=0, memuse=1)
def test_decode(self, size):
pass
@bigmemtest(minsize=0, memuse=1)
def test_encode(self, size):
pass
@bigmemtest(minsize=_2G, memuse=2)
def test_endswith(self, size):
SUBSTR = ' abc def ghi'
s = '-' * size + SUBSTR
self.failUnless(s.endswith(SUBSTR))
self.failUnless(s.endswith(s))
s2 = '...' + s
self.failUnless(s2.endswith(s))
self.failIf(s.endswith('a' + SUBSTR))
self.failIf(SUBSTR.endswith(s))
@bigmemtest(minsize=_2G + 10, memuse=2)
def test_expandtabs(self, size):
s = '-' * size
tabsize = 8
self.assertEquals(s.expandtabs(), s)
del s
slen, remainder = divmod(size, tabsize)
s = ' \t' * slen
s = s.expandtabs(tabsize)
self.assertEquals(len(s), size - remainder)
self.assertEquals(len(s.strip(' ')), 0)
@bigmemtest(minsize=_2G, memuse=2)
def test_find(self, size):
SUBSTR = ' abc def ghi'
sublen = len(SUBSTR)
s = ''.join([SUBSTR, '-' * size, SUBSTR])
self.assertEquals(s.find(' '), 0)
self.assertEquals(s.find(SUBSTR), 0)
self.assertEquals(s.find(' ', sublen), sublen + size)
self.assertEquals(s.find(SUBSTR, len(SUBSTR)), sublen + size)
self.assertEquals(s.find('i'), SUBSTR.find('i'))
self.assertEquals(s.find('i', sublen),
sublen + size + SUBSTR.find('i'))
self.assertEquals(s.find('i', size),
sublen + size + SUBSTR.find('i'))
self.assertEquals(s.find('j'), -1)
@bigmemtest(minsize=_2G, memuse=2)
def test_index(self, size):
SUBSTR = ' abc def ghi'
sublen = len(SUBSTR)
s = ''.join([SUBSTR, '-' * size, SUBSTR])
self.assertEquals(s.index(' '), 0)
self.assertEquals(s.index(SUBSTR), 0)
self.assertEquals(s.index(' ', sublen), sublen + size)
self.assertEquals(s.index(SUBSTR, sublen), sublen + size)
self.assertEquals(s.index('i'), SUBSTR.index('i'))
self.assertEquals(s.index('i', sublen),
sublen + size + SUBSTR.index('i'))
self.assertEquals(s.index('i', size),
sublen + size + SUBSTR.index('i'))
self.assertRaises(ValueError, s.index, 'j')
@bigmemtest(minsize=_2G, memuse=2)
def test_isalnum(self, size):
SUBSTR = '123456'
s = 'a' * size + SUBSTR
self.failUnless(s.isalnum())
s += '.'
self.failIf(s.isalnum())
@bigmemtest(minsize=_2G, memuse=2)
def test_isalpha(self, size):
SUBSTR = 'zzzzzzz'
s = 'a' * size + SUBSTR
self.failUnless(s.isalpha())
s += '.'
self.failIf(s.isalpha())
@bigmemtest(minsize=_2G, memuse=2)
def test_isdigit(self, size):
SUBSTR = '123456'
s = '9' * size + SUBSTR
self.failUnless(s.isdigit())
s += 'z'
self.failIf(s.isdigit())
@bigmemtest(minsize=_2G, memuse=2)
def test_islower(self, size):
chars = ''.join([ chr(c) for c in range(255) if not chr(c).isupper() ])
repeats = size // len(chars) + 2
s = chars * repeats
self.failUnless(s.islower())
s += 'A'
self.failIf(s.islower())
@bigmemtest(minsize=_2G, memuse=2)
def test_isspace(self, size):
whitespace = ' \f\n\r\t\v'
repeats = size // len(whitespace) + 2
s = whitespace * repeats
self.failUnless(s.isspace())
s += 'j'
self.failIf(s.isspace())
@bigmemtest(minsize=_2G, memuse=2)
def test_istitle(self, size):
SUBSTR = '123456'
s = ''.join(['A', 'a' * size, SUBSTR])
self.failUnless(s.istitle())
s += 'A'
self.failUnless(s.istitle())
s += 'aA'
self.failIf(s.istitle())
@bigmemtest(minsize=_2G, memuse=2)
def test_isupper(self, size):
chars = ''.join([ chr(c) for c in range(255) if not chr(c).islower() ])
repeats = size // len(chars) + 2
s = chars * repeats
self.failUnless(s.isupper())
s += 'a'
self.failIf(s.isupper())
@bigmemtest(minsize=_2G, memuse=2)
def test_join(self, size):
s = 'A' * size
x = s.join(['aaaaa', 'bbbbb'])
self.assertEquals(x.count('a'), 5)
self.assertEquals(x.count('b'), 5)
self.failUnless(x.startswith('aaaaaA'))
self.failUnless(x.endswith('Abbbbb'))
@bigmemtest(minsize=_2G + 10, memuse=1)
def test_ljust(self, size):
SUBSTR = ' abc def ghi'
s = SUBSTR.ljust(size)
self.failUnless(s.startswith(SUBSTR + ' '))
self.assertEquals(len(s), size)
self.assertEquals(s.strip(), SUBSTR.strip())
@bigmemtest(minsize=_2G + 10, memuse=2)
def test_lower(self, size):
s = 'A' * size
s = s.lower()
self.assertEquals(len(s), size)
self.assertEquals(s.count('a'), size)
@bigmemtest(minsize=_2G + 10, memuse=1)
def test_lstrip(self, size):
SUBSTR = 'abc def ghi'
s = SUBSTR.rjust(size)
self.assertEquals(len(s), size)
self.assertEquals(s.lstrip(), SUBSTR.lstrip())
del s
s = SUBSTR.ljust(size)
self.assertEquals(len(s), size)
stripped = s.lstrip()
self.failUnless(stripped is s)
@bigmemtest(minsize=_2G + 10, memuse=2)
def test_replace(self, size):
replacement = 'a'
s = ' ' * size
s = s.replace(' ', replacement)
self.assertEquals(len(s), size)
self.assertEquals(s.count(replacement), size)
s = s.replace(replacement, ' ', size - 4)
self.assertEquals(len(s), size)
self.assertEquals(s.count(replacement), 4)
self.assertEquals(s[-10:], ' aaaa')
@bigmemtest(minsize=_2G, memuse=2)
def test_rfind(self, size):
SUBSTR = ' abc def ghi'
sublen = len(SUBSTR)
s = ''.join([SUBSTR, '-' * size, SUBSTR])
self.assertEquals(s.rfind(' '), sublen + size + SUBSTR.rfind(' '))
self.assertEquals(s.rfind(SUBSTR), sublen + size)
self.assertEquals(s.rfind(' ', 0, size), SUBSTR.rfind(' '))
self.assertEquals(s.rfind(SUBSTR, 0, sublen + size), 0)
self.assertEquals(s.rfind('i'), sublen + size + SUBSTR.rfind('i'))
self.assertEquals(s.rfind('i', 0, sublen), SUBSTR.rfind('i'))
self.assertEquals(s.rfind('i', 0, sublen + size),
SUBSTR.rfind('i'))
self.assertEquals(s.rfind('j'), -1)
@bigmemtest(minsize=_2G, memuse=2)
def test_rindex(self, size):
SUBSTR = ' abc def ghi'
sublen = len(SUBSTR)
s = ''.join([SUBSTR, '-' * size, SUBSTR])
self.assertEquals(s.rindex(' '),
sublen + size + SUBSTR.rindex(' '))
self.assertEquals(s.rindex(SUBSTR), sublen + size)
self.assertEquals(s.rindex(' ', 0, sublen + size - 1),
SUBSTR.rindex(' '))
self.assertEquals(s.rindex(SUBSTR, 0, sublen + size), 0)
self.assertEquals(s.rindex('i'),
sublen + size + SUBSTR.rindex('i'))
self.assertEquals(s.rindex('i', 0, sublen), SUBSTR.rindex('i'))
self.assertEquals(s.rindex('i', 0, sublen + size),
SUBSTR.rindex('i'))
self.assertRaises(ValueError, s.rindex, 'j')
@bigmemtest(minsize=_2G + 10, memuse=1)
def test_rjust(self, size):
SUBSTR = ' abc def ghi'
s = SUBSTR.ljust(size)
self.failUnless(s.startswith(SUBSTR + ' '))
self.assertEquals(len(s), size)
self.assertEquals(s.strip(), SUBSTR.strip())
@bigmemtest(minsize=_2G + 10, memuse=1)
def test_rstrip(self, size):
SUBSTR = ' abc def ghi'
s = SUBSTR.ljust(size)
self.assertEquals(len(s), size)
self.assertEquals(s.rstrip(), SUBSTR.rstrip())
del s
s = SUBSTR.rjust(size)
self.assertEquals(len(s), size)
stripped = s.rstrip()
self.failUnless(stripped is s)
# The test takes about size bytes to build a string, and then about
# sqrt(size) substrings of sqrt(size) in size and a list to
# hold sqrt(size) items. It's close but just over 2x size.
@bigmemtest(minsize=_2G, memuse=2.1)
def test_split_small(self, size):
# Crudely calculate an estimate so that the result of s.split won't
# take up an inordinate amount of memory
chunksize = int(size ** 0.5 + 2)
SUBSTR = 'a' + ' ' * chunksize
s = SUBSTR * chunksize
l = s.split()
self.assertEquals(len(l), chunksize)
self.assertEquals(set(l), set(['a']))
del l
l = s.split('a')
self.assertEquals(len(l), chunksize + 1)
self.assertEquals(set(l), set(['', ' ' * chunksize]))
# Allocates a string of twice size (and briefly two) and a list of
# size. Because of internal affairs, the s.split() call produces a
# list of size times the same one-character string, so we only
# suffer for the list size. (Otherwise, it'd cost another 48 times
# size in bytes!) Nevertheless, a list of size takes
# 8*size bytes.
@bigmemtest(minsize=_2G + 5, memuse=10)
def test_split_large(self, size):
s = ' a' * size + ' '
l = s.split()
self.assertEquals(len(l), size)
self.assertEquals(set(l), set(['a']))
del l
l = s.split('a')
self.assertEquals(len(l), size + 1)
self.assertEquals(set(l), set([' ']))
@bigmemtest(minsize=_2G, memuse=2.1)
def test_splitlines(self, size):
# Crudely calculate an estimate so that the result of s.split won't
# take up an inordinate amount of memory
chunksize = int(size ** 0.5 + 2) // 2
SUBSTR = ' ' * chunksize + '\n' + ' ' * chunksize + '\r\n'
s = SUBSTR * chunksize
l = s.splitlines()
self.assertEquals(len(l), chunksize * 2)
self.assertEquals(set(l), set([' ' * chunksize]))
@bigmemtest(minsize=_2G, memuse=2)
def test_startswith(self, size):
SUBSTR = ' abc def ghi'
s = '-' * size + SUBSTR
self.failUnless(s.startswith(s))
self.failUnless(s.startswith('-' * size))
self.failIf(s.startswith(SUBSTR))
@bigmemtest(minsize=_2G, memuse=1)
def test_strip(self, size):
SUBSTR = ' abc def ghi '
s = SUBSTR.rjust(size)
self.assertEquals(len(s), size)
self.assertEquals(s.strip(), SUBSTR.strip())
del s
s = SUBSTR.ljust(size)
self.assertEquals(len(s), size)
self.assertEquals(s.strip(), SUBSTR.strip())
@bigmemtest(minsize=_2G, memuse=2)
def test_swapcase(self, size):
SUBSTR = "aBcDeFG12.'\xa9\x00"
sublen = len(SUBSTR)
repeats = size // sublen + 2
s = SUBSTR * repeats
s = s.swapcase()
self.assertEquals(len(s), sublen * repeats)
self.assertEquals(s[:sublen * 3], SUBSTR.swapcase() * 3)
self.assertEquals(s[-sublen * 3:], SUBSTR.swapcase() * 3)
@bigmemtest(minsize=_2G, memuse=2)
def test_title(self, size):
SUBSTR = 'SpaaHAaaAaham'
s = SUBSTR * (size // len(SUBSTR) + 2)
s = s.title()
self.failUnless(s.startswith((SUBSTR * 3).title()))
self.failUnless(s.endswith(SUBSTR.lower() * 3))
@bigmemtest(minsize=_2G, memuse=2)
def test_translate(self, size):
trans = string.maketrans('.aZ', '-!$')
SUBSTR = 'aZz.z.Aaz.'
sublen = len(SUBSTR)
repeats = size // sublen + 2
s = SUBSTR * repeats
s = s.translate(trans)
self.assertEquals(len(s), repeats * sublen)
self.assertEquals(s[:sublen], SUBSTR.translate(trans))
self.assertEquals(s[-sublen:], SUBSTR.translate(trans))
self.assertEquals(s.count('.'), 0)
self.assertEquals(s.count('!'), repeats * 2)
self.assertEquals(s.count('z'), repeats * 3)
@bigmemtest(minsize=_2G + 5, memuse=2)
def test_upper(self, size):
s = 'a' * size
s = s.upper()
self.assertEquals(len(s), size)
self.assertEquals(s.count('A'), size)
@bigmemtest(minsize=_2G + 20, memuse=1)
def test_zfill(self, size):
SUBSTR = '-568324723598234'
s = SUBSTR.zfill(size)
self.failUnless(s.endswith('0' + SUBSTR[1:]))
self.failUnless(s.startswith('-0'))
self.assertEquals(len(s), size)
self.assertEquals(s.count('0'), size - len(SUBSTR))
@bigmemtest(minsize=_2G + 10, memuse=2)
def test_format(self, size):
s = '-' * size
sf = '%s' % (s,)
self.failUnless(s == sf)
del sf
sf = '..%s..' % (s,)
self.assertEquals(len(sf), len(s) + 4)
self.failUnless(sf.startswith('..-'))
self.failUnless(sf.endswith('-..'))
del s, sf
size = (size // 2)
edge = '-' * size
s = ''.join([edge, '%s', edge])
del edge
s = s % '...'
self.assertEquals(len(s), size * 2 + 3)
self.assertEquals(s.count('.'), 3)
self.assertEquals(s.count('-'), size * 2)
@bigmemtest(minsize=_2G + 10, memuse=2)
def test_repr_small(self, size):
s = '-' * size
s = repr(s)
self.assertEquals(len(s), size + 2)
self.assertEquals(s[0], "'")
self.assertEquals(s[-1], "'")
self.assertEquals(s.count('-'), size)
del s
# repr() will create a string four times as large as this 'binary
# string', but we don't want to allocate much more than twice
# size in total. (We do extra testing in test_repr_large())
size = size // 5 * 2
s = '\x00' * size
s = repr(s)
self.assertEquals(len(s), size * 4 + 2)
self.assertEquals(s[0], "'")
self.assertEquals(s[-1], "'")
self.assertEquals(s.count('\\'), size)
self.assertEquals(s.count('0'), size * 2)
@bigmemtest(minsize=_2G + 10, memuse=5)
def test_repr_large(self, size):
s = '\x00' * size
s = repr(s)
self.assertEquals(len(s), size * 4 + 2)
self.assertEquals(s[0], "'")
self.assertEquals(s[-1], "'")
self.assertEquals(s.count('\\'), size)
self.assertEquals(s.count('0'), size * 2)
# This test is meaningful even with size < 2G, as long as the
# doubled string is > 2G (but it tests more if both are > 2G :)
@bigmemtest(minsize=_1G + 2, memuse=3)
def test_concat(self, size):
s = '.' * size
self.assertEquals(len(s), size)
s = s + s
self.assertEquals(len(s), size * 2)
self.assertEquals(s.count('.'), size * 2)
# This test is meaningful even with size < 2G, as long as the
# repeated string is > 2G (but it tests more if both are > 2G :)
@bigmemtest(minsize=_1G + 2, memuse=3)
def test_repeat(self, size):
s = '.' * size
self.assertEquals(len(s), size)
s = s * 2
self.assertEquals(len(s), size * 2)
self.assertEquals(s.count('.'), size * 2)
@bigmemtest(minsize=_2G + 20, memuse=1)
def test_slice_and_getitem(self, size):
SUBSTR = '0123456789'
sublen = len(SUBSTR)
s = SUBSTR * (size // sublen)
stepsize = len(s) // 100
stepsize = stepsize - (stepsize % sublen)
for i in range(0, len(s) - stepsize, stepsize):
self.assertEquals(s[i], SUBSTR[0])
self.assertEquals(s[i:i + sublen], SUBSTR)
self.assertEquals(s[i:i + sublen:2], SUBSTR[::2])
if i > 0:
self.assertEquals(s[i + sublen - 1:i - 1:-3],
SUBSTR[sublen::-3])
# Make sure we do some slicing and indexing near the end of the
# string, too.
self.assertEquals(s[len(s) - 1], SUBSTR[-1])
self.assertEquals(s[-1], SUBSTR[-1])
self.assertEquals(s[len(s) - 10], SUBSTR[0])
self.assertEquals(s[-sublen], SUBSTR[0])
self.assertEquals(s[len(s):], '')
self.assertEquals(s[len(s) - 1:], SUBSTR[-1])
self.assertEquals(s[-1:], SUBSTR[-1])
self.assertEquals(s[len(s) - sublen:], SUBSTR)
self.assertEquals(s[-sublen:], SUBSTR)
self.assertEquals(len(s[:]), len(s))
self.assertEquals(len(s[:len(s) - 5]), len(s) - 5)
self.assertEquals(len(s[5:-5]), len(s) - 10)
self.assertRaises(IndexError, operator.getitem, s, len(s))
self.assertRaises(IndexError, operator.getitem, s, len(s) + 1)
self.assertRaises(IndexError, operator.getitem, s, len(s) + 1<<31)
@bigmemtest(minsize=_2G, memuse=2)
def test_contains(self, size):
SUBSTR = '0123456789'
edge = '-' * (size // 2)
s = ''.join([edge, SUBSTR, edge])
del edge
self.failUnless(SUBSTR in s)
self.failIf(SUBSTR * 2 in s)
self.failUnless('-' in s)
self.failIf('a' in s)
s += 'a'
self.failUnless('a' in s)
@bigmemtest(minsize=_2G + 10, memuse=2)
def test_compare(self, size):
s1 = '-' * size
s2 = '-' * size
self.failUnless(s1 == s2)
del s2
s2 = s1 + 'a'
self.failIf(s1 == s2)
del s2
s2 = '.' * size
self.failIf(s1 == s2)
@bigmemtest(minsize=_2G + 10, memuse=1)
def test_hash(self, size):
# Not sure if we can do any meaningful tests here... Even if we
# start relying on the exact algorithm used, the result will be
# different depending on the size of the C 'long int'. Even this
# test is dodgy (there's no *guarantee* that the two things should
# have a different hash, even if they, in the current
# implementation, almost always do.)
s = '\x00' * size
h1 = hash(s)
del s
s = '\x00' * (size + 1)
self.failIf(h1 == hash(s))
class TupleTest(unittest.TestCase):
# Tuples have a small, fixed-sized head and an array of pointers to
# data. Since we're testing 64-bit addressing, we can assume that the
# pointers are 8 bytes, and that thus that the tuples take up 8 bytes
# per size.
# As a side-effect of testing long tuples, these tests happen to test
# having more than 2<<31 references to any given object. Hence the
# use of different types of objects as contents in different tests.
@bigmemtest(minsize=_2G + 2, memuse=16)
def test_compare(self, size):
t1 = (u'',) * size
t2 = (u'',) * size
self.failUnless(t1 == t2)
del t2
t2 = (u'',) * (size + 1)
self.failIf(t1 == t2)
del t2
t2 = (1,) * size
self.failIf(t1 == t2)
# Test concatenating into a single tuple of more than 2G in length,
# and concatenating a tuple of more than 2G in length separately, so
# the smaller test still gets run even if there isn't memory for the
# larger test (but we still let the tester know the larger test is
# skipped, in verbose mode.)
def basic_concat_test(self, size):
t = ((),) * size
self.assertEquals(len(t), size)
t = t + t
self.assertEquals(len(t), size * 2)
@bigmemtest(minsize=_2G // 2 + 2, memuse=24)
def test_concat_small(self, size):
return self.basic_concat_test(size)
@bigmemtest(minsize=_2G + 2, memuse=24)
def test_concat_large(self, size):
return self.basic_concat_test(size)
@bigmemtest(minsize=_2G // 5 + 10, memuse=8*5)
def test_contains(self, size):
t = (1, 2, 3, 4, 5) * size
self.assertEquals(len(t), size * 5)
self.failUnless(5 in t)
self.failIf((1, 2, 3, 4, 5) in t)
self.failIf(0 in t)
@bigmemtest(minsize=_2G + 10, memuse=8)
def test_hash(self, size):
t1 = (0,) * size
h1 = hash(t1)
del t1
t2 = (0,) * (size + 1)
self.failIf(h1 == hash(t2))
@bigmemtest(minsize=_2G + 10, memuse=8)
def test_index_and_slice(self, size):
t = (None,) * size
self.assertEquals(len(t), size)
self.assertEquals(t[-1], None)
self.assertEquals(t[5], None)
self.assertEquals(t[size - 1], None)
self.assertRaises(IndexError, operator.getitem, t, size)
self.assertEquals(t[:5], (None,) * 5)
self.assertEquals(t[-5:], (None,) * 5)
self.assertEquals(t[20:25], (None,) * 5)
self.assertEquals(t[-25:-20], (None,) * 5)
self.assertEquals(t[size - 5:], (None,) * 5)
self.assertEquals(t[size - 5:size], (None,) * 5)
self.assertEquals(t[size - 6:size - 2], (None,) * 4)
self.assertEquals(t[size:size], ())
self.assertEquals(t[size:size+5], ())
# Like test_concat, split in two.
def basic_test_repeat(self, size):
t = ('',) * size
self.assertEquals(len(t), size)
t = t * 2
self.assertEquals(len(t), size * 2)
@bigmemtest(minsize=_2G // 2 + 2, memuse=24)
def test_repeat_small(self, size):
return self.basic_test_repeat(size)
@bigmemtest(minsize=_2G + 2, memuse=24)
def test_repeat_large(self, size):
return self.basic_test_repeat(size)
# Like test_concat, split in two.
def basic_test_repr(self, size):
t = (0,) * size
s = repr(t)
# The repr of a tuple of 0's is exactly three times the tuple length.
self.assertEquals(len(s), size * 3)
self.assertEquals(s[:5], '(0, 0')
self.assertEquals(s[-5:], '0, 0)')
self.assertEquals(s.count('0'), size)
@bigmemtest(minsize=_2G // 3 + 2, memuse=8+3)
def test_repr_small(self, size):
return self.basic_test_repr(size)
@bigmemtest(minsize=_2G + 2, memuse=8+3)
def test_repr_large(self, size):
return self.basic_test_repr(size)
class ListTest(unittest.TestCase):
# Like tuples, lists have a small, fixed-sized head and an array of
# pointers to data, so 8 bytes per size. Also like tuples, we make the
# lists hold references to various objects to test their refcount
# limits.
@bigmemtest(minsize=_2G + 2, memuse=16)
def test_compare(self, size):
l1 = [u''] * size
l2 = [u''] * size
self.failUnless(l1 == l2)
del l2
l2 = [u''] * (size + 1)
self.failIf(l1 == l2)
del l2
l2 = [2] * size
self.failIf(l1 == l2)
# Test concatenating into a single list of more than 2G in length,
# and concatenating a list of more than 2G in length separately, so
# the smaller test still gets run even if there isn't memory for the
# larger test (but we still let the tester know the larger test is
# skipped, in verbose mode.)
def basic_test_concat(self, size):
l = [[]] * size
self.assertEquals(len(l), size)
l = l + l
self.assertEquals(len(l), size * 2)
@bigmemtest(minsize=_2G // 2 + 2, memuse=24)
def test_concat_small(self, size):
return self.basic_test_concat(size)
@bigmemtest(minsize=_2G + 2, memuse=24)
def test_concat_large(self, size):
return self.basic_test_concat(size)
@bigmemtest(minsize=_2G // 5 + 10, memuse=8*5)
def test_contains(self, size):
l = [1, 2, 3, 4, 5] * size
self.assertEquals(len(l), size * 5)
self.failUnless(5 in l)
self.failIf([1, 2, 3, 4, 5] in l)
self.failIf(0 in l)
@bigmemtest(minsize=_2G + 10, memuse=8)
def test_hash(self, size):
l = [0] * size
self.failUnlessRaises(TypeError, hash, l)
@bigmemtest(minsize=_2G + 10, memuse=8)
def test_index_and_slice(self, size):
l = [None] * size
self.assertEquals(len(l), size)
self.assertEquals(l[-1], None)
self.assertEquals(l[5], None)
self.assertEquals(l[size - 1], None)
self.assertRaises(IndexError, operator.getitem, l, size)
self.assertEquals(l[:5], [None] * 5)
self.assertEquals(l[-5:], [None] * 5)
self.assertEquals(l[20:25], [None] * 5)
self.assertEquals(l[-25:-20], [None] * 5)
self.assertEquals(l[size - 5:], [None] * 5)
self.assertEquals(l[size - 5:size], [None] * 5)
self.assertEquals(l[size - 6:size - 2], [None] * 4)
self.assertEquals(l[size:size], [])
self.assertEquals(l[size:size+5], [])
l[size - 2] = 5
self.assertEquals(len(l), size)
self.assertEquals(l[-3:], [None, 5, None])
self.assertEquals(l.count(5), 1)
self.assertRaises(IndexError, operator.setitem, l, size, 6)
self.assertEquals(len(l), size)
l[size - 7:] = [1, 2, 3, 4, 5]
size -= 2
self.assertEquals(len(l), size)
self.assertEquals(l[-7:], [None, None, 1, 2, 3, 4, 5])
l[:7] = [1, 2, 3, 4, 5]
size -= 2
self.assertEquals(len(l), size)
self.assertEquals(l[:7], [1, 2, 3, 4, 5, None, None])
del l[size - 1]
size -= 1
self.assertEquals(len(l), size)
self.assertEquals(l[-1], 4)
del l[-2:]
size -= 2
self.assertEquals(len(l), size)
self.assertEquals(l[-1], 2)
del l[0]
size -= 1
self.assertEquals(len(l), size)
self.assertEquals(l[0], 2)
del l[:2]
size -= 2
self.assertEquals(len(l), size)
self.assertEquals(l[0], 4)
# Like test_concat, split in two.
def basic_test_repeat(self, size):
l = [] * size
self.failIf(l)
l = [''] * size
self.assertEquals(len(l), size)
l = l * 2
self.assertEquals(len(l), size * 2)
@bigmemtest(minsize=_2G // 2 + 2, memuse=24)
def test_repeat_small(self, size):
return self.basic_test_repeat(size)
@bigmemtest(minsize=_2G + 2, memuse=24)
def test_repeat_large(self, size):
return self.basic_test_repeat(size)
# Test repr-result of >2G
def basic_test_repr(self, size):
l = [0] * size
s = repr(l)
# The repr of a list of 0's is exactly three times the list length.
self.assertEquals(len(s), size * 3)
self.assertEquals(s[:5], '[0, 0')
self.assertEquals(s[-5:], '0, 0]')
self.assertEquals(s.count('0'), size)
@bigmemtest(minsize=_2G // 3 + 2, memuse=8 + 3)
def test_repr_small(self, size):
return self.basic_test_repr(size)
@bigmemtest(minsize=_2G + 2, memuse=8 + 3)
def test_repr_large(self, size):
return self.basic_test_repr(size)
@bigmemtest(minsize=_2G, memuse=8)
def test_append(self, size):
l = [object()] * size
l.append(object())
self.assertEquals(len(l), size+1)
self.failUnless(l[-3] is l[-2])
self.failIf(l[-2] is l[-1])
@bigmemtest(minsize=_2G // 5 + 2, memuse=8 * 5)
def test_count(self, size):
l = [1, 2, 3, 4, 5] * size
self.assertEquals(l.count(1), size)
self.assertEquals(l.count("1"), 0)
def basic_test_extend(self, size):
l = [file] * size
l.extend(l)
self.assertEquals(len(l), size * 2)
self.failUnless(l[0] is l[-1])
self.failUnless(l[size - 1] is l[size + 1])
@bigmemtest(minsize=_2G // 2 + 2, memuse=8)
def test_extend_small(self, size):
return self.basic_test_extend(size)
@bigmemtest(minsize=_2G + 2, memuse=8)
def test_extend_large(self, size):
return self.basic_test_extend(size)
@bigmemtest(minsize=_2G + 10, memuse=8)
def test_index(self, size):
l = [1L, 2L, 3L, 4L, 5L] * (size // 5)
self.assertEquals(l.index(1), 0)
self.assertEquals(l.index(5, size - 5), size - 1)
self.assertEquals(l.index(5, size - 5, size), size - 1)
self.assertRaises(ValueError, l.index, 1, size - 4, size)
self.assertRaises(ValueError, l.index, 6L)
@bigmemtest(minsize=_2G + 10, memuse=8)
def test_insert(self, size):
l = [1.0] * size
l.insert(size - 1, "A")
size += 1
self.assertEquals(len(l), size)
self.assertEquals(l[-3:], [1.0, "A", 1.0])
l.insert(size + 1, "B")
size += 1
self.assertEquals(len(l), size)
self.assertEquals(l[-3:], ["A", 1.0, "B"])
l.insert(1, "C")
size += 1
self.assertEquals(len(l), size)
self.assertEquals(l[:3], [1.0, "C", 1.0])
self.assertEquals(l[size - 3:], ["A", 1.0, "B"])
@bigmemtest(minsize=_2G + 20, memuse=8)
def test_pop(self, size):
l = [u"a", u"b", u"c", u"d", u"e"] * (size // 5)
self.assertEquals(len(l), size)
item = l.pop()
size -= 1
self.assertEquals(len(l), size)
self.assertEquals(item, u"e")
item = l.pop(0)
size -= 1
self.assertEquals(len(l), size)
self.assertEquals(item, u"a")
item = l.pop(size - 2)
size -= 1
self.assertEquals(len(l), size)
self.assertEquals(item, u"c")
@bigmemtest(minsize=_2G + 10, memuse=8)
def test_remove(self, size):
l = [10] * size
self.assertEquals(len(l), size)
l.remove(10)
size -= 1
self.assertEquals(len(l), size)
l.append(5)
size += 1
self.assertEquals(len(l), size)
self.assertEquals(l[-2:], [10, 5])
l.remove(5)
size -= 1
self.assertEquals(len(l), size)
self.assertEquals(l[-2:], [10, 10])
@bigmemtest(minsize=_2G + 10, memuse=8)
def test_reverse(self, size):
l = [1, 2, 3, 4, 5] * (size // 5)
l.reverse()
self.assertEquals(len(l), size)
self.assertEquals(l[-5:], [5, 4, 3, 2, 1])
self.assertEquals(l[:5], [5, 4, 3, 2, 1])
@bigmemtest(minsize=_2G + 10, memuse=8)
def test_sort(self, size):
l = [1, 2, 3, 4, 5] * (size // 5)
l.sort()
self.assertEquals(len(l), size)
self.assertEquals(l.count(1), size // 5)
self.assertEquals(l[:10], [1] * 10)
self.assertEquals(l[-10:], [5] * 10)
def test_main():
test_support.run_unittest(StrTest, TupleTest, ListTest)
if __name__ == '__main__':
if len(sys.argv) > 1:
test_support.set_memlimit(sys.argv[1])
test_main()
......@@ -31,6 +31,8 @@ class ResourceDenied(TestSkipped):
verbose = 1 # Flag set to 0 by regrtest.py
use_resources = None # Flag set to [] by regrtest.py
max_memuse = 0 # Disable bigmem tests (they will still be run with
# small sizes, to make sure they work.)
# _original_stdout is meant to hold stdout at the time regrtest began.
# This may be "the real" stdout, or IDLE's emulation of stdout, or whatever.
......@@ -249,6 +251,72 @@ def open_urlresource(url):
fn, _ = urllib.urlretrieve(url, filename)
return open(fn)
#=======================================================================
# Big-memory-test support. Separate from 'resources' because memory use should be configurable.
# Some handy shorthands. Note that these are used for byte-limits as well
# as size-limits, in the various bigmem tests
_1M = 1024*1024
_1G = 1024 * _1M
_2G = 2 * _1G
def set_memlimit(limit):
import re
global max_memuse
sizes = {
'k': 1024,
'm': _1M,
'g': _1G,
't': 1024*_1G,
}
m = re.match(r'(\d+(\.\d+)?) (K|M|G|T)b?$', limit,
re.IGNORECASE | re.VERBOSE)
if m is None:
raise ValueError('Invalid memory limit %r' % (limit,))
memlimit = int(float(m.group(1)) * sizes[m.group(3).lower()])
if memlimit < 2.5*_1G:
raise ValueError('Memory limit %r too low to be useful' % (limit,))
max_memuse = memlimit
def bigmemtest(minsize, memuse, overhead=5*_1M):
"""Decorator for bigmem tests.
'minsize' is the minimum useful size for the test (in arbitrary,
test-interpreted units.) 'memuse' is the number of 'bytes per size' for
the test, or a good estimate of it. 'overhead' specifies fixed overhead,
independant of the testsize, and defaults to 5Mb.
The decorator tries to guess a good value for 'size' and passes it to
the decorated test function. If minsize * memuse is more than the
allowed memory use (as defined by max_memuse), the test is skipped.
Otherwise, minsize is adjusted upward to use up to max_memuse.
"""
def decorator(f):
def wrapper(self):
if not max_memuse:
# If max_memuse is 0 (the default),
# we still want to run the tests with size set to a few kb,
# to make sure they work. We still want to avoid using
# too much memory, though, but we do that noisily.
maxsize = 1024*5
self.failIf(maxsize * memuse + overhead > 20 * _1M)
else:
maxsize = int((max_memuse - overhead) / memuse)
if maxsize < minsize:
# Really ought to print 'test skipped' or something
if verbose:
sys.stderr.write("Skipping %s because of memory "
"constraint\n" % (f.__name__,))
return
# Try to keep some breathing room in memory use
maxsize = max(maxsize - 50 * _1M, minsize)
return f(self, maxsize)
wrapper.minsize = minsize
wrapper.memuse = memuse
wrapper.overhead = overhead
return wrapper
return decorator
#=======================================================================
# Preliminary PyUNIT integration.
......
......@@ -171,6 +171,11 @@ Tests
it separately and by hand. It also wasn't cleaning up its changes to
the current Decimal context.
- regrtest.py now has a -M option to run tests that test the new limits of
containers, on 64-bit architectures. Running these tests is only sensible
on 64-bit machines with more than two gigabytes of memory. The argument
passed is the maximum amount of memory for the tests to use.
Tools
-----
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment