Make swift-bench not depending on swift.

Remove the dependence on swift, import the only needed functions from
swift.common.utils to swiftbench.utils

Add tests for utils using mock instead.

Change-Id: I1b69dce750b55f3ee0e999fb5a7100cf811f7ebe
This commit is contained in:
Chmouel Boudjnah 2013-11-23 00:49:37 +01:00 committed by Chmouel Boudjnah
parent 64b976e139
commit b207aaca07
7 changed files with 210 additions and 12 deletions

View File

@ -3,6 +3,6 @@ set -e
python setup.py testr --coverage
RET=$?
coverage report -m
coverage report -mswiftbench
rm -f .coverage
exit $RET

View File

@ -23,7 +23,7 @@ from optparse import OptionParser
from swiftbench.bench import (BenchController, DistributedBenchController,
create_containers, delete_containers)
from swiftbench.utils import readconf, LogAdapter, config_true_value
from swiftbench.utils import readconf, config_true_value
# The defaults should be sufficient to run swift-bench on a SAIO
CONF_DEFAULTS = {
@ -172,7 +172,6 @@ if __name__ == '__main__':
options.log_level.lower(), logging.INFO))
loghandler = logging.StreamHandler()
logger.addHandler(loghandler)
logger = LogAdapter(logger, 'swift-bench')
logformat = logging.Formatter('%(server)s %(asctime)s %(levelname)s '
'%(message)s')
loghandler.setFormatter(logformat)

View File

@ -19,8 +19,7 @@ import sys
import signal
from optparse import OptionParser
from swift.common.bench import BenchServer
from swift.common.utils import LogAdapter
from swiftbench.bench import BenchServer
if __name__ == '__main__':
usage = "usage: %prog <ip> <port>"
@ -45,7 +44,6 @@ if __name__ == '__main__':
options.log_level.lower(), logging.INFO))
loghandler = logging.StreamHandler()
logger.addHandler(loghandler)
logger = LogAdapter(logger, 'swift-bench-client')
logformat = logging.Formatter('%(server)s %(asctime)s %(levelname)s '
'%(message)s')
loghandler.setFormatter(logformat)

View File

@ -29,11 +29,21 @@ import eventlet
import eventlet.pools
from eventlet.green.httplib import CannotSendRequest
from swift.common.utils import config_true_value, LogAdapter
import swiftclient as client
from swift.common import direct_client
from swift.common.http import HTTP_CONFLICT
from swift.common.utils import json
from swiftbench.utils import config_true_value
try:
import simplejson as json
except ImportError:
import json
try:
from swift.common import direct_client
except ImportError:
direct_client = None
HTTP_CONFLICT = 409
def _func_on_containers(logger, conf, concurrency_key, func):
@ -152,7 +162,6 @@ class BenchServer(object):
'%(server)s %(asctime)s %(levelname)s %(message)s')
loghandler.setFormatter(logformat)
logger.addHandler(loghandler)
logger = LogAdapter(logger, 'swift-bench-server')
controller = BenchController(logger, conf)
try:
@ -176,6 +185,10 @@ class Bench(object):
self.key = conf.key
self.auth_url = conf.auth
self.use_proxy = config_true_value(conf.use_proxy)
if not self.use_proxy and direct_client is None:
self.logger.critical("You need to have swift installed if you are "
"not using the proxy")
sys.exit(1)
self.auth_version = conf.auth_version
self.logger.info("Auth version: %s" % self.auth_version)
if self.use_proxy:

79
swiftbench/utils.py Normal file
View File

