diff --git a/swift/common/memcached.py b/swift/common/memcached.py index 199e73066c..6a953852c6 100644 --- a/swift/common/memcached.py +++ b/swift/common/memcached.py @@ -44,18 +44,20 @@ version is at: http://github.com/memcached/memcached/blob/1.4.2/doc/protocol.txt """ +import os import six import json import logging import time from bisect import bisect -from eventlet.green import socket +from eventlet.green import socket, ssl from eventlet.pools import Pool from eventlet import Timeout from six.moves import range +from six.moves.configparser import ConfigParser, NoSectionError, NoOptionError from swift.common import utils -from swift.common.utils import md5, human_readable +from swift.common.utils import md5, human_readable, config_true_value DEFAULT_MEMCACHED_PORT = 11211 @@ -204,6 +206,10 @@ class MemcacheRing(object): self.logger = logger self.item_size_warning_threshold = item_size_warning_threshold + @property + def memcache_servers(self): + return list(self._client_cache.keys()) + def _exception_occurred(self, server, e, action='talking', sock=None, fp=None, got_connection=True): if isinstance(e, Timeout): @@ -554,3 +560,96 @@ class MemcacheRing(object): return values except (Exception, Timeout) as e: self._exception_occurred(server, e, sock=sock, fp=fp) + + +def load_memcache(conf, logger): + """ + Build a MemcacheRing object from the given config. It will also use the + passed in logger. + + :param conf: a dict, the config options + :param logger: a logger + """ + memcache_servers = conf.get('memcache_servers') + try: + # Originally, while we documented using memcache_max_connections + # we only accepted max_connections + max_conns = int(conf.get('memcache_max_connections', + conf.get('max_connections', 0))) + except ValueError: + max_conns = 0 + + memcache_options = {} + if (not memcache_servers + or max_conns <= 0): + path = os.path.join(conf.get('swift_dir', '/etc/swift'), + 'memcache.conf') + memcache_conf = ConfigParser() + if memcache_conf.read(path): + # if memcache.conf exists we'll start with those base options + try: + memcache_options = dict(memcache_conf.items('memcache')) + except NoSectionError: + pass + + if not memcache_servers: + try: + memcache_servers = \ + memcache_conf.get('memcache', 'memcache_servers') + except (NoSectionError, NoOptionError): + pass + if max_conns <= 0: + try: + new_max_conns = \ + memcache_conf.get('memcache', + 'memcache_max_connections') + max_conns = int(new_max_conns) + except (NoSectionError, NoOptionError, ValueError): + pass + + # while memcache.conf options are the base for the memcache + # middleware, if you set the same option also in the filter + # section of the proxy config it is more specific. + memcache_options.update(conf) + connect_timeout = float(memcache_options.get( + 'connect_timeout', CONN_TIMEOUT)) + pool_timeout = float(memcache_options.get( + 'pool_timeout', POOL_TIMEOUT)) + tries = int(memcache_options.get('tries', TRY_COUNT)) + io_timeout = float(memcache_options.get('io_timeout', IO_TIMEOUT)) + if config_true_value(memcache_options.get('tls_enabled', 'false')): + tls_cafile = memcache_options.get('tls_cafile') + tls_certfile = memcache_options.get('tls_certfile') + tls_keyfile = memcache_options.get('tls_keyfile') + tls_context = ssl.create_default_context( + cafile=tls_cafile) + if tls_certfile: + tls_context.load_cert_chain(tls_certfile, tls_keyfile) + else: + tls_context = None + error_suppression_interval = float(memcache_options.get( + 'error_suppression_interval', ERROR_LIMIT_TIME)) + error_suppression_limit = float(memcache_options.get( + 'error_suppression_limit', ERROR_LIMIT_COUNT)) + item_size_warning_threshold = int(memcache_options.get( + 'item_size_warning_threshold', DEFAULT_ITEM_SIZE_WARNING_THRESHOLD)) + + if not memcache_servers: + memcache_servers = '127.0.0.1:11211' + if max_conns <= 0: + max_conns = 2 + + return MemcacheRing( + [s.strip() for s in memcache_servers.split(',') + if s.strip()], + connect_timeout=connect_timeout, + pool_timeout=pool_timeout, + tries=tries, + io_timeout=io_timeout, + max_conns=max_conns, + tls_context=tls_context, + logger=logger, + error_limit_count=error_suppression_limit, + error_limit_time=error_suppression_interval, + error_limit_duration=error_suppression_interval, + item_size_warning_threshold=item_size_warning_threshold) diff --git a/swift/common/middleware/memcache.py b/swift/common/middleware/memcache.py index 562b0b9d88..1bb142657d 100644 --- a/swift/common/middleware/memcache.py +++ b/swift/common/middleware/memcache.py @@ -13,15 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -import os - -from eventlet.green import ssl -from six.moves.configparser import ConfigParser, NoSectionError, NoOptionError - -from swift.common.memcached import ( - MemcacheRing, CONN_TIMEOUT, POOL_TIMEOUT, IO_TIMEOUT, TRY_COUNT, - ERROR_LIMIT_COUNT, ERROR_LIMIT_TIME, DEFAULT_ITEM_SIZE_WARNING_THRESHOLD) -from swift.common.utils import get_logger, config_true_value +from swift.common.memcached import load_memcache +from swift.common.utils import get_logger class MemcacheMiddleware(object): @@ -32,90 +25,7 @@ class MemcacheMiddleware(object): def __init__(self, app, conf): self.app = app self.logger = get_logger(conf, log_route='memcache') - self.memcache_servers = conf.get('memcache_servers') - try: - # Originally, while we documented using memcache_max_connections - # we only accepted max_connections - max_conns = int(conf.get('memcache_max_connections', - conf.get('max_connections', 0))) - except ValueError: - max_conns = 0 - - memcache_options = {} - if (not self.memcache_servers - or max_conns <= 0): - path = os.path.join(conf.get('swift_dir', '/etc/swift'), - 'memcache.conf') - memcache_conf = ConfigParser() - if memcache_conf.read(path): - # if memcache.conf exists we'll start with those base options - try: - memcache_options = dict(memcache_conf.items('memcache')) - except NoSectionError: - pass - - if not self.memcache_servers: - try: - self.memcache_servers = \ - memcache_conf.get('memcache', 'memcache_servers') - except (NoSectionError, NoOptionError): - pass - if max_conns <= 0: - try: - new_max_conns = \ - memcache_conf.get('memcache', - 'memcache_max_connections') - max_conns = int(new_max_conns) - except (NoSectionError, NoOptionError, ValueError): - pass - - # while memcache.conf options are the base for the memcache - # middleware, if you set the same option also in the filter - # section of the proxy config it is more specific. - memcache_options.update(conf) - connect_timeout = float(memcache_options.get( - 'connect_timeout', CONN_TIMEOUT)) - pool_timeout = float(memcache_options.get( - 'pool_timeout', POOL_TIMEOUT)) - tries = int(memcache_options.get('tries', TRY_COUNT)) - io_timeout = float(memcache_options.get('io_timeout', IO_TIMEOUT)) - if config_true_value(memcache_options.get('tls_enabled', 'false')): - tls_cafile = memcache_options.get('tls_cafile') - tls_certfile = memcache_options.get('tls_certfile') - tls_keyfile = memcache_options.get('tls_keyfile') - self.tls_context = ssl.create_default_context( - cafile=tls_cafile) - if tls_certfile: - self.tls_context.load_cert_chain(tls_certfile, - tls_keyfile) - else: - self.tls_context = None - error_suppression_interval = float(memcache_options.get( - 'error_suppression_interval', ERROR_LIMIT_TIME)) - error_suppression_limit = float(memcache_options.get( - 'error_suppression_limit', ERROR_LIMIT_COUNT)) - item_size_warning_threshold = int(memcache_options.get( - 'item_size_warning_threshold', - DEFAULT_ITEM_SIZE_WARNING_THRESHOLD)) - - if not self.memcache_servers: - self.memcache_servers = '127.0.0.1:11211' - if max_conns <= 0: - max_conns = 2 - - self.memcache = MemcacheRing( - [s.strip() for s in self.memcache_servers.split(',') if s.strip()], - connect_timeout=connect_timeout, - pool_timeout=pool_timeout, - tries=tries, - io_timeout=io_timeout, - max_conns=max_conns, - tls_context=self.tls_context, - logger=self.logger, - error_limit_count=error_suppression_limit, - error_limit_time=error_suppression_interval, - error_limit_duration=error_suppression_interval, - item_size_warning_threshold=item_size_warning_threshold) + self.memcache = load_memcache(conf, self.logger) def __call__(self, env, start_response): env['swift.cache'] = self.memcache diff --git a/test/unit/common/middleware/test_memcache.py b/test/unit/common/middleware/test_memcache.py index 8ba0c7e150..c74ac32ce8 100644 --- a/test/unit/common/middleware/test_memcache.py +++ b/test/unit/common/middleware/test_memcache.py @@ -19,7 +19,6 @@ import unittest from eventlet.green import ssl import mock -from six.moves.configparser import NoSectionError, NoOptionError from swift.common.middleware import memcache from swift.common.memcached import MemcacheRing @@ -34,63 +33,6 @@ class FakeApp(object): return env -class ExcConfigParser(object): - - def read(self, path): - raise RuntimeError('read called with %r' % path) - - -class EmptyConfigParser(object): - - def read(self, path): - return False - - -def get_config_parser(memcache_servers='1.2.3.4:5', - memcache_max_connections='4', - section='memcache', - item_size_warning_threshold='75'): - _srvs = memcache_servers - _maxc = memcache_max_connections - _section = section - _warn_threshold = item_size_warning_threshold - - class SetConfigParser(object): - - def items(self, section_name): - if section_name != section: - raise NoSectionError(section_name) - return { - 'memcache_servers': memcache_servers, - 'memcache_max_connections': memcache_max_connections - } - - def read(self, path): - return True - - def get(self, section, option): - if _section == section: - if option == 'memcache_servers': - if _srvs == 'error': - raise NoOptionError(option, section) - return _srvs - elif option in ('memcache_max_connections', - 'max_connections'): - if _maxc == 'error': - raise NoOptionError(option, section) - return _maxc - elif option == 'item_size_warning_threshold': - if _warn_threshold == 'error': - raise NoOptionError(option, section) - return _warn_threshold - else: - raise NoOptionError(option, section) - else: - raise NoSectionError(option) - - return SetConfigParser - - def start_response(*args): pass @@ -106,165 +48,13 @@ class TestCacheMiddleware(unittest.TestCase): self.assertTrue('swift.cache' in resp) self.assertTrue(isinstance(resp['swift.cache'], MemcacheRing)) - def test_conf_default_read(self): - with mock.patch.object(memcache, 'ConfigParser', ExcConfigParser): - for d in ({}, - {'memcache_servers': '6.7.8.9:10'}, - {'memcache_max_connections': '30'}, - {'item_size_warning_threshold': 75}, - {'memcache_servers': '6.7.8.9:10', - 'item_size_warning_threshold': '75'}, - {'item_size_warning_threshold': '75', - 'memcache_max_connections': '30'}, - ): - with self.assertRaises(RuntimeError) as catcher: - memcache.MemcacheMiddleware(FakeApp(), d) - self.assertEqual( - str(catcher.exception), - "read called with '/etc/swift/memcache.conf'") - - def test_conf_set_no_read(self): - with mock.patch.object(memcache, 'ConfigParser', ExcConfigParser): - memcache.MemcacheMiddleware( - FakeApp(), {'memcache_servers': '1.2.3.4:5', - 'memcache_max_connections': '30', - 'item_size_warning_threshold': '80'}) - - def test_conf_default(self): - with mock.patch.object(memcache, 'ConfigParser', EmptyConfigParser): - app = memcache.MemcacheMiddleware(FakeApp(), {}) - self.assertEqual(app.memcache_servers, '127.0.0.1:11211') - self.assertEqual( - app.memcache._client_cache['127.0.0.1:11211'].max_size, 2) - self.assertEqual(app.memcache.item_size_warning_threshold, -1) - - def test_conf_inline(self): - with mock.patch.object(memcache, 'ConfigParser', get_config_parser()): - app = memcache.MemcacheMiddleware( - FakeApp(), - {'memcache_servers': '6.7.8.9:10', - 'memcache_max_connections': '5', - 'item_size_warning_threshold': '75'}) - self.assertEqual(app.memcache_servers, '6.7.8.9:10') - self.assertEqual( - app.memcache._client_cache['6.7.8.9:10'].max_size, 5) - self.assertEqual(app.memcache.item_size_warning_threshold, 75) - - def test_conf_inline_ratelimiting(self): - with mock.patch.object(memcache, 'ConfigParser', get_config_parser()): - app = memcache.MemcacheMiddleware( - FakeApp(), - {'error_suppression_limit': '5', - 'error_suppression_interval': '2.5'}) - self.assertEqual(app.memcache._error_limit_count, 5) - self.assertEqual(app.memcache._error_limit_time, 2.5) - self.assertEqual(app.memcache._error_limit_duration, 2.5) - - def test_conf_inline_tls(self): - fake_context = mock.Mock() - with mock.patch.object(ssl, 'create_default_context', - return_value=fake_context): - with mock.patch.object(memcache, 'ConfigParser', - get_config_parser()): - memcache.MemcacheMiddleware( - FakeApp(), - {'tls_enabled': 'true', - 'tls_cafile': 'cafile', - 'tls_certfile': 'certfile', - 'tls_keyfile': 'keyfile'}) - ssl.create_default_context.assert_called_with(cafile='cafile') - fake_context.load_cert_chain.assert_called_with('certfile', - 'keyfile') - - def test_conf_extra_no_section(self): - with mock.patch.object(memcache, 'ConfigParser', - get_config_parser(section='foobar')): - app = memcache.MemcacheMiddleware(FakeApp(), {}) - self.assertEqual(app.memcache_servers, '127.0.0.1:11211') - self.assertEqual( - app.memcache._client_cache['127.0.0.1:11211'].max_size, 2) - - def test_conf_extra_no_option(self): - replacement_parser = get_config_parser( - memcache_servers='error', - memcache_max_connections='error') - with mock.patch.object(memcache, 'ConfigParser', replacement_parser): - app = memcache.MemcacheMiddleware(FakeApp(), {}) - self.assertEqual(app.memcache_servers, '127.0.0.1:11211') - self.assertEqual( - app.memcache._client_cache['127.0.0.1:11211'].max_size, 2) - - def test_conf_inline_other_max_conn(self): - with mock.patch.object(memcache, 'ConfigParser', get_config_parser()): - app = memcache.MemcacheMiddleware( - FakeApp(), - {'memcache_servers': '6.7.8.9:10', - 'max_connections': '5'}) - self.assertEqual(app.memcache_servers, '6.7.8.9:10') - self.assertEqual( - app.memcache._client_cache['6.7.8.9:10'].max_size, 5) - - def test_conf_inline_bad_max_conn(self): - with mock.patch.object(memcache, 'ConfigParser', get_config_parser()): - app = memcache.MemcacheMiddleware( - FakeApp(), - {'memcache_servers': '6.7.8.9:10', - 'max_connections': 'bad42'}) - self.assertEqual(app.memcache_servers, '6.7.8.9:10') - self.assertEqual( - app.memcache._client_cache['6.7.8.9:10'].max_size, 4) - - def test_conf_inline_bad_item_warning_threshold(self): - with mock.patch.object(memcache, 'ConfigParser', get_config_parser()): - with self.assertRaises(ValueError) as err: - memcache.MemcacheMiddleware( - FakeApp(), - {'memcache_servers': '6.7.8.9:10', - 'memcache_serialization_support': '0', - 'item_size_warning_threshold': 'bad42'}) - self.assertIn('invalid literal for int() with base 10:', - str(err.exception)) - - def test_conf_from_extra_conf(self): - with mock.patch.object(memcache, 'ConfigParser', get_config_parser()): - app = memcache.MemcacheMiddleware(FakeApp(), {}) - self.assertEqual(app.memcache_servers, '1.2.3.4:5') - self.assertEqual( - app.memcache._client_cache['1.2.3.4:5'].max_size, 4) - - def test_conf_from_extra_conf_bad_max_conn(self): - with mock.patch.object(memcache, 'ConfigParser', get_config_parser( - memcache_max_connections='bad42')): - app = memcache.MemcacheMiddleware(FakeApp(), {}) - self.assertEqual(app.memcache_servers, '1.2.3.4:5') - self.assertEqual( - app.memcache._client_cache['1.2.3.4:5'].max_size, 2) - - def test_conf_from_inline_and_maxc_from_extra_conf(self): - with mock.patch.object(memcache, 'ConfigParser', get_config_parser()): - app = memcache.MemcacheMiddleware( - FakeApp(), - {'memcache_servers': '6.7.8.9:10'}) - self.assertEqual(app.memcache_servers, '6.7.8.9:10') - self.assertEqual( - app.memcache._client_cache['6.7.8.9:10'].max_size, 4) - - def test_conf_from_inline_and_sers_from_extra_conf(self): - with mock.patch.object(memcache, 'ConfigParser', get_config_parser()): - app = memcache.MemcacheMiddleware( - FakeApp(), - {'memcache_servers': '6.7.8.9:10', - 'memcache_max_connections': '42'}) - self.assertEqual(app.memcache_servers, '6.7.8.9:10') - self.assertEqual( - app.memcache._client_cache['6.7.8.9:10'].max_size, 42) - def test_filter_factory(self): factory = memcache.filter_factory({'max_connections': '3'}, memcache_servers='10.10.10.10:10') thefilter = factory('myapp') self.assertEqual(thefilter.app, 'myapp') - self.assertEqual(thefilter.memcache_servers, '10.10.10.10:10') + self.assertEqual(thefilter.memcache.memcache_servers, + ['10.10.10.10:10']) self.assertEqual( thefilter.memcache._client_cache['10.10.10.10:10'].max_size, 3) diff --git a/test/unit/common/test_memcached.py b/test/unit/common/test_memcached.py index 42c3cab837..75786d8632 100644 --- a/test/unit/common/test_memcached.py +++ b/test/unit/common/test_memcached.py @@ -27,9 +27,11 @@ from uuid import uuid4 import os import mock +from six.moves.configparser import NoSectionError, NoOptionError from eventlet import GreenPool, sleep, Queue from eventlet.pools import Pool +from eventlet.green import ssl from swift.common import memcached from swift.common.memcached import MemcacheConnectionError @@ -1047,5 +1049,229 @@ class TestMemcached(unittest.TestCase): do_test('1' * 2048576, 1000000, True) +class ExcConfigParser(object): + + def read(self, path): + raise Exception('read called with %r' % path) + + +class EmptyConfigParser(object): + + def read(self, path): + return False + + +def get_config_parser(memcache_servers='1.2.3.4:5', + memcache_max_connections='4', + section='memcache', + item_size_warning_threshold='75'): + _srvs = memcache_servers + _maxc = memcache_max_connections + _section = section + _warn_threshold = item_size_warning_threshold + + class SetConfigParser(object): + + def items(self, section_name): + if section_name != section: + raise NoSectionError(section_name) + return { + 'memcache_servers': memcache_servers, + 'memcache_max_connections': memcache_max_connections + } + + def read(self, path): + return True + + def get(self, section, option): + if _section == section: + if option == 'memcache_servers': + if _srvs == 'error': + raise NoOptionError(option, section) + return _srvs + elif option in ('memcache_max_connections', + 'max_connections'): + if _maxc == 'error': + raise NoOptionError(option, section) + return _maxc + elif option == 'item_size_warning_threshold': + if _warn_threshold == 'error': + raise NoOptionError(option, section) + return _warn_threshold + else: + raise NoOptionError(option, section) + else: + raise NoSectionError(option) + + return SetConfigParser + + +def start_response(*args): + pass + + +class TestLoadMemcache(unittest.TestCase): + def setUp(self): + self.logger = debug_logger() + + def test_conf_default_read(self): + with mock.patch.object(memcached, 'ConfigParser', ExcConfigParser): + for d in ({}, + {'memcache_servers': '6.7.8.9:10'}, + {'memcache_max_connections': '30'}, + {'item_size_warning_threshold': 75}, + {'memcache_servers': '6.7.8.9:10', + 'item_size_warning_threshold': '75'}, + {'item_size_warning_threshold': '75', + 'memcache_max_connections': '30'}, + ): + with self.assertRaises(Exception) as catcher: + memcached.load_memcache(d, self.logger) + self.assertEqual( + str(catcher.exception), + "read called with '/etc/swift/memcache.conf'") + + def test_conf_set_no_read(self): + with mock.patch.object(memcached, 'ConfigParser', ExcConfigParser): + exc = None + try: + memcached.load_memcache({ + 'memcache_servers': '1.2.3.4:5', + 'memcache_max_connections': '30', + 'item_size_warning_threshold': '80' + + }, self.logger) + except Exception as err: + exc = err + self.assertIsNone(exc) + + def test_conf_default(self): + with mock.patch.object(memcached, 'ConfigParser', EmptyConfigParser): + memcache = memcached.load_memcache({}, self.logger) + self.assertEqual(memcache.memcache_servers, ['127.0.0.1:11211']) + self.assertEqual( + memcache._client_cache['127.0.0.1:11211'].max_size, 2) + self.assertEqual(memcache.item_size_warning_threshold, -1) + + def test_conf_inline(self): + with mock.patch.object(memcached, 'ConfigParser', get_config_parser()): + memcache = memcached.load_memcache({ + 'memcache_servers': '6.7.8.9:10', + 'memcache_max_connections': '5', + 'item_size_warning_threshold': '75' + }, self.logger) + self.assertEqual(memcache.memcache_servers, ['6.7.8.9:10']) + self.assertEqual( + memcache._client_cache['6.7.8.9:10'].max_size, 5) + self.assertEqual(memcache.item_size_warning_threshold, 75) + + def test_conf_inline_ratelimiting(self): + with mock.patch.object(memcached, 'ConfigParser', get_config_parser()): + memcache = memcached.load_memcache({ + 'error_suppression_limit': '5', + 'error_suppression_interval': '2.5', + }, self.logger) + self.assertEqual(memcache._error_limit_count, 5) + self.assertEqual(memcache._error_limit_time, 2.5) + self.assertEqual(memcache._error_limit_duration, 2.5) + + def test_conf_inline_tls(self): + fake_context = mock.Mock() + with mock.patch.object(ssl, 'create_default_context', + return_value=fake_context): + with mock.patch.object(memcached, 'ConfigParser', + get_config_parser()): + memcached.load_memcache({ + 'tls_enabled': 'true', + 'tls_cafile': 'cafile', + 'tls_certfile': 'certfile', + 'tls_keyfile': 'keyfile', + }, self.logger) + ssl.create_default_context.assert_called_with(cafile='cafile') + fake_context.load_cert_chain.assert_called_with('certfile', + 'keyfile') + + def test_conf_extra_no_section(self): + with mock.patch.object(memcached, 'ConfigParser', + get_config_parser(section='foobar')): + memcache = memcached.load_memcache({}, self.logger) + self.assertEqual(memcache.memcache_servers, ['127.0.0.1:11211']) + self.assertEqual( + memcache._client_cache['127.0.0.1:11211'].max_size, 2) + + def test_conf_extra_no_option(self): + replacement_parser = get_config_parser( + memcache_servers='error', + memcache_max_connections='error') + with mock.patch.object(memcached, 'ConfigParser', replacement_parser): + memcache = memcached.load_memcache({}, self.logger) + self.assertEqual(memcache.memcache_servers, ['127.0.0.1:11211']) + self.assertEqual( + memcache._client_cache['127.0.0.1:11211'].max_size, 2) + + def test_conf_inline_other_max_conn(self): + with mock.patch.object(memcached, 'ConfigParser', get_config_parser()): + memcache = memcached.load_memcache({ + 'memcache_servers': '6.7.8.9:10', + 'max_connections': '5' + }, self.logger) + self.assertEqual(memcache.memcache_servers, ['6.7.8.9:10']) + self.assertEqual( + memcache._client_cache['6.7.8.9:10'].max_size, 5) + + def test_conf_inline_bad_max_conn(self): + with mock.patch.object(memcached, 'ConfigParser', get_config_parser()): + memcache = memcached.load_memcache({ + 'memcache_servers': '6.7.8.9:10', + 'max_connections': 'bad42', + }, self.logger) + self.assertEqual(memcache.memcache_servers, ['6.7.8.9:10']) + self.assertEqual( + memcache._client_cache['6.7.8.9:10'].max_size, 4) + + def test_conf_inline_bad_item_warning_threshold(self): + with mock.patch.object(memcached, 'ConfigParser', get_config_parser()): + with self.assertRaises(ValueError) as err: + memcached.load_memcache({ + 'memcache_servers': '6.7.8.9:10', + 'item_size_warning_threshold': 'bad42', + }, self.logger) + self.assertIn('invalid literal for int() with base 10:', + str(err.exception)) + + def test_conf_from_extra_conf(self): + with mock.patch.object(memcached, 'ConfigParser', get_config_parser()): + memcache = memcached.load_memcache({}, self.logger) + self.assertEqual(memcache.memcache_servers, ['1.2.3.4:5']) + self.assertEqual( + memcache._client_cache['1.2.3.4:5'].max_size, 4) + + def test_conf_from_extra_conf_bad_max_conn(self): + with mock.patch.object(memcached, 'ConfigParser', get_config_parser( + memcache_max_connections='bad42')): + memcache = memcached.load_memcache({}, self.logger) + self.assertEqual(memcache.memcache_servers, ['1.2.3.4:5']) + self.assertEqual( + memcache._client_cache['1.2.3.4:5'].max_size, 2) + + def test_conf_from_inline_and_maxc_from_extra_conf(self): + with mock.patch.object(memcached, 'ConfigParser', get_config_parser()): + memcache = memcached.load_memcache({ + 'memcache_servers': '6.7.8.9:10'}, self.logger) + self.assertEqual(memcache.memcache_servers, ['6.7.8.9:10']) + self.assertEqual( + memcache._client_cache['6.7.8.9:10'].max_size, 4) + + def test_conf_from_inline_and_sers_from_extra_conf(self): + with mock.patch.object(memcached, 'ConfigParser', get_config_parser()): + memcache = memcached.load_memcache({ + 'memcache_servers': '6.7.8.9:10', + 'memcache_max_connections': '42', + }, self.logger) + self.assertEqual(memcache.memcache_servers, ['6.7.8.9:10']) + self.assertEqual( + memcache._client_cache['6.7.8.9:10'].max_size, 42) + + if __name__ == '__main__': unittest.main()