Remove keystoneclient mocks

The majority of the mocks on keystoneclient are not needed. Instead we
use the fixtures that keystoneclient provides to create well formed
responses and use requests_mock to stub out those values when accessed.

This is a closer to real usage pattern and the way that most client
projects are now handling keystoneclient auth.

Change-Id: I294aca1d11c9c5cfb4b82ad16476af4000efee1c
This commit is contained in:
Jamie Lennox 2014-12-16 15:54:08 +10:00
parent 02b1a05226
commit 27f70bbd58
2 changed files with 31 additions and 244 deletions

View File

@ -1,188 +0,0 @@
# 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 copy
import json
import uuid
# these are copied from python-keystoneclient tests
BASE_HOST = 'http://keystone.example.com'
BASE_URL = "%s:5000/" % BASE_HOST
UPDATED = '2013-03-06T00:00:00Z'
V2_URL = "%sv2.0" % BASE_URL
V2_DESCRIBED_BY_HTML = {'href': 'http://docs.openstack.org/api/'
'openstack-identity-service/2.0/content/',
'rel': 'describedby',
'type': 'text/html'}
V2_DESCRIBED_BY_PDF = {'href': 'http://docs.openstack.org/api/openstack-ident'
'ity-service/2.0/identity-dev-guide-2.0.pdf',
'rel': 'describedby',
'type': 'application/pdf'}
V2_VERSION = {'id': 'v2.0',
'links': [{'href': V2_URL, 'rel': 'self'},
V2_DESCRIBED_BY_HTML, V2_DESCRIBED_BY_PDF],
'status': 'stable',
'updated': UPDATED}
V3_URL = "%sv3" % BASE_URL
V3_MEDIA_TYPES = [{'base': 'application/json',
'type': 'application/vnd.openstack.identity-v3+json'},
{'base': 'application/xml',
'type': 'application/vnd.openstack.identity-v3+xml'}]
V3_VERSION = {'id': 'v3.0',
'links': [{'href': V3_URL, 'rel': 'self'}],
'media-types': V3_MEDIA_TYPES,
'status': 'stable',
'updated': UPDATED}
def _create_version_list(versions):
return json.dumps({'versions': {'values': versions}})
def _create_single_version(version):
return json.dumps({'version': version})
V3_VERSION_LIST = _create_version_list([V3_VERSION, V2_VERSION])
V2_VERSION_LIST = _create_version_list([V2_VERSION])
V3_VERSION_ENTRY = _create_single_version(V3_VERSION)
V2_VERSION_ENTRY = _create_single_version(V2_VERSION)
GLANCE_ENDPOINT = 'http://glance.example.com/v1'
def _get_normalized_token_data(**kwargs):
ref = copy.deepcopy(kwargs)
# normalized token data
ref['user_id'] = ref.get('user_id', uuid.uuid4().hex)
ref['username'] = ref.get('username', uuid.uuid4().hex)
ref['project_id'] = ref.get('project_id',
ref.get('tenant_id', uuid.uuid4().hex))
ref['project_name'] = ref.get('tenant_name',
ref.get('tenant_name', uuid.uuid4().hex))
ref['user_domain_id'] = ref.get('user_domain_id', uuid.uuid4().hex)
ref['user_domain_name'] = ref.get('user_domain_name', uuid.uuid4().hex)
ref['project_domain_id'] = ref.get('project_domain_id', uuid.uuid4().hex)
ref['project_domain_name'] = ref.get('project_domain_name',
uuid.uuid4().hex)
ref['roles'] = ref.get('roles', [{'name': uuid.uuid4().hex,
'id': uuid.uuid4().hex}])
ref['roles_link'] = ref.get('roles_link', [])
ref['glance_url'] = ref.get('glance_url', GLANCE_ENDPOINT)
return ref
def generate_v2_project_scoped_token(**kwargs):
"""Generate a Keystone V2 token based on auth request."""
ref = _get_normalized_token_data(**kwargs)
o = {'access': {'token': {'id': uuid.uuid4().hex,
'expires': '2099-05-22T00:02:43.941430Z',
'issued_at': '2013-05-21T00:02:43.941473Z',
'tenant': {'enabled': True,
'id': ref.get('project_id'),
'name': ref.get('project_id')
}
},
'user': {'id': ref.get('user_id'),
'name': uuid.uuid4().hex,
'username': ref.get('username'),
'roles': ref.get('roles'),
'roles_links': ref.get('roles_links')
}
}}
# we only care about Glance and Keystone endpoints
o['access']['serviceCatalog'] = [
{'endpoints': [
{'publicURL': ref.get('glance_url'),
'id': uuid.uuid4().hex,
'region': 'RegionOne'
}],
'endpoints_links': [],
'name': 'Glance',
'type': 'keystore'},
{'endpoints': [
{'publicURL': ref.get('auth_url'),
'adminURL': ref.get('auth_url'),
'id': uuid.uuid4().hex,
'region': 'RegionOne'
}],
'endpoint_links': [],
'name': 'keystone',
'type': 'identity'}]
return o
def generate_v3_project_scoped_token(**kwargs):
"""Generate a Keystone V3 token based on auth request."""
ref = _get_normalized_token_data(**kwargs)
o = {'token': {'expires_at': '2099-05-22T00:02:43.941430Z',
'issued_at': '2013-05-21T00:02:43.941473Z',
'methods': ['password'],
'project': {'id': ref.get('project_id'),
'name': ref.get('project_name'),
'domain': {'id': ref.get('project_domain_id'),
'name': ref.get(
'project_domain_name')
}
},
'user': {'id': ref.get('user_id'),
'name': ref.get('username'),
'domain': {'id': ref.get('user_domain_id'),
'name': ref.get('user_domain_name')
}
},
'roles': ref.get('roles')
}}
# we only care about Glance and Keystone endpoints
o['token']['catalog'] = [
{'endpoints': [
{
'id': uuid.uuid4().hex,
'interface': 'public',
'region': 'RegionTwo',
'url': ref.get('glance_url')
}],
'id': uuid.uuid4().hex,
'type': 'keystore'},
{'endpoints': [
{
'id': uuid.uuid4().hex,
'interface': 'public',
'region': 'RegionTwo',
'url': ref.get('auth_url')
},
{
'id': uuid.uuid4().hex,
'interface': 'admin',
'region': 'RegionTwo',
'url': ref.get('auth_url')
}],
'id': uuid.uuid4().hex,
'type': 'identity'}]
# token ID is conveyed via the X-Subject-Token header so we are generating
# one to stash there
token_id = uuid.uuid4().hex
return token_id, o