@ -0,0 +1,79 @@
# Copyright (c) 2010-2013 OpenStack Foundation
#
# 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 sys
from ConfigParser import ConfigParser, RawConfigParser
# Used when reading config values
TRUE_VALUES = set(('true', '1', 'yes', 'on', 't', 'y'))
# NOTE(chmouel): Imported from swift without the modular directory feature.
def readconf(conf_path, section_name=None, log_name=None, defaults=None,
raw=False):
"""
Read config file(s) and return config items as a dict
:param conf_path: path to config file, or a file-like object
(hasattr readline)
:param section_name: config section to read (will return all sections if
not defined)
:param log_name: name to be used with logging (will use section_name if
not defined)
:param defaults: dict of default values to pre-populate the config with
:returns: dict of config items
"""
if defaults is None:
defaults = {}
if raw:
c = RawConfigParser(defaults)
else:
c = ConfigParser(defaults)
if hasattr(conf_path, 'readline'):
c.readfp(conf_path)
else:
success = c.read(conf_path)
if not success:
print "Unable to read config from %s" % conf_path
sys.exit(1)
if section_name:
if c.has_section(section_name):
conf = dict(c.items(section_name))
else:
print "Unable to find %s config section in %s" % \
(section_name, conf_path)
sys.exit(1)
if "log_name" not in conf:
if log_name is not None:
conf['log_name'] = log_name
else:
conf['log_name'] = section_name
else:
conf = {}
for s in c.sections():
conf.update({s: dict(c.items(s))})
if 'log_name' not in conf:
conf['log_name'] = log_name
conf['__file__'] = conf_path
return conf
def config_true_value(value):
"""
Returns True if the value is either True or a string in TRUE_VALUES.
Returns False otherwise.
"""
return value is True or \
(isinstance(value, basestring) and value.lower() in TRUE_VALUES)

View File

@ -1,4 +1,4 @@
# Copyright (c) 2010-2012 OpenStack Foundation
# Copyright (c) 2010-2013 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

109
tests/test_utils.py Normal file
View File

@ -0,0 +1,109 @@
# Copyright (c) 2010-2013 OpenStack Foundation
#
# 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 mock
import os
import tempfile
import unittest
from StringIO import StringIO
from swiftbench import utils
class TestUtils(unittest.TestCase):
@mock.patch.object(utils, "TRUE_VALUES")
def test_config_true_value(self, mocked):
utils.TRUE_VALUES = 'hello world'.split()
for val in 'hello world HELLO WORLD'.split():
self.assertTrue(utils.config_true_value(val) is True)
self.assertTrue(utils.config_true_value(True) is True)
self.assertTrue(utils.config_true_value('foo') is False)
self.assertTrue(utils.config_true_value(False) is False)
def test_readconf(self):
conf = '''[section1]
foo = bar
[section2]
log_name = yarr'''
# setup a real file
fd, temppath = tempfile.mkstemp(dir='/tmp')
with os.fdopen(fd, 'wb') as f:
f.write(conf)
make_filename = lambda: temppath
# setup a file stream
make_fp = lambda: StringIO(conf)
for conf_object_maker in (make_filename, make_fp):
conffile = conf_object_maker()
result = utils.readconf(conffile)
expected = {'__file__': conffile,
'log_name': None,
'section1': {'foo': 'bar'},
'section2': {'log_name': 'yarr'}}
self.assertEquals(result, expected)
conffile = conf_object_maker()
result = utils.readconf(conffile, 'section1')
expected = {'__file__': conffile, 'log_name': 'section1',
'foo': 'bar'}
self.assertEquals(result, expected)
conffile = conf_object_maker()
result = utils.readconf(conffile,
'section2').get('log_name')
expected = 'yarr'
self.assertEquals(result, expected)
conffile = conf_object_maker()
result = utils.readconf(conffile, 'section1',
log_name='foo').get('log_name')
expected = 'foo'
self.assertEquals(result, expected)
conffile = conf_object_maker()
result = utils.readconf(conffile, 'section1',
defaults={'bar': 'baz'})
expected = {'__file__': conffile, 'log_name': 'section1',
'foo': 'bar', 'bar': 'baz'}
self.assertEquals(result, expected)
self.assertRaises(SystemExit, utils.readconf, temppath, 'section3')
os.unlink(temppath)
self.assertRaises(SystemExit, utils.readconf, temppath)
def test_readconf_raw(self):
conf = '''[section1]
foo = bar
[section2]
log_name = %(yarr)s'''
# setup a real file
fd, temppath = tempfile.mkstemp(dir='/tmp')
with os.fdopen(fd, 'wb') as f:
f.write(conf)
make_filename = lambda: temppath
# setup a file stream
make_fp = lambda: StringIO(conf)
for conf_object_maker in (make_filename, make_fp):
conffile = conf_object_maker()
result = utils.readconf(conffile, raw=True)
expected = {'__file__': conffile,
'log_name': None,
'section1': {'foo': 'bar'},
'section2': {'log_name': '%(yarr)s'}}
self.assertEquals(result, expected)
os.unlink(temppath)
self.assertRaises(SystemExit, utils.readconf, temppath)
if __name__ == '__main__':
unittest.main()