Merge "MockMemcached cleanup"

This commit is contained in:
Jenkins 2016-07-07 21:14:23 +00:00 committed by Gerrit Code Review
commit c350a481b8

View File

@ -62,6 +62,8 @@ class ExplodingMockMemcached(object):
class MockMemcached(object): class MockMemcached(object):
# See https://github.com/memcached/memcached/blob/master/doc/protocol.txt
# In particular, the "Storage commands" section may be interesting.
def __init__(self): def __init__(self):
self.inbuf = '' self.inbuf = ''
@ -79,56 +81,65 @@ class MockMemcached(object):
while '\n' in self.inbuf: while '\n' in self.inbuf:
cmd, self.inbuf = self.inbuf.split('\n', 1) cmd, self.inbuf = self.inbuf.split('\n', 1)
parts = cmd.split() parts = cmd.split()
if parts[0].lower() == 'set': handler = getattr(self, 'handle_%s' % parts[0].lower(), None)
self.cache[parts[1]] = parts[2], parts[3], \ if handler:
self.inbuf[:int(parts[4])] handler(*parts[1:])
self.inbuf = self.inbuf[int(parts[4]) + 2:] else:
if len(parts) < 6 or parts[5] != 'noreply': raise ValueError('Unhandled command: %s' % parts[0])
def handle_set(self, key, flags, exptime, num_bytes, noreply=''):
self.cache[key] = flags, exptime, self.inbuf[:int(num_bytes)]
self.inbuf = self.inbuf[int(num_bytes) + 2:]
if noreply != 'noreply':
self.outbuf += 'STORED\r\n' self.outbuf += 'STORED\r\n'
elif parts[0].lower() == 'add':
value = self.inbuf[:int(parts[4])] def handle_add(self, key, flags, exptime, num_bytes, noreply=''):
self.inbuf = self.inbuf[int(parts[4]) + 2:] value = self.inbuf[:int(num_bytes)]
if parts[1] in self.cache: self.inbuf = self.inbuf[int(num_bytes) + 2:]
if len(parts) < 6 or parts[5] != 'noreply': if key in self.cache:
if noreply != 'noreply':
self.outbuf += 'NOT_STORED\r\n' self.outbuf += 'NOT_STORED\r\n'
else: else:
self.cache[parts[1]] = parts[2], parts[3], value self.cache[key] = flags, exptime, value
if len(parts) < 6 or parts[5] != 'noreply': if noreply != 'noreply':
self.outbuf += 'STORED\r\n' self.outbuf += 'STORED\r\n'
elif parts[0].lower() == 'delete':
def handle_delete(self, key, noreply=''):
if self.exc_on_delete: if self.exc_on_delete:
raise Exception('mock is has exc_on_delete set') raise Exception('mock is has exc_on_delete set')
if parts[1] in self.cache: if key in self.cache:
del self.cache[parts[1]] del self.cache[key]
if 'noreply' not in parts: if noreply != 'noreply':
self.outbuf += 'DELETED\r\n' self.outbuf += 'DELETED\r\n'
elif 'noreply' not in parts: elif noreply != 'noreply':
self.outbuf += 'NOT_FOUND\r\n' self.outbuf += 'NOT_FOUND\r\n'
elif parts[0].lower() == 'get':
for key in parts[1:]: def handle_get(self, *keys):
for key in keys:
if key in self.cache: if key in self.cache:
val = self.cache[key] val = self.cache[key]
self.outbuf += 'VALUE %s %s %s\r\n' % ( self.outbuf += 'VALUE %s %s %s\r\n' % (
key, val[0], len(val[2])) key, val[0], len(val[2]))
self.outbuf += val[2] + '\r\n' self.outbuf += val[2] + '\r\n'
self.outbuf += 'END\r\n' self.outbuf += 'END\r\n'
elif parts[0].lower() == 'incr':
if parts[1] in self.cache: def handle_incr(self, key, value, noreply=''):
val = list(self.cache[parts[1]]) if key in self.cache:
val[2] = str(int(val[2]) + int(parts[2])) current = self.cache[key][2]
self.cache[parts[1]] = val new_val = str(int(current) + int(value))
self.outbuf += str(val[2]) + '\r\n' self.cache[key] = self.cache[key][:2] + (new_val, )
self.outbuf += str(new_val) + '\r\n'
else: else:
self.outbuf += 'NOT_FOUND\r\n' self.outbuf += 'NOT_FOUND\r\n'
elif parts[0].lower() == 'decr':
if parts[1] in self.cache: def handle_decr(self, key, value, noreply=''):
val = list(self.cache[parts[1]]) if key in self.cache:
if int(val[2]) - int(parts[2]) > 0: current = self.cache[key][2]
val[2] = str(int(val[2]) - int(parts[2])) new_val = str(int(current) - int(value))
else: if new_val[0] == '-': # ie, val is negative
val[2] = '0' new_val = '0'
self.cache[parts[1]] = val self.cache[key] = self.cache[key][:2] + (new_val, )
self.outbuf += str(val[2]) + '\r\n' self.outbuf += str(new_val) + '\r\n'
else: else:
self.outbuf += 'NOT_FOUND\r\n' self.outbuf += 'NOT_FOUND\r\n'