Moved run_test logic into abstract class.

Useful for testing in some custom environment, e.g. during backend writing.
Example using of new class is at http://paste.openstack.org/show/2180/.
This script runs all unittests with the real LDAP connection.
The config template is at http://paste.openstack.org/show/2181/.

Change-Id: I4d89e8c4e9458cd982d73dd973d2da63989f4c93
This commit is contained in:
Yuriy Taraday 2011-08-16 12:53:10 +04:00 committed by Dolph Mathews
parent 920298f5e8
commit eb803079d6
2 changed files with 126 additions and 110 deletions

View File

@ -0,0 +1,107 @@
import os
import sys
import subprocess
import tempfile
import time
TEST_DIR = os.path.abspath(os.path.dirname(__file__))
BASE_DIR = os.path.abspath(os.path.join(TEST_DIR, '..', '..'))
def execute(cmd, raise_error=True):
"""
Executes a command in a subprocess. Returns a tuple
of (exitcode, out, err), where out is the string output
from stdout and err is the string output from stderr when
executing the command.
:param cmd: Command string to execute
:param raise_error: If returncode is not 0 (success), then
raise a RuntimeError? Default: True)
"""
env = os.environ.copy()
# Make sure that we use the programs in the
# current source directory's bin/ directory.
env['PATH'] = os.path.join(BASE_DIR, 'bin') + ':' + env['PATH']
process = subprocess.Popen(cmd,
shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=env)
result = process.communicate()
(out, err) = result
exitcode = process.returncode
if process.returncode != 0 and raise_error:
msg = "Command %(cmd)s did not succeed. Returned an exit "\
"code of %(exitcode)d."\
"\n\nSTDOUT: %(out)s"\
"\n\nSTDERR: %(err)s" % locals()
raise RuntimeError(msg)
return exitcode, out, err
class KeystoneTest(object):
CONF_PARAMS = {'test_dir': TEST_DIR}
def clear_database(self):
"""Remove any test databases or files generated by previous tests."""
for fname in self.test_files:
fpath = os.path.join(TEST_DIR, fname)
if os.path.exists(fpath):
print "Removing test file %s" % fname
os.unlink(fpath)
def construct_temp_conf_file(self):
"""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.conf_fp = tempfile.NamedTemporaryFile()
self.conf_fp.write(conf_contents)
self.conf_fp.flush()
def setUp(self):
self.clear_database()
self.construct_temp_conf_file()
# Populate the test database
print "Populating registry and token databases..."
execute('sampledata.sh -c %s' % self.conf_fp.name)
# run the keystone server
print "Starting the keystone server..."
self.server = subprocess.Popen(
[os.path.join(BASE_DIR, 'bin/keystone'), '-c', self.conf_fp.name])
# blatent hack.
time.sleep(3)
if self.server.poll() is not None:
raise RuntimeError('Failed to start server')
def tearDown(self):
# kill the keystone server
print "Stopping the keystone server..."
self.server.kill()
self.clear_database()
def run(self):
try:
self.setUp()
except:
self.clear_database()
raise
try:
# discover and run tests
print "Running tests..."
if '--with-coverage' in sys.argv:
print "running coverage"
execute('coverage run %s discover -t %s -s %s' %
('/usr/bin/unit2', BASE_DIR, TEST_DIR))
else:
execute('unit2 discover -f -t %s -s %s' %
(BASE_DIR, TEST_DIR))
finally:
self.tearDown()

View File

@ -1,122 +1,31 @@
#!/usr/bin/env python
"""Manages execution of keystone test suites"""
import os
import sys
import subprocess
import tempfile
import time
BASE_DIR = os.path.abspath(os.path.dirname(__file__))
TEST_DIR = os.path.join(BASE_DIR, 'keystone', 'test')
CONFIG_FILES = (
'sql.conf.template',
# not passing 'memcache.conf.template',
'ldap.conf.template')
TEST_FILES = (
'keystone.db',
'keystone.token.db',
'ldap.db',
'ldap.db.db')
from keystone.test import KeystoneTest
def execute(cmd, raise_error=True):
"""
Executes a command in a subprocess. Returns a tuple
of (exitcode, out, err), where out is the string output
from stdout and err is the string output from stderr when
executing the command.
:param cmd: Command string to execute
:param raise_error: If returncode is not 0 (success), then
raise a RuntimeError? Default: True)
"""
env = os.environ.copy()
# Make sure that we use the programs in the
# current source directory's bin/ directory.
env['PATH'] = os.path.join(BASE_DIR, 'bin') + ':' + env['PATH']
process = subprocess.Popen(cmd,
shell=True,
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=env)
result = process.communicate()
(out, err) = result
exitcode = process.returncode
if process.returncode != 0 and raise_error:
msg = "Command %(cmd)s did not succeed. Returned an exit "\
"code of %(exitcode)d."\
"\n\nSTDOUT: %(out)s"\
"\n\nSTDERR: %(err)s" % locals()
raise RuntimeError(msg)
return exitcode, out, err
class SQLTest(KeystoneTest):
config_name = 'sql.conf.template'
test_files = ('keystone.db',)
def remove_test_files():
"""Remove any test databases or files generated by previous tests."""
for fname in TEST_FILES:
fpath = os.path.join(TEST_DIR, fname)
if os.path.exists(fpath):
print "Removing test file %s" % fname
os.unlink(fpath)
class MemcacheTest(KeystoneTest):
config_name = 'memcache.conf.template'
test_files = ('keystone.db',)
def construct_temp_conf_file(temp_fp, config_name):
"""Populates a configuration template, and writes to a file pointer."""
template_fpath = os.path.join(TEST_DIR, 'etc', config_name)
conf_contents = open(template_fpath).read()
conf_contents = conf_contents % {'test_dir': TEST_DIR}
temp_fp.write(conf_contents)
temp_fp.flush()
class LDAPTest(KeystoneTest):
config_name = 'ldap.conf.template'
test_files = ('keystone.db', 'ldap.db', 'ldap.db.db',)
TESTS = [
SQLTest,
# not running MemcacheTest,
LDAPTest,
]
if __name__ == '__main__':
for config in CONFIG_FILES:
print 'Using config file', CONFIG_FILES.index(config) + 1, 'of', \
str(len(CONFIG_FILES)) + ':', config
remove_test_files()
try:
# Create a configuration file to supply to the keystone
# server for the test run
with tempfile.NamedTemporaryFile() as conf_fp:
construct_temp_conf_file(conf_fp, config)
# Populate the test database
print "Populating registry and token databases..."
execute('sampledata.sh -c %s' % conf_fp.name)
# run the keystone server
print "Starting the keystone server..."
server = subprocess.Popen(
[os.path.join(BASE_DIR, 'bin/keystone'),
'-c', conf_fp.name])
# blatent hack.
time.sleep(3)
if server.poll() is not None:
print >> sys.stderr, 'Failed to start server'
sys.exit(-1)
try:
# discover and run tests
print "Running tests..."
if '--with-coverage' in sys.argv:
print "running coverage"
execute('coverage run %s discover -t %s -s %s' %
('/usr/bin/unit2', BASE_DIR, TEST_DIR))
else:
execute('unit2 discover -t %s -s %s' %
(BASE_DIR, TEST_DIR))
finally:
#kill the keystone server
print "Stopping the keystone server..."
server.kill()
finally:
remove_test_files()
for test_num, test_cls in enumerate(TESTS):
print 'Starting test %d of %d with config: %s' % \
(test_num + 1, len(TESTS), test_cls.config_name)
test_cls().run()