Modify functional tests to use ostestr/testr

Defcore uses Tempest, which uses Test Repository.
This change makes it easier for Defcore to pull functional
tests from Swift and run them.  Additionally, using testr
allows tests to be run in parallel.

Concurrency set to 1 for now, >1 causes failures for
reasons that are still TBD.

With switch to ostestr all the server logs are being sent to stdout
which makes it completely unreadable. Suppressing the logs by default
now with a flag to enable it if desired.

Co-Authored-By: John Dickinson <me@not.mn>
Co-Authored-By: Robert Collins <rbtcollins@hpe.com>
Co-Authored-By: Matthew Oliver <matt@oliver.net.au>
Co-Authored-By: Ganesh Maharaj Mahalingam <ganesh.mahalingam@intel.com>

Change-Id: I53ef4a116996a772cf1f3abc2eb0ad60047322d5
Related-Bug: 1177924
This commit is contained in:
Richard Hawkins 2015-08-07 18:14:13 -05:00 committed by Ganesh Maharaj Mahalingam
parent b3d6fa1319
commit 9d7f71d575
12 changed files with 91 additions and 16 deletions

View File

@ -1,9 +1,11 @@
#!/bin/bash
SRC_DIR=$(python -c "import os; print os.path.dirname(os.path.realpath('$0'))")
set -e
cd ${SRC_DIR}/test/functional
nosetests --exe $@
cd ${SRC_DIR}
export TESTS_DIR=${SRC_DIR}/test/functional
ostestr --serial --pretty $@
rvalue=$?
cd -

2
.gitignore vendored
View File

