adding docs to test classes,

updating run_tests.sh to match reality
adding debug middleware factory
adding docs on enabling debug middleware
resolving pep8 issues

blueprint keystone-documentation

Change-Id: If16e908f21082bab770b19e1aa384fccc7ee5643
This commit is contained in:
Joe Heck 2011-11-02 05:53:27 -07:00 committed by Dolph Mathews
parent c07262c730
commit 29adc2f151
8 changed files with 217 additions and 20 deletions

139
doc/source/developing.rst Normal file
View File

@ -0,0 +1,139 @@
..
Copyright 2011 OpenStack, LLC
All Rights Reserved.
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.
========================
Developing with Keystone
========================
Get your development environment set up according to :doc:`setup`.
Running a development instance
==============================
Setting up a virtualenv
-----------------------
We recommend establishing a virtualenv to run keystone within. To establish
this environment, use the command::
$> python tools/install_venv.py
This will create a local virtual environment in the directory ``.keystone-venv``.
Once created, you can activate this virtualenv for your current shell using:
$> source .keystone-venv/bin/activate
The virtual environment can be disabled using the command::
$> deactivate
You can also use ``tools\with_venv.sh`` to prefix commands so that they run
within the virtual environment. For more information on virtual environments,
see virtualenv_.
.. _virtualenv: http://www.virtualenv.org/
Running Keystone
----------------
To run the keystone Admin and API server instances, use::
$> tools/with_venv.sh bin/keystone
Running a demo service that uses Keystone
-----------------------------------------
To run client demo (with all auth middleware running locally on sample service):
$> tools/with_venv.sh examples/echo/bin/echod
which spins up a simple "echo" service on port 8090. To use a simple echo client:
$> python examples/echo/echo_client.py
Interacting with Keystone
=========================
You can interact with Keystone through the command line using :doc:`keystone-manage`
which allows you to establish tenants, users, etc.
You can also interact with Keystone through it's REST API. There is a python
keystone client library python-keystoneclient_ which interacts exclusively through
the REST API.
.. _python-keystoneclient: https://github.com/4P/python-keystoneclient
The easiest way to establish some base information in Keystone to interact with is
to invoke::
$> tools/with_venv.sh bin/sampledata
You can see the details of what that creates in ``keystone/test/sampledata.py``
interacting with keystone using curl
------------------------------------
Get an unscoped token::
$> curl -d '{"auth": {"passwordCredentials": {"username": "joeuser", "password": "secrete"}}}' -H "Content-type: application/json" http://localhost:5000/v2.0/tokens
Get a token for a tenant::
$> curl -d '{"auth": {"passwordCredentials": {"username": "joeuser", "password": "secrete"}, "tenantName": "customer-x"}}' -H "Content-type: application/json" http://localhost:5000/v2.0/tokens
Get an admin token::
$> curl -d '{"auth": {"passwordCredentials": {"username": "admin", "password": "secrete"}}}' -H "Content-type: application/json" http://localhost:35357/v2.0/tokens
Get a list of tenants using the admin token::
$> curl -d '{"auth": {"passwordCredentials": {"username": "admin", "password": "secrete"}}}' -H "Content-type: application/json" http://localhost:35357/v2.0/tokens
Enabling debugging middleware
-----------------------------
You can enable a huge amount of additional data (debugging information) about
the request and repsonse objects flowing through Keystone using the debugging
WSGI middleware.
To enable this, just modify the pipelines in ``etc/keystone.conf``, changing::
[pipeline:admin]
pipeline =
urlrewritefilter
admin_api
[pipeline:keystone-legacy-auth]
pipeline =
urlrewritefilter
legacy_auth
RAX-KEY-extension
service_api
to::
[pipeline:admin]
pipeline =
debug
urlrewritefilter
admin_api
[pipeline:keystone-legacy-auth]
pipeline =
debug
urlrewritefilter
legacy_auth
RAX-KEY-extension
service_api

View File

@ -71,6 +71,7 @@ Developer Docs
.. toctree::
:maxdepth: 1
developing
architecture
sourcecode/autoindex

View File

@ -62,12 +62,12 @@ sql_idle_timeout = 30
[pipeline:admin]
pipeline =
urlrewritefilter
admin_api
urlrewritefilter
admin_api
[pipeline:keystone-legacy-auth]
pipeline =
urlrewritefilter
urlrewritefilter
legacy_auth
RAX-KEY-extension
service_api
@ -86,3 +86,6 @@ paste.filter_factory = keystone.frontends.legacy_token_auth:filter_factory
[filter:RAX-KEY-extension]
paste.filter_factory = keystone.contrib.extensions.service.raxkey.frontend:filter_factory
[filter:debug]
paste.filter_factory = keystone.common.wsgi:debug_filter_factory

View File

