217 lines
7.2 KiB
Python
217 lines
7.2 KiB
Python
from pymemcache.client.hash import HashClient
|
|
from pymemcache.client.base import Client, PooledClient
|
|
from pymemcache.exceptions import MemcacheUnknownError
|
|
from pymemcache import pool
|
|
|
|
from .test_client import ClientTestMixin, MockSocket
|
|
import unittest
|
|
import pytest
|
|
import mock
|
|
import socket
|
|
|
|
|
|
class TestHashClient(ClientTestMixin, unittest.TestCase):
|
|
|
|
def make_client_pool(self, hostname, mock_socket_values,
|
|
serializer=None, **kwargs):
|
|
mock_client = Client(hostname, serializer=serializer, **kwargs)
|
|
mock_client.sock = MockSocket(mock_socket_values)
|
|
client = PooledClient(hostname, serializer=serializer)
|
|
client.client_pool = pool.ObjectPool(lambda: mock_client)
|
|
return mock_client
|
|
|
|
def make_client(self, *mock_socket_values, **kwargs):
|
|
current_port = 11012
|
|
client = HashClient([], **kwargs)
|
|
ip = '127.0.0.1'
|
|
|
|
for vals in mock_socket_values:
|
|
s = '%s:%s' % (ip, current_port)
|
|
c = self.make_client_pool(
|
|
(ip, current_port),
|
|
vals,
|
|
**kwargs
|
|
)
|
|
client.clients[s] = c
|
|
client.hasher.add_node(s)
|
|
current_port += 1
|
|
|
|
return client
|
|
|
|
def test_setup_client_without_pooling(self):
|
|
with mock.patch('pymemcache.client.hash.Client') as internal_client:
|
|
client = HashClient([], timeout=999, key_prefix='foo_bar_baz')
|
|
client.add_server('127.0.0.1', '11211')
|
|
|
|
assert internal_client.call_args[0][0] == ('127.0.0.1', '11211')
|
|
kwargs = internal_client.call_args[1]
|
|
assert kwargs['timeout'] == 999
|
|
assert kwargs['key_prefix'] == 'foo_bar_baz'
|
|
|
|
def test_get_many_all_found(self):
|
|
client = self.make_client(*[
|
|
[b'STORED\r\n', b'VALUE key3 0 6\r\nvalue2\r\nEND\r\n', ],
|
|
[b'STORED\r\n', b'VALUE key1 0 6\r\nvalue1\r\nEND\r\n', ],
|
|
])
|
|
|
|
def get_clients(key):
|
|
if key == b'key3':
|
|
return client.clients['127.0.0.1:11012']
|
|
else:
|
|
return client.clients['127.0.0.1:11013']
|
|
|
|
client._get_client = get_clients
|
|
|
|
result = client.set(b'key1', b'value1', noreply=False)
|
|
result = client.set(b'key3', b'value2', noreply=False)
|
|
result = client.get_many([b'key1', b'key3'])
|
|
assert result == {b'key1': b'value1', b'key3': b'value2'}
|
|
|
|
def test_get_many_some_found(self):
|
|
client = self.make_client(*[
|
|
[b'END\r\n', ],
|
|
[b'STORED\r\n', b'VALUE key1 0 6\r\nvalue1\r\nEND\r\n', ],
|
|
])
|
|
|
|
def get_clients(key):
|
|
if key == b'key3':
|
|
return client.clients['127.0.0.1:11012']
|
|
else:
|
|
return client.clients['127.0.0.1:11013']
|
|
|
|
client._get_client = get_clients
|
|
result = client.set(b'key1', b'value1', noreply=False)
|
|
result = client.get_many([b'key1', b'key3'])
|
|
|
|
assert result == {b'key1': b'value1'}
|
|
|
|
def test_get_many_bad_server_data(self):
|
|
client = self.make_client(*[
|
|
[b'STORED\r\n', b'VAXLUE key3 0 6\r\nvalue2\r\nEND\r\n', ],
|
|
[b'STORED\r\n', b'VAXLUE key1 0 6\r\nvalue1\r\nEND\r\n', ],
|
|
])
|
|
|
|
def get_clients(key):
|
|
if key == b'key3':
|
|
return client.clients['127.0.0.1:11012']
|
|
else:
|
|
return client.clients['127.0.0.1:11013']
|
|
|
|
client._get_client = get_clients
|
|
|
|
with pytest.raises(MemcacheUnknownError):
|
|
client.set(b'key1', b'value1', noreply=False)
|
|
client.set(b'key3', b'value2', noreply=False)
|
|
client.get_many([b'key1', b'key3'])
|
|
|
|
def test_get_many_bad_server_data_ignore(self):
|
|
client = self.make_client(*[
|
|
[b'STORED\r\n', b'VAXLUE key3 0 6\r\nvalue2\r\nEND\r\n', ],
|
|
[b'STORED\r\n', b'VAXLUE key1 0 6\r\nvalue1\r\nEND\r\n', ],
|
|
], ignore_exc=True)
|
|
|
|
def get_clients(key):
|
|
if key == b'key3':
|
|
return client.clients['127.0.0.1:11012']
|
|
else:
|
|
return client.clients['127.0.0.1:11013']
|
|
|
|
client._get_client = get_clients
|
|
|
|
client.set(b'key1', b'value1', noreply=False)
|
|
client.set(b'key3', b'value2', noreply=False)
|
|
result = client.get_many([b'key1', b'key3'])
|
|
assert result == {}
|
|
|
|
def test_gets_many(self):
|
|
client = self.make_client(*[
|
|
[b'STORED\r\n', b'VALUE key3 0 6 1\r\nvalue2\r\nEND\r\n', ],
|
|
[b'STORED\r\n', b'VALUE key1 0 6 1\r\nvalue1\r\nEND\r\n', ],
|
|
])
|
|
|
|
def get_clients(key):
|
|
if key == b'key3':
|
|
return client.clients['127.0.0.1:11012']
|
|
else:
|
|
return client.clients['127.0.0.1:11013']
|
|
|
|
client._get_client = get_clients
|
|
|
|
assert client.set(b'key1', b'value1', noreply=False) is True
|
|
assert client.set(b'key3', b'value2', noreply=False) is True
|
|
result = client.gets_many([b'key1', b'key3'])
|
|
assert (result ==
|
|
{b'key1': (b'value1', b'1'), b'key3': (b'value2', b'1')})
|
|
|
|
def test_no_servers_left(self):
|
|
from pymemcache.client.hash import HashClient
|
|
client = HashClient(
|
|
[], use_pooling=True,
|
|
ignore_exc=True,
|
|
timeout=1, connect_timeout=1
|
|
)
|
|
|
|
hashed_client = client._get_client('foo')
|
|
assert hashed_client is None
|
|
|
|
def test_no_servers_left_raise_exception(self):
|
|
from pymemcache.client.hash import HashClient
|
|
client = HashClient(
|
|
[], use_pooling=True,
|
|
ignore_exc=False,
|
|
timeout=1, connect_timeout=1
|
|
)
|
|
|
|
with pytest.raises(Exception) as e:
|
|
client._get_client('foo')
|
|
|
|
assert str(e.value) == 'All servers seem to be down right now'
|
|
|
|
def test_unavailable_servers_zero_retry_raise_exception(self):
|
|
from pymemcache.client.hash import HashClient
|
|
client = HashClient(
|
|
[('example.com', 11211)], use_pooling=True,
|
|
ignore_exc=False,
|
|
retry_attempts=0, timeout=1, connect_timeout=1
|
|
)
|
|
|
|
with pytest.raises(socket.error):
|
|
client.get('foo')
|
|
|
|
def test_no_servers_left_with_commands_return_default_value(self):
|
|
from pymemcache.client.hash import HashClient
|
|
client = HashClient(
|
|
[], use_pooling=True,
|
|
ignore_exc=True,
|
|
timeout=1, connect_timeout=1
|
|
)
|
|
|
|
result = client.get('foo')
|
|
assert result is None
|
|
result = client.set('foo', 'bar')
|
|
assert result is False
|
|
|
|
def test_no_servers_left_with_set_many(self):
|
|
from pymemcache.client.hash import HashClient
|
|
client = HashClient(
|
|
[], use_pooling=True,
|
|
ignore_exc=True,
|
|
timeout=1, connect_timeout=1
|
|
)
|
|
|
|
result = client.set_many({'foo': 'bar'})
|
|
assert result is False
|
|
|
|
def test_no_servers_left_with_get_many(self):
|
|
from pymemcache.client.hash import HashClient
|
|
client = HashClient(
|
|
[], use_pooling=True,
|
|
ignore_exc=True,
|
|
timeout=1, connect_timeout=1
|
|
)
|
|
|
|
result = client.get_many(['foo', 'bar'])
|
|
assert result == {'foo': False, 'bar': False}
|
|
|
|
# TODO: Test failover logic
|