@ -15,4 +15,6 @@ pycscope.*
.idea
MANIFEST
.testrepository/*
subunit.log
test/probe/.noseids

6
.testr.conf Normal file
View File

@ -0,0 +1,6 @@
[DEFAULT]
test_command=SWIFT_TEST_DEBUG_LOGS=${SWIFT_TEST_DEBUG_LOGS} \
${PYTHON:-python} -m subunit.run \
discover -t ./ ${TESTS_DIR:-./test/functional/} $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE
test_list_option=--list

View File

@ -10,6 +10,7 @@ nosexcover
nosehtmloutput
oslosphinx
sphinx>=1.1.2,<1.2
os-testr>=0.4.1
mock>=1.0
python-swiftclient
python-keystoneclient>=1.3.0

View File

@ -109,7 +109,7 @@ orig_hash_path_suff_pref = ('', '')
orig_swift_conf_name = None
in_process = False
_testdir = _test_servers = _test_coros = None
_testdir = _test_servers = _test_coros = _test_socks = None
policy_specified = None
@ -290,6 +290,7 @@ def in_process_setup(the_object_server=object_server):
_info('IN-PROCESS SERVERS IN USE FOR FUNCTIONAL TESTS')
_info('Using object_server class: %s' % the_object_server.__name__)
conf_src_dir = os.environ.get('SWIFT_TEST_IN_PROCESS_CONF_DIR')
show_debug_logs = os.environ.get('SWIFT_TEST_DEBUG_LOGS')
if conf_src_dir is not None:
if not os.path.isdir(conf_src_dir):
@ -339,10 +340,13 @@ def in_process_setup(the_object_server=object_server):
orig_hash_path_suff_pref = utils.HASH_PATH_PREFIX, utils.HASH_PATH_SUFFIX
utils.validate_hash_conf()
global _test_socks
_test_socks = []
# We create the proxy server listening socket to get its port number so
# that we can add it as the "auth_port" value for the functional test
# clients.
prolis = eventlet.listen(('localhost', 0))
_test_socks.append(prolis)
# The following set of configuration values is used both for the
# functional test frame work and for the various proxy, account, container
@ -388,6 +392,7 @@ def in_process_setup(the_object_server=object_server):
acc2lis = eventlet.listen(('localhost', 0))
con1lis = eventlet.listen(('localhost', 0))
con2lis = eventlet.listen(('localhost', 0))
_test_socks += [acc1lis, acc2lis, con1lis, con2lis] + obj_sockets
account_ring_path = os.path.join(_testdir, 'account.ring.gz')
with closing(GzipFile(account_ring_path, 'wb')) as f:
@ -416,23 +421,30 @@ def in_process_setup(the_object_server=object_server):
# Default to only 4 seconds for in-process functional test runs
eventlet.wsgi.WRITE_TIMEOUT = 4
def get_logger_name(name):
if show_debug_logs:
return debug_logger(name)
else:
return None
acc1srv = account_server.AccountController(
config, logger=debug_logger('acct1'))
config, logger=get_logger_name('acct1'))
acc2srv = account_server.AccountController(
config, logger=debug_logger('acct2'))
config, logger=get_logger_name('acct2'))
con1srv = container_server.ContainerController(
config, logger=debug_logger('cont1'))
config, logger=get_logger_name('cont1'))
con2srv = container_server.ContainerController(
config, logger=debug_logger('cont2'))
config, logger=get_logger_name('cont2'))
objsrvs = [
(obj_sockets[index],
the_object_server.ObjectController(
config, logger=debug_logger('obj%d' % (index + 1))))
config, logger=get_logger_name('obj%d' % (index + 1))))
for index in range(len(obj_sockets))
]
logger = debug_logger('proxy')
if show_debug_logs:
logger = debug_logger('proxy')
def get_logger(name, *args, **kwargs):
return logger
@ -446,6 +458,8 @@ def in_process_setup(the_object_server=object_server):
raise InProcessException(e)
nl = utils.NullLogger()
global proxy_srv
proxy_srv = prolis
prospa = eventlet.spawn(eventlet.wsgi.server, prolis, app, nl)
acc1spa = eventlet.spawn(eventlet.wsgi.server, acc1lis, acc1srv, nl)
acc2spa = eventlet.spawn(eventlet.wsgi.server, acc2lis, acc2srv, nl)
@ -487,6 +501,7 @@ def get_cluster_info():
# We'll update those constraints based on what the /info API provides, if
# anything.
global cluster_info
global config
try:
conn = Connection(config)
conn.authenticate()
@ -536,6 +551,7 @@ def setup_package():
global in_process
global config
if use_in_process:
# Explicitly set to True, so barrel on ahead with in-process
# functional test setup.
@ -722,7 +738,6 @@ def setup_package():
% policy_specified)
raise Exception('Failed to find specified policy %s'
% policy_specified)
get_cluster_info()
@ -731,16 +746,21 @@ def teardown_package():
locale.setlocale(locale.LC_COLLATE, orig_collate)
# clean up containers and objects left behind after running tests
global config
conn = Connection(config)
conn.authenticate()
account = Account(conn, config.get('account', config['username']))
account.delete_containers()
global in_process
global _test_socks
if in_process:
try:
for server in _test_coros:
for i, server in enumerate(_test_coros):
server.kill()
if not server.dead:
# kill it from the socket level
_test_socks[i].close()
except Exception:
pass
try:
@ -751,6 +771,7 @@ def teardown_package():
orig_hash_path_suff_pref
utils.SWIFT_CONF_FILE = orig_swift_conf_name
constraints.reload_constraints()
reset_globals()
class AuthError(Exception):
@ -768,6 +789,17 @@ parsed = [None, None, None, None, None]
conn = [None, None, None, None, None]
def reset_globals():
global url, token, service_token, parsed, conn, config
url = [None, None, None, None, None]
token = [None, None, None, None, None]
service_token = [None, None, None, None, None]
parsed = [None, None, None, None, None]
conn = [None, None, None, None, None]
if config:
config = {}
def connection(url):
if has_insecure:
parsed_url, http_conn = http_connection(url, insecure=insecure)

View File

@ -29,6 +29,14 @@ from test.functional import check_response, retry, requires_acls, \
import test.functional as tf
def setUpModule():
tf.setup_package()
def tearDownModule():
tf.teardown_package()
class TestAccount(unittest.TestCase):
def setUp(self):

View File

@ -27,6 +27,14 @@ import test.functional as tf
from six.moves import range
def setUpModule():
tf.setup_package()
def tearDownModule():
tf.teardown_package()
class TestContainer(unittest.TestCase):
def setUp(self):

View File

@ -27,6 +27,14 @@ from test.functional import check_response, retry, requires_acls, \
import test.functional as tf
def setUpModule():
tf.setup_package()
def tearDownModule():
tf.teardown_package()
class TestObject(unittest.TestCase):
def setUp(self):

View File

@ -39,6 +39,14 @@ from test.functional.swift_test_client import Account, Connection, File, \
ResponseError
def setUpModule():
tf.setup_package()
def tearDownModule():
tf.teardown_package()
class Utils(object):
@classmethod
def create_ascii_name(cls, length=None):

View File

@ -37,7 +37,7 @@ from test.unit import patch_policies, with_tempdir, make_timestamp_iter
from swift.common.db import DatabaseConnectionError
from swift.common.storage_policy import StoragePolicy, POLICIES
from test.unit.common.test_db import TestExampleBroker
from test.unit.common import test_db
@patch_policies
@ -979,7 +979,7 @@ def premetadata_create_account_stat_table(self, conn, put_timestamp):
put_timestamp))
class TestCommonAccountBroker(TestExampleBroker):
class TestCommonAccountBroker(test_db.TestExampleBroker):
broker_class = AccountBroker

View File

@ -36,7 +36,7 @@ import mock
from test.unit import (patch_policies, with_tempdir, make_timestamp_iter,
EMPTY_ETAG)
from test.unit.common.test_db import TestExampleBroker
from test.unit.common import test_db
class TestContainerBroker(unittest.TestCase):
@ -1680,7 +1680,7 @@ class TestContainerBroker(unittest.TestCase):
self.assertEqual(broker.get_policy_stats(), expected)
class TestCommonContainerBroker(TestExampleBroker):
class TestCommonContainerBroker(test_db.TestExampleBroker):
broker_class = ContainerBroker

View File

@ -45,7 +45,7 @@ commands =
flake8 --filename=swift* bin
[testenv:func]
commands = nosetests {posargs:test/functional}
commands = ./.functests {posargs}
[testenv:venv]
commands = {posargs}