Skip to content

Instantly share code, notes, and snippets.

@BenjamenMeyer
Last active August 29, 2015 14:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BenjamenMeyer/1a0712c10fc6beb01a84 to your computer and use it in GitHub Desktop.
Save BenjamenMeyer/1a0712c10fc6beb01a84 to your computer and use it in GitHub Desktop.
Keystone Mocking issue...
import base64
import binascii
import simplejson as json
import redis
from keystoneclient.v2_0 import client as keystonev2_client
import keystone.exceptions
import keystoneclient.access as keystone_access
LOG = logging.getLogger(__name__)
def _send_data_to_cache(redis_client, url, access_info):
"""Stores the authentication data to memcache
:param redis_client: redis.Redis object connected to the redis cache
:param url: URL used for authentication
:param access_info: keystoneclient.access.AccessInfo containing
the auth data
:returns: True on success, otherwise False
"""
try:
# Convert the access_info dictionary into a string for storage
data = {}
data.update(access_info)
cache_data = json.dumps(data)
cache_data_utf8 = cache_data.encode(encoding='utf-8', errors='strict')
cache_data_b64 = base64.b64encode(cache_data_utf8)
tenant = access_info.tenant_id
token = access_info.auth_token
# Guild the cache key and store the value
# Use the token's expiration time for the cache expiration
cache_key = _tuple_to_cache_key((tenant, token, url))
redis_client.set(cache_key, cache_data)
redis_client.pexpire(cache_key, access_info.expires)
return True
except Exception as ex:
msg = _('Failed to cache the data - Exception: %(s_except)s') % {
's_except': ex,
}
LOG.error(msg)
return False
def _retrieve_data_from_keystone(redis_client, url, tenant, token):
"""Retrieve the authentication data from OpenStack Keystone
:param redis_client: redis.Redis object connected to the redis cache
:param url: Keystone Identity URL to authenticate against
:param tenant: tenant id of user data to retrieve
:param token: auth_token for the tenant_id
:returns: a keystoneclient.access.AccessInfo on success or None on error
"""
try:
keystone = keystonev2_client.Client(tenant_id=tenant, token=token, auth_url=url)
except Exception as ex:
msg = _('Failed to retrieve Keystone client - %(s_except)s') % {
's_except': ex
}
LOG.debug(msg)
return None
# Now try to authenticate the user and get the user information using
# only the data provided, no special administrative tokens required
try:
access_info = keystone.get_raw_token_from_identity_service(
auth_url=url, tenant_id=tenant, token=token)
# cache the data so it is easier to access next time
_send_data_to_cache(redis_client, url, access_info)
return access_info
except keystoneclient.exceptions.AuthorizationFailure as ex:
# Provided data was invalid
msg = _('Failed to authenticate against %(s_url) - %(s_except)s') % {
's_url' : auth_url,
's_except' : ex
}
LOG.debug( msg )
return None
from __future__ import division
from wsgiref import simple_server
import fakeredis
import mock
import base64
import binascii
import simplejson as json
import keystoneclient.exceptions
from keystoneclient.access import AccessInfoV2
from eom import auth
import tests
from . import util
from .mocks import servicecatalog
def fakeredis_connection():
return fakeredis.FakeRedis()
def run_server(app, host, port):
httpd = simple_server.make_server(host, port, app)
httpd.serve_forever()
class TestAuth(tests.util.TestCase):
def setUp(self):
super(TestAuth, self).setUp()
redis_client = fakeredis_connection()
self.auth = auth.wrap(tests.util.app, redis_client)
self.test_url = '/v2/vault'
#config = auth.CONF['eom:auth']
#self.runtime_url = config['auth_url']
#config['auth_url'] = 'localhost/v2'
def tearDown(self):
super(TestAuth, self).tearDown()
redis_client = fakeredis_connection()
redis_client.flushall()
#config = auth.CONF['eom:auth']
#config['auth_url'] = self.runtime_url
def test_retrieve_keystone_stone(self):
url = 'myurl'
tenant_id = '789012345'
token = 'abcdefABCDEF'
redis_client = fakeredis_connection()
with mock.patch(
'keystoneclient.v2_0.client.Client', autospec=True) as MockKeystoneClient:
MockKeystoneClient.side_effect = Exception('Mock - invalid client object')
keystone_create_error = auth._retrieve_data_from_keystone(redis_client, url, tenant_id, token)
self.assertIsNone(keystone_create_error)
with mock.patch(
'keystoneclient.v2_0.client.Client', autospec=True) as MockKeystoneClient:
reload(keystoneclient)
# Fail to get a valid Client object
# Note: Client() uses the requests package to do an auth;
# on failure it is the requests module that fails.
MockKeystoneClient.get_raw_token_from_identity_service = mock.Mock(side_effect = \
keystoneclient.exceptions.AuthorizationFailure('mock Keystone error'))
keystone_error = auth._retrieve_data_from_keystone(redis_client, url, tenant_id, token)
self.assertIsNone(keystone_error)
# Note: This fails because the side effect on get_raw_token_from_identity_service is not happening. Why???
@BenjamenMeyer
Copy link
Author

Lines 55-59 pass.

Lines 61-73 fail due to a mocking issue. I am trying to figure out why it is not raising the Exception like it should. I've tried a number of methods, including a new mock.patch on the function, or setting the function to a function that simply raises the exception without any luck.

What am I doing wrong?

@BenjamenMeyer
Copy link
Author

(Note: I can provide more of the code if required)

@BenjamenMeyer
Copy link
Author

Here's the run:
(py27)bmeyer@ben-linux-ubuntu:~/rackspace/envs/eom$ nosetests tests.test_auth
tests.test_auth.TestAuth.test_cache_key ... ok
tests.test_auth.TestAuth.test_retrieve_cache_data ... ok
tests.test_auth.TestAuth.test_retrieve_keystone_stone ... FAIL
tests.test_auth.TestAuth.test_store_data_to_cache ... ok

FAIL: tests.test_auth.TestAuth.test_retrieve_keystone_stone

_StringException: Traceback (most recent call last):
File "/home/bmeyer/rackspace/envs/eom/tests/test_auth.py", line 231, in test_retrieve_keystone_stone
self.assertIsNone(keystone_error)
File "/home/bmeyer/rackspace/envs/eom/.tox/py27/local/lib/python2.7/site-packages/testtools/testcase.py", line 353, in assertIsNone
self.assertThat(observed, matcher, message)
File "/home/bmeyer/rackspace/envs/eom/.tox/py27/local/lib/python2.7/site-packages/testtools/testcase.py", line 423, in assertThat
raise mismatch_error
MismatchError: is not:
reference = None
actual =

-------------------- >> begin captured logging << --------------------
eom.auth: DEBUG: Failed to retrieve Keystone client - Mock - invalid client object
eom.auth: ERROR: Failed to cache the data - Exception: sequence item 0: expected string, MagicMock found
--------------------- >> end captured logging << ---------------------

Note: the eom.auth.ERROR is generated by line 43 in implementation.py because the parameter access_info in line 77 is a mock object due to the exception not happening

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment