Merge branch 'py3' of ssh://github.com/haypo/python-memcached into haypo-py3

Conflicts:
	tests/test_memcache.py
This commit is contained in:
Sean Reifschneider 2015-08-02 17:50:40 -06:00
commit 94089e66cd
4 changed files with 91 additions and 321 deletions

View File

@ -258,12 +258,12 @@ class Client(threading.local):
return key
def _encode_cmd(self, cmd, key, headers, noreply, *args):
cmd_bytes = cmd.encode() if six.PY3 else cmd
cmd_bytes = cmd.encode('utf-8') if six.PY3 else cmd
fullcmd = [cmd_bytes, b' ', key]
if headers:
if six.PY3:
headers = headers.encode()
headers = headers.encode('utf-8')
fullcmd.append(b' ')
fullcmd.append(headers)
@ -410,7 +410,10 @@ class Client(threading.local):
if server.connect():
# print("(using server %s)" % server,)
return server, key
serverhash = serverHashFunction(str(serverhash) + str(i))
serverhash = str(serverhash) + str(i)
if isinstance(serverhash, six.text_type):
serverhash = serverhash.encode('ascii')
serverhash = serverHashFunction(serverhash)
return None, None
def disconnect_all(self):
@ -456,15 +459,15 @@ class Client(threading.local):
for server in six.iterkeys(server_keys):
bigcmd = []
write = bigcmd.append
extra = ' noreply' if noreply else ''
if time is not None:
for key in server_keys[server]: # These are mangled keys
write("delete %s %d%s\r\n" % (key, time, extra))
headers = str(time)
else:
for key in server_keys[server]: # These are mangled keys
write("delete %s%s\r\n" % (key, extra))
headers = None
for key in server_keys[server]: # These are mangled keys
cmd = self._encode_cmd('delete', key, headers, noreply, b'\r\n')
write(cmd)
try:
server.send_cmds(''.join(bigcmd))
server.send_cmds(b''.join(bigcmd))
except socket.error as msg:
rc = 0
if isinstance(msg, tuple):
@ -483,7 +486,7 @@ class Client(threading.local):
for server, keys in six.iteritems(server_keys):
try:
for key in keys:
server.expect("DELETED")
server.expect(b"DELETED")
except socket.error as msg:
if isinstance(msg, tuple):
msg = msg[1]
@ -528,9 +531,10 @@ class Client(threading.local):
return 0
self._statlog(cmd)
if time is not None and time != 0:
fullcmd = self._encode_cmd(cmd, key, str(time), noreply)
headers = str(time)
else:
fullcmd = self._encode_cmd(cmd, key, None, noreply)
headers = None
fullcmd = self._encode_cmd(cmd, key, headers, noreply)
try:
server.send_cmd(fullcmd)
@ -905,12 +909,12 @@ class Client(threading.local):
# short-circuit if there are no servers, just return all keys
if not server_keys:
return(mapping.keys())
return list(mapping.keys())
for server, keys in six.iteritems(server_keys):
try:
for key in keys:
if server.readline() == 'STORED':
if server.readline() == b'STORED':
continue
else:
# un-mangle.
@ -1039,7 +1043,7 @@ class Client(threading.local):
self._statlog(cmd)
try:
cmd_bytes = cmd.encode() if six.PY3 else cmd
cmd_bytes = cmd.encode('utf-8') if six.PY3 else cmd
fullcmd = b''.join((cmd_bytes, b' ', key))
server.send_cmd(fullcmd)
rkey = flags = rlen = cas_id = None
@ -1434,9 +1438,11 @@ class _Host(object):
if self.debug and line != text:
if six.PY3:
text = text.decode('utf8')
line = line.decode('utf8', 'replace')
log_line = line.decode('utf8', 'replace')
else:
log_line = line
self.debuglog("while expecting %r, got unexpected response %r"
% (text, line))
% (text, log_line))
return line
def recv(self, rlen):
@ -1472,236 +1478,13 @@ def _doctest():
import doctest
import memcache
servers = ["127.0.0.1:11211"]
mc = Client(servers, debug=1)
mc = memcache.Client(servers, debug=1)
globs = {"mc": mc}
return doctest.testmod(memcache, globs=globs)
if __name__ == "__main__":
failures = 0
print("Testing docstrings...")
_doctest()
print("Running tests:")
print()
serverList = [["127.0.0.1:11211"]]
if '--do-unix' in sys.argv:
serverList.append([os.path.join(os.getcwd(), 'memcached.socket')])
for servers in serverList:
mc = Client(servers, debug=1)
def to_s(val):
if not isinstance(val, _str_cls):
return "%s (%s)" % (val, type(val))
return "%s" % val
def test_setget(key, val, noreply=False):
global failures
print("Testing set/get (noreply=%s) {'%s': %s} ..."
% (noreply, to_s(key), to_s(val)), end=" ")
mc.set(key, val, noreply=noreply)
newval = mc.get(key)
if newval == val:
print("OK")
return 1
else:
print("FAIL")
failures += 1
return 0
class FooStruct(object):
def __init__(self):
self.bar = "baz"
def __str__(self):
return "A FooStruct"
def __eq__(self, other):
if isinstance(other, FooStruct):
return self.bar == other.bar
return 0
test_setget("a_string", "some random string")
test_setget("a_string_2", "some random string", noreply=True)
test_setget("an_integer", 42)
test_setget("an_integer_2", 42, noreply=True)
if six.PY3:
ok = test_setget("long", 1 << 30)
else:
ok = test_setget("long", long(1 << 30))
if ok:
print("Testing delete ...", end=" ")
if mc.delete("long"):
print("OK")
else:
print("FAIL")
failures += 1
print("Checking results of delete ...", end=" ")
if mc.get("long") is None:
print("OK")
else:
print("FAIL")
failures += 1
print("Testing get_multi ...",)
print(mc.get_multi(["a_string", "an_integer", "a_string_2",
"an_integer_2"]))
# removed from the protocol
# if test_setget("timed_delete", 'foo'):
# print "Testing timed delete ...",
# if mc.delete("timed_delete", 1):
# print("OK")
# else:
# print("FAIL")
# failures += 1
# print "Checking results of timed delete ..."
# if mc.get("timed_delete") is None:
# print("OK")
# else:
# print("FAIL")
# failures += 1
print("Testing get(unknown value) ...", end=" ")
print(to_s(mc.get("unknown_value")))
f = FooStruct()
test_setget("foostruct", f)
test_setget("foostruct_2", f, noreply=True)
print("Testing incr ...", end=" ")
x = mc.incr("an_integer", 1)
if x == 43:
print("OK")
else:
print("FAIL")
failures += 1
print("Testing incr (noreply=True) ...", end=" ")
mc.incr("an_integer_2", 1, noreply=True)
x = mc.get("an_integer_2")
if x == 43:
print("OK")
else:
print("FAIL")
failures += 1
print("Testing decr ...", end=" ")
x = mc.decr("an_integer", 1)
if x == 42:
print("OK")
else:
print("FAIL")
failures += 1
sys.stdout.flush()
print("Testing decr (noreply=True) ...", end=" ")
mc.decr("an_integer_2", 1, noreply=True)
x = mc.get("an_integer_2")
if x == 42:
print("OK")
else:
print("FAIL")
failures += 1
sys.stdout.flush()
# sanity tests
print("Testing sending spaces...", end=" ")
sys.stdout.flush()
try:
x = mc.set("this has spaces", 1)
except Client.MemcachedKeyCharacterError as msg:
print("OK")
else:
print("FAIL")
failures += 1
print("Testing sending control characters...", end=" ")
try:
x = mc.set("this\x10has\x11control characters\x02", 1)
except Client.MemcachedKeyCharacterError as msg:
print("OK")
else:
print("FAIL")
failures += 1
print("Testing using insanely long key...", end=" ")
try:
x = mc.set('a'*SERVER_MAX_KEY_LENGTH, 1)
x = mc.set('a'*SERVER_MAX_KEY_LENGTH, 1, noreply=True)
except Client.MemcachedKeyLengthError as msg:
print("FAIL")
failures += 1
else:
print("OK")
try:
x = mc.set('a'*SERVER_MAX_KEY_LENGTH + 'a', 1)
except Client.MemcachedKeyLengthError as msg:
print("OK")
else:
print("FAIL")
failures += 1
print("Testing sending a unicode-string key...", end=" ")
try:
x = mc.set(unicode('keyhere'), 1)
except Client.MemcachedStringEncodingError as msg:
print("OK", end=" ")
else:
print("FAIL", end=" ")
failures += 1
try:
x = mc.set((unicode('a')*SERVER_MAX_KEY_LENGTH).encode('utf-8'), 1)
except Client.MemcachedKeyError:
print("FAIL", end=" ")
failures += 1
else:
print("OK", end=" ")
s = pickle.loads('V\\u4f1a\np0\n.')
try:
x = mc.set((s * SERVER_MAX_KEY_LENGTH).encode('utf-8'), 1)
except Client.MemcachedKeyLengthError:
print("OK")
else:
print("FAIL")
failures += 1
print("Testing using a value larger than the memcached value limit...")
print('NOTE: "MemCached: while expecting[...]" is normal...')
x = mc.set('keyhere', 'a'*SERVER_MAX_VALUE_LENGTH)
if mc.get('keyhere') is None:
print("OK", end=" ")
else:
print("FAIL", end=" ")
failures += 1
x = mc.set('keyhere', 'a'*SERVER_MAX_VALUE_LENGTH + 'aaa')
if mc.get('keyhere') is None:
print("OK")
else:
print("FAIL")
failures += 1
print("Testing set_multi() with no memcacheds running", end=" ")
mc.disconnect_all()
errors = mc.set_multi({'keyhere': 'a', 'keythere': 'b'})
if errors != []:
print("FAIL")
failures += 1
else:
print("OK")
print("Testing delete_multi() with no memcacheds running", end=" ")
mc.disconnect_all()
ret = mc.delete_multi({'keyhere': 'a', 'keythere': 'b'})
if ret != 1:
print("FAIL")
failures += 1
else:
print("OK")
if failures > 0:
print('*** THERE WERE FAILED TESTS')
results = doctest.testmod(memcache, globs=globs)
mc.disconnect_all()
print("Doctests: %s" % (results,))
if results.failed:
sys.exit(1)
sys.exit(0)
# vim: ts=4 sw=4 et :