@ -183,6 +183,14 @@ class Debug(Middleware):
print
def debug_filter_factory(global_conf):
"""Filter factor to easily insert a debugging middleware into the
paste.deploy pipeline"""
def filter(app):
return Debug(app)
return filter
class Router(object):
"""
WSGI middleware that maps incoming requests to WSGI apps.

View File

@ -46,6 +46,18 @@ def execute(cmd, raise_error=True):
class KeystoneTest(object):
"""Primary test class for invoking keystone tests. Controls
initialization of environment with temporary configuration files,
starts keystone admin and service API WSIG servers, and then uses
:py:mod:`unittest2` to discover and iterate over existing tests.
:py:class:`keystone.test.KeystoneTest` is expected to be
subclassed and invoked in ``run_tests.py`` where subclasses define
a config_name (that matches a template existing in
``keystone/test/etc``) and test_files (that are cleared at the
end of test execution from the temporary space used to run these
tests).
"""
CONF_PARAMS = {'test_dir': TEST_DIR}
def clear_database(self):

View File

@ -6,7 +6,14 @@ from xml.etree import ElementTree
class HttpTestCase(unittest.TestCase):
"""Performs generic HTTP request testing"""
"""Performs generic HTTP request testing.
Defines a ``request`` method for use in test cases that makes
HTTP requests, and two new asserts:
* assertResponseSuccessful
* assertResponseStatus
"""
def request(self, host='127.0.0.1', port=80, method='GET', path='/',
headers=None, body=None, assert_status=None):
@ -38,13 +45,29 @@ class HttpTestCase(unittest.TestCase):
return response
def assertResponseSuccessful(self, response):
"""Asserts that a status code lies inside the 2xx range"""
"""Asserts that a status code lies inside the 2xx range
:param response: :py:class:`httplib.HTTPResponse` to be
verified to have a status code between 200 and 299.
example::
>>> self.assertResponseSuccessful(response, 203)
"""
self.assertTrue(response.status >= 200 and response.status <= 299,
'Status code %d is outside of the expected range (2xx)\n\n%s' %
(response.status, response.body))
def assertResponseStatus(self, response, assert_status):
"""Asserts a specific status code on the response"""
"""Asserts a specific status code on the response
:param response: :py:class:`httplib.HTTPResponse`
:param assert_status: The specific ``status`` result expected
example::
>>> self.assertResponseStatus(response, 203)
"""
self.assertEqual(response.status, assert_status,
'Status code %s is not %s, as expected)\n\n%s' %
(response.status, assert_status, response.body))
@ -104,11 +127,27 @@ class RestfulTestCase(HttpTestCase):
@staticmethod
def _encode_json(data):
"""Returns a JSON-encoded string of the given python dictionary"""
"""Returns a JSON-encoded string of the given python dictionary
:param data: python object to be encoded into JSON
:returns: string of JSON encoded data
"""
return json.dumps(data)
def _decode_response_body(self, response):
"""Detects response body type, and attempts to decode it"""
"""Detects response body type, and attempts to decode it
:param response: :py:class:`httplib.HTTPResponse`
:returns: response object with additions:
If context type is application/json, the response will have an
additional attribute ``json`` that will have the decoded JSON
result (typically a dict)
If context type is application/xml, the response will have an
additional attribute ``xml`` that will have the an ElementTree
result.
"""
if response.body != None and response.body.strip():
if 'application/json' in response.getheader('Content-Type', ''):
response.json = self._decode_json(response.body)

View File

@ -5,16 +5,19 @@ from keystone.test import KeystoneTest
class SQLTest(KeystoneTest):
"""Test defined using only SQLAlchemy back-end"""
config_name = 'sql.conf.template'
test_files = ('keystone.db',)
class MemcacheTest(KeystoneTest):
"""Test defined using only SQLAlchemy and Memcache back-end"""
config_name = 'memcache.conf.template'
test_files = ('keystone.db',)
class LDAPTest(KeystoneTest):
"""Test defined using only SQLAlchemy and LDAP back-end"""
config_name = 'ldap.conf.template'
test_files = ('keystone.db', 'ldap.db', 'ldap.db.db',)

View File

@ -7,7 +7,6 @@ function usage {
echo " -V, --virtual-env Always use virtualenv. Install automatically if not present"
echo " -N, --no-virtual-env Don't use virtualenv. Run tests in local environment"
echo " -f, --force Force a clean re-build of the virtual environment. Useful when dependencies have been added."
echo " --unittests-only Run unit tests only, exclude functional tests."
echo " --with-coverage Runs tests with python code coverage (useful for jenkins)"
echo " Note: cannot be used in combination --with-progress"
echo " --with-progress Runs tests with progress (useful for developers)"
@ -30,8 +29,7 @@ function process_option {
-p|--pep8) let just_pep8=1;;
-l|--pylint) let just_pylint=1; let never_venv=0;;
-f|--force) let force=1;;
--unittests-only) noseargs="$noseargs --exclude-dir=keystone/tests/functional --exclude-dir=keystone/tests/system";;
*) noseargs="$noseargs $1"
*) addlargs="$addlargs $1"
esac
}
@ -40,10 +38,11 @@ with_venv=tools/with_venv.sh
always_venv=0
never_venv=0
force=0
noseargs=
addlargs=
wrapper=""
just_pep8=0
just_pylint=0
RUNTESTS="python run_tests.py $addlargs"
for arg in "$@"; do
process_option $arg
@ -51,7 +50,7 @@ done
function run_tests {
# Just run the test suites in current environment
${wrapper} $NOSETESTS
${wrapper} $RUNTESTS
}
function run_pep8 {
@ -71,9 +70,6 @@ function run_pylint {
echo "Run 'pylint $PYLINT_OPTIONS $PYLINT_INCLUDE' for a full report."
}
NOSETESTS="python run_tests.py $noseargs"
if [ $never_venv -eq 0 ]
then
# Remove the virtual environment if --force used
@ -111,7 +107,3 @@ if [ $just_pylint -eq 1 ]; then
fi
run_tests || exit
#if [ -z "$noseargs" ]; then
# run_pep8
#fi