Tests use free TCP/IP ports
- test.KeystoneTest loads server (in ClientTests only) on free TCP/IP port and sets globals in keystone.test.client to point to the server. Client tests pick that info up and use the provided server ports. - All defaults to 35357/5000 remain Change-Id: Ifc4ff023e3004cf886d26eaefeb42e1b469e9b81
This commit is contained in:
parent
a5e7587c8d
commit
1c6c351566
@ -16,9 +16,12 @@
|
||||
|
||||
import httplib
|
||||
import json
|
||||
import logging
|
||||
|
||||
import keystone.common.exception
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ServiceClient(object):
|
||||
"""Keystone v2.0 HTTP API client for normal service function.
|
||||
@ -52,6 +55,7 @@ class ServiceClient(object):
|
||||
:returns: httplib.HTTPResponse object
|
||||
|
||||
"""
|
||||
LOG.debug("Connecting to %s" % self.auth_address)
|
||||
if (self.is_ssl):
|
||||
connection = httplib.HTTPSConnection(self.auth_address,
|
||||
cert_file=self.cert_file)
|
||||
|
@ -50,6 +50,7 @@ HTTP_X_AUTHORIZATION
|
||||
the client identity being passed in
|
||||
|
||||
"""
|
||||
import logging
|
||||
import sys
|
||||
import optparse
|
||||
|
||||
@ -58,6 +59,8 @@ from keystone.routers.service import ServiceApi
|
||||
from keystone.routers.admin import AdminApi
|
||||
from keystone import version
|
||||
|
||||
logger = logging.getLogger('keystone.server')
|
||||
|
||||
|
||||
def service_app_factory(global_conf, **local_conf):
|
||||
"""paste.deploy app factory for creating OpenStack API server apps"""
|
||||
@ -125,6 +128,9 @@ class Server():
|
||||
self.config = config_name or self.name
|
||||
self.key = None
|
||||
self.server = None
|
||||
self.port = None
|
||||
self.host = None
|
||||
self.protocol = None
|
||||
|
||||
def start(self, host=None, port=None, wait=True):
|
||||
"""Starts the Keystone server
|
||||
@ -179,19 +185,21 @@ class Server():
|
||||
ca_certs=ca_certs,
|
||||
cert_required=cert_required,
|
||||
key=self.key)
|
||||
self.protocol = 'https'
|
||||
else:
|
||||
self.server = wsgi.Server()
|
||||
self.server.start(app, port, host,
|
||||
key="%s-%s:%s" % (self.config, host, port))
|
||||
self.protocol = 'http'
|
||||
|
||||
self.port = port
|
||||
self.host = host
|
||||
|
||||
print "%s listening on %s://%s:%s" % (
|
||||
self.name, ['http', 'https'][service_ssl], host, port)
|
||||
|
||||
# Wait until done
|
||||
if wait:
|
||||
# For Debugging LDAP
|
||||
#from keystone.test import sampledata
|
||||
#sampledata.load_fixture()
|
||||
self.server.wait()
|
||||
|
||||
def stop(self):
|
||||
|
@ -48,6 +48,7 @@ test suites"""
|
||||
|
||||
import cgitb
|
||||
import heapq
|
||||
import logging
|
||||
from nose import config as noseconfig
|
||||
from nose import core
|
||||
from nose import result
|
||||
@ -63,11 +64,15 @@ import keystone
|
||||
import keystone.server
|
||||
import keystone.version
|
||||
from keystone.common import config
|
||||
from keystone.test import utils
|
||||
from keystone.test import client as client_tests
|
||||
|
||||
TEST_DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
BASE_DIR = os.path.abspath(os.path.join(TEST_DIR, os.pardir, os.pardir))
|
||||
TEST_CERT = os.path.join(BASE_DIR, 'examples/ssl/certs/middleware-key.pem')
|
||||
|
||||
logger = logging.getLogger('test')
|
||||
|
||||
|
||||
class _AnsiColorizer(object):
|
||||
"""
|
||||
@ -346,7 +351,7 @@ class KeystoneTest(object):
|
||||
end of test execution from the temporary space used to run these
|
||||
tests).
|
||||
"""
|
||||
CONF_PARAMS = {'test_dir': TEST_DIR, 'base_dir': BASE_DIR}
|
||||
config_params = {'test_dir': TEST_DIR, 'base_dir': BASE_DIR}
|
||||
isSsl = False
|
||||
config_name = None
|
||||
test_files = None
|
||||
@ -371,7 +376,9 @@ class KeystoneTest(object):
|
||||
"""Populates a configuration template, and writes to a file pointer."""
|
||||
template_fpath = os.path.join(TEST_DIR, 'etc', self.config_name)
|
||||
conf_contents = open(template_fpath).read()
|
||||
conf_contents = conf_contents % self.CONF_PARAMS
|
||||
self.config_params['service_port'] = utils.get_unused_port()
|
||||
self.config_params['admin_port'] = utils.get_unused_port()
|
||||
conf_contents = conf_contents % self.config_params
|
||||
self.conf_fp = tempfile.NamedTemporaryFile()
|
||||
self.conf_fp.write(conf_contents)
|
||||
self.conf_fp.flush()
|
||||
@ -380,6 +387,7 @@ class KeystoneTest(object):
|
||||
pass
|
||||
|
||||
def startServer(self):
|
||||
""" Starts a Keystone server on random ports for testing """
|
||||
self.server = None
|
||||
self.admin_server = None
|
||||
|
||||
@ -391,7 +399,7 @@ class KeystoneTest(object):
|
||||
os.environ['cert_file'] = TEST_CERT
|
||||
|
||||
# run the keystone server
|
||||
print "Starting the keystone server..."
|
||||
logger.info("Starting the keystone server...")
|
||||
|
||||
parser = optparse.OptionParser(version='%%prog %s' %
|
||||
keystone.version.version())
|
||||
@ -414,17 +422,33 @@ class KeystoneTest(object):
|
||||
config_name='keystone-legacy-auth',
|
||||
options=options, args=args)
|
||||
service.start(wait=False)
|
||||
|
||||
# Client tests will use these globals to find out where
|
||||
# the server is
|
||||
client_tests.TEST_TARGET_SERVER_SERVICE_PROTOCOL = service.protocol
|
||||
client_tests.TEST_TARGET_SERVER_SERVICE_ADDRESS = service.host
|
||||
client_tests.TEST_TARGET_SERVER_SERVICE_PORT = service.port
|
||||
|
||||
except RuntimeError, e:
|
||||
sys.exit("ERROR: %s" % e)
|
||||
|
||||
try:
|
||||
# Load Admin API server
|
||||
port = options.get('admin_port', None)
|
||||
host = options.get('bind_host', None)
|
||||
port = options.get('admin_port',
|
||||
client_tests.TEST_TARGET_SERVER_ADMIN_PORT)
|
||||
host = options.get('bind_host',
|
||||
client_tests.TEST_TARGET_SERVER_ADMIN_ADDRESS)
|
||||
admin = keystone.server.Server(name='Admin API',
|
||||
config_name='admin',
|
||||
options=options, args=args)
|
||||
admin.start(host=host, port=port, wait=False)
|
||||
|
||||
# Client tests will use these globals to find out where
|
||||
# the server is
|
||||
client_tests.TEST_TARGET_SERVER_ADMIN_PROTOCOL = admin.protocol
|
||||
client_tests.TEST_TARGET_SERVER_ADMIN_ADDRESS = admin.host
|
||||
client_tests.TEST_TARGET_SERVER_ADMIN_PORT = admin.port
|
||||
|
||||
except RuntimeError, e:
|
||||
service.stop()
|
||||
sys.exit("ERROR: %s" % e)
|
||||
|
@ -0,0 +1,37 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2010 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.
|
||||
|
||||
""" Client Tests
|
||||
|
||||
Client tests are tests that use HTTP(S) calls to a Keystone server to exercise
|
||||
request/response test cases.
|
||||
|
||||
In order to avoid port conflicts, client tests use the global settings below
|
||||
to know which server to talk to.
|
||||
|
||||
When a server is started for testing purposes (usually by the
|
||||
keystone.test.KeystoneTest class) it will update these values so client tests
|
||||
know where to find the server
|
||||
|
||||
"""
|
||||
TEST_TARGET_SERVER_ADMIN_PROTOCOL = 'http'
|
||||
TEST_TARGET_SERVER_ADMIN_ADDRESS = '127.0.0.1'
|
||||
TEST_TARGET_SERVER_ADMIN_PORT = 35357
|
||||
|
||||
TEST_TARGET_SERVER_SERVICE_PROTOCOL = 'http'
|
||||
TEST_TARGET_SERVER_SERVICE_ADDRESS = '127.0.0.1'
|
||||
TEST_TARGET_SERVER_SERVICE_PORT = 5000
|
@ -3,6 +3,7 @@ import unittest
|
||||
import keystone.common.exception
|
||||
import keystone.client
|
||||
from keystone.test.functional.common import isSsl
|
||||
from keystone.test import client as client_tests
|
||||
|
||||
|
||||
class TestAdminClient(unittest.TestCase):
|
||||
@ -16,11 +17,13 @@ class TestAdminClient(unittest.TestCase):
|
||||
Run before each test.
|
||||
"""
|
||||
cert_file = isSsl()
|
||||
self.client = keystone.client.AdminClient("127.0.0.1",
|
||||
is_ssl=(cert_file != None),
|
||||
cert_file=cert_file,
|
||||
admin_name="admin",
|
||||
admin_pass="secrete")
|
||||
self.client = keystone.client.AdminClient(
|
||||
client_tests.TEST_TARGET_SERVER_ADMIN_ADDRESS,
|
||||
port=client_tests.TEST_TARGET_SERVER_ADMIN_PORT,
|
||||
is_ssl=(cert_file is not None),
|
||||
cert_file=cert_file,
|
||||
admin_name="admin",
|
||||
admin_pass="secrete")
|
||||
|
||||
def test_admin_validate_token(self):
|
||||
"""
|
||||
@ -77,9 +80,11 @@ class TestServiceClient(unittest.TestCase):
|
||||
Run before each test.
|
||||
"""
|
||||
cert_file = isSsl()
|
||||
self.client = keystone.client.ServiceClient("127.0.0.1",
|
||||
is_ssl=(cert_file != None),
|
||||
cert_file=cert_file)
|
||||
self.client = keystone.client.ServiceClient(
|
||||
client_tests.TEST_TARGET_SERVER_SERVICE_ADDRESS,
|
||||
port=client_tests.TEST_TARGET_SERVER_SERVICE_PORT,
|
||||
is_ssl=(cert_file is not None),
|
||||
cert_file=cert_file)
|
||||
|
||||
def test_admin_get_token(self):
|
||||
"""
|
||||
|
@ -2,6 +2,7 @@ import unittest2 as unittest
|
||||
|
||||
import keystone.common.exception
|
||||
from keystone.test.functional import common
|
||||
from keystone.test import client as client_tests
|
||||
|
||||
#
|
||||
# Auth Token
|
||||
@ -55,10 +56,14 @@ class TestQuantumMiddleware(common.MiddlewareTestCase):
|
||||
json['access']
|
||||
self.admin_token = access['token']['id']
|
||||
settings = {'delay_auth_decision': '0',
|
||||
'auth_host': '127.0.0.1',
|
||||
'auth_port': '35357',
|
||||
'auth_protocol': 'http',
|
||||
'auth_uri': 'http://localhost:35357/',
|
||||
'auth_host': client_tests.TEST_TARGET_SERVER_ADMIN_ADDRESS,
|
||||
'auth_port': client_tests.TEST_TARGET_SERVER_ADMIN_PORT,
|
||||
'auth_protocol':
|
||||
client_tests.TEST_TARGET_SERVER_ADMIN_PROTOCOL,
|
||||
'auth_uri': ('%s://%s:%s/' % \
|
||||
(client_tests.TEST_TARGET_SERVER_SERVICE_PROTOCOL,
|
||||
client_tests.TEST_TARGET_SERVER_SERVICE_ADDRESS,
|
||||
client_tests.TEST_TARGET_SERVER_SERVICE_PORT)),
|
||||
'auth_version': '2.0',
|
||||
'auth_admin_token': self.admin_token,
|
||||
'auth_admin_user': self.admin_username,
|
||||
|
@ -11,10 +11,10 @@ service-header-mappings = {
|
||||
'swift' : 'X-Storage-Url',
|
||||
'cdn' : 'X-CDN-Management-Url'}
|
||||
service_host = 0.0.0.0
|
||||
service_port = 5000
|
||||
service_port = %(service_port)s
|
||||
service_ssl = False
|
||||
admin_host = 0.0.0.0
|
||||
admin_port = 35357
|
||||
admin_port = %(admin_port)s
|
||||
admin_ssl = False
|
||||
keystone-admin-role = Admin
|
||||
keystone-service-admin-role = KeystoneServiceAdmin
|
||||
|
@ -11,10 +11,10 @@ service-header-mappings = {
|
||||
'swift' : 'X-Storage-Url',
|
||||
'cdn' : 'X-CDN-Management-Url'}
|
||||
service_host = 0.0.0.0
|
||||
service_port = 5000
|
||||
service_port = %(service_port)s
|
||||
service_ssl = False
|
||||
admin_host = 0.0.0.0
|
||||
admin_port = 35357
|
||||
admin_port = %(admin_port)s
|
||||
admin_ssl = False
|
||||
keystone-admin-role = Admin
|
||||
keystone-service-admin-role = KeystoneServiceAdmin
|
||||
|
@ -11,10 +11,10 @@ service-header-mappings = {
|
||||
'swift' : 'X-Storage-Url',
|
||||
'cdn' : 'X-CDN-Management-Url'}
|
||||
service_host = 0.0.0.0
|
||||
service_port = 5000
|
||||
service_port = %(service_port)s
|
||||
service_ssl = False
|
||||
admin_host = 0.0.0.0
|
||||
admin_port = 35357
|
||||
admin_port = %(admin_port)s
|
||||
admin_ssl = False
|
||||
keystone-admin-role = Admin
|
||||
keystone-service-admin-role = KeystoneServiceAdmin
|
||||
|
@ -10,10 +10,10 @@ service-header-mappings = {
|
||||
'swift' : 'X-Storage-Url',
|
||||
'cdn' : 'X-CDN-Management-Url'}
|
||||
service_host = 0.0.0.0
|
||||
service_port = 5000
|
||||
service_port = %(service_port)s
|
||||
service_ssl = True
|
||||
admin_host = 0.0.0.0
|
||||
admin_port = 35357
|
||||
admin_port = %(admin_port)s
|
||||
admin_ssl = True
|
||||
keystone-admin-role = Admin
|
||||
keystone-service-admin-role = KeystoneServiceAdmin
|
||||
|
@ -10,6 +10,7 @@ from xml.etree import ElementTree
|
||||
|
||||
from keystone import server
|
||||
import keystone.backends.api as db_api
|
||||
from keystone.test import client as client_tests
|
||||
|
||||
logger = logging.getLogger('test.functional.common')
|
||||
|
||||
@ -31,15 +32,16 @@ class HttpTestCase(unittest.TestCase):
|
||||
* assertResponseStatus
|
||||
"""
|
||||
|
||||
def request(self, host='127.0.0.1', port=80, method='GET', path='/',
|
||||
headers=None, body=None, assert_status=None):
|
||||
def request(self, host='127.0.0.1', protocol='http', port=80, method='GET',
|
||||
path='/', headers=None, body=None, assert_status=None):
|
||||
"""Perform request and fetch httplib.HTTPResponse from the server"""
|
||||
|
||||
# Initialize headers dictionary
|
||||
headers = {} if not headers else headers
|
||||
|
||||
cert_file = isSsl()
|
||||
if (cert_file is not None):
|
||||
logger.debug("Connecting to %s://%s:%s", protocol, host, port)
|
||||
if protocol == 'https':
|
||||
cert_file = isSsl()
|
||||
connection = httplib.HTTPSConnection(host, port,
|
||||
cert_file=cert_file,
|
||||
timeout=20)
|
||||
@ -324,14 +326,17 @@ class ApiTestCase(RestfulTestCase):
|
||||
def tearDown(self):
|
||||
pass
|
||||
|
||||
def request(self, host='127.0.0.1', port=80, method='GET', path='/',
|
||||
headers=None, body=None, assert_status=None, server=None):
|
||||
def request(self, host='127.0.0.1', protocol='http', port=80, method='GET',
|
||||
path='/', headers=None, body=None, assert_status=None,
|
||||
server=None):
|
||||
"""Overrides HttpTestCase and uses local calls"""
|
||||
if self.use_server:
|
||||
# Call a real server (bypass the override)
|
||||
return super(ApiTestCase, self).request(host=host, port=port,
|
||||
method=method, path=path, headers=headers,
|
||||
body=body, assert_status=assert_status)
|
||||
protocol=protocol, method=method,
|
||||
path=path, headers=headers, body=body,
|
||||
assert_status=assert_status)
|
||||
|
||||
req = Request.blank(path)
|
||||
req.method = method
|
||||
req.headers = headers
|
||||
@ -413,8 +418,8 @@ class ApiTestCase(RestfulTestCase):
|
||||
'Status code %s is not %s, as expected)\n\n%s' %
|
||||
(response.status_int, assert_status, response.body))
|
||||
|
||||
def service_request(self, version='2.0', path='', port=5000, headers=None,
|
||||
**kwargs):
|
||||
def service_request(self, version='2.0', path='', port=None, headers=None,
|
||||
host=None, protocol=None, **kwargs):
|
||||
"""Returns a request to the service API"""
|
||||
|
||||
# Initialize headers dictionary
|
||||
@ -422,17 +427,23 @@ class ApiTestCase(RestfulTestCase):
|
||||
|
||||
if self.use_server:
|
||||
path = ApiTestCase._version_path(version, path)
|
||||
if port is None:
|
||||
port = client_tests.TEST_TARGET_SERVER_SERVICE_PORT
|
||||
if host is None:
|
||||
host = client_tests.TEST_TARGET_SERVER_SERVICE_ADDRESS
|
||||
if protocol is None:
|
||||
protocol = client_tests.TEST_TARGET_SERVER_SERVICE_PROTOCOL
|
||||
|
||||
if self.service_token:
|
||||
headers['X-Auth-Token'] = self.service_token
|
||||
elif self.admin_token:
|
||||
headers['X-Auth-Token'] = self.admin_token
|
||||
|
||||
return self.restful_request(port=port, path=path, headers=headers,
|
||||
server=self.service_api, **kwargs)
|
||||
return self.restful_request(host=host, protocol=protocol, port=port,
|
||||
path=path, headers=headers, server=self.service_api, **kwargs)
|
||||
|
||||
def admin_request(self, version='2.0', path='', port=35357, headers=None,
|
||||
**kwargs):
|
||||
def admin_request(self, version='2.0', path='', port=None, headers=None,
|
||||
host=None, protocol=None, **kwargs):
|
||||
"""Returns a request to the admin API"""
|
||||
|
||||
# Initialize headers dictionary
|
||||
@ -440,12 +451,18 @@ class ApiTestCase(RestfulTestCase):
|
||||
|
||||
if self.use_server:
|
||||
path = ApiTestCase._version_path(version, path)
|
||||
if port is None:
|
||||
port = client_tests.TEST_TARGET_SERVER_ADMIN_PORT
|
||||
if host is None:
|
||||
host = client_tests.TEST_TARGET_SERVER_ADMIN_ADDRESS
|
||||
if protocol is None:
|
||||
protocol = client_tests.TEST_TARGET_SERVER_ADMIN_PROTOCOL
|
||||
|
||||
if self.admin_token:
|
||||
headers['X-Auth-Token'] = self.admin_token
|
||||
|
||||
return self.restful_request(port=port, path=path, headers=headers,
|
||||
server=self.admin_api, **kwargs)
|
||||
return self.restful_request(host=host, protocol=protocol, port=port,
|
||||
path=path, headers=headers, server=self.admin_api, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def _version_path(version, path):
|
||||
@ -1490,18 +1507,20 @@ class MiddlewareTestCase(FunctionalTestCase):
|
||||
super(MiddlewareTestCase, self).setUp()
|
||||
if settings is None:
|
||||
settings = {'delay_auth_decision': '0',
|
||||
'auth_host': '127.0.0.1',
|
||||
'auth_port': '35357',
|
||||
'auth_protocol': 'http',
|
||||
'auth_uri': 'http://localhost:35357/',
|
||||
'auth_host': client_tests.TEST_TARGET_SERVER_ADMIN_ADDRESS,
|
||||
'auth_port': client_tests.TEST_TARGET_SERVER_ADMIN_PORT,
|
||||
'auth_protocol':
|
||||
client_tests.TEST_TARGET_SERVER_ADMIN_PROTOCOL,
|
||||
'auth_uri': ('%s://%s:%s/' % \
|
||||
(client_tests.TEST_TARGET_SERVER_SERVICE_PROTOCOL,
|
||||
client_tests.TEST_TARGET_SERVER_SERVICE_ADDRESS,
|
||||
client_tests.TEST_TARGET_SERVER_SERVICE_PORT)),
|
||||
'admin_token': self.admin_token,
|
||||
'auth_admin_user': self.admin_username,
|
||||
'auth_admin_password': self.admin_password}
|
||||
cert_file = isSsl()
|
||||
if cert_file:
|
||||
settings['auth_protocol'] = 'https'
|
||||
settings['certfile'] = cert_file
|
||||
settings['auth_uri'] = 'https://localhost:35357/'
|
||||
if isinstance(middleware, tuple):
|
||||
self.test_middleware = HeaderApp()
|
||||
for filter in middleware:
|
||||
@ -1543,12 +1562,11 @@ class MiddlewareTestCase(FunctionalTestCase):
|
||||
self.assertEquals(resp.status_int, 401)
|
||||
headers = resp.headers
|
||||
self.assertTrue("WWW-Authenticate" in headers)
|
||||
if isSsl():
|
||||
self.assertEquals(headers['WWW-Authenticate'],
|
||||
"Keystone uri='https://localhost:35357/'")
|
||||
else:
|
||||
self.assertEquals(headers['WWW-Authenticate'],
|
||||
"Keystone uri='http://localhost:35357/'")
|
||||
self.assertEquals(headers['WWW-Authenticate'],
|
||||
"Keystone uri='%s://%s:%s/'" % \
|
||||
(client_tests.TEST_TARGET_SERVER_SERVICE_PROTOCOL,
|
||||
client_tests.TEST_TARGET_SERVER_SERVICE_ADDRESS,
|
||||
client_tests.TEST_TARGET_SERVER_SERVICE_PORT))
|
||||
|
||||
def test_401_bad_token(self):
|
||||
resp = Request.blank('/',
|
||||
|
@ -1,4 +1,5 @@
|
||||
import re
|
||||
import socket
|
||||
import string
|
||||
from lxml import etree
|
||||
|
||||
@ -46,3 +47,14 @@ class XMLTools():
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def get_unused_port():
|
||||
"""
|
||||
Returns an unused port on localhost.
|
||||
"""
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
s.bind(('localhost', 0))
|
||||
addr, port = s.getsockname()
|
||||
s.close()
|
||||
return port
|
||||
|
Loading…
Reference in New Issue
Block a user