import logging
import random
import string
logger = logging.getLogger(__name__)
[docs]def cpuset(min_inc=0, max_inc=100, max_len=1000, used_vcpu=None):
cnt = int_exp(1, max_len)
cpus = []
cpusets = set()
for _ in range(cnt):
choice = random.randint(0, 2)
if choice == 0:
# Number
num = int_exp(min_inc, max_inc)
cpusets.add(num)
cpus.append(str(num))
elif choice == 1:
# Range
upper = int_exp(min_inc, max_inc - 1)
lower = int_exp(min_inc, upper)
cpusets.update(set(range(lower, upper + 1)))
cpus.append('-'.join((str(lower), str(upper))))
elif choice == 2:
# Negation
num = int_exp(min_inc, max_inc)
cpusets.discard(num)
cpus.append('^' + str(num))
if used_vcpu is not None:
for cpu in (used_vcpu & cpusets):
cpusets.discard(cpu)
cpus.append('^' + str(cpu))
if not cpusets:
cpusets.update(set(range(min_inc, max_inc + 1)))
cpus.append('-'.join((str(min_inc), str(max_inc))))
for cpu in (used_vcpu & cpusets):
cpusets.discard(cpu)
cpus.append('^' + str(cpu))
used_vcpu.update(cpusets)
cpu_str = ','.join(cpus)
return cpu_str
[docs]def count(min_inc=0, max_inc=None, lambd=0.1):
return int_exp(min_inc=min_inc, max_inc=max_inc, lambd=lambd)
[docs]def int_exp(min_inc=0, max_inc=None, lambd=0.01):
"""
A non accurate exponentially distributed integer generator.
"""
shift = int(random.expovariate(lambd))
if max_inc is not None:
if max_inc - min_inc == 0:
shift = 0
else:
shift %= max_inc - min_inc
if min_inc is not None and min_inc >= 0:
return min_inc + shift
else:
minus = random.random() > 0.5
if min_inc is not None and minus and shift > - min_inc:
shift %= - min_inc
return - shift if minus else shift
[docs]def integer(min_inc=0, max_inc=10):
return random.randint(min_inc, max_inc)
[docs]def text(min_len=5, max_len=10, charset=None, excludes=None):
"""
Generate a randomized string.
"""
if not excludes:
excludes = "\n\t\r\x0b\x0c"
if charset:
chars = list(charset)
else:
chars = []
for char in string.printable:
if char not in excludes:
chars.append(char)
length = random.randint(min_len, max_len)
result_str = ''.join(random.choice(chars) for _ in range(length))
return result_str
ALL_CHARS = set(string.ascii_letters) - set('&\'"<>')
# ALL_CHARS = set(string.printable)
[docs]def regex(re_str):
"""
Generate a random string matches given regular expression.
"""
def _end_chose(chosen, cmin, cmax):
current_group = result_stack[-1]
current_group.append((chosen, cmin, cmax, neg_chose))
def _start_group():
current_group = [[]]
result_stack.append(current_group[0])
result_stack[-2].append(current_group)
def _end_sub_group():
current_sub_group = []
result_stack[-2][-1].append(current_sub_group)
result_stack.pop()
result_stack.append(current_sub_group)
def _end_group(cmin, cmax):
parent_group = result_stack[-2]
result_stack.pop()
parent_group.append((tuple(parent_group.pop()), cmin, cmax))
def _randomize(stack):
if len(stack) == 3:
sub_stacks, cmin, cmax = stack
assert isinstance(sub_stacks, tuple)
sub_stacks = random.choice(sub_stacks)
assert isinstance(sub_stacks, list)
elif len(stack) == 4:
chose_str, cmin, cmax, neg = stack
sub_stacks = None
assert isinstance(chose_str, str)
if neg:
chose_str = ''.join(ALL_CHARS - set(chose_str))
if cmax is None:
cnt = int(random.expovariate(0.1)) + cmin
else:
cnt = random.randint(cmin, cmax)
rnd_str = ""
if sub_stacks is not None:
for _ in range(cnt):
for sub_stack in sub_stacks:
rnd_str += _randomize(sub_stack)
else:
for _ in range(cnt):
rnd_str += random.choice(chose_str)
return rnd_str
spanning = False
escaping = False
chosen = []
choosing = False
neg_chose = False
counting = None
count_min = 0
count_max = None
root_result = []
result_stack = [[root_result], root_result]
_start_group()
char_list = list(re_str)
while char_list:
c = char_list.pop(0)
if choosing:
if spanning:
span_from = chosen[-1]
span_to = c
cur = ord(span_from)
while cur < ord(span_to):
cur += 1
chosen += chr(cur)
spanning = False
continue
if escaping:
if c == 'n':
chosen += '\n'
elif c == 't':
chosen += '\t'
elif c == 'r':
chosen += '\r'
else:
chosen += c
escaping = False
continue
if c == ']':
choosing = False
if char_list and char_list[0] in '{?+*':
counting = 'chose'
else:
_end_chose(chosen, 1, 1)
continue
if c == '-':
spanning = True
continue
if c == '\\':
escaping = True
continue
else:
chosen += c
continue
if counting:
if c == ',':
count_max = 0
continue
if c == '}':
if count_max is None:
count_max = count_min
if counting == 'chose':
_end_chose(chosen, count_min, count_max)
elif counting == 'group':
_end_group(count_min, count_max)
else:
logger.error("Unknown counting type %s", counting)
counting = None
continue
if c in string.digits:
if count_max is None:
count_min = 10 * count_min + int(c)
else:
count_max = 10 * count_max + int(c)
continue
if c == '{':
count_min = 0
count_max = None
continue
if c in '?+*':
count_min = 0
count_max = None
if c == '+':
count_min = 1
if c == '?':
count_max = 1
if counting == 'chose':
_end_chose(chosen, count_min, count_max)
elif counting == 'group':
_end_group(count_min, count_max)
else:
logger.error("Unknown counting type %s", counting)
counting = None
continue
logger.error("Not handled counting character: %s", c)
if escaping:
_end_chose(c, 1, 1)
escaping = False
continue
if c == '(':
_start_group()
continue
if c == ')':
if char_list and char_list[0] in '{?+*':
counting = 'group'
else:
_end_group(1, 1)
continue
if c == '[':
choosing = True
if char_list[0] == '^':
char_list.pop(0)
neg_chose = True
chosen = ''
continue
if c == '\\':
escaping = True
continue
if c == '|':
_end_sub_group()
continue
chosen = c
if char_list and char_list[0] in '{?+*':
counting = 'chose'
else:
_end_chose(chosen, 1, 1)
continue
_end_group(1, 1)
return _randomize(result_stack[0][0][0])