Add tests for _memcache_pool
While trying to use oslo.cache, the keystone team noticed that an exception was referenced, but not defined. This led to finding further issues, since _memcache_pool had no tests. Change-Id: Ia4d025fb05575c30ff37b480b92c82595241046d
This commit is contained in:
parent
f7414633ed
commit
98537c8e0d
@ -90,3 +90,10 @@ class NotImplemented(Error):
|
|||||||
" been implemented.")
|
" been implemented.")
|
||||||
code = 501
|
code = 501
|
||||||
title = 'Not Implemented'
|
title = 'Not Implemented'
|
||||||
|
|
||||||
|
|
||||||
|
class UnexpectedError(Error):
|
||||||
|
message_format = _("An unexpected error prevented the server from "
|
||||||
|
"fulfilling your request.")
|
||||||
|
code = 500
|
||||||
|
title = 'Internal Server Error'
|
||||||
|
147
oslo_cache/tests/test_connection_pool.py
Normal file
147
oslo_cache/tests/test_connection_pool.py
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
|
import mock
|
||||||
|
import six
|
||||||
|
from six.moves import queue
|
||||||
|
import testtools
|
||||||
|
from testtools import matchers
|
||||||
|
|
||||||
|
from oslo_cache import _memcache_pool
|
||||||
|
from oslo_cache import exception
|
||||||
|
from oslo_cache.tests import test_cache
|
||||||
|
|
||||||
|
|
||||||
|
class _TestConnectionPool(_memcache_pool.ConnectionPool):
|
||||||
|
destroyed_value = 'destroyed'
|
||||||
|
|
||||||
|
def _create_connection(self):
|
||||||
|
return mock.MagicMock()
|
||||||
|
|
||||||
|
def _destroy_connection(self, conn):
|
||||||
|
conn(self.destroyed_value)
|
||||||
|
|
||||||
|
|
||||||
|
class TestConnectionPool(test_cache.BaseTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestConnectionPool, self).setUp()
|
||||||
|
self.unused_timeout = 10
|
||||||
|
self.maxsize = 2
|
||||||
|
self.connection_pool = _TestConnectionPool(
|
||||||
|
maxsize=self.maxsize,
|
||||||
|
unused_timeout=self.unused_timeout)
|
||||||
|
self.addCleanup(self.cleanup_instance('connection_pool'))
|
||||||
|
|
||||||
|
def cleanup_instance(self, *names):
|
||||||
|
"""Create a function suitable for use with self.addCleanup.
|
||||||
|
|
||||||
|
:returns: a callable that uses a closure to delete instance attributes
|
||||||
|
"""
|
||||||
|
|
||||||
|
def cleanup():
|
||||||
|
for name in names:
|
||||||
|
if hasattr(self, name):
|
||||||
|
delattr(self, name)
|
||||||
|
return cleanup
|
||||||
|
|
||||||
|
def test_get_context_manager(self):
|
||||||
|
self.assertThat(self.connection_pool.queue, matchers.HasLength(0))
|
||||||
|
with self.connection_pool.acquire() as conn:
|
||||||
|
self.assertEqual(1, self.connection_pool._acquired)
|
||||||
|
self.assertEqual(0, self.connection_pool._acquired)
|
||||||
|
self.assertThat(self.connection_pool.queue, matchers.HasLength(1))
|
||||||
|
self.assertEqual(conn, self.connection_pool.queue[0].connection)
|
||||||
|
|
||||||
|
def test_cleanup_pool(self):
|
||||||
|
self.test_get_context_manager()
|
||||||
|
newtime = time.time() + self.unused_timeout * 2
|
||||||
|
non_expired_connection = _memcache_pool._PoolItem(
|
||||||
|
ttl=(newtime * 2),
|
||||||
|
connection=mock.MagicMock())
|
||||||
|
self.connection_pool.queue.append(non_expired_connection)
|
||||||
|
self.assertThat(self.connection_pool.queue, matchers.HasLength(2))
|
||||||
|
with mock.patch.object(time, 'time', return_value=newtime):
|
||||||
|
conn = self.connection_pool.queue[0].connection
|
||||||
|
with self.connection_pool.acquire():
|
||||||
|
pass
|
||||||
|
conn.assert_has_calls(
|
||||||
|
[mock.call(self.connection_pool.destroyed_value)])
|
||||||
|
self.assertThat(self.connection_pool.queue, matchers.HasLength(1))
|
||||||
|
self.assertEqual(0, non_expired_connection.connection.call_count)
|
||||||
|
|
||||||
|
def test_acquire_conn_exception_returns_acquired_count(self):
|
||||||
|
class TestException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
with mock.patch.object(_TestConnectionPool, '_create_connection',
|
||||||
|
side_effect=TestException):
|
||||||
|
with testtools.ExpectedException(TestException):
|
||||||
|
with self.connection_pool.acquire():
|
||||||
|
pass
|
||||||
|
self.assertThat(self.connection_pool.queue,
|
||||||
|
matchers.HasLength(0))
|
||||||
|
self.assertEqual(0, self.connection_pool._acquired)
|
||||||
|
|
||||||
|
def test_connection_pool_limits_maximum_connections(self):
|
||||||
|
# NOTE(morganfainberg): To ensure we don't lockup tests until the
|
||||||
|
# job limit, explicitly call .get_nowait() and .put_nowait() in this
|
||||||
|
# case.
|
||||||
|
conn1 = self.connection_pool.get_nowait()
|
||||||
|
conn2 = self.connection_pool.get_nowait()
|
||||||
|
|
||||||
|
# Use a nowait version to raise an Empty exception indicating we would
|
||||||
|
# not get another connection until one is placed back into the queue.
|
||||||
|
self.assertRaises(queue.Empty, self.connection_pool.get_nowait)
|
||||||
|
|
||||||
|
# Place the connections back into the pool.
|
||||||
|
self.connection_pool.put_nowait(conn1)
|
||||||
|
self.connection_pool.put_nowait(conn2)
|
||||||
|
|
||||||
|
# Make sure we can get a connection out of the pool again.
|
||||||
|
self.connection_pool.get_nowait()
|
||||||
|
|
||||||
|
def test_connection_pool_maximum_connection_get_timeout(self):
|
||||||
|
connection_pool = _TestConnectionPool(
|
||||||
|
maxsize=1,
|
||||||
|
unused_timeout=self.unused_timeout,
|
||||||
|
conn_get_timeout=0)
|
||||||
|
|
||||||
|
def _acquire_connection():
|
||||||
|
with connection_pool.acquire():
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Make sure we've consumed the only available connection from the pool
|
||||||
|
conn = connection_pool.get_nowait()
|
||||||
|
|
||||||
|
self.assertRaises(exception.UnexpectedError, _acquire_connection)
|
||||||
|
|
||||||
|
# Put the connection back and ensure we can acquire the connection
|
||||||
|
# after it is available.
|
||||||
|
connection_pool.put_nowait(conn)
|
||||||
|
_acquire_connection()
|
||||||
|
|
||||||
|
|
||||||
|
class TestMemcacheClientOverrides(test_cache.BaseTestCase):
|
||||||
|
|
||||||
|
def test_client_stripped_of_threading_local(self):
|
||||||
|
"""threading.local overrides are restored for _MemcacheClient"""
|
||||||
|
client_class = _memcache_pool._MemcacheClient
|
||||||
|
# get the genuine thread._local from MRO
|
||||||
|
thread_local = client_class.__mro__[2]
|
||||||
|
self.assertTrue(thread_local is threading.local)
|
||||||
|
for field in six.iterkeys(thread_local.__dict__):
|
||||||
|
if field not in ('__dict__', '__weakref__'):
|
||||||
|
self.assertNotEqual(id(getattr(thread_local, field, None)),
|
||||||
|
id(getattr(client_class, field, None)))
|
@ -9,3 +9,4 @@ oslo.config>=1.11.0 # Apache-2.0
|
|||||||
oslo.i18n>=1.5.0 # Apache-2.0
|
oslo.i18n>=1.5.0 # Apache-2.0
|
||||||
oslo.log>=1.2.0 # Apache-2.0
|
oslo.log>=1.2.0 # Apache-2.0
|
||||||
oslo.utils>=1.6.0 # Apache-2.0
|
oslo.utils>=1.6.0 # Apache-2.0
|
||||||
|
python-memcached>=1.48
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
# of appearance. Changing the order has an impact on the overall integration
|
# of appearance. Changing the order has an impact on the overall integration
|
||||||
# process, which may cause wedges in the gate later.
|
# process, which may cause wedges in the gate later.
|
||||||
hacking<0.11,>=0.10.0
|
hacking<0.11,>=0.10.0
|
||||||
|
mock>=1.0
|
||||||
oslotest>=1.5.1 # Apache-2.0
|
oslotest>=1.5.1 # Apache-2.0
|
||||||
oslosphinx>=2.5.0 # Apache-2.0
|
oslosphinx>=2.5.0 # Apache-2.0
|
||||||
sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2
|
sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2
|
||||||
|
Loading…
x
Reference in New Issue
Block a user