object-storage: use tox for unit tests; fix em too
Add the ability to use tox for unit tests, since it helps us solve the problem of supporting multiple branches that require different versions of dependencies, and allows us to possibly support multiple versions of python in the future. Also fix the code to work with pre-grizzly environments, by not requiring the constraints backport. Also fixed the xattr support to work with both pyxattr and xattr modules. And fixed the ring tests to also work without a live /etc/swift directory. BUG: 948657 (https://bugzilla.redhat.com/show_bug.cgi?id=948657) Change-Id: I2be79c8ef8916bb6552ef957094f9186a963a068 Signed-off-by: Peter Portante <peter.portante@redhat.com> Reviewed-on: http://review.gluster.org/4781 Reviewed-by: Alex Wheeler <wheelear@gmail.com> Tested-by: Alex Wheeler <wheelear@gmail.com> Reviewed-by: Anand Avati <avati@redhat.com>
This commit is contained in:
parent
a56dca94c3
commit
6a7d28c0f8
2
.gitignore
vendored
2
.gitignore
vendored
@ -22,6 +22,8 @@ Makefile
|
||||
stamp-h1
|
||||
|
||||
# Generated files
|
||||
ufo/.tox
|
||||
ufo/test/unit/.coverage
|
||||
contrib/uuid/uuid_types.h
|
||||
extras/init.d/glusterd.plist
|
||||
extras/init.d/glusterd-Debian
|
||||
|
@ -35,8 +35,8 @@ do
|
||||
zone=1
|
||||
for volname in $@
|
||||
do
|
||||
add $builder_file $zone ${port[$builder_file]} $volname
|
||||
zone=$(expr $zone + 1)
|
||||
add $builder_file $zone ${port[$builder_file]} $volname
|
||||
zone=$(expr $zone + 1)
|
||||
done
|
||||
|
||||
rebalance $builder_file
|
||||
|
@ -13,15 +13,20 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from webob.exc import HTTPBadRequest
|
||||
|
||||
try:
|
||||
from webob.exc import HTTPBadRequest
|
||||
except ImportError:
|
||||
from swift.common.swob import HTTPBadRequest
|
||||
import swift.common.constraints
|
||||
import swift.common.ring as _ring
|
||||
from gluster.swift.common import Glusterfs, ring
|
||||
|
||||
|
||||
MAX_OBJECT_NAME_COMPONENT_LENGTH = swift.common.constraints.constraints_conf_int(
|
||||
'max_object_name_component_length', 255)
|
||||
if hasattr(swift.common.constraints, 'constraints_conf_int'):
|
||||
MAX_OBJECT_NAME_COMPONENT_LENGTH = \
|
||||
swift.common.constraints.constraints_conf_int(
|
||||
'max_object_name_component_length', 255)
|
||||
else:
|
||||
MAX_OBJECT_NAME_COMPONENT_LENGTH = 255
|
||||
|
||||
def validate_obj_name_component(obj):
|
||||
if len(obj) > MAX_OBJECT_NAME_COMPONENT_LENGTH:
|
||||
|
@ -70,7 +70,7 @@ def read_metadata(path):
|
||||
key = 0
|
||||
while metadata is None:
|
||||
try:
|
||||
metadata_s += xattr.get(path, '%s%s' % (METADATA_KEY, (key or '')))
|
||||
metadata_s += xattr.getxattr(path, '%s%s' % (METADATA_KEY, (key or '')))
|
||||
except IOError as err:
|
||||
if err.errno == errno.ENODATA:
|
||||
if key > 0:
|
||||
@ -86,7 +86,7 @@ def read_metadata(path):
|
||||
# to the caller we have no metadata.
|
||||
metadata = {}
|
||||
else:
|
||||
logging.exception("xattr.get failed on %s key %s err: %s",
|
||||
logging.exception("xattr.getxattr failed on %s key %s err: %s",
|
||||
path, key, str(err))
|
||||
# Note that we don't touch the keys on errors fetching the
|
||||
# data since it could be a transient state.
|
||||
@ -120,9 +120,9 @@ def write_metadata(path, metadata):
|
||||
key = 0
|
||||
while metastr:
|
||||
try:
|
||||
xattr.set(path, '%s%s' % (METADATA_KEY, key or ''), metastr[:MAX_XATTR_SIZE])
|
||||
xattr.setxattr(path, '%s%s' % (METADATA_KEY, key or ''), metastr[:MAX_XATTR_SIZE])
|
||||
except IOError as err:
|
||||
logging.exception("xattr.set failed on %s key %s err: %s", path, key, str(err))
|
||||
logging.exception("setxattr failed on %s key %s err: %s", path, key, str(err))
|
||||
raise
|
||||
metastr = metastr[MAX_XATTR_SIZE:]
|
||||
key += 1
|
||||
@ -131,7 +131,7 @@ def clean_metadata(path):
|
||||
key = 0
|
||||
while True:
|
||||
try:
|
||||
xattr.remove(path, '%s%s' % (METADATA_KEY, (key or '')))
|
||||
xattr.removexattr(path, '%s%s' % (METADATA_KEY, (key or '')))
|
||||
except IOError as err:
|
||||
if err.errno == errno.ENODATA:
|
||||
break
|
||||
@ -142,12 +142,12 @@ def check_user_xattr(path):
|
||||
if not os_path.exists(path):
|
||||
return False
|
||||
try:
|
||||
xattr.set(path, 'user.test.key1', 'value1')
|
||||
xattr.setxattr(path, 'user.test.key1', 'value1')
|
||||
except IOError as err:
|
||||
logging.exception("check_user_xattr: set failed on %s err: %s", path, str(err))
|
||||
raise
|
||||
try:
|
||||
xattr.remove(path, 'user.test.key1')
|
||||
xattr.removexattr(path, 'user.test.key1')
|
||||
except IOError as err:
|
||||
logging.exception("check_user_xattr: remove failed on %s err: %s", path, str(err))
|
||||
#Remove xattr may fail in case of concurrent remove.
|
||||
|
3
ufo/test/unit/common/data/README.rings
Normal file
3
ufo/test/unit/common/data/README.rings
Normal file
@ -0,0 +1,3 @@
|
||||
The unit tests expect certain ring data built using the following command:
|
||||
|
||||
../../../../bin/gluster-swift-gen-builders test iops
|
BIN
ufo/test/unit/common/data/account.builder
Normal file
BIN
ufo/test/unit/common/data/account.builder
Normal file
Binary file not shown.
BIN
ufo/test/unit/common/data/account.ring.gz
Normal file
BIN
ufo/test/unit/common/data/account.ring.gz
Normal file
Binary file not shown.
BIN
ufo/test/unit/common/data/backups/1365124498.account.builder
Normal file
BIN
ufo/test/unit/common/data/backups/1365124498.account.builder
Normal file
Binary file not shown.
BIN
ufo/test/unit/common/data/backups/1365124498.container.builder
Normal file
BIN
ufo/test/unit/common/data/backups/1365124498.container.builder
Normal file
Binary file not shown.
BIN
ufo/test/unit/common/data/backups/1365124498.object.builder
Normal file
BIN
ufo/test/unit/common/data/backups/1365124498.object.builder
Normal file
Binary file not shown.
BIN
ufo/test/unit/common/data/backups/1365124499.object.builder
Normal file
BIN
ufo/test/unit/common/data/backups/1365124499.object.builder
Normal file
Binary file not shown.
BIN
ufo/test/unit/common/data/container.builder
Normal file
BIN
ufo/test/unit/common/data/container.builder
Normal file
Binary file not shown.
BIN
ufo/test/unit/common/data/container.ring.gz
Normal file
BIN
ufo/test/unit/common/data/container.ring.gz
Normal file
Binary file not shown.
BIN
ufo/test/unit/common/data/object.builder
Normal file
BIN
ufo/test/unit/common/data/object.builder
Normal file
Binary file not shown.
BIN
ufo/test/unit/common/data/object.ring.gz
Normal file
BIN
ufo/test/unit/common/data/object.ring.gz
Normal file
Binary file not shown.
@ -13,69 +13,43 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import gluster.swift.common.constraints
|
||||
from gluster.swift.common.ring import *
|
||||
from gluster.swift.common.Glusterfs import SWIFT_DIR
|
||||
import swift.common.utils
|
||||
from gluster.swift.common.ring import Ring
|
||||
|
||||
def _mock_ring_data():
|
||||
return [{'zone': 1, 'weight': 100.0, 'ip': '127.0.0.1', 'port': 6012, \
|
||||
'meta': '', 'device': 'test', 'id': 0},
|
||||
{'zone': 2, 'weight': 100.0, 'ip': '127.0.0.1', 'id': 1, \
|
||||
'meta': '', 'device': 'iops', 'port': 6012}]
|
||||
|
||||
class TestRing(unittest.TestCase):
|
||||
""" Tests for common.utils """
|
||||
|
||||
def setUp(self):
|
||||
self.ring = Ring(SWIFT_DIR, ring_name='object')
|
||||
swift.common.utils.HASH_PATH_SUFFIX = 'endcap'
|
||||
swiftdir = os.path.join(os.getcwd(), "common", "data")
|
||||
self.ring = Ring(swiftdir, ring_name='object')
|
||||
|
||||
def test_first_device(self):
|
||||
try:
|
||||
__devs = self.ring._devs
|
||||
self.ring._devs = _mock_ring_data()
|
||||
|
||||
part, node = self.ring.get_nodes('test')
|
||||
assert node[0]['device'] == 'test'
|
||||
node = self.ring.get_part_nodes(0)
|
||||
assert node[0]['device'] == 'test'
|
||||
for node in self.ring.get_more_nodes(0):
|
||||
assert node['device'] == 'volume_not_in_ring'
|
||||
finally:
|
||||
self.ring._devs = __devs
|
||||
part, node = self.ring.get_nodes('test')
|
||||
assert node[0]['device'] == 'test'
|
||||
node = self.ring.get_part_nodes(0)
|
||||
assert node[0]['device'] == 'test'
|
||||
for node in self.ring.get_more_nodes(0):
|
||||
assert node['device'] == 'volume_not_in_ring'
|
||||
|
||||
def test_invalid_device(self):
|
||||
try:
|
||||
__devs = self.ring._devs
|
||||
self.ring._devs = _mock_ring_data()
|
||||
|
||||
part, node = self.ring.get_nodes('test2')
|
||||
assert node[0]['device'] == 'volume_not_in_ring'
|
||||
node = self.ring.get_part_nodes(0)
|
||||
assert node[0]['device'] == 'volume_not_in_ring'
|
||||
finally:
|
||||
self.ring._devs = __devs
|
||||
part, node = self.ring.get_nodes('test2')
|
||||
assert node[0]['device'] == 'volume_not_in_ring'
|
||||
node = self.ring.get_part_nodes(0)
|
||||
assert node[0]['device'] == 'volume_not_in_ring'
|
||||
|
||||
def test_second_device(self):
|
||||
try:
|
||||
__devs = self.ring._devs
|
||||
self.ring._devs = _mock_ring_data()
|
||||
|
||||
part, node = self.ring.get_nodes('iops')
|
||||
assert node[0]['device'] == 'iops'
|
||||
node = self.ring.get_part_nodes(0)
|
||||
assert node[0]['device'] == 'iops'
|
||||
for node in self.ring.get_more_nodes(0):
|
||||
assert node['device'] == 'volume_not_in_ring'
|
||||
finally:
|
||||
self.ring._devs = __devs
|
||||
part, node = self.ring.get_nodes('iops')
|
||||
assert node[0]['device'] == 'iops'
|
||||
node = self.ring.get_part_nodes(0)
|
||||
assert node[0]['device'] == 'iops'
|
||||
for node in self.ring.get_more_nodes(0):
|
||||
assert node['device'] == 'volume_not_in_ring'
|
||||
|
||||
def test_second_device_with_reseller_prefix(self):
|
||||
try:
|
||||
__devs = self.ring._devs
|
||||
self.ring._devs = _mock_ring_data()
|
||||
|
||||
part, node = self.ring.get_nodes('AUTH_iops')
|
||||
assert node[0]['device'] == 'iops'
|
||||
finally:
|
||||
self.ring._devs = __devs
|
||||
part, node = self.ring.get_nodes('AUTH_iops')
|
||||
assert node[0]['device'] == 'iops'
|
||||
|
@ -41,7 +41,7 @@ _xattr_rem_err = {}
|
||||
def _xkey(path, key):
|
||||
return "%s:%s" % (path, key)
|
||||
|
||||
def _setxattr(path, key, value):
|
||||
def _setxattr(path, key, value, *args, **kwargs):
|
||||
_xattr_op_cnt['set'] += 1
|
||||
xkey = _xkey(path, key)
|
||||
if xkey in _xattr_set_err:
|
||||
@ -51,7 +51,7 @@ def _setxattr(path, key, value):
|
||||
global _xattrs
|
||||
_xattrs[xkey] = value
|
||||
|
||||
def _getxattr(path, key):
|
||||
def _getxattr(path, key, *args, **kwargs):
|
||||
_xattr_op_cnt['get'] += 1
|
||||
xkey = _xkey(path, key)
|
||||
if xkey in _xattr_get_err:
|
||||
@ -67,7 +67,7 @@ def _getxattr(path, key):
|
||||
raise e
|
||||
return ret_val
|
||||
|
||||
def _removexattr(path, key):
|
||||
def _removexattr(path, key, *args, **kwargs):
|
||||
_xattr_op_cnt['remove'] += 1
|
||||
xkey = _xkey(path, key)
|
||||
if xkey in _xattr_rem_err:
|
||||
@ -93,20 +93,20 @@ def _initxattr():
|
||||
_xattr_rem_err = {}
|
||||
|
||||
# Save the current methods
|
||||
global _xattr_set; _xattr_set = xattr.set
|
||||
global _xattr_get; _xattr_get = xattr.get
|
||||
global _xattr_remove; _xattr_remove = xattr.remove
|
||||
global _xattr_set; _xattr_set = xattr.setxattr
|
||||
global _xattr_get; _xattr_get = xattr.getxattr
|
||||
global _xattr_remove; _xattr_remove = xattr.removexattr
|
||||
|
||||
# Monkey patch the calls we use with our internal unit test versions
|
||||
xattr.set = _setxattr
|
||||
xattr.get = _getxattr
|
||||
xattr.remove = _removexattr
|
||||
xattr.setxattr = _setxattr
|
||||
xattr.getxattr = _getxattr
|
||||
xattr.removexattr = _removexattr
|
||||
|
||||
def _destroyxattr():
|
||||
# Restore the current methods just in case
|
||||
global _xattr_set; xattr.set = _xattr_set
|
||||
global _xattr_get; xattr.get = _xattr_get
|
||||
global _xattr_remove; xattr.remove = _xattr_remove
|
||||
global _xattr_set; xattr.setxattr = _xattr_set
|
||||
global _xattr_get; xattr.getxattr = _xattr_get
|
||||
global _xattr_remove; xattr.removexattr = _xattr_remove
|
||||
# Destroy the stored values and
|
||||
global _xattrs; _xattrs = None
|
||||
|
||||
|
6
ufo/tools/test-requires
Normal file
6
ufo/tools/test-requires
Normal file
@ -0,0 +1,6 @@
|
||||
coverage
|
||||
nose
|
||||
nosexcover
|
||||
openstack.nose_plugin
|
||||
nosehtmloutput
|
||||
mock>=0.8.0
|
25
ufo/tox.ini
Normal file
25
ufo/tox.ini
Normal file
@ -0,0 +1,25 @@
|
||||
[tox]
|
||||
envlist = py26,py27
|
||||
|
||||
[testenv]
|
||||
setenv = VIRTUAL_ENV={envdir}
|
||||
NOSE_WITH_OPENSTACK=1
|
||||
NOSE_OPENSTACK_COLOR=1
|
||||
NOSE_OPENSTACK_RED=0.05
|
||||
NOSE_OPENSTACK_YELLOW=0.025
|
||||
NOSE_OPENSTACK_SHOW_ELAPSED=1
|
||||
NOSE_OPENSTACK_STDOUT=1
|
||||
deps =
|
||||
https://launchpad.net/swift/grizzly/1.8.0/+download/swift-1.8.0.tar.gz
|
||||
-r{toxinidir}/tools/test-requires
|
||||
changedir = {toxinidir}/test/unit
|
||||
commands = nosetests -v --exe --with-coverage --cover-package gluster --cover-erase {posargs}
|
||||
|
||||
[tox:jenkins]
|
||||
downloadcache = ~/cache/pip
|
||||
|
||||
[testenv:cover]
|
||||
setenv = NOSE_WITH_COVERAGE=1
|
||||
|
||||
[testenv:venv]
|
||||
commands = {posargs}
|
Loading…
x
Reference in New Issue
Block a user