Add rw functional tests for share networks
Add base client methods for share networks and use them in rw functional tests. Partially implements bp rw-functional-tests Change-Id: I469f3101ead4ce47ea68370aa7f29137696f01ec
This commit is contained in:
parent
c6eace1d34
commit
17f76edfa4
@ -92,6 +92,9 @@ class BaseTestCase(base.ClientTestBase):
|
||||
if res["type"] is "share_type":
|
||||
client.delete_share_type(res_id)
|
||||
client.wait_for_share_type_deletion(res_id)
|
||||
elif res["type"] is "share_network":
|
||||
client.delete_share_network(res_id)
|
||||
client.wait_for_share_network_deletion(res_id)
|
||||
else:
|
||||
LOG.warn("Provided unsupported resource type for "
|
||||
"cleanup '%s'. Skipping." % res["type"])
|
||||
@ -148,3 +151,27 @@ class BaseTestCase(base.ClientTestBase):
|
||||
else:
|
||||
self.method_resources.insert(0, resource)
|
||||
return share_type
|
||||
|
||||
@classmethod
|
||||
def create_share_network(cls, name=None, description=None,
|
||||
nova_net_id=None, neutron_net_id=None,
|
||||
neutron_subnet_id=None, client=None,
|
||||
cleanup_in_class=True):
|
||||
if client is None:
|
||||
client = cls.get_admin_client()
|
||||
share_network = client.create_share_network(
|
||||
name=name,
|
||||
description=description,
|
||||
nova_net_id=nova_net_id,
|
||||
neutron_net_id=neutron_net_id,
|
||||
neutron_subnet_id=neutron_subnet_id)
|
||||
resource = {
|
||||
"type": "share_network",
|
||||
"id": share_network["id"],
|
||||
"client": client,
|
||||
}
|
||||
if cleanup_in_class:
|
||||
cls.class_resources.insert(0, resource)
|
||||
else:
|
||||
cls.method_resources.insert(0, resource)
|
||||
return share_network
|
||||
|
@ -13,6 +13,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import re
|
||||
import time
|
||||
|
||||
import six
|
||||
@ -25,6 +26,21 @@ from manilaclient.tests.functional import exceptions
|
||||
from manilaclient.tests.functional import utils
|
||||
|
||||
SHARE_TYPE = 'share_type'
|
||||
SHARE_NETWORK = 'share_network'
|
||||
|
||||
|
||||
def not_found_wrapper(f):
|
||||
|
||||
def wrapped_func(self, *args, **kwargs):
|
||||
try:
|
||||
return f(self, *args, **kwargs)
|
||||
except tempest_lib_exc.CommandFailed as e:
|
||||
if re.search('No (\w+) with a name or ID', e.stderr):
|
||||
# Raise appropriate 'NotFound' error
|
||||
raise tempest_lib_exc.NotFound()
|
||||
raise
|
||||
|
||||
return wrapped_func
|
||||
|
||||
|
||||
class ManilaCLIClient(base.CLIClient):
|
||||
@ -64,6 +80,8 @@ class ManilaCLIClient(base.CLIClient):
|
||||
# TODO(vponomaryov): add support for other resource types
|
||||
if res_type == SHARE_TYPE:
|
||||
func = self.is_share_type_deleted
|
||||
elif res_type == SHARE_NETWORK:
|
||||
func = self.is_share_network_deleted
|
||||
else:
|
||||
raise exceptions.InvalidResource(message=res_type)
|
||||
|
||||
@ -78,6 +96,8 @@ class ManilaCLIClient(base.CLIClient):
|
||||
raise exceptions.ResourceReleaseFailed(
|
||||
res_type=res_type, res_id=res_id)
|
||||
|
||||
# Share types
|
||||
|
||||
def create_share_type(self, name=None, driver_handles_share_servers=True,
|
||||
is_public=True):
|
||||
"""Creates share type.
|
||||
@ -112,16 +132,10 @@ class ManilaCLIClient(base.CLIClient):
|
||||
share_type = output_parser.listing(share_type_raw)[0]
|
||||
return share_type
|
||||
|
||||
@not_found_wrapper
|
||||
def delete_share_type(self, share_type):
|
||||
"""Deletes share type by its Name or ID."""
|
||||
try:
|
||||
return self.manila('type-delete %s' % share_type)
|
||||
except tempest_lib_exc.CommandFailed as e:
|
||||
not_found_msg = 'No sharetype with a name or ID'
|
||||
if not_found_msg in e.stderr:
|
||||
# Assuming it was deleted in tests
|
||||
raise tempest_lib_exc.NotFound()
|
||||
raise
|
||||
return self.manila('type-delete %s' % share_type)
|
||||
|
||||
def list_share_types(self, list_all=True):
|
||||
"""List share types.
|
||||
@ -161,20 +175,24 @@ class ManilaCLIClient(base.CLIClient):
|
||||
'project show -f value -c id %s' % name_or_id)
|
||||
return project_id.strip()
|
||||
|
||||
@not_found_wrapper
|
||||
def add_share_type_access(self, share_type_name_or_id, project_id):
|
||||
data = dict(st=share_type_name_or_id, project=project_id)
|
||||
self.manila('type-access-add %(st)s %(project)s' % data)
|
||||
|
||||
@not_found_wrapper
|
||||
def remove_share_type_access(self, share_type_name_or_id, project_id):
|
||||
data = dict(st=share_type_name_or_id, project=project_id)
|
||||
self.manila('type-access-remove %(st)s %(project)s' % data)
|
||||
|
||||
@not_found_wrapper
|
||||
def list_share_type_access(self, share_type_id):
|
||||
projects_raw = self.manila('type-access-list %s' % share_type_id)
|
||||
projects = output_parser.listing(projects_raw)
|
||||
project_ids = [pr['Project_ID'] for pr in projects]
|
||||
return project_ids
|
||||
|
||||
@not_found_wrapper
|
||||
def set_share_type_extra_specs(self, share_type_name_or_id, extra_specs):
|
||||
"""Set key-value pair for share type."""
|
||||
if not (isinstance(extra_specs, dict) and extra_specs):
|
||||
@ -185,6 +203,7 @@ class ManilaCLIClient(base.CLIClient):
|
||||
cmd += '%(key)s=%(value)s ' % {'key': key, 'value': value}
|
||||
return self.manila(cmd)
|
||||
|
||||
@not_found_wrapper
|
||||
def unset_share_type_extra_specs(self, share_type_name_or_id,
|
||||
extra_specs_keys):
|
||||
"""Unset key-value pair for share type."""
|
||||
@ -209,3 +228,144 @@ class ManilaCLIClient(base.CLIClient):
|
||||
if share_type_name_or_id in (share_type['ID'], share_type['Name']):
|
||||
return share_type['all_extra_specs']
|
||||
raise exceptions.ShareTypeNotFound(share_type=share_type_name_or_id)
|
||||
|
||||
# Share networks
|
||||
|
||||
def create_share_network(self, name=None, description=None,
|
||||
nova_net_id=None, neutron_net_id=None,
|
||||
neutron_subnet_id=None):
|
||||
"""Creates share network.
|
||||
|
||||
:param name: text -- desired name of new share network
|
||||
:param description: text -- desired description of new share network
|
||||
:param nova_net_id: text -- ID of Nova network
|
||||
:param neutron_net_id: text -- ID of Neutron network
|
||||
:param neutron_subnet_id: text -- ID of Neutron subnet
|
||||
|
||||
NOTE: 'nova_net_id' and 'neutron_net_id'/'neutron_subnet_id' are
|
||||
mutually exclusive.
|
||||
"""
|
||||
params = self._combine_share_network_data(
|
||||
name=name,
|
||||
description=description,
|
||||
nova_net_id=nova_net_id,
|
||||
neutron_net_id=neutron_net_id,
|
||||
neutron_subnet_id=neutron_subnet_id)
|
||||
share_network_raw = self.manila('share-network-create %s' % params)
|
||||
share_network = output_parser.details(share_network_raw)
|
||||
return share_network
|
||||
|
||||
def _combine_share_network_data(self, name=None, description=None,
|
||||
nova_net_id=None, neutron_net_id=None,
|
||||
neutron_subnet_id=None):
|
||||
"""Combines params for share network operations 'create' and 'update'.
|
||||
|
||||
:returns: text -- set of CLI parameters
|
||||
"""
|
||||
data = dict()
|
||||
if name is not None:
|
||||
data['--name'] = name
|
||||
if description is not None:
|
||||
data['--description'] = description
|
||||
if nova_net_id is not None:
|
||||
data['--nova_net_id'] = nova_net_id
|
||||
if neutron_net_id is not None:
|
||||
data['--neutron_net_id'] = neutron_net_id
|
||||
if neutron_subnet_id is not None:
|
||||
data['--neutron_subnet_id'] = neutron_subnet_id
|
||||
cmd = ''
|
||||
for key, value in data.items():
|
||||
cmd += "%(k)s='%(v)s' " % dict(k=key, v=value)
|
||||
return cmd
|
||||
|
||||
@not_found_wrapper
|
||||
def get_share_network(self, share_network):
|
||||
"""Returns share network by its Name or ID."""
|
||||
share_network_raw = self.manila(
|
||||
'share-network-show %s' % share_network)
|
||||
share_network = output_parser.details(share_network_raw)
|
||||
return share_network
|
||||
|
||||
@not_found_wrapper
|
||||
def update_share_network(self, share_network, name=None, description=None,
|
||||
nova_net_id=None, neutron_net_id=None,
|
||||
neutron_subnet_id=None):
|
||||
"""Updates share-network by its name or ID.
|
||||
|
||||
:param name: text -- new name for share network
|
||||
:param description: text -- new description for share network
|
||||
:param nova_net_id: text -- ID of some Nova network
|
||||
:param neutron_net_id: text -- ID of some Neutron network
|
||||
:param neutron_subnet_id: text -- ID of some Neutron subnet
|
||||
|
||||
NOTE: 'nova_net_id' and 'neutron_net_id'/'neutron_subnet_id' are
|
||||
mutually exclusive.
|
||||
"""
|
||||
sn_params = self._combine_share_network_data(
|
||||
name=name,
|
||||
description=description,
|
||||
nova_net_id=nova_net_id,
|
||||
neutron_net_id=neutron_net_id,
|
||||
neutron_subnet_id=neutron_subnet_id)
|
||||
share_network_raw = self.manila(
|
||||
'share-network-update %(sn)s %(params)s' % dict(
|
||||
sn=share_network, params=sn_params))
|
||||
share_network = output_parser.details(share_network_raw)
|
||||
return share_network
|
||||
|
||||
@not_found_wrapper
|
||||
def delete_share_network(self, share_network):
|
||||
"""Deletes share network by its Name or ID."""
|
||||
return self.manila('share-network-delete %s' % share_network)
|
||||
|
||||
@staticmethod
|
||||
def _stranslate_to_cli_optional_param(param):
|
||||
if len(param) < 1 or not isinstance(param, six.string_types):
|
||||
raise exceptions.InvalidData(
|
||||
'Provided wrong parameter for translation.')
|
||||
while not param[0:2] == '--':
|
||||
param = '-' + param
|
||||
return param.replace('_', '-')
|
||||
|
||||
def list_share_networks(self, all_tenants=False, filters=None):
|
||||
"""List share networks.
|
||||
|
||||
:param all_tenants: bool -- whether to list share-networks that belong
|
||||
only to current project or for all projects.
|
||||
:param filters: dict -- filters for listing of share networks.
|
||||
Example, input:
|
||||
{'project_id': 'foo'}
|
||||
{'-project_id': 'foo'}
|
||||
{'--project_id': 'foo'}
|
||||
{'project-id': 'foo'}
|
||||
will be transformed to filter parameter "--project-id=foo"
|
||||
"""
|
||||
cmd = 'share-network-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}
|
||||
share_networks_raw = self.manila(cmd)
|
||||
share_networks = utils.listing(share_networks_raw)
|
||||
return share_networks
|
||||
|
||||
def is_share_network_deleted(self, share_network):
|
||||
"""Says whether share network is deleted or not.
|
||||
|
||||
:param share_network: text -- Name or ID of share network
|
||||
"""
|
||||
share_types = self.list_share_networks(True)
|
||||
for list_element in share_types:
|
||||
if share_network in (list_element['id'], list_element['name']):
|
||||
return False
|
||||
return True
|
||||
|
||||
def wait_for_share_network_deletion(self, share_network):
|
||||
"""Wait for share network deletion by its Name or ID.
|
||||
|
||||
:param share_network: text -- Name or ID of share network
|
||||
"""
|
||||
self.wait_for_resource_deletion(
|
||||
SHARE_NETWORK, res_id=share_network, interval=2, timeout=6)
|
||||
|
@ -32,5 +32,5 @@ class InvalidData(exceptions.TempestException):
|
||||
message = "Provided invalid data: %(message)s"
|
||||
|
||||
|
||||
class ShareTypeNotFound(exceptions.TempestException):
|
||||
class ShareTypeNotFound(exceptions.NotFound):
|
||||
message = "Share type '%(share_type)s' was not found"
|
||||
|
169
manilaclient/tests/functional/test_share_networks.py
Normal file
169
manilaclient/tests/functional/test_share_networks.py
Normal file
@ -0,0 +1,169 @@
|
||||
# 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.
|
||||
|
||||
import ddt
|
||||
from tempest_lib.common.utils import data_utils
|
||||
from tempest_lib import exceptions as tempest_lib_exc
|
||||
|
||||
from manilaclient.tests.functional import base
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareNetworksReadWriteTest(base.BaseTestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(ShareNetworksReadWriteTest, cls).setUpClass()
|
||||
cls.name = data_utils.rand_name('autotest')
|
||||
cls.description = 'fake_description'
|
||||
cls.neutron_net_id = 'fake_neutron_net_id'
|
||||
cls.neutron_subnet_id = 'fake_neutron_subnet_id'
|
||||
|
||||
cls.sn = cls.create_share_network(
|
||||
name=cls.name,
|
||||
description=cls.description,
|
||||
neutron_net_id=cls.neutron_net_id,
|
||||
neutron_subnet_id=cls.neutron_subnet_id,
|
||||
)
|
||||
|
||||
@ddt.data(
|
||||
{'name': data_utils.rand_name('autotest_share_network_name')},
|
||||
{'description': 'fake_description'},
|
||||
{'nova_net_id': 'fake_nova_net_id'},
|
||||
{'neutron_net_id': 'fake_neutron_net_id',
|
||||
'neutron_subnet_id': 'fake_neutron_subnet_id'},
|
||||
)
|
||||
def test_create_delete_share_network(self, net_data):
|
||||
sn = self.create_share_network(cleanup_in_class=False, **net_data)
|
||||
|
||||
expected_data = {
|
||||
'name': 'None',
|
||||
'description': 'None',
|
||||
'nova_net_id': 'None',
|
||||
'neutron_net_id': 'None',
|
||||
'neutron_subnet_id': 'None',
|
||||
}
|
||||
expected_data.update(net_data)
|
||||
|
||||
for k, v in expected_data.items():
|
||||
self.assertEqual(v, sn[k])
|
||||
|
||||
self.admin_client.delete_share_network(sn['id'])
|
||||
self.admin_client.wait_for_share_network_deletion(sn['id'])
|
||||
|
||||
def test_get_share_network_with_neutron_data(self):
|
||||
get = self.admin_client.get_share_network(self.sn['id'])
|
||||
|
||||
self.assertEqual(self.name, get['name'])
|
||||
self.assertEqual(self.description, get['description'])
|
||||
self.assertEqual(self.neutron_net_id, get['neutron_net_id'])
|
||||
self.assertEqual(self.neutron_subnet_id, get['neutron_subnet_id'])
|
||||
|
||||
# We did not set Nova data, so, we expect these fields to be set
|
||||
# to None.
|
||||
self.assertEqual('None', get['nova_net_id'])
|
||||
|
||||
def test_get_share_network_with_nova_data(self):
|
||||
name = data_utils.rand_name('autotest')
|
||||
description = 'fake_description'
|
||||
nova_net_id = 'fake_nova_net_id'
|
||||
|
||||
create = self.create_share_network(
|
||||
name=name,
|
||||
description=description,
|
||||
nova_net_id=nova_net_id,
|
||||
cleanup_in_class=False)
|
||||
|
||||
self.assertEqual(name, create['name'])
|
||||
self.assertEqual(description, create['description'])
|
||||
self.assertEqual(nova_net_id, create['nova_net_id'])
|
||||
|
||||
# We did not set Neutron data, so, we expect these fields to be set
|
||||
# to None.
|
||||
self.assertEqual('None', create['neutron_net_id'])
|
||||
self.assertEqual('None', create['neutron_subnet_id'])
|
||||
|
||||
@ddt.data(
|
||||
{'name': data_utils.rand_name('autotest_share_network_name')},
|
||||
{'description': 'fake_description'},
|
||||
{'nova_net_id': 'fake_nova_net_id'},
|
||||
{'neutron_net_id': 'fake_neutron_net_id',
|
||||
'neutron_subnet_id': 'fake_neutron_subnet_id'},
|
||||
)
|
||||
def test_create_update_share_network(self, net_data):
|
||||
sn = self.create_share_network(cleanup_in_class=False)
|
||||
|
||||
update = self.admin_client.update_share_network(sn['id'], **net_data)
|
||||
|
||||
expected_data = {
|
||||
'name': 'None',
|
||||
'description': 'None',
|
||||
'nova_net_id': 'None',
|
||||
'neutron_net_id': 'None',
|
||||
'neutron_subnet_id': 'None',
|
||||
}
|
||||
expected_data.update(net_data)
|
||||
|
||||
for k, v in expected_data.items():
|
||||
self.assertEqual(v, update[k])
|
||||
|
||||
self.admin_client.delete_share_network(sn['id'])
|
||||
self.admin_client.wait_for_share_network_deletion(sn['id'])
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_list_share_networks(self, all_tenants):
|
||||
share_networks = self.admin_client.list_share_networks(all_tenants)
|
||||
|
||||
self.assertTrue(
|
||||
any(self.sn['id'] == sn['id'] for sn in share_networks))
|
||||
for sn in share_networks:
|
||||
self.assertEqual(2, len(sn))
|
||||
self.assertIn('id', sn)
|
||||
self.assertIn('name', sn)
|
||||
|
||||
def _list_share_networks_with_filters(self, filters):
|
||||
share_networks = self.admin_client.list_share_networks(filters=filters)
|
||||
|
||||
self.assertTrue(len(share_networks) > 0)
|
||||
self.assertTrue(
|
||||
any(self.sn['id'] == sn['id'] for sn in share_networks))
|
||||
for sn in share_networks:
|
||||
try:
|
||||
get = self.admin_client.get_share_network(sn['id'])
|
||||
except tempest_lib_exc.NotFound:
|
||||
# NOTE(vponomaryov): Case when some share network was deleted
|
||||
# between our 'list' and 'get' requests. Skip such case.
|
||||
continue
|
||||
for k, v in filters.items():
|
||||
self.assertIn(k, get)
|
||||
self.assertEqual(v, get[k])
|
||||
|
||||
def test_list_share_networks_filter_by_project_id(self):
|
||||
project_id = self.admin_client.get_project_id(
|
||||
self.admin_client.tenant_name)
|
||||
filters = {'project_id': project_id}
|
||||
self._list_share_networks_with_filters(filters)
|
||||
|
||||
def test_list_share_networks_filter_by_name(self):
|
||||
filters = {'name': self.name}
|
||||
self._list_share_networks_with_filters(filters)
|
||||
|
||||
def test_list_share_networks_filter_by_neutron_net_id(self):
|
||||
filters = {'neutron_net_id': self.neutron_net_id}
|
||||
self._list_share_networks_with_filters(filters)
|
||||
|
||||
def test_list_share_networks_filter_by_neutron_subnet_id(self):
|
||||
filters = {'neutron_subnet_id': self.neutron_subnet_id}
|
||||
self._list_share_networks_with_filters(filters)
|
Loading…
Reference in New Issue
Block a user