MockMemcached cleanup

* Break sendall's switch into different functions
* Actually name some parameters
* Raise errors on unexpected input
* Consistently use tuples in self.cache

Change-Id: I93aa33f83cdf6943a43f14a1868b1497bc7f4478
This commit is contained in:
Tim Burke 2016-06-23 10:46:27 -07:00
parent c0217a4845
commit 143b0eec92

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,58 +81,67 @@ 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])
self.outbuf += 'STORED\r\n'
elif parts[0].lower() == 'add': def handle_set(self, key, flags, exptime, num_bytes, noreply=''):
value = self.inbuf[:int(parts[4])] self.cache[key] = flags, exptime, self.inbuf[:int(num_bytes)]
self.inbuf = self.inbuf[int(parts[4]) + 2:] self.inbuf = self.inbuf[int(num_bytes) + 2:]
if parts[1] in self.cache: if noreply != 'noreply':
if len(parts) < 6 or parts[5] != 'noreply': self.outbuf += 'STORED\r\n'
self.outbuf += 'NOT_STORED\r\n'
else: def handle_add(self, key, flags, exptime, num_bytes, noreply=''):
self.cache[parts[1]] = parts[2], parts[3], value value = self.inbuf[:int(num_bytes)]
if len(parts) < 6 or parts[5] != 'noreply': self.inbuf = self.inbuf[int(num_bytes) + 2:]
self.outbuf += 'STORED\r\n' if key in self.cache:
elif parts[0].lower() == 'delete': if noreply != 'noreply':
if self.exc_on_delete: self.outbuf += 'NOT_STORED\r\n'
raise Exception('mock is has exc_on_delete set') else:
if parts[1] in self.cache: self.cache[key] = flags, exptime, value
del self.cache[parts[1]] if noreply != 'noreply':
if 'noreply' not in parts: self.outbuf += 'STORED\r\n'
self.outbuf += 'DELETED\r\n'
elif 'noreply' not in parts: def handle_delete(self, key, noreply=''):
self.outbuf += 'NOT_FOUND\r\n' if self.exc_on_delete:
elif parts[0].lower() == 'get': raise Exception('mock is has exc_on_delete set')
for key in parts[1:]: if key in self.cache:
if key in self.cache: del self.cache[key]
val = self.cache[key] if noreply != 'noreply':
self.outbuf += 'VALUE %s %s %s\r\n' % ( self.outbuf += 'DELETED\r\n'
key, val[0], len(val[2])) elif noreply != 'noreply':
self.outbuf += val[2] + '\r\n' self.outbuf += 'NOT_FOUND\r\n'
self.outbuf += 'END\r\n'
elif parts[0].lower() == 'incr': def handle_get(self, *keys):
if parts[1] in self.cache: for key in keys:
val = list(self.cache[parts[1]]) if key in self.cache:
val[2] = str(int(val[2]) + int(parts[2])) val = self.cache[key]
self.cache[parts[1]] = val self.outbuf += 'VALUE %s %s %s\r\n' % (
self.outbuf += str(val[2]) + '\r\n' key, val[0], len(val[2]))
else: self.outbuf += val[2] + '\r\n'
self.outbuf += 'NOT_FOUND\r\n' self.outbuf += 'END\r\n'
elif parts[0].lower() == 'decr':
if parts[1] in self.cache: def handle_incr(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: self.cache[key] = self.cache[key][:2] + (new_val, )
val[2] = '0' self.outbuf += str(new_val) + '\r\n'
self.cache[parts[1]] = val else:
self.outbuf += str(val[2]) + '\r\n' self.outbuf += 'NOT_FOUND\r\n'
else:
self.outbuf += 'NOT_FOUND\r\n' def handle_decr(self, key, value, noreply=''):
if key in self.cache:
current = self.cache[key][2]
new_val = str(int(current) - int(value))
if new_val[0] == '-': # ie, val is negative
new_val = '0'
self.cache[key] = self.cache[key][:2] + (new_val, )
self.outbuf += str(new_val) + '\r\n'
else:
self.outbuf += 'NOT_FOUND\r\n'
def readline(self): def readline(self):
if self.read_return_none: if self.read_return_none: