Adds a base class for functional tests

Change-Id: Ifd27edad8f004c42c4b9c7fad412394d01c5eaa8
Implements: bp functional-testing
This commit is contained in:
David Stanek 2015-07-17 16:16:37 +00:00 committed by Marek Denis
parent 93239e455c
commit e04758e50a
7 changed files with 217 additions and 15 deletions

View File

View File

@ -0,0 +1,91 @@
# 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.
class AuthTestMixin(object):
"""To hold auth building helper functions."""
def _build_auth_scope(self, project_id=None, project_name=None,
project_domain_id=None, project_domain_name=None,
domain_id=None, domain_name=None, trust_id=None,
unscoped=None):
scope_data = {}
if unscoped:
scope_data['unscoped'] = {}
if project_id or project_name:
scope_data['project'] = {}
if project_id:
scope_data['project']['id'] = project_id
else:
scope_data['project']['name'] = project_name
if project_domain_id or project_domain_name:
project_domain_json = {}
if project_domain_id:
project_domain_json['id'] = project_domain_id
else:
project_domain_json['name'] = project_domain_name
scope_data['project']['domain'] = project_domain_json
if domain_id or domain_name:
scope_data['domain'] = {}
if domain_id:
scope_data['domain']['id'] = domain_id
else:
scope_data['domain']['name'] = domain_name
if trust_id:
scope_data['OS-TRUST:trust'] = {}
scope_data['OS-TRUST:trust']['id'] = trust_id
return scope_data
def _build_password_auth(self, user_id=None, username=None,
user_domain_id=None, user_domain_name=None,
password=None):
password_data = {'user': {}}
if user_id:
password_data['user']['id'] = user_id
else:
password_data['user']['name'] = username
if user_domain_id or user_domain_name:
password_data['user']['domain'] = {}
if user_domain_id:
password_data['user']['domain']['id'] = user_domain_id
else:
password_data['user']['domain']['name'] = user_domain_name
password_data['user']['password'] = password
return password_data
def _build_token_auth(self, token):
return {'id': token}
def build_authentication_request(self, token=None, user_id=None,
username=None, user_domain_id=None,
user_domain_name=None, password=None,
kerberos=False, **kwargs):
"""Build auth dictionary.
It will create an auth dictionary based on all the arguments
that it receives.
"""
auth_data = {}
auth_data['identity'] = {'methods': []}
if kerberos:
auth_data['identity']['methods'].append('kerberos')
auth_data['identity']['kerberos'] = {}
if token:
auth_data['identity']['methods'].append('token')
auth_data['identity']['token'] = self._build_token_auth(token)
if user_id or username:
auth_data['identity']['methods'].append('password')
auth_data['identity']['password'] = self._build_password_auth(
user_id, username, user_domain_id, user_domain_name, password)
if kwargs:
auth_data['scope'] = self._build_auth_scope(**kwargs)
return {'auth': auth_data}

View File

@ -0,0 +1,85 @@
# 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 os
import requests
import testtools
from keystone.tests.common import auth as common_auth
class BaseTestCase(testtools.TestCase, common_auth.AuthTestMixin):
request_headers = {'content-type': 'application/json'}
def setUp(self):
self.ADMIN_URL = os.environ.get('KSTEST_ADMIN_URL',
'http://localhost:35357')
self.PUBLIC_URL = os.environ.get('KSTEST_PUBLIC_URL',
'http://localhost:5000')
self.admin = {
'name': os.environ.get('KSTEST_ADMIN_USERNAME', 'admin'),
'password': os.environ.get('KSTEST_ADMIN_PASSWORD', ''),
'domain_id': os.environ.get('KSTEST_ADMIN_DOMAIN_ID', 'default')
}
self.user = {
'name': os.environ.get('KSTEST_USER_USERNAME', 'demo'),
'password': os.environ.get('KSTEST_USER_PASSWORD', ''),
'domain_id': os.environ.get('KSTEST_USER_DOMAIN_ID', 'default')
}
self.project_id = os.environ.get('KSTEST_PROJECT_ID')
super(BaseTestCase, self).setUp()
def _http_headers(self, token=None):
headers = {'content-type': 'application/json'}
if token:
headers['X-Auth-Token'] = token
return headers
def get_scoped_token_response(self, user):
"""Convenience method so that we can test authenticated requests
:param user: A dictionary with user information like 'username',
'password', 'domain_id'
:returns: urllib3.Response object
"""
body = self.build_authentication_request(
username=user['name'], user_domain_name=user['domain_id'],
password=user['password'], project_id=self.project_id)
return requests.post(self.PUBLIC_URL + '/v3/auth/tokens',
headers=self.request_headers,
json=body)
def get_scoped_token(self, user):
"""Convenience method for getting scoped token
This method doesn't do any token validaton.
:param user: A dictionary with user information like 'username',
'password', 'domain_id'
:returns: An OpenStack token for further use
:rtype: str
"""
r = self.get_scoped_token_response(user)
return r.headers.get('X-Subject-Token')
def get_scoped_admin_token(self):
return self.get_scoped_token(self.admin)
def get_scoped_user_token(self):
return self.get_scoped_token(self.user)

