graph = {}
graph['start'] = {
'set': {},
- 'choices': ['node1']
+ 'choices': ['node2']
}
graph['leaf'] = {
'set': {
},
'choices': ['leaf']
}
+ graph['node2'] = {
+ 'set': {
+ 'randkey': 'value-{random 10-15 printable}',
+ 'path': '/{bucket_readable}',
+ 'indirect_key1': '{key1}'
+ },
+ 'choices': ['leaf']
+ }
graph['bad_node'] = {
'set': {
'key1': 'value1'
eq(decision['key2'], 'value2')
e = assert_raises(KeyError, lambda x: decision[x], 'key3')
+
def test_descend_node():
graph = build_graph()
prng = random.Random(1)
eq(decision['key2'], 'value2')
eq(decision['key3'], 'value3')
+
def test_descend_bad_node():
graph = build_graph()
prng = random.Random(1)
assert_raises(KeyError, descend_graph, graph, 'bad_node', prng)
+
+def test_SpecialVariables_dict():
+ prng = random.Random(1)
+ testdict = {'foo': 'bar'}
+ tester = SpecialVariables(testdict, prng)
+
+ eq(tester['foo'], 'bar')
+ eq(tester['random 10-15 printable'], '[/pNI$;92@') #FIXME: how should I test pseudorandom content?
+
+def test_assemble_decision():
+ graph = build_graph()
+ prng = random.Random(1)
+ decision = assemble_decision(graph, prng)
+
+ eq(decision['key1'], 'value1')
+ eq(decision['key2'], 'value2')
+ eq(decision['randkey'], 'value-{random 10-15 printable}')
+ eq(decision['indirect_key1'], '{key1}')
+ eq(decision['path'], '/{bucket_readable}')
+ assert_raises(KeyError, lambda x: decision[x], 'key3')
+
+def test_expand_decision():
+ graph = build_graph()
+ prng = random.Random(1)
+
+ decision = assemble_decision(graph, prng)
+ decision.update({'bucket_readable': 'my-readable-bucket'})
+
+ request = expand_decision(decision, prng)
+
+ eq(request['key1'], 'value1')
+ eq(request['indirect_key1'], 'value1')
+ eq(request['path'], '/my-readable-bucket')
+ eq(request['randkey'], 'value-?') #FIXME: again, how to handle the pseudorandom content?
+ assert_raises(KeyError, lambda x: decision[x], 'key3')
+
the node's "set" list, pick a choice from the "choice" list, and
recurse. Finally, return dictionary of values
"""
+ node = decision_graph[node_name]
+
try:
- choice = prng.choice(decision_graph[node_name]['choices'])
+ #TODO: Give weights to each choice
+ choice = prng.choice(node['choices'])
decision = descend_graph(decision_graph, choice, prng)
except IndexError:
decision = {}
- node = decision_graph[node_name]
-
+ #TODO: Add in headers
for key in node['set']:
if decision.has_key(key):
raise KeyError("Node %s tried to set '%s', but that key was already set by a lower node!" %(node_name, key))
raise NotImplementedError
+class SpecialVariables(dict):
+ charsets = {
+ 'printable': string.printable,
+ 'punctuation': string.punctuation,
+ 'whitespace': string.whitespace
+ }
+
+ def __init__(self, orig_dict, prng):
+ self.update(orig_dict)
+ self.prng = prng
+
+
+ def __getitem__(self, key):
+ fields = key.split(None, 1)
+ fn = getattr(self, 'special_{name}'.format(name=fields[0]), None)
+ if fn is None:
+ return super(SpecialVariables, self).__getitem__(key)
+
+ if len(fields) == 1:
+ fields.apppend('')
+ return fn(fields[1])
+
+
+ def special_random(self, args):
+ arg_list = args.split()
+ try:
+ size_min, size_max = [int(x) for x in arg_list[0].split('-')]
+ except IndexError:
+ size_min = 0
+ size_max = 1000
+ try:
+ charset = self.charsets[arg_list[1]]
+ except IndexError:
+ charset = self.charsets['printable']
+
+ length = self.prng.randint(size_min, size_max)
+ return ''.join([self.prng.choice(charset) for _ in xrange(length)]) # Won't scale nicely
+
+
+
def parse_options():
parser = OptionParser()
parser.add_option('-O', '--outfile', help='write output to FILE. Defaults to STDOUT', metavar='FILE')