Add rw functional tests for shares
Add base client methods for shares and use them in rw functional tests. Partially implements bp rw-functional-tests Change-Id: Ibc611ed5c54d2635f36018f3590ca56f4f2eb7dd
This commit is contained in:
parent
c668f00d5b
commit
ada9825bf6
|
@ -26,7 +26,7 @@ sudo chown -R jenkins:stack .
|
|||
# Create manilaclient config file
|
||||
touch $MANILACLIENT_CONF
|
||||
|
||||
# Import 'iniset' func from devstack functions
|
||||
# Import functions from devstack
|
||||
source $BASE/new/devstack/functions
|
||||
|
||||
# Set options to config client.
|
||||
|
@ -46,11 +46,43 @@ iniset $MANILACLIENT_CONF DEFAULT admin_auth_url $OS_AUTH_URL
|
|||
SUPPRESS_ERRORS=${SUPPRESS_ERRORS_IN_CLEANUP:-True}
|
||||
iniset $MANILACLIENT_CONF DEFAULT suppress_errors_in_cleanup $SUPPRESS_ERRORS
|
||||
|
||||
# Create share network and use it for functional tests if required
|
||||
USE_SHARE_NETWORK=$(trueorfalse True USE_SHARE_NETWORK)
|
||||
if [[ ${USE_SHARE_NETWORK} = True ]]; then
|
||||
SHARE_NETWORK_NAME=${SHARE_NETWORK_NAME:-ci}
|
||||
|
||||
if [[ "$JOB_NAME" =~ "neutron" ]]; then
|
||||
DEFAULT_NEUTRON_NET=$(neutron net-show private -c id -f value)
|
||||
DEFAULT_NEUTRON_SUBNET=$(neutron subnet-show private-subnet -c id -f value)
|
||||
NEUTRON_NET=${NEUTRON_NET:-$DEFAULT_NEUTRON_NET}
|
||||
NEUTRON_SUBNET=${NEUTRON_SUBNET:-$DEFAULT_NEUTRON_SUBNET}
|
||||
manila share-network-create \
|
||||
--name $SHARE_NETWORK_NAME \
|
||||
--neutron-net $NEUTRON_NET \
|
||||
--neutron-subnet $NEUTRON_SUBNET
|
||||
else
|
||||
DEFAULT_NOVA_NET=$(nova net-list | grep private | awk '{print $2}')
|
||||
NOVA_NET=${NOVA_NET:-$DEFAULT_NOVA_NET}
|
||||
manila share-network-create \
|
||||
--name $SHARE_NETWORK_NAME \
|
||||
--nova-net $NOVA_NET
|
||||
fi
|
||||
iniset $MANILACLIENT_CONF DEFAULT share_network $SHARE_NETWORK_NAME
|
||||
iniset $MANILACLIENT_CONF DEFAULT admin_share_network $SHARE_NETWORK_NAME
|
||||
fi
|
||||
|
||||
# Set share type if required
|
||||
if [[ "$SHARE_TYPE" ]]; then
|
||||
iniset $MANILACLIENT_CONF DEFAULT share_type $SHARE_TYPE
|
||||
fi
|
||||
|
||||
# let us control if we die or not
|
||||
set +o errexit
|
||||
|
||||
CONCURRENCY=${CONCURRENCY:-8}
|
||||
|
||||
# Run functional tests
|
||||
sudo -H -u jenkins tox -e functional -v
|
||||
sudo -H -u jenkins tox -e functional -v -- --concurrency=$CONCURRENCY
|
||||
EXIT_CODE=$?
|
||||
|
||||
if [ -d ".testrepository" ] ; then
|
||||
|
|
|
@ -66,6 +66,33 @@ base_opts = [
|
|||
"or not."),
|
||||
]
|
||||
|
||||
share_opts = [
|
||||
cfg.StrOpt("share_network",
|
||||
default=None,
|
||||
help="Share network Name or ID, that will be used for shares. "
|
||||
"Some backend drivers require a share network for share "
|
||||
"creation."),
|
||||
cfg.StrOpt("admin_share_network",
|
||||
default=None,
|
||||
help="Share network Name or ID, that will be used for shares "
|
||||
"in admin tenant."),
|
||||
cfg.StrOpt("share_type",
|
||||
default=None,
|
||||
help="Share type Name or ID, that will be used with share "
|
||||
"creation scheduling. Optional."),
|
||||
cfg.ListOpt("enable_protocols",
|
||||
default=["nfs", "cifs"],
|
||||
help="List of all enabled protocols. The first protocol in "
|
||||
"the list will be used as the default protocol."),
|
||||
cfg.IntOpt("build_interval",
|
||||
default=3,
|
||||
help="Time in seconds between share availability checks."),
|
||||
cfg.IntOpt("build_timeout",
|
||||
default=500,
|
||||
help="Timeout in seconds to wait for a share to become "
|
||||
"available."),
|
||||
]
|
||||
|
||||
# 2. Generate config
|
||||
|
||||
PROJECT_NAME = 'manilaclient'
|
||||
|
@ -99,6 +126,7 @@ else:
|
|||
|
||||
CONF.register_opts(auth_opts)
|
||||
CONF.register_opts(base_opts)
|
||||
CONF.register_opts(share_opts)
|
||||
|
||||
# 4. Define list_opts for config sample generator
|
||||
|
||||
|
@ -108,6 +136,7 @@ def list_opts():
|
|||
opts = [
|
||||
(None, copy.deepcopy(auth_opts)),
|
||||
(None, copy.deepcopy(base_opts)),
|
||||
(None, copy.deepcopy(share_opts)),
|
||||
]
|
||||
opts.extend(log_options.list_opts())
|
||||
return opts
|
||||
|
|
|
@ -95,6 +95,9 @@ class BaseTestCase(base.ClientTestBase):
|
|||
elif res["type"] is "share_network":
|
||||
client.delete_share_network(res_id)
|
||||
client.wait_for_share_network_deletion(res_id)
|
||||
elif res["type"] is "share":
|
||||
client.delete_share(res_id)
|
||||
client.wait_for_share_deletion(res_id)
|
||||
else:
|
||||
LOG.warn("Provided unsupported resource type for "
|
||||
"cleanup '%s'. Skipping." % res["type"])
|
||||
|
@ -102,21 +105,27 @@ class BaseTestCase(base.ClientTestBase):
|
|||
|
||||
@classmethod
|
||||
def get_admin_client(cls):
|
||||
return client.ManilaCLIClient(
|
||||
manilaclient = client.ManilaCLIClient(
|
||||
username=CONF.admin_username,
|
||||
password=CONF.admin_password,
|
||||
tenant_name=CONF.admin_tenant_name,
|
||||
uri=CONF.admin_auth_url or CONF.auth_url,
|
||||
cli_dir=CONF.manila_exec_dir)
|
||||
# Set specific for admin project share network
|
||||
manilaclient.share_network = CONF.admin_share_network
|
||||
return manilaclient
|
||||
|
||||
@classmethod
|
||||
def get_user_client(cls):
|
||||
return client.ManilaCLIClient(
|
||||
manilaclient = client.ManilaCLIClient(
|
||||
username=CONF.username,
|
||||
password=CONF.password,
|
||||
tenant_name=CONF.tenant_name,
|
||||
uri=CONF.auth_url,
|
||||
cli_dir=CONF.manila_exec_dir)
|
||||
# Set specific for user project share network
|
||||
manilaclient.share_network = CONF.share_network
|
||||
return manilaclient
|
||||
|
||||
@property
|
||||
def admin_client(self):
|
||||
|
@ -133,10 +142,11 @@ class BaseTestCase(base.ClientTestBase):
|
|||
def _get_clients(self):
|
||||
return {'admin': self.admin_client, 'user': self.user_client}
|
||||
|
||||
def create_share_type(self, name=None, driver_handles_share_servers=True,
|
||||
@classmethod
|
||||
def create_share_type(cls, name=None, driver_handles_share_servers=True,
|
||||
is_public=True, client=None, cleanup_in_class=True):
|
||||
if client is None:
|
||||
client = self.admin_client
|
||||
client = cls.get_admin_client()
|
||||
share_type = client.create_share_type(
|
||||
name=name,
|
||||
driver_handles_share_servers=driver_handles_share_servers,
|
||||
|
@ -147,9 +157,9 @@ class BaseTestCase(base.ClientTestBase):
|
|||
"client": client,
|
||||
}
|
||||
if cleanup_in_class:
|
||||
self.class_resources.insert(0, resource)
|
||||
cls.class_resources.insert(0, resource)
|
||||
else:
|
||||
self.method_resources.insert(0, resource)
|
||||
cls.method_resources.insert(0, resource)
|
||||
return share_type
|
||||
|
||||
@classmethod
|
||||
|
@ -175,3 +185,40 @@ class BaseTestCase(base.ClientTestBase):
|
|||
else:
|
||||
cls.method_resources.insert(0, resource)
|
||||
return share_network
|
||||
|
||||
@classmethod
|
||||
def create_share(cls, share_protocol=None, size=None, share_network=None,
|
||||
share_type=None, name=None, description=None,
|
||||
public=False, snapshot=None, metadata=None,
|
||||
client=None, cleanup_in_class=False,
|
||||
wait_for_creation=True):
|
||||
if client is None:
|
||||
client = cls.get_admin_client()
|
||||
data = {
|
||||
'share_protocol': share_protocol or client.share_protocol,
|
||||
'size': size or 1,
|
||||
'name': name,
|
||||
'description': description,
|
||||
'public': public,
|
||||
'snapshot': snapshot,
|
||||
'metadata': metadata,
|
||||
}
|
||||
share_network = share_network or client.share_network
|
||||
share_type = share_type or CONF.share_type
|
||||
if share_network:
|
||||
data['share_network'] = share_network
|
||||
if share_type:
|
||||
data['share_type'] = share_type
|
||||
share = client.create_share(**data)
|
||||
resource = {
|
||||
"type": "share",
|
||||
"id": share["id"],
|
||||
"client": client,
|
||||
}
|
||||
if cleanup_in_class:
|
||||
cls.class_resources.insert(0, resource)
|
||||
else:
|
||||
cls.method_resources.insert(0, resource)
|
||||
if wait_for_creation:
|
||||
client.wait_for_share_status(share['id'], 'available')
|
||||
return share
|
||||
|
|
|
@ -16,15 +16,19 @@
|
|||
import re
|
||||
import time
|
||||
|
||||
from oslo_utils import strutils
|
||||
import six
|
||||
from tempest_lib.cli import base
|
||||
from tempest_lib.cli import output_parser
|
||||
from tempest_lib.common.utils import data_utils
|
||||
from tempest_lib import exceptions as tempest_lib_exc
|
||||
|
||||
from manilaclient import config
|
||||
from manilaclient.tests.functional import exceptions
|
||||
from manilaclient.tests.functional import utils
|
||||
|
||||
CONF = config.CONF
|
||||
SHARE = 'share'
|
||||
SHARE_TYPE = 'share_type'
|
||||
SHARE_NETWORK = 'share_network'
|
||||
|
||||
|
@ -43,8 +47,32 @@ def not_found_wrapper(f):
|
|||
return wrapped_func
|
||||
|
||||
|
||||
def forbidden_wrapper(f):
|
||||
|
||||
def wrapped_func(self, *args, **kwargs):
|
||||
try:
|
||||
return f(self, *args, **kwargs)
|
||||
except tempest_lib_exc.CommandFailed as e:
|
||||
if re.search('HTTP 403', e.stderr):
|
||||
# Raise appropriate 'Forbidden' error.
|
||||
raise tempest_lib_exc.Forbidden()
|
||||
raise
|
||||
|
||||
return wrapped_func
|
||||
|
||||
|
||||
class ManilaCLIClient(base.CLIClient):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ManilaCLIClient, self).__init__(*args, **kwargs)
|
||||
if CONF.enable_protocols:
|
||||
self.share_protocol = CONF.enable_protocols[0]
|
||||
else:
|
||||
msg = "Configuration option 'enable_protocols' is not defined."
|
||||
raise exceptions.InvalidConfiguration(reason=msg)
|
||||
self.build_interval = CONF.build_interval
|
||||
self.build_timeout = CONF.build_timeout
|
||||
|
||||
def manila(self, action, flags='', params='', fail_ok=False,
|
||||
endpoint_type='publicURL', merge_stderr=False):
|
||||
"""Executes manila command for the given action.
|
||||
|
@ -82,6 +110,8 @@ class ManilaCLIClient(base.CLIClient):
|
|||
func = self.is_share_type_deleted
|
||||
elif res_type == SHARE_NETWORK:
|
||||
func = self.is_share_network_deleted
|
||||
elif res_type == SHARE:
|
||||
func = self.is_share_deleted
|
||||
else:
|
||||
raise exceptions.InvalidResource(message=res_type)
|
||||
|
||||
|
@ -149,6 +179,17 @@ class ManilaCLIClient(base.CLIClient):
|
|||
share_types = output_parser.listing(share_types_raw)
|
||||
return share_types
|
||||
|
||||
def get_share_type(self, share_type):
|
||||
"""Get share type.
|
||||
|
||||
:param share_type: str -- Name or ID of share type
|
||||
"""
|
||||
share_types = self.list_share_types(True)
|
||||
for st in share_types:
|
||||
if share_type in (st['ID'], st['Name']):
|
||||
return st
|
||||
raise tempest_lib_exc.NotFound()
|
||||
|
||||
def is_share_type_deleted(self, share_type):
|
||||
"""Says whether share type is deleted or not.
|
||||
|
||||
|
@ -369,3 +410,158 @@ class ManilaCLIClient(base.CLIClient):
|
|||
"""
|
||||
self.wait_for_resource_deletion(
|
||||
SHARE_NETWORK, res_id=share_network, interval=2, timeout=6)
|
||||
|
||||
# Shares
|
||||
|
||||
def create_share(self, share_protocol, size, share_network=None,
|
||||
share_type=None, name=None, description=None,
|
||||
public=False, snapshot=None, metadata=None):
|
||||
"""Creates a share.
|
||||
|
||||
:param share_protocol: str -- share protocol of a share.
|
||||
:param size: int/str -- desired size of a share.
|
||||
:param share_network: str -- Name or ID of share network to use.
|
||||
:param share_type: str -- Name or ID of share type to use.
|
||||
:param name: str -- desired name of new share.
|
||||
:param description: str -- desired description of new share.
|
||||
:param public: bool -- should a share be public or not.
|
||||
Default is False.
|
||||
:param snapshot: str -- Name or ID of a snapshot to use as source.
|
||||
:param metadata: dict -- key-value data to provide with share creation.
|
||||
"""
|
||||
cmd = 'create %(share_protocol)s %(size)s ' % {
|
||||
'share_protocol': share_protocol, 'size': size}
|
||||
if share_network is not None:
|
||||
cmd += '--share-network %s ' % share_network
|
||||
if share_type is not None:
|
||||
cmd += '--share-type %s ' % share_type
|
||||
if name is None:
|
||||
name = data_utils.rand_name('autotest_share_name')
|
||||
cmd += '--name %s ' % name
|
||||
if description is None:
|
||||
description = data_utils.rand_name('autotest_share_description')
|
||||
cmd += '--description %s ' % description
|
||||
if public:
|
||||
cmd += '--public'
|
||||
if snapshot is not None:
|
||||
cmd += '--snapshot %s ' % snapshot
|
||||
if metadata:
|
||||
metadata_cli = ''
|
||||
for k, v in metadata.items():
|
||||
metadata_cli += '%(k)s=%(v)s ' % {'k': k, 'v': v}
|
||||
if metadata_cli:
|
||||
cmd += '--metadata %s ' % metadata_cli
|
||||
share_raw = self.manila(cmd)
|
||||
share = output_parser.details(share_raw)
|
||||
return share
|
||||
|
||||
@not_found_wrapper
|
||||
def get_share(self, share):
|
||||
"""Returns a share by its Name or ID."""
|
||||
share_raw = self.manila('show %s' % share)
|
||||
share = output_parser.details(share_raw)
|
||||
return share
|
||||
|
||||
@not_found_wrapper
|
||||
def update_share(self, share, name=None, description=None,
|
||||
is_public=False):
|
||||
"""Updates a share.
|
||||
|
||||
:param share: str -- name or ID of a share that should be updated.
|
||||
:param name: str -- desired name of new share.
|
||||
:param description: str -- desired description of new share.
|
||||
:param is_public: bool -- should a share be public or not.
|
||||
Default is False.
|
||||
"""
|
||||
cmd = 'update %s ' % share
|
||||
if name:
|
||||
cmd += '--name %s ' % name
|
||||
if description:
|
||||
cmd += '--description %s ' % description
|
||||
is_public = strutils.bool_from_string(is_public, strict=True)
|
||||
cmd += '--is-public %s ' % is_public
|
||||
|
||||
return self.manila(cmd)
|
||||
|
||||
@not_found_wrapper
|
||||
@forbidden_wrapper
|
||||
def delete_share(self, shares):
|
||||
"""Deletes share[s] by Names or IDs.
|
||||
|
||||
:param shares: either str or list of str that can be either Name
|
||||
or ID of a share(s) that should be deleted.
|
||||
"""
|
||||
if not isinstance(shares, list):
|
||||
shares = [shares]
|
||||
cmd = 'delete '
|
||||
for share in shares:
|
||||
cmd += '%s ' % share
|
||||
return self.manila(cmd)
|
||||
|
||||
def list_shares(self, all_tenants=False, filters=None):
|
||||
"""List shares.
|
||||
|
||||
:param all_tenants: bool -- whether to list shares that belong
|
||||
only to current project or for all projects.
|
||||
:param filters: dict -- filters for listing of shares.
|
||||
Example, input:
|
||||
{'project_id': 'foo'}
|
||||
{-'project_id': 'foo'}
|
||||
{--'project_id': 'foo'}
|
||||
{'project-id': 'foo'}
|
||||
will be transformed to filter parameter "--project-id=foo"
|
||||
"""
|
||||
cmd = 'list '
|
||||
if all_tenants:
|
||||
cmd += '--all-tenants '
|
||||
if filters and isinstance(filters, dict):
|
||||
for k, v in filters.items():
|
||||
cmd += '%(k)s=%(v)s ' % {
|
||||
'k': self._stranslate_to_cli_optional_param(k), 'v': v}
|
||||
shares_raw = self.manila(cmd)
|
||||
shares = utils.listing(shares_raw)
|
||||
return shares
|
||||
|
||||
def is_share_deleted(self, share):
|
||||
"""Says whether share is deleted or not.
|
||||
|
||||
:param share: str -- Name or ID of share
|
||||
"""
|
||||
try:
|
||||
self.get_share(share)
|
||||
return False
|
||||
except tempest_lib_exc.NotFound:
|
||||
return True
|
||||
|
||||
def wait_for_share_deletion(self, share):
|
||||
"""Wait for share deletion by its Name or ID.
|
||||
|
||||
:param share: str -- Name or ID of share
|
||||
"""
|
||||
self.wait_for_resource_deletion(
|
||||
SHARE, res_id=share, interval=5, timeout=300)
|
||||
|
||||
def wait_for_share_status(self, share, status):
|
||||
"""Waits for a share to reach a given status."""
|
||||
body = self.get_share(share)
|
||||
share_name = body['name']
|
||||
share_status = body['status']
|
||||
start = int(time.time())
|
||||
|
||||
while share_status != status:
|
||||
time.sleep(self.build_interval)
|
||||
body = self.get_share(share)
|
||||
share_status = body['status']
|
||||
|
||||
if share_status == status:
|
||||
return
|
||||
elif 'error' in share_status.lower():
|
||||
raise exceptions.ShareBuildErrorException(share=share)
|
||||
|
||||
if int(time.time()) - start >= self.build_timeout:
|
||||
message = (
|
||||
"Share %(share_name)s failed to reach %(status)s status "
|
||||
"within the required time (%(build_timeout)s s)." % {
|
||||
"share_name": share_name, "status": status,
|
||||
"build_timeout": self.build_timeout})
|
||||
raise tempest_lib_exc.TimeoutException(message)
|
||||
|
|
|
@ -34,3 +34,11 @@ class InvalidData(exceptions.TempestException):
|
|||
|
||||
class ShareTypeNotFound(exceptions.NotFound):
|
||||
message = "Share type '%(share_type)s' was not found"
|
||||
|
||||
|
||||
class InvalidConfiguration(exceptions.TempestException):
|
||||
message = "Invalid configuration: %(reason)s"
|
||||
|
||||
|
||||
class ShareBuildErrorException(exceptions.TempestException):
|
||||
message = "Share %(share)s failed to build and is in ERROR status"
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
# Copyright 2015 Mirantis Inc.
|
||||
# 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.
|
||||
|
||||
from tempest_lib.common.utils import data_utils
|
||||
|
||||
from manilaclient import config
|
||||
from manilaclient.tests.functional import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
class SharesReadWriteBase(base.BaseTestCase):
|
||||
protocol = None
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(SharesReadWriteBase, cls).setUpClass()
|
||||
if cls.protocol not in CONF.enable_protocols:
|
||||
message = "%s tests are disabled" % cls.protocol
|
||||
raise cls.skipException(message)
|
||||
cls.name = data_utils.rand_name('autotest_share_name')
|
||||
cls.description = data_utils.rand_name('autotest_share_description')
|
||||
|
||||
# NOTE(vponomaryov): following share is used only in one test
|
||||
# until tests for snapshots appear.
|
||||
cls.share = cls.create_share(
|
||||
share_protocol=cls.protocol,
|
||||
size=1,
|
||||
name=cls.name,
|
||||
description=cls.description,
|
||||
client=cls.get_user_client(),
|
||||
cleanup_in_class=True)
|
||||
|
||||
def test_create_delete_share(self):
|
||||
name = data_utils.rand_name('autotest_share_name')
|
||||
|
||||
create = self.create_share(
|
||||
self.protocol, name=name, client=self.user_client)
|
||||
|
||||
self.assertEqual(name, create['name'])
|
||||
self.assertEqual('1', create['size'])
|
||||
self.assertEqual(self.protocol.upper(), create['share_proto'])
|
||||
|
||||
self.user_client.delete_share(create['id'])
|
||||
|
||||
self.user_client.wait_for_share_deletion(create['id'])
|
||||
|
||||
def test_create_update_share(self):
|
||||
name = data_utils.rand_name('autotest_share_name')
|
||||
new_name = 'new_' + name
|
||||
description = data_utils.rand_name('autotest_share_description')
|
||||
new_description = 'new_' + description
|
||||
|
||||
create = self.create_share(
|
||||
self.protocol, name=name, description=description,
|
||||
client=self.user_client)
|
||||
|
||||
self.assertEqual(name, create['name'])
|
||||
self.assertEqual(description, create['description'])
|
||||
self.assertEqual('False', create['is_public'])
|
||||
|
||||
self.user_client.update_share(
|
||||
create['id'], new_name, new_description, True)
|
||||
get = self.user_client.get_share(create['id'])
|
||||
|
||||
self.assertEqual(new_name, get['name'])
|
||||
self.assertEqual(new_description, get['description'])
|
||||
self.assertEqual('True', get['is_public'])
|
||||
|
||||
def test_get_share(self):
|
||||
get = self.user_client.get_share(self.share['id'])
|
||||
|
||||
self.assertEqual(self.name, get['name'])
|
||||
self.assertEqual(self.description, get['description'])
|
||||
self.assertEqual('1', get['size'])
|
||||
self.assertEqual(self.protocol.upper(), get['share_proto'])
|
||||
self.assertTrue(get.get('export_locations', []) > 0)
|
||||
|
||||
|
||||
class NFSSharesReadWriteTest(SharesReadWriteBase):
|
||||
protocol = 'nfs'
|
||||
|
||||
|
||||
class CIFSSharesReadWriteTest(SharesReadWriteBase):
|
||||
protocol = 'cifs'
|
||||
|
||||
|
||||
class GlusterFSSharesReadWriteTest(SharesReadWriteBase):
|
||||
protocol = 'glusterfs'
|
||||
|
||||
|
||||
class HDFSSharesReadWriteTest(SharesReadWriteBase):
|
||||
protocol = 'hdfs'
|
|
@ -14,10 +14,15 @@
|
|||
# under the License.
|
||||
|
||||
import ddt
|
||||
from tempest_lib.common.utils import data_utils
|
||||
from tempest_lib import exceptions
|
||||
import testtools
|
||||
|
||||
from manilaclient import config
|
||||
from manilaclient.tests.functional import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class SharesListReadOnlyTest(base.BaseTestCase):
|
||||
|
@ -89,3 +94,112 @@ class SharesListReadOnlyTest(base.BaseTestCase):
|
|||
@ddt.data('admin', 'user')
|
||||
def test_snapshot_list_filter_by_status(self, role):
|
||||
self.clients[role].manila('snapshot-list', params='--status status')
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class SharesListReadWriteTest(base.BaseTestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(SharesListReadWriteTest, cls).setUpClass()
|
||||
cls.private_name = data_utils.rand_name('autotest_share_name')
|
||||
cls.private_description = data_utils.rand_name(
|
||||
'autotest_share_description')
|
||||
cls.public_name = data_utils.rand_name('autotest_public_share_name')
|
||||
cls.public_description = data_utils.rand_name(
|
||||
'autotest_public_share_description')
|
||||
|
||||
cls.private_share = cls.create_share(
|
||||
name=cls.private_name,
|
||||
description=cls.private_description,
|
||||
public=False,
|
||||
cleanup_in_class=True,
|
||||
client=cls.get_user_client(),
|
||||
wait_for_creation=False)
|
||||
|
||||
cls.public_share = cls.create_share(
|
||||
name=cls.public_name,
|
||||
description=cls.public_description,
|
||||
public=True,
|
||||
client=cls.get_user_client(),
|
||||
cleanup_in_class=True)
|
||||
|
||||
for share_id in (cls.private_share['id'], cls.public_share['id']):
|
||||
cls.get_admin_client().wait_for_share_status(share_id, 'available')
|
||||
|
||||
def _list_shares(self, filters=None):
|
||||
filters = filters or dict()
|
||||
shares = self.user_client.list_shares(filters=filters)
|
||||
|
||||
self.assertTrue(len(shares) > 1)
|
||||
for s_id in (self.private_share['id'], self.public_share['id']):
|
||||
self.assertTrue(any(s_id == s['ID'] for s in shares))
|
||||
if filters:
|
||||
for share in shares:
|
||||
try:
|
||||
get = self.user_client.get_share(share['ID'])
|
||||
except exceptions.NotFound:
|
||||
# NOTE(vponomaryov): Case when some share was deleted
|
||||
# between our 'list' and 'get' requests. Skip such case.
|
||||
# It occurs with concurrently running tests.
|
||||
continue
|
||||
for k, v in filters.items():
|
||||
if k in ('share_network', 'share-network'):
|
||||
k = 'share_network_id'
|
||||
if v != 'deleting' and get[k] == 'deleting':
|
||||
continue
|
||||
self.assertEqual(v, get[k])
|
||||
|
||||
def test_list_shares(self):
|
||||
self._list_shares()
|
||||
|
||||
def test_list_shares_for_all_tenants(self):
|
||||
shares = self.user_client.list_shares(True)
|
||||
self.assertTrue(len(shares) > 1)
|
||||
for s_id in (self.private_share['id'], self.public_share['id']):
|
||||
self.assertTrue(any(s_id == s['ID'] for s in shares))
|
||||
|
||||
def test_list_shares_by_name(self):
|
||||
shares = self.user_client.list_shares(
|
||||
filters={'name': self.private_name})
|
||||
|
||||
self.assertEqual(1, len(shares))
|
||||
self.assertTrue(
|
||||
any(self.private_share['id'] == s['ID'] for s in shares))
|
||||
for share in shares:
|
||||
get = self.user_client.get_share(share['ID'])
|
||||
self.assertEqual(self.private_name, get['name'])
|
||||
|
||||
def test_list_shares_by_share_type(self):
|
||||
share_type_name = self.user_client.get_share_type(
|
||||
self.private_share['share_type'])['Name']
|
||||
self._list_shares({'share_type': share_type_name})
|
||||
|
||||
def test_list_shares_by_status(self):
|
||||
self._list_shares({'status': 'available'})
|
||||
|
||||
def test_list_shares_by_project_id(self):
|
||||
project_id = self.user_client.get_project_id(
|
||||
self.admin_client.tenant_name)
|
||||
self._list_shares({'project_id': project_id})
|
||||
|
||||
@testtools.skipUnless(
|
||||
CONF.share_network, "Usage of Share networks is disabled")
|
||||
def test_list_shares_by_share_network(self):
|
||||
share_network_id = self.user_client.get_share_network(
|
||||
CONF.share_network)['id']
|
||||
self._list_shares({'share_network': share_network_id})
|
||||
|
||||
def test_list_shares_by_host(self):
|
||||
get = self.user_client.get_share(self.private_share['id'])
|
||||
self._list_shares({'host': get['host']})
|
||||
|
||||
@ddt.data(
|
||||
{'limit': 1},
|
||||
{'limit': 2},
|
||||
{'limit': 1, 'offset': 1},
|
||||
{'limit': 2, 'offset': 0},
|
||||
)
|
||||
def test_list_shares_with_limit(self, filters):
|
||||
shares = self.user_client.list_shares(filters=filters)
|
||||
self.assertEqual(filters['limit'], len(shares))
|
||||
|
|
Loading…
Reference in New Issue