View File

@ -13,42 +13,46 @@
import requests
import testtools.matchers
from keystone.tests.functional import core as functests
is_multiple_choices = testtools.matchers.Equals(
requests.status_codes.codes.multiple_choices)
is_ok = testtools.matchers.Equals(requests.status_codes.codes.ok)
versions = ('v2.0', 'v3')
class TestServerRunning(testtools.TestCase):
versions = ('v2.0', 'v3')
admin_url = 'http://localhost:35357'
public_url = 'http://localhost:5000'
class TestServerRunning(functests.BaseTestCase):
def test_admin_responds_with_multiple_choices(self):
resp = requests.get(self.admin_url)
resp = requests.get(self.ADMIN_URL)
self.assertThat(resp.status_code, is_multiple_choices)
def test_admin_versions(self):
for version in self.versions:
resp = requests.get(self.admin_url + '/' + version)
for version in versions:
resp = requests.get(self.ADMIN_URL + '/' + version)
self.assertThat(
resp.status_code,
testtools.matchers.Annotate(
'failed for version %s' % version, is_ok))
def test_public_responds_with_multiple_choices(self):
resp = requests.get(self.public_url)
resp = requests.get(self.PUBLIC_URL)
self.assertThat(resp.status_code, is_multiple_choices)
def test_public_versions(self):
for version in self.versions:
resp = requests.get(self.public_url + '/' + version)
for version in versions:
resp = requests.get(self.PUBLIC_URL + '/' + version)
self.assertThat(
resp.status_code,
testtools.matchers.Annotate(
'failed for version %s' % version, is_ok))
def test_get_user_token(self):
token = self.get_scoped_user_token()
self.assertIsNotNone(token)
class TestServerRunningOnPath(TestServerRunning):
admin_url = 'http://localhost/identity_admin'
public_url = 'http://localhost/identity'
def test_get_admin_token(self):
token = self.get_scoped_admin_token()
self.assertIsNotNone(token)

View File

@ -27,6 +27,7 @@ from keystone.common import cache
from keystone import exception
from keystone import middleware
from keystone.policy.backends import rules
from keystone.tests.common import auth as common_auth
from keystone.tests import unit
from keystone.tests.unit import rest
@ -118,7 +119,7 @@ class AuthTestMixin(object):
class RestfulTestCase(unit.SQLDriverOverrides, rest.RestfulTestCase,
AuthTestMixin):
common_auth.AuthTestMixin):
def config_files(self):
config_files = super(RestfulTestCase, self).config_files()
config_files.append(unit.dirs.tests_conf('backend_sql.conf'))

View File

@ -31,6 +31,7 @@ from keystone import auth
from keystone.common import utils
from keystone import exception
from keystone.policy.backends import rules
from keystone.tests.common import auth as common_auth
from keystone.tests import unit
from keystone.tests.unit import ksfixtures
from keystone.tests.unit import test_v3
@ -38,7 +39,7 @@ from keystone.tests.unit import test_v3
CONF = cfg.CONF
class TestAuthInfo(test_v3.AuthTestMixin, testcase.TestCase):
class TestAuthInfo(common_auth.AuthTestMixin, testcase.TestCase):
def setUp(self):
super(TestAuthInfo, self).setUp()
auth.controllers.load_auth_methods()

20
tox.ini
View File

@ -92,12 +92,32 @@ commands = {posargs}
[testenv:debug]
commands = oslo_debug_helper {posargs}
passenv =
KSTEST_ADMIN_URL
KSTEST_ADMIN_USERNAME
KSTEST_ADMIN_PASSWORD
KSTEST_ADMIN_DOMAIN_ID
KSTEST_PUBLIC_URL
KSTEST_USER_USERNAME
KSTEST_USER_PASSWORD
KSTEST_USER_DOMAIN_ID
KSTEST_PROJECT_ID
[testenv:functional]
basepython = python3.4
deps = -r{toxinidir}/test-requirements.txt
setenv = OS_TEST_PATH=./keystone/tests/functional
commands = python setup.py testr --slowest --testr-args='{posargs}'
passenv =
KSTEST_ADMIN_URL
KSTEST_ADMIN_USERNAME
KSTEST_ADMIN_PASSWORD
KSTEST_ADMIN_DOMAIN_ID
KSTEST_PUBLIC_URL
KSTEST_USER_USERNAME
KSTEST_USER_PASSWORD
KSTEST_USER_DOMAIN_ID
KSTEST_PROJECT_ID
[flake8]
filename= *.py,keystone-all,keystone-manage