View File

@ -19,7 +19,11 @@ import os
import sys
import fixtures
from keystoneclient import exceptions as ks_exc
from keystoneclient import fixture as ks_fixture
import mock
import requests
from requests_mock.contrib import fixture as rm_fixture
import six
from glanceclient import exc
@ -28,12 +32,8 @@ from glanceclient import shell as openstack_shell
#NOTE (esheffield) Used for the schema caching tests
from glanceclient.v2 import schemas as schemas
import json
from tests import keystone_client_fixtures
from tests import utils
import keystoneclient
from keystoneclient.openstack.common.apiclient import exceptions as ks_exc
DEFAULT_IMAGE_URL = 'http://127.0.0.1:5000/'
DEFAULT_USERNAME = 'username'
@ -43,8 +43,8 @@ DEFAULT_TENANT_NAME = 'tenant_name'
DEFAULT_PROJECT_ID = '0123456789'
DEFAULT_USER_DOMAIN_NAME = 'user_domain_name'
DEFAULT_UNVERSIONED_AUTH_URL = 'http://127.0.0.1:5000/'
DEFAULT_V2_AUTH_URL = 'http://127.0.0.1:5000/v2.0/'
DEFAULT_V3_AUTH_URL = 'http://127.0.0.1:5000/v3/'
DEFAULT_V2_AUTH_URL = '%sv2.0' % DEFAULT_UNVERSIONED_AUTH_URL
DEFAULT_V3_AUTH_URL = '%sv3' % DEFAULT_UNVERSIONED_AUTH_URL
DEFAULT_AUTH_TOKEN = ' 3bcc3d3a03f44e3d8377f9247b0ad155'
TEST_SERVICE_URL = 'http://127.0.0.1:5000/'
@ -66,6 +66,7 @@ class ShellTest(utils.TestCase):
# auth environment to use
auth_env = FAKE_V2_ENV.copy()
# expected auth plugin to invoke
token_url = DEFAULT_V2_AUTH_URL + '/tokens'
auth_plugin = 'keystoneclient.auth.identity.v2.Password'
# Patch os.environ to avoid required auth info
@ -78,6 +79,17 @@ class ShellTest(utils.TestCase):
global _old_env
_old_env, os.environ = os.environ, self.auth_env
self.requests = self.useFixture(rm_fixture.Fixture())
json_list = ks_fixture.DiscoveryList(DEFAULT_UNVERSIONED_AUTH_URL)
self.requests.get(DEFAULT_IMAGE_URL, json=json_list, status_code=300)
json_v2 = {'version': ks_fixture.V2Discovery(DEFAULT_V2_AUTH_URL)}
self.requests.get(DEFAULT_V2_AUTH_URL, json=json_v2)
json_v3 = {'version': ks_fixture.V3Discovery(DEFAULT_V3_AUTH_URL)}
self.requests.get(DEFAULT_V3_AUTH_URL, json=json_v3)
global shell, _shell, assert_called, assert_called_anytime
_shell = openstack_shell.OpenStackImagesShell()
shell = lambda cmd: _shell.main(cmd.split())
@ -187,20 +199,14 @@ class ShellTest(utils.TestCase):
def _assert_auth_plugin_args(self, mock_auth_plugin):
# make sure our auth plugin is invoked with the correct args
mock_auth_plugin.assert_called_once_with(
keystone_client_fixtures.V2_URL,
DEFAULT_V2_AUTH_URL,
self.auth_env['OS_USERNAME'],
self.auth_env['OS_PASSWORD'],
tenant_name=self.auth_env['OS_TENANT_NAME'],
tenant_id='')
@mock.patch('glanceclient.v1.client.Client')
@mock.patch('keystoneclient.session.Session')
@mock.patch.object(keystoneclient.discover.Discover, 'url_for',
side_effect=[keystone_client_fixtures.V2_URL, None])
def test_auth_plugin_invocation_with_v1(self,
v1_client,
ks_session,
url_for):
def test_auth_plugin_invocation_with_v1(self, v1_client):
with mock.patch(self.auth_plugin) as mock_auth_plugin:
args = 'image-list'
glance_shell = openstack_shell.OpenStackImagesShell()
@ -208,14 +214,9 @@ class ShellTest(utils.TestCase):
self._assert_auth_plugin_args(mock_auth_plugin)
@mock.patch('glanceclient.v2.client.Client')
@mock.patch('keystoneclient.session.Session')
@mock.patch.object(openstack_shell.OpenStackImagesShell, '_cache_schemas')
@mock.patch.object(keystoneclient.discover.Discover, 'url_for',
side_effect=[keystone_client_fixtures.V2_URL, None])
def test_auth_plugin_invocation_with_v2(self,
v2_client,
ks_session,
url_for,
cache_schemas):
with mock.patch(self.auth_plugin) as mock_auth_plugin:
args = '--os-image-api-version 2 image-list'
@ -224,40 +225,29 @@ class ShellTest(utils.TestCase):
self._assert_auth_plugin_args(mock_auth_plugin)
@mock.patch('glanceclient.v1.client.Client')
@mock.patch('keystoneclient.session.Session')
@mock.patch.object(keystoneclient.discover.Discover, 'url_for',
side_effect=[keystone_client_fixtures.V2_URL,
keystone_client_fixtures.V3_URL])
def test_auth_plugin_invocation_with_unversioned_auth_url_with_v1(
self, v1_client, ks_session, url_for):
self, v1_client):
with mock.patch(self.auth_plugin) as mock_auth_plugin:
args = '--os-auth-url %s image-list' % (
keystone_client_fixtures.BASE_URL)
args = '--os-auth-url %s image-list' % DEFAULT_UNVERSIONED_AUTH_URL
glance_shell = openstack_shell.OpenStackImagesShell()
glance_shell.main(args.split())
self._assert_auth_plugin_args(mock_auth_plugin)
@mock.patch('glanceclient.v2.client.Client')
@mock.patch('keystoneclient.session.Session')
@mock.patch.object(openstack_shell.OpenStackImagesShell, '_cache_schemas')
@mock.patch.object(keystoneclient.discover.Discover, 'url_for',
side_effect=[keystone_client_fixtures.V2_URL,
keystone_client_fixtures.V3_URL])
def test_auth_plugin_invocation_with_unversioned_auth_url_with_v2(
self, v2_client, ks_session, cache_schemas, url_for):
self, v2_client, cache_schemas):
with mock.patch(self.auth_plugin) as mock_auth_plugin:
args = ('--os-auth-url %s --os-image-api-version 2 '
'image-list') % (keystone_client_fixtures.BASE_URL)
'image-list') % DEFAULT_UNVERSIONED_AUTH_URL
glance_shell = openstack_shell.OpenStackImagesShell()
glance_shell.main(args.split())
self._assert_auth_plugin_args(mock_auth_plugin)
@mock.patch('sys.stdin', side_effect=mock.MagicMock)
@mock.patch('getpass.getpass', return_value='password')
@mock.patch('keystoneclient.session.Session.get_token',
side_effect=ks_exc.ConnectionRefused)
def test_password_prompted_with_v2(self, mock_session, mock_getpass,
mock_stdin):
def test_password_prompted_with_v2(self, mock_getpass, mock_stdin):
self.requests.post(self.token_url, exc=requests.ConnectionError)
glance_shell = openstack_shell.OpenStackImagesShell()
self.make_env(exclude='OS_PASSWORD')
self.assertRaises(ks_exc.ConnectionRefused,
@ -352,12 +342,13 @@ class ShellTest(utils.TestCase):
class ShellTestWithKeystoneV3Auth(ShellTest):
# auth environment to use
auth_env = FAKE_V3_ENV.copy()
token_url = DEFAULT_V3_AUTH_URL + '/auth/tokens'
# expected auth plugin to invoke
auth_plugin = 'keystoneclient.auth.identity.v3.Password'
def _assert_auth_plugin_args(self, mock_auth_plugin):
mock_auth_plugin.assert_called_once_with(
keystone_client_fixtures.V3_URL,
DEFAULT_V3_AUTH_URL,
user_id='',
username=self.auth_env['OS_USERNAME'],
password=self.auth_env['OS_PASSWORD'],
@ -369,13 +360,7 @@ class ShellTestWithKeystoneV3Auth(ShellTest):
project_domain_name='')
@mock.patch('glanceclient.v1.client.Client')
@mock.patch('keystoneclient.session.Session')
@mock.patch.object(keystoneclient.discover.Discover, 'url_for',
side_effect=[None, keystone_client_fixtures.V3_URL])
def test_auth_plugin_invocation_with_v1(self,
v1_client,
ks_session,
url_for):
def test_auth_plugin_invocation_with_v1(self, v1_client):
with mock.patch(self.auth_plugin) as mock_auth_plugin:
args = 'image-list'
glance_shell = openstack_shell.OpenStackImagesShell()
@ -383,29 +368,19 @@ class ShellTestWithKeystoneV3Auth(ShellTest):
self._assert_auth_plugin_args(mock_auth_plugin)
@mock.patch('glanceclient.v2.client.Client')
@mock.patch('keystoneclient.session.Session')
@mock.patch.object(openstack_shell.OpenStackImagesShell, '_cache_schemas')
@mock.patch.object(keystoneclient.discover.Discover, 'url_for',
side_effect=[None, keystone_client_fixtures.V3_URL])
def test_auth_plugin_invocation_with_v2(self,
v2_client,
ks_session,
url_for,
cache_schemas):
def test_auth_plugin_invocation_with_v2(self, v2_client, cache_schemas):
with mock.patch(self.auth_plugin) as mock_auth_plugin:
args = '--os-image-api-version 2 image-list'
glance_shell = openstack_shell.OpenStackImagesShell()
glance_shell.main(args.split())
self._assert_auth_plugin_args(mock_auth_plugin)
@mock.patch('keystoneclient.session.Session')
@mock.patch('keystoneclient.discover.Discover',
side_effect=ks_exc.ClientException())
def test_api_discovery_failed_with_unversioned_auth_url(self,
ks_session,
discover):
args = '--os-auth-url %s image-list' % (
keystone_client_fixtures.BASE_URL)
args = '--os-auth-url %s image-list' % DEFAULT_UNVERSIONED_AUTH_URL
glance_shell = openstack_shell.OpenStackImagesShell()
self.assertRaises(exc.CommandError, glance_shell.main, args.split())