View File

@ -1,10 +1,11 @@
from __future__ import print_function
from unittest import TestCase
import time
import unittest
import six
from memcache import Client, SERVER_MAX_KEY_LENGTH
from memcache import Client, SERVER_MAX_KEY_LENGTH, SERVER_MAX_VALUE_LENGTH
try:
_str_cls = basestring
@ -32,12 +33,14 @@ class FooStruct(object):
return 0
class TestMemcache(TestCase):
class TestMemcache(unittest.TestCase):
def setUp(self):
# TODO: unix socket server stuff
servers = ["127.0.0.1:11211"]
self.mc = Client(servers, debug=1)
pass
def tearDown(self):
self.mc.disconnect_all()
def check_setget(self, key, val, noreply=False):
self.mc.set(key, val, noreply=noreply)
@ -64,6 +67,8 @@ class TestMemcache(TestCase):
{"gm_an_integer": 42, "gm_a_string": "some random string"})
def test_get_unknown_value(self):
self.mc.delete("unknown_value")
self.assertEqual(self.mc.get("unknown_value"), None)
def test_setget_foostruct(self):
@ -124,78 +129,56 @@ class TestMemcache(TestCase):
"""GitHub issue #75. Set/get with boolean values."""
self.check_setget("bool", True)
if __name__ == "__main__":
# failures = 0
# print("Testing docstrings...")
# _doctest()
# print("Running tests:")
# print()
# serverList = [["127.0.0.1:11211"]]
# if '--do-unix' in sys.argv:
# serverList.append([os.path.join(os.getcwd(), 'memcached.socket')])
# for servers in serverList:
# mc = Client(servers, debug=1)
if False:
def test_unicode_key(self):
s = six.u('\u4f1a')
maxlen = SERVER_MAX_KEY_LENGTH // len(s.encode('utf-8'))
key = s * maxlen
print("Testing sending a unicode-string key...", end=" ")
try:
x = mc.set(six.u('keyhere'), 1)
except Client.MemcachedStringEncodingError as msg:
print("OK", end=" ")
else:
print("FAIL", end=" ")
failures += 1
try:
x = mc.set((six.u('a')*SERVER_MAX_KEY_LENGTH).encode('utf-8'), 1)
except Client.MemcachedKeyError:
print("FAIL", end=" ")
failures += 1
else:
print("OK", end=" ")
s = pickle.loads('V\\u4f1a\np0\n.')
try:
x = mc.set((s * SERVER_MAX_KEY_LENGTH).encode('utf-8'), 1)
except Client.MemcachedKeyLengthError:
print("OK")
else:
print("FAIL")
failures += 1
self.mc.set(key, 5)
value = self.mc.get(key)
self.assertEqual(value, 5)
print("Testing using a value larger than the memcached value limit...")
print('NOTE: "MemCached: while expecting[...]" is normal...')
x = mc.set('keyhere', 'a'*SERVER_MAX_VALUE_LENGTH)
if mc.get('keyhere') is None:
print("OK", end=" ")
else:
print("FAIL", end=" ")
failures += 1
x = mc.set('keyhere', 'a'*SERVER_MAX_VALUE_LENGTH + 'aaa')
if mc.get('keyhere') is None:
print("OK")
else:
print("FAIL")
failures += 1
def test_ignore_too_large_value(self):
# NOTE: "MemCached: while expecting[...]" is normal...
key = 'keyhere'
print("Testing set_multi() with no memcacheds running", end=" ")
mc.disconnect_all()
errors = mc.set_multi({'keyhere': 'a', 'keythere': 'b'})
if errors != []:
print("FAIL")
failures += 1
else:
print("OK")
value = 'a' * (SERVER_MAX_VALUE_LENGTH // 2)
self.assertTrue(self.mc.set(key, value))
self.assertEqual(self.mc.get(key), value)
print("Testing delete_multi() with no memcacheds running", end=" ")
mc.disconnect_all()
ret = mc.delete_multi({'keyhere': 'a', 'keythere': 'b'})
if ret != 1:
print("FAIL")
failures += 1
else:
print("OK")
value = 'a' * SERVER_MAX_VALUE_LENGTH
self.assertFalse(self.mc.set(key, value))
# This test fails if the -I option is used on the memcached server
self.assertIsNone(self.mc.get(key))
if failures > 0:
print('*** THERE WERE FAILED TESTS')
sys.exit(1)
sys.exit(0)
def test_get_set_multi_key_prefix(self):
"""Testing set_multi() with no memcacheds running."""
prefix = 'pfx_'
values = {'key1': 'a', 'key2': 'b'}
errors = self.mc.set_multi(values, key_prefix=prefix)
self.assertEqual(errors, [])
keys = list(values)
self.assertEqual(self.mc.get_multi(keys, key_prefix=prefix),
values)
def test_set_multi_dead_servers(self):
"""Testing set_multi() with no memcacheds running."""
self.mc.disconnect_all()
for server in self.mc.servers:
server.mark_dead('test')
errors = self.mc.set_multi({'key1': 'a', 'key2': 'b'})
self.assertEqual(sorted(errors), ['key1', 'key2'])
def test_disconnect_all_delete_multi(self):
"""Testing delete_multi() with no memcacheds running."""
self.mc.disconnect_all()
ret = self.mc.delete_multi({'keyhere': 'a', 'keythere': 'b'})
self.assertEqual(ret, 1)
if __name__ == '__main__':
unittest.main()

View File

@ -53,18 +53,20 @@ class test_Memcached_Set_Multi(unittest.TestCase):
self.old_socket = socket.socket
socket.socket = FakeSocket
self.mc = memcache.Client(['memcached'], debug=True)
def tearDown(self):
socket.socket = self.old_socket
def test_Socket_Disconnect(self):
client = memcache.Client(['memcached'], debug=True)
mapping = {'foo': 'FOO', 'bar': 'BAR'}
bad_keys = client.set_multi(mapping)
bad_keys = self.mc.set_multi(mapping)
self.assertEqual(sorted(bad_keys), ['bar', 'foo'])
if DEBUG:
print('set_multi({0!r}) -> {1!r}'.format(mapping, bad_keys))
if __name__ == '__main__':
unittest.main()

View File

@ -9,7 +9,9 @@ usedevelop = True
install_command = pip install -U {opts} {packages}
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
commands = nosetests {posargs}
commands =
nosetests {posargs}
python -c 'import memcache; memcache._doctest()'
[tox:jenkins]
downloadcache = ~/cache/pip