[Tempest] Add functional tests for share groups feature
Add functional tempest tests to new 'share group' feature [1]. [1] I79a80a62ae4e0015d6161edc2b93fd1f9ba69537 Co-Authored-By: Andrew Kerr <andrew.kerr@netapp.com> Co-Authored-By: Valeriy Ponomaryov <vponomaryov@mirantis.com> Partially-implements-blueprint: manila-share-groups Depends-On: I8e29baed62355fc31caeec9c7a66eaebfcbdf184 Change-Id: I820eb959082995d961b1be992e4b2d1d1a985c1c
This commit is contained in:
parent
d25f101ab4
commit
1002642674
@ -70,7 +70,7 @@ RUN_MANILA_QUOTA_TESTS=${RUN_MANILA_QUOTA_TESTS:-True}
|
||||
RUN_MANILA_SHRINK_TESTS=${RUN_MANILA_SHRINK_TESTS:-True}
|
||||
RUN_MANILA_SNAPSHOT_TESTS=${RUN_MANILA_SNAPSHOT_TESTS:-True}
|
||||
RUN_MANILA_REVERT_TO_SNAPSHOT_TESTS=${RUN_MANILA_REVERT_TO_SNAPSHOT_TESTS:-False}
|
||||
RUN_MANILA_CG_TESTS=${RUN_MANILA_CG_TESTS:-False}
|
||||
RUN_MANILA_SG_TESTS=${RUN_MANILA_SG_TESTS:-${RUN_MANILA_CG_TESTS:-True}}
|
||||
RUN_MANILA_MANAGE_TESTS=${RUN_MANILA_MANAGE_TESTS:-True}
|
||||
RUN_MANILA_MANAGE_SNAPSHOT_TESTS=${RUN_MANILA_MANAGE_SNAPSHOT_TESTS:-False}
|
||||
RUN_MANILA_REPLICATION_TESTS=${RUN_MANILA_REPLICATION_TESTS:-False}
|
||||
@ -157,12 +157,13 @@ elif [[ "$DRIVER" == "generic" ]]; then
|
||||
iniset $TEMPEST_CONFIG share enable_protocols nfs
|
||||
fi
|
||||
MANILA_TESTS="(^manila_tempest_tests.tests.api)(?=.*\[.*\bbackend\b.*\])"
|
||||
RUN_MANILA_SG_TESTS=False
|
||||
fi
|
||||
|
||||
if [[ "$DRIVER" == "lvm" ]]; then
|
||||
MANILA_TESTS="(^manila_tempest_tests.tests)(?=.*\[.*\bbackend\b.*\])"
|
||||
MANILA_TEMPEST_CONCURRENCY=8
|
||||
RUN_MANILA_CG_TESTS=False
|
||||
RUN_MANILA_SG_TESTS=False
|
||||
RUN_MANILA_MANAGE_TESTS=False
|
||||
RUN_MANILA_HOST_ASSISTED_MIGRATION_TESTS=True
|
||||
RUN_MANILA_SHRINK_TESTS=False
|
||||
@ -185,7 +186,7 @@ if [[ "$DRIVER" == "lvm" ]]; then
|
||||
elif [[ "$DRIVER" == "zfsonlinux" ]]; then
|
||||
MANILA_TESTS="(^manila_tempest_tests.tests)(?=.*\[.*\bbackend\b.*\])"
|
||||
MANILA_TEMPEST_CONCURRENCY=8
|
||||
RUN_MANILA_CG_TESTS=False
|
||||
RUN_MANILA_SG_TESTS=False
|
||||
RUN_MANILA_MANAGE_TESTS=True
|
||||
RUN_MANILA_MANAGE_SNAPSHOT_TESTS=True
|
||||
RUN_MANILA_DRIVER_ASSISTED_MIGRATION_TESTS=True
|
||||
@ -207,7 +208,7 @@ elif [[ "$DRIVER" == "zfsonlinux" ]]; then
|
||||
iniset $TEMPEST_CONFIG share capability_snapshot_support True
|
||||
elif [[ "$DRIVER" == "dummy" ]]; then
|
||||
MANILA_TEMPEST_CONCURRENCY=24
|
||||
RUN_MANILA_CG_TESTS=False
|
||||
RUN_MANILA_SG_TESTS=True
|
||||
RUN_MANILA_MANAGE_TESTS=False
|
||||
RUN_MANILA_DRIVER_ASSISTED_MIGRATION_TESTS=True
|
||||
RUN_MANILA_REVERT_TO_SNAPSHOT_TESTS=True
|
||||
@ -226,7 +227,7 @@ elif [[ "$DRIVER" == "dummy" ]]; then
|
||||
elif [[ "$DRIVER" == "container" ]]; then
|
||||
MANILA_TESTS="(^manila_tempest_tests.tests.api)(?=.*\[.*\bbackend\b.*\])"
|
||||
MANILA_TEMPEST_CONCURRENCY=8
|
||||
RUN_MANILA_CG_TESTS=False
|
||||
RUN_MANILA_SG_TESTS=False
|
||||
RUN_MANILA_MANAGE_TESTS=False
|
||||
RUN_MANILA_QUOTA_TESTS=False
|
||||
RUN_MANILA_SHRINK_TESTS=False
|
||||
@ -250,8 +251,8 @@ iniset $TEMPEST_CONFIG share run_snapshot_tests $RUN_MANILA_SNAPSHOT_TESTS
|
||||
# Enable revert to snapshot tests
|
||||
iniset $TEMPEST_CONFIG share run_revert_to_snapshot_tests $RUN_MANILA_REVERT_TO_SNAPSHOT_TESTS
|
||||
|
||||
# Enable consistency group tests
|
||||
iniset $TEMPEST_CONFIG share run_consistency_group_tests $RUN_MANILA_CG_TESTS
|
||||
# Enable share group tests
|
||||
iniset $TEMPEST_CONFIG share run_share_group_tests $RUN_MANILA_SG_TESTS
|
||||
|
||||
# Enable manage/unmanage tests
|
||||
iniset $TEMPEST_CONFIG share run_manage_unmanage_tests $RUN_MANILA_MANAGE_TESTS
|
||||
|
@ -181,6 +181,7 @@ function configure_manila {
|
||||
iniset $MANILA_CONF DEFAULT osapi_share_extension manila.api.contrib.standard_extensions
|
||||
iniset $MANILA_CONF DEFAULT state_path $MANILA_STATE_PATH
|
||||
iniset $MANILA_CONF DEFAULT default_share_type $MANILA_DEFAULT_SHARE_TYPE
|
||||
iniset $MANILA_CONF DEFAULT default_share_group_type $MANILA_DEFAULT_SHARE_GROUP_TYPE
|
||||
|
||||
if ! [[ -z $MANILA_SHARE_MIGRATION_PERIOD_TASK_INTERVAL ]]; then
|
||||
iniset $MANILA_CONF DEFAULT migration_driver_continue_update_interval $MANILA_SHARE_MIGRATION_PERIOD_TASK_INTERVAL
|
||||
@ -455,6 +456,17 @@ function create_manila_accounts {
|
||||
"$MANILA_SERVICE_PROTOCOL://$MANILA_SERVICE_HOST:$MANILA_SERVICE_PORT/v2/\$(tenant_id)s"
|
||||
}
|
||||
|
||||
# create_default_share_group_type - create share group type that will be set as default.
|
||||
function create_default_share_group_type {
|
||||
local type_exists=$( manila share-group-type-list | grep " $MANILA_DEFAULT_SHARE_GROUP_TYPE " )
|
||||
if [[ -z $type_exists ]]; then
|
||||
manila share-group-type-create $MANILA_DEFAULT_SHARE_GROUP_TYPE $MANILA_DEFAULT_SHARE_TYPE
|
||||
fi
|
||||
if [[ $MANILA_DEFAULT_SHARE_GROUP_TYPE_SPECS ]]; then
|
||||
manila share-group-type-key $MANILA_DEFAULT_SHARE_GROUP_TYPE set $MANILA_DEFAULT_SHARE_GROUP_TYPE_SPECS
|
||||
fi
|
||||
}
|
||||
|
||||
# create_default_share_type - create share type that will be set as default.
|
||||
function create_default_share_type {
|
||||
echo "Waiting for Manila API to start..."
|
||||
@ -915,6 +927,9 @@ elif [[ "$1" == "stack" && "$2" == "extra" ]]; then
|
||||
echo_summary "Creating Manila default share type"
|
||||
create_default_share_type
|
||||
|
||||
echo_summary "Creating Manila default share group type"
|
||||
create_default_share_group_type
|
||||
|
||||
echo_summary "Creating Manila custom share types"
|
||||
create_custom_share_types
|
||||
|
||||
|
@ -60,6 +60,16 @@ MANILA_DEFAULT_SHARE_TYPE_EXTRA_SPECS=${MANILA_DEFAULT_SHARE_TYPE_EXTRA_SPECS:-'
|
||||
MANILA_DHSS_TRUE_SHARE_TYPE_EXTRA_SPECS=${MANILA_DHSS_TRUE_SHARE_TYPE_EXTRA_SPECS:-$MANILA_DEFAULT_SHARE_TYPE_EXTRA_SPECS}
|
||||
MANILA_DHSS_FALSE_SHARE_TYPE_EXTRA_SPECS=${MANILA_DHSS_FALSE_SHARE_TYPE_EXTRA_SPECS:-$MANILA_DEFAULT_SHARE_TYPE_EXTRA_SPECS}
|
||||
|
||||
# Share groups and their specs
|
||||
MANILA_DEFAULT_SHARE_GROUP_TYPE=${MANILA_DEFAULT_SHARE_GROUP_TYPE:-default}
|
||||
# MANILA_DEFAULT_SHARE_GROUP_TYPE_SPECS is expected to contain key-value pairs,
|
||||
# that should be assigned to default share group type. Both - qualified and unqualified specs are supported.
|
||||
# Pairs are separated by spaces, value is assigned to key using sign of equality. Examples:
|
||||
# MANILA_DEFAULT_SHARE_GROUP_TYPE_SPECS='foo=bar'
|
||||
# MANILA_DEFAULT_SHARE_GROUP_TYPE_SPECS='foo=bar quuz=xyzzy'
|
||||
# MANILA_DEFAULT_SHARE_GROUP_TYPE_SPECS='foo=bar quuz=xyzzy fakeprefix:baz=waldo'
|
||||
MANILA_DEFAULT_SHARE_GROUP_TYPE_SPECS=${MANILA_DEFAULT_SHARE_GROUP_TYPE_SPECS:-''}
|
||||
|
||||
# Public facing bits
|
||||
MANILA_SERVICE_HOST=${MANILA_SERVICE_HOST:-$SERVICE_HOST}
|
||||
MANILA_SERVICE_PORT=${MANILA_SERVICE_PORT:-8786}
|
||||
|
@ -60,3 +60,24 @@ REVERT_TO_SNAPSHOT_SUPPORT = 'revert_to_snapshot_support'
|
||||
STATUS_RESTORING = 'restoring'
|
||||
STATUS_REVERTING = 'reverting'
|
||||
STATUS_REVERTING_ERROR = 'reverting_error'
|
||||
|
||||
# Share groups
|
||||
MIN_SHARE_GROUP_MICROVERSION = '2.31'
|
||||
SHARE_GROUP_SIMPLE_KEYS = {
|
||||
'id', 'name', 'links',
|
||||
}
|
||||
SHARE_GROUP_DETAIL_REQUIRED_KEYS = {
|
||||
'id', 'name', 'description', 'created_at', 'status', 'share_types',
|
||||
'project_id', 'host', 'links', 'share_group_type_id',
|
||||
}
|
||||
SHARE_GROUP_SNAPSHOT_SIMPLE_KEYS = {
|
||||
'id', 'name', 'links',
|
||||
}
|
||||
SHARE_GROUP_SNAPSHOT_DETAIL_REQUIRED_KEYS = {
|
||||
'id', 'name', 'description', 'created_at', 'status', 'project_id',
|
||||
'links', 'share_group_id', 'members',
|
||||
}
|
||||
|
||||
SHARE_GROUP_TYPE_REQUIRED_KEYS = {
|
||||
'id', 'name', 'share_types', 'is_public', 'group_specs',
|
||||
}
|
||||
|
@ -170,11 +170,10 @@ ShareGroup = [
|
||||
help="Defines whether to run tests that revert shares "
|
||||
"to snapshots or not. Enable this feature if used "
|
||||
"driver supports it."),
|
||||
cfg.BoolOpt("run_consistency_group_tests",
|
||||
default=False,
|
||||
help="Defines whether to run consistency group tests or not. "
|
||||
"Disable this feature if used driver doesn't support "
|
||||
"it."),
|
||||
cfg.BoolOpt("run_share_group_tests",
|
||||
default=True,
|
||||
deprecated_name="run_consistency_group_tests",
|
||||
help="Defines whether to run share group tests or not."),
|
||||
cfg.BoolOpt("run_replication_tests",
|
||||
default=False,
|
||||
help="Defines whether to run replication tests or not. "
|
||||
|
@ -173,12 +173,16 @@ class SharesV2Client(shares_client.SharesClient):
|
||||
if "share_instance_id" in kwargs:
|
||||
return self._is_resource_deleted(
|
||||
self.get_share_instance, kwargs.get("share_instance_id"))
|
||||
elif "cg_id" in kwargs:
|
||||
elif "share_group_id" in kwargs:
|
||||
return self._is_resource_deleted(
|
||||
self.get_consistency_group, kwargs.get("cg_id"))
|
||||
elif "cgsnapshot_id" in kwargs:
|
||||
self.get_share_group, kwargs.get("share_group_id"))
|
||||
elif "share_group_snapshot_id" in kwargs:
|
||||
return self._is_resource_deleted(
|
||||
self.get_cgsnapshot, kwargs.get("cgsnapshot_id"))
|
||||
self.get_share_group_snapshot,
|
||||
kwargs.get("share_group_snapshot_id"))
|
||||
elif "share_group_type_id" in kwargs:
|
||||
return self._is_resource_deleted(
|
||||
self.get_share_group_type, kwargs.get("share_group_type_id"))
|
||||
elif "replica_id" in kwargs:
|
||||
return self._is_resource_deleted(
|
||||
self.get_share_replica, kwargs.get("replica_id"))
|
||||
@ -192,8 +196,9 @@ class SharesV2Client(shares_client.SharesClient):
|
||||
name=None, snapshot_id=None, description=None,
|
||||
metadata=None, share_network_id=None,
|
||||
share_type_id=None, is_public=False,
|
||||
consistency_group_id=None, availability_zone=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
share_group_id=None, availability_zone=None,
|
||||
version=LATEST_MICROVERSION, experimental=False):
|
||||
headers = EXPERIMENTAL if experimental else None
|
||||
metadata = metadata or {}
|
||||
if name is None:
|
||||
name = data_utils.rand_name("tempest-created-share")
|
||||
@ -222,29 +227,37 @@ class SharesV2Client(shares_client.SharesClient):
|
||||
post_body["share"]["share_network_id"] = share_network_id
|
||||
if share_type_id:
|
||||
post_body["share"]["share_type"] = share_type_id
|
||||
if consistency_group_id:
|
||||
post_body["share"]["consistency_group_id"] = consistency_group_id
|
||||
if share_group_id:
|
||||
post_body["share"]["share_group_id"] = share_group_id
|
||||
body = json.dumps(post_body)
|
||||
resp, body = self.post("shares", body, version=version)
|
||||
resp, body = self.post("shares", body, headers=headers,
|
||||
extra_headers=experimental, version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def list_shares(self, detailed=False, params=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
version=LATEST_MICROVERSION, experimental=False):
|
||||
"""Get list of shares w/o filters."""
|
||||
headers = EXPERIMENTAL if experimental else None
|
||||
uri = 'shares/detail' if detailed else 'shares'
|
||||
uri += '?%s' % urlparse.urlencode(params) if params else ''
|
||||
resp, body = self.get(uri, version=version)
|
||||
resp, body = self.get(uri, headers=headers, extra_headers=experimental,
|
||||
version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def list_shares_with_detail(self, params=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
version=LATEST_MICROVERSION,
|
||||
experimental=False):
|
||||
"""Get detailed list of shares w/o filters."""
|
||||
return self.list_shares(detailed=True, params=params, version=version)
|
||||
return self.list_shares(detailed=True, params=params,
|
||||
version=version, experimental=experimental)
|
||||
|
||||
def get_share(self, share_id, version=LATEST_MICROVERSION):
|
||||
resp, body = self.get("shares/%s" % share_id, version=version)
|
||||
def get_share(self, share_id, version=LATEST_MICROVERSION,
|
||||
experimental=False):
|
||||
headers = EXPERIMENTAL if experimental else None
|
||||
resp, body = self.get("shares/%s" % share_id, headers=headers,
|
||||
extra_headers=experimental, version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
@ -881,62 +894,68 @@ class SharesV2Client(shares_client.SharesClient):
|
||||
|
||||
###############
|
||||
|
||||
def create_consistency_group(self, name=None, description=None,
|
||||
share_type_ids=(), share_network_id=None,
|
||||
source_cgsnapshot_id=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
"""Create a new consistency group."""
|
||||
uri = 'consistency-groups'
|
||||
def create_share_group(self, name=None, description=None,
|
||||
share_group_type_id=None, share_type_ids=(),
|
||||
share_network_id=None,
|
||||
source_share_group_snapshot_id=None,
|
||||
availability_zone=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
"""Create a new share group."""
|
||||
uri = 'share-groups'
|
||||
post_body = {}
|
||||
if name:
|
||||
post_body['name'] = name
|
||||
if description:
|
||||
post_body['description'] = description
|
||||
if share_group_type_id:
|
||||
post_body['share_group_type_id'] = share_group_type_id
|
||||
if share_type_ids:
|
||||
post_body['share_types'] = share_type_ids
|
||||
if source_cgsnapshot_id:
|
||||
post_body['source_cgsnapshot_id'] = source_cgsnapshot_id
|
||||
if source_share_group_snapshot_id:
|
||||
post_body['source_share_group_snapshot_id'] = (
|
||||
source_share_group_snapshot_id)
|
||||
if share_network_id:
|
||||
post_body['share_network_id'] = share_network_id
|
||||
body = json.dumps({'consistency_group': post_body})
|
||||
if availability_zone:
|
||||
post_body['availability_zone'] = availability_zone
|
||||
body = json.dumps({'share_group': post_body})
|
||||
|
||||
resp, body = self.post(uri, body, headers=EXPERIMENTAL,
|
||||
extra_headers=True, version=version)
|
||||
|
||||
self.expected_success(202, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def delete_consistency_group(self, consistency_group_id,
|
||||
version=LATEST_MICROVERSION):
|
||||
"""Delete a consistency group."""
|
||||
uri = 'consistency-groups/%s' % consistency_group_id
|
||||
def delete_share_group(self, share_group_id, version=LATEST_MICROVERSION):
|
||||
"""Delete a share group."""
|
||||
uri = 'share-groups/%s' % share_group_id
|
||||
resp, body = self.delete(uri, headers=EXPERIMENTAL,
|
||||
extra_headers=True, version=version)
|
||||
self.expected_success(202, resp.status)
|
||||
return body
|
||||
return self._parse_resp(body)
|
||||
|
||||
def list_consistency_groups(self, detailed=False, params=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
"""Get list of consistency groups w/o filters."""
|
||||
uri = 'consistency-groups%s' % ('/detail' if detailed else '')
|
||||
def list_share_groups(self, detailed=False, params=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
"""Get list of share groups w/o filters."""
|
||||
uri = 'share-groups%s' % ('/detail' if detailed else '')
|
||||
uri += '?%s' % (urlparse.urlencode(params) if params else '')
|
||||
resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
|
||||
version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def get_consistency_group(self, consistency_group_id,
|
||||
version=LATEST_MICROVERSION):
|
||||
"""Get consistency group info."""
|
||||
uri = 'consistency-groups/%s' % consistency_group_id
|
||||
def get_share_group(self, share_group_id, version=LATEST_MICROVERSION):
|
||||
"""Get share group info."""
|
||||
uri = 'share-groups/%s' % share_group_id
|
||||
resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
|
||||
version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def update_consistency_group(self, consistency_group_id, name=None,
|
||||
description=None,
|
||||
version=LATEST_MICROVERSION, **kwargs):
|
||||
"""Update an existing consistency group."""
|
||||
uri = 'consistency-groups/%s' % consistency_group_id
|
||||
def update_share_group(self, share_group_id, name=None, description=None,
|
||||
version=LATEST_MICROVERSION, **kwargs):
|
||||
"""Update an existing share group."""
|
||||
uri = 'share-groups/%s' % share_group_id
|
||||
post_body = {}
|
||||
if name:
|
||||
post_body['name'] = name
|
||||
@ -944,147 +963,291 @@ class SharesV2Client(shares_client.SharesClient):
|
||||
post_body['description'] = description
|
||||
if kwargs:
|
||||
post_body.update(kwargs)
|
||||
body = json.dumps({'consistency_group': post_body})
|
||||
body = json.dumps({'share_group': post_body})
|
||||
|
||||
resp, body = self.put(uri, body, headers=EXPERIMENTAL,
|
||||
extra_headers=True, version=version)
|
||||
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def consistency_group_reset_state(self, id, status,
|
||||
version=LATEST_MICROVERSION):
|
||||
self.reset_state(id, status=status,
|
||||
s_type='consistency-groups', headers=EXPERIMENTAL,
|
||||
version=version)
|
||||
def share_group_reset_state(self, share_group_id, status='error',
|
||||
version=LATEST_MICROVERSION):
|
||||
self.reset_state(share_group_id, status=status, s_type='groups',
|
||||
headers=EXPERIMENTAL, version=version)
|
||||
|
||||
def consistency_group_force_delete(self, id, version=LATEST_MICROVERSION):
|
||||
self.force_delete(id, s_type='consistency-groups',
|
||||
def share_group_force_delete(self, share_group_id,
|
||||
version=LATEST_MICROVERSION):
|
||||
self.force_delete(share_group_id, s_type='share-groups',
|
||||
headers=EXPERIMENTAL, version=version)
|
||||
|
||||
def wait_for_consistency_group_status(self, consistency_group_id, status):
|
||||
"""Waits for a consistency group to reach a given status."""
|
||||
body = self.get_consistency_group(consistency_group_id)
|
||||
consistency_group_name = body['name']
|
||||
consistency_group_status = body['status']
|
||||
def wait_for_share_group_status(self, share_group_id, status):
|
||||
"""Waits for a share group to reach a given status."""
|
||||
body = self.get_share_group(share_group_id)
|
||||
sg_name = body['name']
|
||||
sg_status = body['status']
|
||||
start = int(time.time())
|
||||
|
||||
while consistency_group_status != status:
|
||||
while sg_status != status:
|
||||
time.sleep(self.build_interval)
|
||||
body = self.get_consistency_group(consistency_group_id)
|
||||
consistency_group_status = body['status']
|
||||
if 'error' in consistency_group_status and status != 'error':
|
||||
raise share_exceptions.ConsistencyGroupBuildErrorException(
|
||||
consistency_group_id=consistency_group_id)
|
||||
body = self.get_share_group(share_group_id)
|
||||
sg_status = body['status']
|
||||
if 'error' in sg_status and status != 'error':
|
||||
raise share_exceptions.ShareGroupBuildErrorException(
|
||||
share_group_id=share_group_id)
|
||||
|
||||
if int(time.time()) - start >= self.build_timeout:
|
||||
consistency_group_name = (
|
||||
consistency_group_name if consistency_group_name else
|
||||
consistency_group_id
|
||||
)
|
||||
message = ('Consistency Group %s failed to reach %s status '
|
||||
sg_name = sg_name or share_group_id
|
||||
message = ('Share Group %s failed to reach %s status '
|
||||
'within the required time (%s s). '
|
||||
'Current status: %s' %
|
||||
(consistency_group_name, status,
|
||||
self.build_timeout, consistency_group_status))
|
||||
(sg_name, status, self.build_timeout, sg_status))
|
||||
raise exceptions.TimeoutException(message)
|
||||
|
||||
###############
|
||||
|
||||
def create_cgsnapshot(self, consistency_group_id,
|
||||
name=None, description=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
"""Create a new cgsnapshot of an existing consistency group."""
|
||||
uri = 'cgsnapshots'
|
||||
post_body = {'consistency_group_id': consistency_group_id}
|
||||
if name:
|
||||
def create_share_group_type(self, name=None, share_types=(),
|
||||
is_public=None, group_specs=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
"""Create a new share group type."""
|
||||
uri = 'share-group-types'
|
||||
post_body = {}
|
||||
if isinstance(share_types, (tuple, list)):
|
||||
share_types = list(share_types)
|
||||
else:
|
||||
share_types = [share_types]
|
||||
if name is not None:
|
||||
post_body['name'] = name
|
||||
if description:
|
||||
post_body['description'] = description
|
||||
body = json.dumps({'cgsnapshot': post_body})
|
||||
if share_types:
|
||||
post_body['share_types'] = share_types
|
||||
if is_public is not None:
|
||||
post_body['is_public'] = is_public
|
||||
if group_specs:
|
||||
post_body['group_specs'] = group_specs
|
||||
body = json.dumps({'share_group_type': post_body})
|
||||
resp, body = self.post(uri, body, headers=EXPERIMENTAL,
|
||||
extra_headers=True, version=version)
|
||||
self.expected_success(202, resp.status)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def delete_cgsnapshot(self, cgsnapshot_id,
|
||||
version=LATEST_MICROVERSION):
|
||||
"""Delete an existing cgsnapshot."""
|
||||
uri = 'cgsnapshots/%s' % cgsnapshot_id
|
||||
resp, body = self.delete(uri, headers=EXPERIMENTAL,
|
||||
extra_headers=True, version=version)
|
||||
self.expected_success(202, resp.status)
|
||||
return body
|
||||
|
||||
def list_cgsnapshots(self, detailed=False, params=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
"""Get list of cgsnapshots w/o filters."""
|
||||
uri = 'cgsnapshots/detail' if detailed else 'cgsnapshots'
|
||||
def list_share_group_types(self, detailed=False, params=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
"""Get list of share group types."""
|
||||
uri = 'share-group-types%s' % ('/detail' if detailed else '')
|
||||
uri += '?%s' % (urlparse.urlencode(params) if params else '')
|
||||
resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
|
||||
version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def list_cgsnapshot_members(self, cgsnapshot_id,
|
||||
def get_share_group_type(self, share_group_type_id,
|
||||
version=LATEST_MICROVERSION):
|
||||
"""Get share group type info."""
|
||||
uri = 'share-group-types/%s' % share_group_type_id
|
||||
resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
|
||||
version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def get_default_share_group_type(self, version=LATEST_MICROVERSION):
|
||||
"""Get default share group type info."""
|
||||
uri = 'share-group-types/default'
|
||||
resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
|
||||
version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def delete_share_group_type(self, share_group_type_id,
|
||||
version=LATEST_MICROVERSION):
|
||||
"""Get list of members of a cgsnapshots."""
|
||||
uri = 'cgsnapshots/%s/members' % cgsnapshot_id
|
||||
"""Delete an existing share group type."""
|
||||
uri = 'share-group-types/%s' % share_group_type_id
|
||||
resp, body = self.delete(uri, headers=EXPERIMENTAL,
|
||||
extra_headers=True, version=version)
|
||||
self.expected_success(204, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def add_access_to_share_group_type(self, share_group_type_id, project_id,
|
||||
version=LATEST_MICROVERSION):
|
||||
uri = 'share-group-types/%s/action' % share_group_type_id
|
||||
post_body = {'project': project_id}
|
||||
post_body = json.dumps({'addProjectAccess': post_body})
|
||||
resp, body = self.post(uri, post_body, headers=EXPERIMENTAL,
|
||||
extra_headers=True, version=version)
|
||||
self.expected_success(202, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def remove_access_from_share_group_type(self, share_group_type_id,
|
||||
project_id,
|
||||
version=LATEST_MICROVERSION):
|
||||
uri = 'share-group-types/%s/action' % share_group_type_id
|
||||
post_body = {'project': project_id}
|
||||
post_body = json.dumps({'removeProjectAccess': post_body})
|
||||
resp, body = self.post(uri, post_body, headers=EXPERIMENTAL,
|
||||
extra_headers=True, version=version)
|
||||
self.expected_success(202, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def list_access_to_share_group_type(self, share_group_type_id,
|
||||
version=LATEST_MICROVERSION):
|
||||
uri = 'share-group-types/%s/access' % share_group_type_id
|
||||
resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
|
||||
version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def get_cgsnapshot(self, cgsnapshot_id, version=LATEST_MICROVERSION):
|
||||
"""Get cgsnapshot info."""
|
||||
uri = 'cgsnapshots/%s' % cgsnapshot_id
|
||||
###############
|
||||
|
||||
def create_share_group_type_specs(self, share_group_type_id,
|
||||
group_specs_dict,
|
||||
version=LATEST_MICROVERSION):
|
||||
url = "share-group-types/%s/group-specs" % share_group_type_id
|
||||
post_body = json.dumps({'group_specs': group_specs_dict})
|
||||
resp, body = self.post(url, post_body, headers=EXPERIMENTAL,
|
||||
extra_headers=True, version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def get_share_group_type_spec(self, share_group_type_id, group_spec_key,
|
||||
version=LATEST_MICROVERSION):
|
||||
uri = "group-types/%s/group_specs/%s" % (
|
||||
share_group_type_id, group_spec_key)
|
||||
resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
|
||||
version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def update_cgsnapshot(self, cgsnapshot_id, name=None, description=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
"""Update an existing cgsnapshot."""
|
||||
uri = 'cgsnapshots/%s' % cgsnapshot_id
|
||||
def list_share_group_type_specs(self, share_group_type_id, params=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
uri = "share-group-types/%s/group_specs" % share_group_type_id
|
||||
if params is not None:
|
||||
uri += '?%s' % urlparse.urlencode(params)
|
||||
resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
|
||||
version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def update_share_group_type_spec(self, share_group_type_id, group_spec_key,
|
||||
group_spec_value,
|
||||
version=LATEST_MICROVERSION):
|
||||
uri = "share-group-types/%s/group-specs/%s" % (
|
||||
share_group_type_id, group_spec_key)
|
||||
group_spec = {group_spec_key: group_spec_value}
|
||||
post_body = json.dumps(group_spec)
|
||||
resp, body = self.put(uri, post_body, headers=EXPERIMENTAL,
|
||||
extra_headers=True, version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def update_share_group_type_specs(self, share_group_type_id,
|
||||
group_specs_dict,
|
||||
version=LATEST_MICROVERSION):
|
||||
return self.create_share_group_type_specs(
|
||||
share_group_type_id, group_specs_dict, version=version)
|
||||
|
||||
def delete_share_group_type_spec(self, share_type_id, group_spec_key,
|
||||
version=LATEST_MICROVERSION):
|
||||
uri = "share-group-types/%s/group-specs/%s" % (
|
||||
share_type_id, group_spec_key)
|
||||
resp, body = self.delete(uri, headers=EXPERIMENTAL, extra_headers=True,
|
||||
version=version)
|
||||
self.expected_success(204, resp.status)
|
||||
return body
|
||||
|
||||
###############
|
||||
|
||||
def create_share_group_snapshot(self, share_group_id, name=None,
|
||||
description=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
"""Create a new share group snapshot of an existing share group."""
|
||||
uri = 'share-group-snapshots'
|
||||
post_body = {'share_group_id': share_group_id}
|
||||
if name:
|
||||
post_body['name'] = name
|
||||
if description:
|
||||
post_body['description'] = description
|
||||
body = json.dumps({'share_group_snapshot': post_body})
|
||||
resp, body = self.post(uri, body, headers=EXPERIMENTAL,
|
||||
extra_headers=True, version=version)
|
||||
self.expected_success(202, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def delete_share_group_snapshot(self, share_group_snapshot_id,
|
||||
version=LATEST_MICROVERSION):
|
||||
"""Delete an existing share group snapshot."""
|
||||
uri = 'share-group-snapshots/%s' % share_group_snapshot_id
|
||||
resp, body = self.delete(uri, headers=EXPERIMENTAL,
|
||||
extra_headers=True, version=version)
|
||||
self.expected_success(202, resp.status)
|
||||
return body
|
||||
|
||||
def list_share_group_snapshots(self, detailed=False, params=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
"""Get list of share group snapshots w/o filters."""
|
||||
uri = 'share-group-snapshots%s' % ('/detail' if detailed else '')
|
||||
uri += '?%s' % (urlparse.urlencode(params) if params else '')
|
||||
resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
|
||||
version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def get_share_group_snapshot(self, share_group_snapshot_id,
|
||||
version=LATEST_MICROVERSION):
|
||||
"""Get share group snapshot info."""
|
||||
uri = 'share-group-snapshots/%s' % share_group_snapshot_id
|
||||
resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
|
||||
version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def update_share_group_snapshot(self, share_group_snapshot_id, name=None,
|
||||
description=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
"""Update an existing share group snapshot."""
|
||||
uri = 'share-group-snapshots/%s' % share_group_snapshot_id
|
||||
post_body = {}
|
||||
if name:
|
||||
post_body['name'] = name
|
||||
if description:
|
||||
post_body['description'] = description
|
||||
body = json.dumps({'cgsnapshot': post_body})
|
||||
body = json.dumps({'share_group_snapshot': post_body})
|
||||
resp, body = self.put(uri, body, headers=EXPERIMENTAL,
|
||||
extra_headers=True, version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def cgsnapshot_reset_state(self, id, status,
|
||||
version=LATEST_MICROVERSION):
|
||||
self.reset_state(id, status=status,
|
||||
s_type='cgsnapshots', headers=EXPERIMENTAL,
|
||||
version=version)
|
||||
def share_group_snapshot_reset_state(self, share_group_snapshot_id,
|
||||
status='error',
|
||||
version=LATEST_MICROVERSION):
|
||||
self.reset_state(
|
||||
share_group_snapshot_id, status=status,
|
||||
s_type='group-snapshots', headers=EXPERIMENTAL, version=version)
|
||||
|
||||
def cgsnapshot_force_delete(self, id, version=LATEST_MICROVERSION):
|
||||
self.force_delete(id, s_type='cgsnapshots', headers=EXPERIMENTAL,
|
||||
version=version)
|
||||
def share_group_snapshot_force_delete(self, share_group_snapshot_id,
|
||||
version=LATEST_MICROVERSION):
|
||||
self.force_delete(
|
||||
share_group_snapshot_id, s_type='share-group-snapshots',
|
||||
headers=EXPERIMENTAL, version=version)
|
||||
|
||||
def wait_for_cgsnapshot_status(self, cgsnapshot_id, status):
|
||||
"""Waits for a cgsnapshot to reach a given status."""
|
||||
body = self.get_cgsnapshot(cgsnapshot_id)
|
||||
cgsnapshot_name = body['name']
|
||||
cgsnapshot_status = body['status']
|
||||
def wait_for_share_group_snapshot_status(self, share_group_snapshot_id,
|
||||
status):
|
||||
"""Waits for a share group snapshot to reach a given status."""
|
||||
body = self.get_share_group_snapshot(share_group_snapshot_id)
|
||||
sg_snapshot_name = body['name']
|
||||
sg_snapshot_status = body['status']
|
||||
start = int(time.time())
|
||||
|
||||
while cgsnapshot_status != status:
|
||||
while sg_snapshot_status != status:
|
||||
time.sleep(self.build_interval)
|
||||
body = self.get_cgsnapshot(cgsnapshot_id)
|
||||
cgsnapshot_status = body['status']
|
||||
if 'error' in cgsnapshot_status and status != 'error':
|
||||
raise share_exceptions.CGSnapshotBuildErrorException(
|
||||
cgsnapshot_id=cgsnapshot_id)
|
||||
body = self.get_share_group_snapshot(share_group_snapshot_id)
|
||||
sg_snapshot_status = body['status']
|
||||
if 'error' in sg_snapshot_status and status != 'error':
|
||||
raise share_exceptions.ShareGroupSnapshotBuildErrorException(
|
||||
share_group_snapshot_id=share_group_snapshot_id)
|
||||
|
||||
if int(time.time()) - start >= self.build_timeout:
|
||||
message = ('CGSnapshot %s failed to reach %s status '
|
||||
message = ('Share Group Snapshot %s failed to reach %s status '
|
||||
'within the required time (%s s).' %
|
||||
(cgsnapshot_name, status, self.build_timeout))
|
||||
(sg_snapshot_name, status, self.build_timeout))
|
||||
raise exceptions.TimeoutException(message)
|
||||
|
||||
###############
|
||||
|
@ -24,9 +24,9 @@ class ShareInstanceBuildErrorException(exceptions.TempestException):
|
||||
message = "Share instance %(id)s failed to build and is in ERROR status"
|
||||
|
||||
|
||||
class ConsistencyGroupBuildErrorException(exceptions.TempestException):
|
||||
message = ("Consistency group %(consistency_group_id)s failed to build "
|
||||
"and is in ERROR status")
|
||||
class ShareGroupBuildErrorException(exceptions.TempestException):
|
||||
message = ("Share group %(share_group_id)s failed to build and "
|
||||
"is in ERROR status")
|
||||
|
||||
|
||||
class AccessRuleBuildErrorException(exceptions.TempestException):
|
||||
@ -42,9 +42,9 @@ class SnapshotInstanceBuildErrorException(exceptions.TempestException):
|
||||
"ERROR status.")
|
||||
|
||||
|
||||
class CGSnapshotBuildErrorException(exceptions.TempestException):
|
||||
message = ("CGSnapshot %(cgsnapshot_id)s failed to build and is in ERROR "
|
||||
"status")
|
||||
class ShareGroupSnapshotBuildErrorException(exceptions.TempestException):
|
||||
message = ("Share Group Snapshot %(share_group_snapshot_id)s failed "
|
||||
"to build and is in ERROR status")
|
||||
|
||||
|
||||
class ShareProtocolNotSpecified(exceptions.TempestException):
|
||||
|
@ -1,151 +0,0 @@
|
||||
# Copyright 2015 Andrew Kerr
|
||||
# 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 import config
|
||||
from tempest.lib.common.utils import data_utils
|
||||
import testtools
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@testtools.skipUnless(CONF.share.run_consistency_group_tests,
|
||||
'Consistency Group tests disabled.')
|
||||
class ConsistencyGroupActionsTest(base.BaseSharesAdminTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ConsistencyGroupActionsTest, cls).resource_setup()
|
||||
# Create 2 share_types
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
extra_specs = cls.add_extra_specs_to_dict()
|
||||
share_type = cls.create_share_type(name, extra_specs=extra_specs)
|
||||
cls.share_type = share_type['share_type']
|
||||
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
share_type = cls.create_share_type(name, extra_specs=extra_specs)
|
||||
cls.share_type2 = share_type['share_type']
|
||||
|
||||
# Create a consistency group
|
||||
cls.consistency_group = cls.create_consistency_group(
|
||||
share_type_ids=[cls.share_type['id'], cls.share_type2['id']])
|
||||
cls.consistency_group = cls.shares_v2_client.get_consistency_group(
|
||||
cls.consistency_group['id'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
def test_create_cg_from_cgsnapshot_with_multiple_share_types_v2_4(self):
|
||||
# Create cgsnapshot
|
||||
cgsnapshot = self.create_cgsnapshot_wait_for_active(
|
||||
self.consistency_group["id"],
|
||||
cleanup_in_class=False,
|
||||
version='2.4',
|
||||
)
|
||||
|
||||
new_consistency_group = self.create_consistency_group(
|
||||
cleanup_in_class=False,
|
||||
source_cgsnapshot_id=cgsnapshot['id'],
|
||||
version='2.4',
|
||||
)
|
||||
|
||||
# Verify share_types are the same
|
||||
expected_types = sorted(self.consistency_group['share_types'])
|
||||
actual_types = sorted(new_consistency_group['share_types'])
|
||||
self.assertEqual(expected_types, actual_types,
|
||||
'Expected share types of %s, but got %s.' % (
|
||||
expected_types, actual_types))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
def test_create_cg_from_multi_typed_populated_cgsnapshot_v2_4(self):
|
||||
share_name = data_utils.rand_name("tempest-share-name")
|
||||
share_desc = data_utils.rand_name("tempest-share-description")
|
||||
|
||||
shares = self.create_shares([
|
||||
{'kwargs': {
|
||||
'cleanup_in_class': False,
|
||||
'name': share_name,
|
||||
'description': share_desc,
|
||||
'consistency_group_id': self.consistency_group['id'],
|
||||
'share_type_id': st_id,
|
||||
}} for st_id in (self.share_type['id'], self.share_type2['id'])
|
||||
])
|
||||
|
||||
cg_shares = self.shares_v2_client.list_shares(
|
||||
detailed=True,
|
||||
params={'consistency_group_id': self.consistency_group['id']},
|
||||
version='2.4',
|
||||
)
|
||||
|
||||
cg_share_ids = [s['id'] for s in cg_shares]
|
||||
for share_id in (shares[0]['id'], shares[1]['id']):
|
||||
self.assertIn(share_id, cg_share_ids, 'Share %s not in '
|
||||
'consistency group %s.' %
|
||||
(share_id, self.consistency_group['id']))
|
||||
|
||||
cgsnap_name = data_utils.rand_name("tempest-cgsnap-name")
|
||||
cgsnap_desc = data_utils.rand_name("tempest-cgsnap-description")
|
||||
cgsnapshot = self.create_cgsnapshot_wait_for_active(
|
||||
self.consistency_group["id"],
|
||||
name=cgsnap_name,
|
||||
description=cgsnap_desc,
|
||||
cleanup_in_class=False,
|
||||
version='2.4',
|
||||
)
|
||||
|
||||
new_cg = self.create_consistency_group(
|
||||
cleanup_in_class=False, source_cgsnapshot_id=cgsnapshot['id'],
|
||||
version='2.4')
|
||||
new_cg_shares = self.shares_v2_client.list_shares(
|
||||
detailed=True,
|
||||
params={'consistency_group_id': new_cg['id']},
|
||||
version='2.4')
|
||||
|
||||
# TODO(akerr): Skip until bug 1483886 is resolved
|
||||
# Verify that the new shares correspond to correct share types
|
||||
# expected_share_types = [self.share_type['id'], self.share_type2[
|
||||
# 'id']]
|
||||
# actual_share_types = [s['share_type'] for s in new_cg_shares]
|
||||
# self.assertEqual(sorted(expected_share_types),
|
||||
# sorted(actual_share_types),
|
||||
# 'Expected shares of types %s, got %s.' % (
|
||||
# sorted(expected_share_types),
|
||||
# sorted(actual_share_types)))
|
||||
|
||||
# Ensure that share_server information of the child CG and associated
|
||||
# shares match with that of the parent CG
|
||||
self.assertEqual(self.consistency_group['share_network_id'],
|
||||
new_cg['share_network_id'])
|
||||
self.assertEqual(self.consistency_group['share_server_id'],
|
||||
new_cg['share_server_id'])
|
||||
|
||||
for share in new_cg_shares:
|
||||
msg = ('Share %(share)s has %(attr)s=%(value)s and it does not '
|
||||
'match that of the parent CG where %(attr)s=%(orig)s.')
|
||||
payload = {
|
||||
'share': share['id'],
|
||||
'attr': 'share_network_id',
|
||||
'value': share['share_network_id'],
|
||||
'orig': self.consistency_group['share_network_id'],
|
||||
}
|
||||
self.assertEqual(self.consistency_group['share_network_id'],
|
||||
share['share_network_id'], msg % payload)
|
||||
|
||||
payload.update({'attr': 'share_server_id',
|
||||
'value': share['share_server_id'],
|
||||
'orig': self.consistency_group['share_server_id'],
|
||||
})
|
||||
self.assertEqual(self.consistency_group['share_server_id'],
|
||||
share['share_server_id'], msg % payload)
|
@ -1,99 +0,0 @@
|
||||
# Copyright 2015 Andrew Kerr
|
||||
# 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 import config
|
||||
from tempest.lib.common.utils import data_utils
|
||||
import testtools
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
CG_REQUIRED_ELEMENTS = {"id", "name", "description", "created_at", "status",
|
||||
"share_types", "project_id", "host", "links"}
|
||||
|
||||
|
||||
@testtools.skipUnless(CONF.share.run_consistency_group_tests,
|
||||
'Consistency Group tests disabled.')
|
||||
class ConsistencyGroupsTest(base.BaseSharesAdminTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ConsistencyGroupsTest, cls).resource_setup()
|
||||
# Create 2 share_types
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
extra_specs = cls.add_extra_specs_to_dict()
|
||||
share_type = cls.create_share_type(name, extra_specs=extra_specs)
|
||||
cls.share_type = share_type['share_type']
|
||||
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
share_type = cls.create_share_type(name, extra_specs=extra_specs)
|
||||
cls.share_type2 = share_type['share_type']
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_cg_with_multiple_share_types_v2_4(self):
|
||||
# Create a consistency group
|
||||
consistency_group = self.create_consistency_group(
|
||||
cleanup_in_class=False,
|
||||
share_type_ids=[self.share_type['id'], self.share_type2['id']],
|
||||
version='2.4',
|
||||
)
|
||||
|
||||
self.assertTrue(CG_REQUIRED_ELEMENTS.issubset(
|
||||
consistency_group.keys()),
|
||||
'At least one expected element missing from consistency group '
|
||||
'response. Expected %(expected)s, got %(actual)s.' % {
|
||||
"expected": CG_REQUIRED_ELEMENTS,
|
||||
"actual": consistency_group.keys()})
|
||||
|
||||
actual_share_types = consistency_group['share_types']
|
||||
expected_share_types = [self.share_type['id'], self.share_type2['id']]
|
||||
self.assertEqual(sorted(expected_share_types),
|
||||
sorted(actual_share_types),
|
||||
'Incorrect share types applied to consistency group '
|
||||
'%s. Expected %s, got %s' % (consistency_group['id'],
|
||||
expected_share_types,
|
||||
actual_share_types))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipIf(
|
||||
not CONF.share.multitenancy_enabled, "Only for multitenancy.")
|
||||
def test_create_cg_from_cgsnapshot_verify_share_server_information(self):
|
||||
# Create a consistency group
|
||||
orig_consistency_group = self.create_consistency_group(
|
||||
cleanup_in_class=False,
|
||||
share_type_ids=[self.share_type['id']],
|
||||
version='2.4')
|
||||
|
||||
# Get latest CG information
|
||||
orig_consistency_group = self.shares_v2_client.get_consistency_group(
|
||||
orig_consistency_group['id'], version='2.4')
|
||||
|
||||
# Assert share server information
|
||||
self.assertIsNotNone(orig_consistency_group['share_network_id'])
|
||||
self.assertIsNotNone(orig_consistency_group['share_server_id'])
|
||||
|
||||
cg_snapshot = self.create_cgsnapshot_wait_for_active(
|
||||
orig_consistency_group['id'], cleanup_in_class=False,
|
||||
version='2.4')
|
||||
new_consistency_group = self.create_consistency_group(
|
||||
cleanup_in_class=False, version='2.4',
|
||||
source_cgsnapshot_id=cg_snapshot['id'])
|
||||
|
||||
# Assert share server information
|
||||
self.assertEqual(orig_consistency_group['share_network_id'],
|
||||
new_consistency_group['share_network_id'])
|
||||
self.assertEqual(orig_consistency_group['share_server_id'],
|
||||
new_consistency_group['share_server_id'])
|
@ -1,292 +0,0 @@
|
||||
# Copyright 2015 Andrew Kerr
|
||||
# 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 import config
|
||||
from tempest.lib.common.utils import data_utils
|
||||
from tempest.lib import exceptions
|
||||
import testtools
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@testtools.skipUnless(CONF.share.run_consistency_group_tests,
|
||||
'Consistency Group tests disabled.')
|
||||
class ConsistencyGroupsNegativeTest(base.BaseSharesAdminTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ConsistencyGroupsNegativeTest, cls).resource_setup()
|
||||
# Create share_type
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
extra_specs = cls.add_extra_specs_to_dict()
|
||||
share_type = cls.create_share_type(name, extra_specs=extra_specs)
|
||||
cls.share_type = share_type['share_type']
|
||||
|
||||
# Create a consistency group
|
||||
cls.consistency_group = cls.create_consistency_group(
|
||||
share_type_ids=[cls.share_type['id']])
|
||||
|
||||
# Create share inside consistency group
|
||||
cls.share_name = data_utils.rand_name("tempest-share-name")
|
||||
cls.share_desc = data_utils.rand_name("tempest-share-description")
|
||||
cls.share = cls.create_share(
|
||||
name=cls.share_name,
|
||||
description=cls.share_desc,
|
||||
consistency_group_id=cls.consistency_group['id'],
|
||||
share_type_id=cls.share_type['id'],
|
||||
)
|
||||
|
||||
# Create a cgsnapshot of the consistency group
|
||||
cls.cgsnap_name = data_utils.rand_name("tempest-cgsnap-name")
|
||||
cls.cgsnap_desc = data_utils.rand_name("tempest-cgsnap-description")
|
||||
cls.cgsnapshot = cls.create_cgsnapshot_wait_for_active(
|
||||
cls.consistency_group["id"],
|
||||
name=cls.cgsnap_name,
|
||||
description=cls.cgsnap_desc)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_delete_share_type_in_use_by_cg(self):
|
||||
# Attempt delete of share type
|
||||
self.assertRaises(exceptions.BadRequest,
|
||||
self.shares_client.delete_share_type,
|
||||
self.share_type['id'])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_share_of_unsupported_type_in_cg_v2_4(self):
|
||||
# Attempt to create share of default type in the cg
|
||||
self.assertRaises(exceptions.BadRequest,
|
||||
self.create_share,
|
||||
size=1,
|
||||
consistency_group_id=self.consistency_group['id'],
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_share_in_cg_that_is_not_available_v2_4(self):
|
||||
consistency_group = self.create_consistency_group(
|
||||
cleanup_in_class=False, version='2.4')
|
||||
self.addCleanup(self.shares_v2_client.consistency_group_reset_state,
|
||||
consistency_group['id'],
|
||||
status='available',
|
||||
version='2.4')
|
||||
# creating
|
||||
self.shares_v2_client.consistency_group_reset_state(
|
||||
consistency_group['id'], status='creating', version='2.4')
|
||||
self.shares_v2_client.wait_for_consistency_group_status(
|
||||
consistency_group['id'], 'creating')
|
||||
self.assertRaises(exceptions.BadRequest, self.create_share,
|
||||
name=self.share_name,
|
||||
description=self.share_desc,
|
||||
consistency_group_id=consistency_group['id'],
|
||||
cleanup_in_class=False,
|
||||
version='2.4')
|
||||
# deleting
|
||||
self.shares_v2_client.consistency_group_reset_state(
|
||||
consistency_group['id'], status='deleting', version='2.4')
|
||||
self.shares_v2_client.wait_for_consistency_group_status(
|
||||
consistency_group['id'], 'deleting')
|
||||
self.assertRaises(exceptions.BadRequest, self.create_share,
|
||||
name=self.share_name,
|
||||
description=self.share_desc,
|
||||
consistency_group_id=consistency_group['id'],
|
||||
cleanup_in_class=False,
|
||||
version='2.4')
|
||||
# error
|
||||
self.shares_v2_client.consistency_group_reset_state(
|
||||
consistency_group['id'], status='error', version='2.4')
|
||||
self.shares_v2_client.wait_for_consistency_group_status(
|
||||
consistency_group['id'], 'error')
|
||||
self.assertRaises(exceptions.BadRequest, self.create_share,
|
||||
name=self.share_name,
|
||||
description=self.share_desc,
|
||||
consistency_group_id=consistency_group['id'],
|
||||
cleanup_in_class=False,
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_cgsnapshot_of_cg_that_is_not_available_v2_4(self):
|
||||
consistency_group = self.create_consistency_group(
|
||||
cleanup_in_class=False, version='2.4')
|
||||
self.addCleanup(self.shares_v2_client.consistency_group_reset_state,
|
||||
consistency_group['id'],
|
||||
status='available',
|
||||
version='2.4')
|
||||
# creating
|
||||
self.shares_v2_client.consistency_group_reset_state(
|
||||
consistency_group['id'], status='creating', version='2.4')
|
||||
self.shares_v2_client.wait_for_consistency_group_status(
|
||||
consistency_group['id'], 'creating')
|
||||
self.assertRaises(exceptions.Conflict,
|
||||
self.create_cgsnapshot_wait_for_active,
|
||||
consistency_group['id'],
|
||||
cleanup_in_class=False,
|
||||
version='2.4')
|
||||
# deleting
|
||||
self.shares_v2_client.consistency_group_reset_state(
|
||||
consistency_group['id'], status='deleting', version='2.4')
|
||||
self.shares_v2_client.wait_for_consistency_group_status(
|
||||
consistency_group['id'], 'deleting')
|
||||
self.assertRaises(exceptions.Conflict,
|
||||
self.create_cgsnapshot_wait_for_active,
|
||||
consistency_group['id'],
|
||||
cleanup_in_class=False,
|
||||
version='2.4')
|
||||
# error
|
||||
self.shares_v2_client.consistency_group_reset_state(
|
||||
consistency_group['id'], status='error', version='2.4')
|
||||
self.shares_v2_client.wait_for_consistency_group_status(
|
||||
consistency_group['id'], 'error')
|
||||
self.assertRaises(exceptions.Conflict,
|
||||
self.create_cgsnapshot_wait_for_active,
|
||||
consistency_group['id'],
|
||||
cleanup_in_class=False,
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_cgsnapshot_of_cg_with_share_in_error_state_v2_4(self):
|
||||
consistency_group = self.create_consistency_group(version='2.4')
|
||||
share_name = data_utils.rand_name("tempest-share-name")
|
||||
share_desc = data_utils.rand_name("tempest-share-description")
|
||||
share = self.create_share(
|
||||
name=share_name,
|
||||
description=share_desc,
|
||||
consistency_group_id=consistency_group['id'],
|
||||
cleanup_in_class=False,
|
||||
version='2.4',
|
||||
)
|
||||
self.shares_client.reset_state(s_id=share['id'])
|
||||
self.shares_client.wait_for_share_status(share['id'], 'error')
|
||||
self.assertRaises(exceptions.Conflict,
|
||||
self.create_cgsnapshot_wait_for_active,
|
||||
consistency_group['id'],
|
||||
cleanup_in_class=False,
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_delete_cgsnapshot_not_in_available_or_error_v2_4(self):
|
||||
cgsnapshot = self.create_cgsnapshot_wait_for_active(
|
||||
self.consistency_group['id'],
|
||||
cleanup_in_class=False,
|
||||
version='2.4',
|
||||
)
|
||||
self.addCleanup(self.shares_v2_client.cgsnapshot_reset_state,
|
||||
cgsnapshot['id'],
|
||||
status='available',
|
||||
version='2.4')
|
||||
|
||||
# creating
|
||||
self.shares_v2_client.cgsnapshot_reset_state(cgsnapshot['id'],
|
||||
status='creating',
|
||||
version='2.4')
|
||||
self.shares_v2_client.wait_for_cgsnapshot_status(cgsnapshot['id'],
|
||||
'creating')
|
||||
self.assertRaises(exceptions.Conflict,
|
||||
self.shares_v2_client.delete_cgsnapshot,
|
||||
cgsnapshot['id'],
|
||||
version='2.4')
|
||||
# deleting
|
||||
self.shares_v2_client.cgsnapshot_reset_state(cgsnapshot['id'],
|
||||
status='deleting',
|
||||
version='2.4')
|
||||
self.shares_v2_client.wait_for_cgsnapshot_status(cgsnapshot['id'],
|
||||
'deleting')
|
||||
self.assertRaises(exceptions.Conflict,
|
||||
self.shares_v2_client.delete_cgsnapshot,
|
||||
cgsnapshot['id'],
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_delete_cg_not_in_available_or_error_v2_4(self):
|
||||
consistency_group = self.create_consistency_group(
|
||||
cleanup_in_class=False, version='2.4')
|
||||
self.addCleanup(self.shares_v2_client.consistency_group_reset_state,
|
||||
consistency_group['id'],
|
||||
status='available',
|
||||
version='2.4')
|
||||
# creating
|
||||
self.shares_v2_client.consistency_group_reset_state(
|
||||
consistency_group['id'], status='creating', version='2.4')
|
||||
self.shares_v2_client.wait_for_consistency_group_status(
|
||||
consistency_group['id'], 'creating')
|
||||
self.assertRaises(exceptions.Conflict,
|
||||
self.shares_v2_client.delete_consistency_group,
|
||||
consistency_group['id'],
|
||||
version='2.4')
|
||||
# deleting
|
||||
self.shares_v2_client.consistency_group_reset_state(
|
||||
consistency_group['id'], status='deleting', version='2.4')
|
||||
self.shares_v2_client.wait_for_consistency_group_status(
|
||||
consistency_group['id'], 'deleting')
|
||||
self.assertRaises(exceptions.Conflict,
|
||||
self.shares_v2_client.delete_consistency_group,
|
||||
consistency_group['id'],
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_cg_with_conflicting_share_types_v2_4(self):
|
||||
# Create conflicting share types
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
extra_specs = {"driver_handles_share_servers": False}
|
||||
share_type = self.create_share_type(name, extra_specs=extra_specs)
|
||||
single_tenant_share_type = share_type['share_type']
|
||||
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
extra_specs = {"driver_handles_share_servers": True}
|
||||
share_type = self.create_share_type(name, extra_specs=extra_specs)
|
||||
multi_tenant_share_type = share_type['share_type']
|
||||
|
||||
self.assertRaises(exceptions.BadRequest,
|
||||
self.create_consistency_group,
|
||||
share_type_ids=[single_tenant_share_type['id'],
|
||||
multi_tenant_share_type['id']],
|
||||
cleanup_in_class=False,
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_cg_with_multi_tenant_share_type_and_no_share_network_v2_4(
|
||||
self):
|
||||
# Create multi tenant share type
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
extra_specs = {"driver_handles_share_servers": True}
|
||||
share_type = self.create_share_type(name, extra_specs=extra_specs)
|
||||
multi_tenant_share_type = share_type['share_type']
|
||||
|
||||
def create_cg():
|
||||
cg = self.shares_v2_client.create_consistency_group(
|
||||
share_type_ids=[multi_tenant_share_type['id']],
|
||||
version='2.4'
|
||||
)
|
||||
resource = {
|
||||
"type": "consistency_group",
|
||||
"id": cg["id"],
|
||||
"client": self.shares_client
|
||||
}
|
||||
self.method_resources.insert(0, resource)
|
||||
return cg
|
||||
|
||||
self.assertRaises(exceptions.BadRequest, create_cg)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_update_cg_share_types(self):
|
||||
consistency_group = self.create_consistency_group(
|
||||
cleanup_in_class=False, version='2.4')
|
||||
|
||||
self.assertRaises(exceptions.BadRequest,
|
||||
self.shares_v2_client.update_consistency_group,
|
||||
consistency_group['id'],
|
||||
share_types=[self.share_type['id']],
|
||||
version='2.4')
|
236
manila_tempest_tests/tests/api/admin/test_share_group_types.py
Normal file
236
manila_tempest_tests/tests/api/admin/test_share_group_types.py
Normal file
@ -0,0 +1,236 @@
|
||||
# Copyright 2016 Andrew Kerr
|
||||
# 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 import config
|
||||
from tempest.lib.common.utils import data_utils
|
||||
import testtools
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.common import constants
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
|
||||
@base.skip_if_microversion_lt(constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
class ShareGroupTypesTest(base.BaseSharesAdminTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareGroupTypesTest, cls).resource_setup()
|
||||
|
||||
# Create 2 share_types
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
extra_specs = cls.add_extra_specs_to_dict()
|
||||
share_type = cls.create_share_type(name, extra_specs=extra_specs)
|
||||
cls.share_type = share_type['share_type']
|
||||
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
share_type = cls.create_share_type(name, extra_specs=extra_specs)
|
||||
cls.share_type2 = share_type['share_type']
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_create_get_delete_share_group_type_min(self):
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
|
||||
# Create share group type
|
||||
sg_type_c = self.create_share_group_type(
|
||||
name=name,
|
||||
share_types=self.share_type['id'],
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
self.assertEqual(
|
||||
[self.share_type['id']],
|
||||
sg_type_c['share_types'],
|
||||
'Share type not applied correctly.')
|
||||
|
||||
# Read share group type
|
||||
sg_type_r = self.shares_v2_client.get_share_group_type(sg_type_c['id'])
|
||||
keys = set(sg_type_r.keys())
|
||||
self.assertTrue(
|
||||
constants.SHARE_GROUP_TYPE_REQUIRED_KEYS.issubset(keys),
|
||||
'At least one expected key missing from share group type '
|
||||
'response. Expected %s, got %s.' % (
|
||||
constants.SHARE_GROUP_TYPE_REQUIRED_KEYS, keys))
|
||||
self.assertEqual(sg_type_c['name'], sg_type_r['name'])
|
||||
|
||||
# Delete share group type
|
||||
self.shares_v2_client.delete_share_group_type(
|
||||
sg_type_r['id'], version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
share_group_type_id=sg_type_r['id'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_create_share_group_type_multiple_share_types_min(self):
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
|
||||
sg_type = self.create_share_group_type(
|
||||
name=name,
|
||||
share_types=[self.share_type['id'], self.share_type2['id']],
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
self.assertEqual(
|
||||
{self.share_type['id'], self.share_type2['id']},
|
||||
set(sg_type['share_types']),
|
||||
'Share types not applied correctly.')
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_create_share_group_type_with_one_spec_min(self):
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
group_specs = {'key': 'value'}
|
||||
|
||||
sg_type = self.create_share_group_type(
|
||||
name=name,
|
||||
share_types=self.share_type['id'],
|
||||
group_specs=group_specs,
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
self.assertDictMatch(group_specs, sg_type['group_specs'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_create_share_group_type_with_multiple_specs_min(self):
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
group_specs = {'key1': 'value1', 'key2': 'value2'}
|
||||
|
||||
sg_type = self.create_share_group_type(
|
||||
name=name,
|
||||
share_types=self.share_type['id'],
|
||||
group_specs=group_specs,
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
self.assertDictMatch(group_specs, sg_type['group_specs'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_update_single_share_group_type_spec_min(self):
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
group_specs = {'key1': 'value1', 'key2': 'value2'}
|
||||
|
||||
sg_type = self.create_share_group_type(
|
||||
name=name,
|
||||
share_types=self.share_type['id'],
|
||||
group_specs=group_specs,
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
self.assertDictMatch(group_specs, sg_type['group_specs'])
|
||||
|
||||
group_specs = {'key1': 'value3', 'key2': 'value2'}
|
||||
|
||||
self.shares_v2_client.update_share_group_type_spec(
|
||||
sg_type['id'], 'key1', 'value3')
|
||||
sg_type = self.shares_v2_client.get_share_group_type(sg_type['id'])
|
||||
|
||||
self.assertDictMatch(group_specs, sg_type['group_specs'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_update_all_share_group_type_specs_min(self):
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
group_specs = {'key1': 'value1', 'key2': 'value2'}
|
||||
|
||||
sg_type = self.create_share_group_type(
|
||||
name=name,
|
||||
share_types=self.share_type['id'],
|
||||
group_specs=group_specs,
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
self.assertDictMatch(group_specs, sg_type['group_specs'])
|
||||
|
||||
group_specs = {'key1': 'value3', 'key2': 'value4'}
|
||||
|
||||
self.shares_v2_client.update_share_group_type_specs(
|
||||
sg_type['id'], group_specs)
|
||||
sg_type = self.shares_v2_client.get_share_group_type(sg_type['id'])
|
||||
|
||||
self.assertDictMatch(group_specs, sg_type['group_specs'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_delete_single_share_group_type_spec_min(self):
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
group_specs = {'key1': 'value1', 'key2': 'value2'}
|
||||
|
||||
sg_type = self.create_share_group_type(
|
||||
name=name,
|
||||
share_types=self.share_type['id'],
|
||||
group_specs=group_specs,
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
self.assertDictMatch(group_specs, sg_type['group_specs'])
|
||||
|
||||
key_to_delete = 'key1'
|
||||
group_specs.pop(key_to_delete)
|
||||
|
||||
self.shares_v2_client.delete_share_group_type_spec(
|
||||
sg_type['id'], key_to_delete)
|
||||
sg_type = self.shares_v2_client.get_share_group_type(
|
||||
sg_type['id'])
|
||||
|
||||
self.assertDictMatch(group_specs, sg_type['group_specs'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_private_share_group_type_access(self):
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
group_specs = {"key1": "value1", "key2": "value2"}
|
||||
project_id = self.shares_v2_client.tenant_id
|
||||
|
||||
# Create private share group type
|
||||
sgt_create = self.create_share_group_type(
|
||||
name=name,
|
||||
share_types=[self.share_type['id']],
|
||||
is_public=False,
|
||||
group_specs=group_specs,
|
||||
)
|
||||
self.assertEqual(name, sgt_create['name'])
|
||||
sgt_id = sgt_create["id"]
|
||||
|
||||
# It should not be listed without access
|
||||
sgt_list = self.shares_v2_client.list_share_group_types()
|
||||
self.assertFalse(any(sgt_id == sgt["id"] for sgt in sgt_list))
|
||||
|
||||
# List projects that have access for share group type - none expected
|
||||
access = self.shares_v2_client.list_access_to_share_group_type(sgt_id)
|
||||
self.assertEqual([], access)
|
||||
|
||||
# Add project access to share group type
|
||||
access = self.shares_v2_client.add_access_to_share_group_type(
|
||||
sgt_id, project_id)
|
||||
|
||||
# Now it should be listed
|
||||
sgt_list = self.shares_v2_client.list_share_group_types()
|
||||
self.assertTrue(any(sgt_id == sgt["id"] for sgt in sgt_list))
|
||||
|
||||
# List projects that have access for share group type - one expected
|
||||
access = self.shares_v2_client.list_access_to_share_group_type(sgt_id)
|
||||
expected = [{'share_group_type_id': sgt_id, 'project_id': project_id}]
|
||||
self.assertEqual(expected, access)
|
||||
|
||||
# Remove project access from share group type
|
||||
access = self.shares_v2_client.remove_access_from_share_group_type(
|
||||
sgt_id, project_id)
|
||||
|
||||
# It should not be listed without access
|
||||
sgt_list = self.shares_v2_client.list_share_group_types()
|
||||
self.assertFalse(any(sgt_id == sgt["id"] for sgt in sgt_list))
|
||||
|
||||
# List projects that have access for share group type - none expected
|
||||
access = self.shares_v2_client.list_access_to_share_group_type(sgt_id)
|
||||
self.assertEqual([], access)
|
@ -0,0 +1,128 @@
|
||||
# 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 import config
|
||||
from tempest.lib.common.utils import data_utils
|
||||
from tempest.lib import exceptions as lib_exc
|
||||
import testtools
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.common import constants
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
|
||||
@base.skip_if_microversion_lt(constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
class ShareGroupTypesAdminNegativeTest(base.BaseSharesMixedTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareGroupTypesAdminNegativeTest, cls).resource_setup()
|
||||
cls.share_type = cls.create_share_type(
|
||||
data_utils.rand_name("unique_st_name"),
|
||||
extra_specs=cls.add_extra_specs_to_dict({"key": "value"}),
|
||||
client=cls.admin_shares_v2_client)
|
||||
cls.share_group_type = cls.create_share_group_type(
|
||||
data_utils.rand_name("unique_sgt_name"),
|
||||
share_types=[cls.share_type['share_type']['id']],
|
||||
client=cls.admin_shares_v2_client)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_create_share_ggroup_with_nonexistent_share_type(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.admin_shares_v2_client.create_share_group_type,
|
||||
share_types=data_utils.rand_name("fake"))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_create_share_group_type_with_empty_name(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share_group_type, '',
|
||||
client=self.admin_shares_v2_client)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_create_share_group_type_with_too_big_name(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share_group_type,
|
||||
"x" * 256, client=self.admin_shares_v2_client)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_get_share_group_type_using_nonexistent_id(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.get_share_group_type,
|
||||
data_utils.rand_name("fake"))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_delete_share_group_type_using_nonexistent_id(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.delete_share_group_type,
|
||||
data_utils.rand_name("fake"))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_create_duplicate_of_share_group_type(self):
|
||||
unique_name = data_utils.rand_name("unique_sgt_name")
|
||||
list_of_ids = set()
|
||||
for step in (1, 2):
|
||||
sg_type = self.create_share_group_type(
|
||||
unique_name,
|
||||
share_types=[self.share_type['share_type']['id']],
|
||||
client=self.admin_shares_v2_client,
|
||||
cleanup_in_class=False)
|
||||
self.assertRaises(
|
||||
lib_exc.Conflict,
|
||||
self.create_share_group_type,
|
||||
unique_name,
|
||||
share_types=[self.share_type['share_type']['id']],
|
||||
client=self.admin_shares_v2_client)
|
||||
list_of_ids.add(sg_type['id'])
|
||||
self.assertEqual(unique_name, sg_type['name'])
|
||||
self.admin_shares_v2_client.delete_share_group_type(sg_type['id'])
|
||||
self.assertEqual(2, len(list_of_ids))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_add_project_access_to_public_share_group_type(self):
|
||||
self.assertRaises(
|
||||
lib_exc.Conflict,
|
||||
self.admin_shares_v2_client.add_access_to_share_group_type,
|
||||
self.share_group_type["id"],
|
||||
self.admin_shares_v2_client.tenant_id)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_remove_project_access_from_public_share_group_type(self):
|
||||
self.assertRaises(
|
||||
lib_exc.Conflict,
|
||||
self.admin_shares_v2_client.remove_access_from_share_group_type,
|
||||
self.share_group_type["id"],
|
||||
self.admin_shares_v2_client.tenant_id)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_add_project_access_to_nonexistent_share_group_type(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.add_access_to_share_group_type,
|
||||
data_utils.rand_name("fake"),
|
||||
self.admin_shares_v2_client.tenant_id)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_remove_project_access_from_nonexistent_share_group_type(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.admin_shares_v2_client.remove_access_from_share_group_type,
|
||||
data_utils.rand_name("fake"),
|
||||
self.admin_shares_v2_client.tenant_id)
|
175
manila_tempest_tests/tests/api/admin/test_share_groups.py
Normal file
175
manila_tempest_tests/tests/api/admin/test_share_groups.py
Normal file
@ -0,0 +1,175 @@
|
||||
# Copyright 2016 Andrew Kerr
|
||||
# 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 import config
|
||||
from tempest.lib.common.utils import data_utils
|
||||
import testtools
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.common import constants
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
|
||||
@base.skip_if_microversion_lt(constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
class ShareGroupsTest(base.BaseSharesAdminTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareGroupsTest, cls).resource_setup()
|
||||
# Create 2 share_types
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
extra_specs = cls.add_extra_specs_to_dict()
|
||||
share_type = cls.create_share_type(name, extra_specs=extra_specs)
|
||||
cls.share_type = share_type['share_type']
|
||||
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
share_type = cls.create_share_type(name, extra_specs=extra_specs)
|
||||
cls.share_type2 = share_type['share_type']
|
||||
|
||||
cls.sg_type = cls.create_share_group_type(
|
||||
name=name,
|
||||
share_types=[cls.share_type['id'], cls.share_type2['id']],
|
||||
cleanup_in_class=True,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_create_share_group_with_single_share_type_min(self):
|
||||
share_group = self.create_share_group(
|
||||
share_group_type_id=self.sg_type['id'],
|
||||
cleanup_in_class=False,
|
||||
share_type_ids=[self.share_type['id']],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
keys = set(share_group.keys())
|
||||
self.assertTrue(
|
||||
constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS.issubset(keys),
|
||||
'At least one expected element missing from share group '
|
||||
'response. Expected %(expected)s, got %(actual)s.' % {
|
||||
"expected": constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS,
|
||||
"actual": keys})
|
||||
|
||||
actual_sg_type = share_group['share_group_type_id']
|
||||
expected_sg_type = self.sg_type['id']
|
||||
self.assertEqual(
|
||||
expected_sg_type, actual_sg_type,
|
||||
'Incorrect share group type applied to share group '
|
||||
'%s. Expected %s, got %s' % (
|
||||
share_group['id'], expected_sg_type, actual_sg_type))
|
||||
|
||||
actual_share_types = share_group['share_types']
|
||||
expected_share_types = [self.share_type['id']]
|
||||
self.assertEqual(
|
||||
sorted(expected_share_types),
|
||||
sorted(actual_share_types),
|
||||
'Incorrect share types applied to share group %s. '
|
||||
'Expected %s, got %s' % (
|
||||
share_group['id'], expected_share_types, actual_share_types))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_create_share_group_with_multiple_share_types_min(self):
|
||||
share_group = self.create_share_group(
|
||||
share_group_type_id=self.sg_type['id'],
|
||||
cleanup_in_class=False,
|
||||
share_type_ids=[self.share_type['id'], self.share_type2['id']],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
keys = set(share_group.keys())
|
||||
self.assertTrue(
|
||||
constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS.issubset(keys),
|
||||
'At least one expected element missing from share group '
|
||||
'response. Expected %(expected)s, got %(actual)s.' % {
|
||||
"expected": constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS,
|
||||
"actual": keys})
|
||||
|
||||
actual_sg_type = share_group['share_group_type_id']
|
||||
expected_sg_type = self.sg_type['id']
|
||||
self.assertEqual(
|
||||
expected_sg_type, actual_sg_type,
|
||||
'Incorrect share group type applied to share group %s. '
|
||||
'Expected %s, got %s' % (
|
||||
share_group['id'], expected_sg_type, actual_sg_type))
|
||||
|
||||
actual_share_types = share_group['share_types']
|
||||
expected_share_types = [self.share_type['id'], self.share_type2['id']]
|
||||
self.assertEqual(
|
||||
sorted(expected_share_types),
|
||||
sorted(actual_share_types),
|
||||
'Incorrect share types applied to share group %s. '
|
||||
'Expected %s, got %s' % (
|
||||
share_group['id'], expected_share_types, actual_share_types))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_default_share_group_type_applied(self):
|
||||
default_type = self.shares_v2_client.get_default_share_group_type()
|
||||
default_share_types = default_type['share_types']
|
||||
|
||||
share_group = self.create_share_group(
|
||||
cleanup_in_class=False,
|
||||
share_type_ids=default_share_types,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
keys = set(share_group.keys())
|
||||
self.assertTrue(
|
||||
constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS.issubset(keys),
|
||||
'At least one expected element missing from share group '
|
||||
'response. Expected %(expected)s, got %(actual)s.' % {
|
||||
"expected": constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS,
|
||||
"actual": keys})
|
||||
|
||||
actual_sg_type = share_group['share_group_type_id']
|
||||
expected_sg_type = default_type['id']
|
||||
self.assertEqual(
|
||||
expected_sg_type, actual_sg_type,
|
||||
'Incorrect share group type applied to share group %s. '
|
||||
'Expected %s, got %s' % (
|
||||
share_group['id'], expected_sg_type, actual_sg_type))
|
||||
|
||||
@testtools.skipUnless(
|
||||
CONF.share.multitenancy_enabled, "Only for multitenancy.")
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_create_sg_from_snapshot_verify_share_server_information_min(self):
|
||||
# Create a share group
|
||||
orig_sg = self.create_share_group(
|
||||
share_group_type_id=self.sg_type['id'],
|
||||
cleanup_in_class=False,
|
||||
share_type_ids=[self.share_type['id']],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
# Get latest share group information
|
||||
orig_sg = self.shares_v2_client.get_share_group(
|
||||
orig_sg['id'], version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
# Assert share server information
|
||||
self.assertIsNotNone(orig_sg['share_network_id'])
|
||||
self.assertIsNotNone(orig_sg['share_server_id'])
|
||||
|
||||
sg_snapshot = self.create_share_group_snapshot_wait_for_active(
|
||||
orig_sg['id'], cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
new_sg = self.create_share_group(
|
||||
share_group_type_id=self.sg_type['id'],
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
source_share_group_snapshot_id=sg_snapshot['id'])
|
||||
|
||||
# Assert share server information
|
||||
self.assertEqual(
|
||||
orig_sg['share_network_id'], new_sg['share_network_id'])
|
||||
self.assertEqual(
|
||||
orig_sg['share_server_id'], new_sg['share_server_id'])
|
@ -392,7 +392,7 @@ class BaseSharesTest(test.BaseTestCase):
|
||||
def _create_share(cls, share_protocol=None, size=None, name=None,
|
||||
snapshot_id=None, description=None, metadata=None,
|
||||
share_network_id=None, share_type_id=None,
|
||||
consistency_group_id=None, client=None,
|
||||
share_group_id=None, client=None,
|
||||
cleanup_in_class=True, is_public=False, **kwargs):
|
||||
client = client or cls.shares_v2_client
|
||||
description = description or "Tempest's share"
|
||||
@ -410,12 +410,12 @@ class BaseSharesTest(test.BaseTestCase):
|
||||
'share_type_id': share_type_id,
|
||||
'is_public': is_public,
|
||||
})
|
||||
if consistency_group_id:
|
||||
kwargs['consistency_group_id'] = consistency_group_id
|
||||
if share_group_id:
|
||||
kwargs['share_group_id'] = share_group_id
|
||||
|
||||
share = client.create_share(**kwargs)
|
||||
resource = {"type": "share", "id": share["id"], "client": client,
|
||||
"consistency_group_id": consistency_group_id}
|
||||
"share_group_id": share_group_id}
|
||||
cleanup_list = (cls.class_resources if cleanup_in_class else
|
||||
cls.method_resources)
|
||||
cleanup_list.insert(0, resource)
|
||||
@ -540,41 +540,63 @@ class BaseSharesTest(test.BaseTestCase):
|
||||
return [d["share"] for d in data]
|
||||
|
||||
@classmethod
|
||||
def create_consistency_group(cls, client=None, cleanup_in_class=True,
|
||||
share_network_id=None, **kwargs):
|
||||
def create_share_group(cls, client=None, cleanup_in_class=True,
|
||||
share_network_id=None, **kwargs):
|
||||
client = client or cls.shares_v2_client
|
||||
if kwargs.get('source_cgsnapshot_id') is None:
|
||||
if kwargs.get('source_share_group_snapshot_id') is None:
|
||||
kwargs['share_network_id'] = (share_network_id or
|
||||
client.share_network_id or None)
|
||||
consistency_group = client.create_consistency_group(**kwargs)
|
||||
share_group = client.create_share_group(**kwargs)
|
||||
resource = {
|
||||
"type": "consistency_group",
|
||||
"id": consistency_group["id"],
|
||||
"client": client}
|
||||
"type": "share_group",
|
||||
"id": share_group["id"],
|
||||
"client": client,
|
||||
}
|
||||
if cleanup_in_class:
|
||||
cls.class_resources.insert(0, resource)
|
||||
else:
|
||||
cls.method_resources.insert(0, resource)
|
||||
|
||||
if kwargs.get('source_cgsnapshot_id'):
|
||||
new_cg_shares = client.list_shares(
|
||||
if kwargs.get('source_share_group_snapshot_id'):
|
||||
new_share_group_shares = client.list_shares(
|
||||
detailed=True,
|
||||
params={'consistency_group_id': consistency_group['id']})
|
||||
params={'share_group_id': share_group['id']},
|
||||
experimental=True)
|
||||
|
||||
for share in new_cg_shares:
|
||||
for share in new_share_group_shares:
|
||||
resource = {"type": "share",
|
||||
"id": share["id"],
|
||||
"client": client,
|
||||
"consistency_group_id": share.get(
|
||||
'consistency_group_id')}
|
||||
"share_group_id": share.get("share_group_id")}
|
||||
if cleanup_in_class:
|
||||
cls.class_resources.insert(0, resource)
|
||||
else:
|
||||
cls.method_resources.insert(0, resource)
|
||||
|
||||
client.wait_for_consistency_group_status(consistency_group['id'],
|
||||
'available')
|
||||
return consistency_group
|
||||
client.wait_for_share_group_status(share_group['id'], 'available')
|
||||
return share_group
|
||||
|
||||
@classmethod
|
||||
def create_share_group_type(cls, name=None, share_types=(), is_public=None,
|
||||
group_specs=None, client=None,
|
||||
cleanup_in_class=True, **kwargs):
|
||||
client = client or cls.shares_v2_client
|
||||
share_group_type = client.create_share_group_type(
|
||||
name=name,
|
||||
share_types=share_types,
|
||||
is_public=is_public,
|
||||
group_specs=group_specs,
|
||||
**kwargs)
|
||||
resource = {
|
||||
"type": "share_group_type",
|
||||
"id": share_group_type["id"],
|
||||
"client": client,
|
||||
}
|
||||
if cleanup_in_class:
|
||||
cls.class_resources.insert(0, resource)
|
||||
else:
|
||||
cls.method_resources.insert(0, resource)
|
||||
return share_group_type
|
||||
|
||||
@classmethod
|
||||
def create_snapshot_wait_for_active(cls, share_id, name=None,
|
||||
@ -598,28 +620,26 @@ class BaseSharesTest(test.BaseTestCase):
|
||||
return snapshot
|
||||
|
||||
@classmethod
|
||||
def create_cgsnapshot_wait_for_active(cls, consistency_group_id,
|
||||
name=None, description=None,
|
||||
client=None, cleanup_in_class=True,
|
||||
**kwargs):
|
||||
def create_share_group_snapshot_wait_for_active(
|
||||
cls, share_group_id, name=None, description=None, client=None,
|
||||
cleanup_in_class=True, **kwargs):
|
||||
client = client or cls.shares_v2_client
|
||||
if description is None:
|
||||
description = "Tempest's cgsnapshot"
|
||||
cgsnapshot = client.create_cgsnapshot(consistency_group_id,
|
||||
name=name,
|
||||
description=description,
|
||||
**kwargs)
|
||||
description = "Tempest's share group snapshot"
|
||||
sg_snapshot = client.create_share_group_snapshot(
|
||||
share_group_id, name=name, description=description, **kwargs)
|
||||
resource = {
|
||||
"type": "cgsnapshot",
|
||||
"id": cgsnapshot["id"],
|
||||
"type": "share_group_snapshot",
|
||||
"id": sg_snapshot["id"],
|
||||
"client": client,
|
||||
}
|
||||
if cleanup_in_class:
|
||||
cls.class_resources.insert(0, resource)
|
||||
else:
|
||||
cls.method_resources.insert(0, resource)
|
||||
client.wait_for_cgsnapshot_status(cgsnapshot["id"], "available")
|
||||
return cgsnapshot
|
||||
client.wait_for_share_group_snapshot_status(
|
||||
sg_snapshot["id"], "available")
|
||||
return sg_snapshot
|
||||
|
||||
@classmethod
|
||||
def get_availability_zones(cls, client=None):
|
||||
@ -800,7 +820,6 @@ class BaseSharesTest(test.BaseTestCase):
|
||||
|
||||
:param resources: dict with keys 'type','id','client' and 'deleted'
|
||||
"""
|
||||
|
||||
if resources is None:
|
||||
resources = cls.method_resources
|
||||
for res in resources:
|
||||
@ -814,9 +833,9 @@ class BaseSharesTest(test.BaseTestCase):
|
||||
with handle_cleanup_exceptions():
|
||||
if res["type"] is "share":
|
||||
cls.clear_share_replicas(res_id)
|
||||
cg_id = res.get('consistency_group_id')
|
||||
if cg_id:
|
||||
params = {'consistency_group_id': cg_id}
|
||||
share_group_id = res.get('share_group_id')
|
||||
if share_group_id:
|
||||
params = {'share_group_id': share_group_id}
|
||||
client.delete_share(res_id, params=params)
|
||||
else:
|
||||
client.delete_share(res_id)
|
||||
@ -833,12 +852,18 @@ class BaseSharesTest(test.BaseTestCase):
|
||||
elif res["type"] is "share_type":
|
||||
client.delete_share_type(res_id)
|
||||
client.wait_for_resource_deletion(st_id=res_id)
|
||||
elif res["type"] is "consistency_group":
|
||||
client.delete_consistency_group(res_id)
|
||||
client.wait_for_resource_deletion(cg_id=res_id)
|
||||
elif res["type"] is "cgsnapshot":
|
||||
client.delete_cgsnapshot(res_id)
|
||||
client.wait_for_resource_deletion(cgsnapshot_id=res_id)
|
||||
elif res["type"] is "share_group":
|
||||
client.delete_share_group(res_id)
|
||||
client.wait_for_resource_deletion(
|
||||
share_group_id=res_id)
|
||||
elif res["type"] is "share_group_type":
|
||||
client.delete_share_group_type(res_id)
|
||||
client.wait_for_resource_deletion(
|
||||
share_group_type_id=res_id)
|
||||
elif res["type"] is "share_group_snapshot":
|
||||
client.delete_share_group_snapshot(res_id)
|
||||
client.wait_for_resource_deletion(
|
||||
share_group_snapshot_id=res_id)
|
||||
elif res["type"] is "share_replica":
|
||||
client.delete_share_replica(res_id)
|
||||
client.wait_for_resource_deletion(replica_id=res_id)
|
||||
|
@ -1,377 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2015 Andrew Kerr
|
||||
# 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 import config
|
||||
from tempest.lib.common.utils import data_utils
|
||||
import testtools
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
CG_SIMPLE_KEYS = {"id", "name", "links"}
|
||||
CG_DETAIL_REQUIRED_KEYS = {"id", "name", "description", "created_at", "status",
|
||||
"project_id", "host", "links"}
|
||||
CGSNAPSHOT_SIMPLE_KEYS = {"id", "name", "links"}
|
||||
CGSNAPSHOT_DETAIL_REQUIRED_KEYS = {"id", "name", "description", "created_at",
|
||||
"status", "project_id", "links"}
|
||||
|
||||
|
||||
@testtools.skipUnless(CONF.share.run_consistency_group_tests,
|
||||
'Consistency Group tests disabled.')
|
||||
class ConsistencyGroupActionsTest(base.BaseSharesTest):
|
||||
"""Covers consistency group functionality."""
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ConsistencyGroupActionsTest, cls).resource_setup()
|
||||
|
||||
# Create first consistency group
|
||||
cls.cg_name = data_utils.rand_name("tempest-cg-name")
|
||||
cls.cg_desc = data_utils.rand_name("tempest-cg-description")
|
||||
cls.cg = cls.create_consistency_group(
|
||||
name=cls.cg_name, description=cls.cg_desc)
|
||||
|
||||
# Create second consistency group for purposes of sorting and snapshot
|
||||
# filtering
|
||||
cls.cg2 = cls.create_consistency_group(
|
||||
name=cls.cg_name, description=cls.cg_desc)
|
||||
|
||||
# Create 2 shares inside first CG and 1 inside second CG
|
||||
cls.share_name = data_utils.rand_name("tempest-share-name")
|
||||
cls.share_desc = data_utils.rand_name("tempest-share-description")
|
||||
cls.share_size = CONF.share.share_size
|
||||
cls.share_size2 = cls.share_size + 1
|
||||
cls.shares = cls.create_shares([
|
||||
{'kwargs': {
|
||||
'name': cls.share_name,
|
||||
'description': cls.share_desc,
|
||||
'size': size,
|
||||
'consistency_group_id': cg_id,
|
||||
}} for size, cg_id in ((cls.share_size, cls.cg['id']),
|
||||
(cls.share_size2, cls.cg['id']),
|
||||
(cls.share_size, cls.cg2['id']))
|
||||
])
|
||||
|
||||
# Create CG snapshots
|
||||
cls.cgsnap_name = data_utils.rand_name("tempest-cgsnap-name")
|
||||
cls.cgsnap_desc = data_utils.rand_name("tempest-cgsnap-description")
|
||||
|
||||
cls.cgsnapshot = cls.create_cgsnapshot_wait_for_active(
|
||||
cls.cg["id"],
|
||||
name=cls.cgsnap_name,
|
||||
description=cls.cgsnap_desc)
|
||||
|
||||
cls.cgsnapshot2 = cls.create_cgsnapshot_wait_for_active(
|
||||
cls.cg2['id'], name=cls.cgsnap_name, description=cls.cgsnap_desc)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_consistency_group_v2_4(self):
|
||||
|
||||
# Get consistency group
|
||||
consistency_group = self.shares_v2_client.get_consistency_group(
|
||||
self.cg['id'], version='2.4')
|
||||
|
||||
# Verify keys
|
||||
actual_keys = set(consistency_group.keys())
|
||||
self.assertTrue(CG_DETAIL_REQUIRED_KEYS.issubset(actual_keys),
|
||||
'Not all required keys returned for consistency '
|
||||
'group %s. Expected at least: %s, found %s' % (
|
||||
consistency_group['id'],
|
||||
CG_DETAIL_REQUIRED_KEYS,
|
||||
actual_keys))
|
||||
|
||||
# Verify values
|
||||
msg = "Expected name: '%s', actual name: '%s'" % (
|
||||
self.cg_name, consistency_group["name"])
|
||||
self.assertEqual(self.cg_name, str(consistency_group["name"]), msg)
|
||||
|
||||
msg = "Expected description: '%s', actual description: '%s'" % (
|
||||
self.cg_desc, consistency_group["description"])
|
||||
self.assertEqual(self.cg_desc, str(consistency_group["description"]),
|
||||
msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_share_v2_4(self):
|
||||
|
||||
# Get share
|
||||
share = self.shares_v2_client.get_share(self.shares[0]['id'],
|
||||
version='2.4')
|
||||
|
||||
# Verify keys
|
||||
expected_keys = {"status", "description", "links", "availability_zone",
|
||||
"created_at", "export_location", "share_proto",
|
||||
"name", "snapshot_id", "id", "size",
|
||||
"consistency_group_id"}
|
||||
actual_keys = set(share.keys())
|
||||
self.assertTrue(expected_keys.issubset(actual_keys),
|
||||
'Not all required keys returned for share %s. '
|
||||
'Expected at least: %s, found %s' % (share['id'],
|
||||
expected_keys,
|
||||
actual_keys))
|
||||
|
||||
# Verify values
|
||||
msg = "Expected name: '%s', actual name: '%s'" % (self.share_name,
|
||||
share["name"])
|
||||
self.assertEqual(self.share_name, str(share["name"]), msg)
|
||||
|
||||
msg = "Expected description: '%s', actual description: '%s'" % (
|
||||
self.share_desc, share["description"])
|
||||
self.assertEqual(self.share_desc, str(share["description"]), msg)
|
||||
|
||||
msg = "Expected size: '%s', actual size: '%s'" % (self.share_size,
|
||||
share["size"])
|
||||
self.assertEqual(self.share_size, int(share["size"]), msg)
|
||||
|
||||
msg = "Expected consistency_group_id: '%s', actual value: '%s'" % (
|
||||
self.cg["id"], share["consistency_group_id"])
|
||||
self.assertEqual(self.cg["id"], share["consistency_group_id"], msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_consistency_groups_v2_4(self):
|
||||
|
||||
# List consistency groups
|
||||
consistency_groups = self.shares_v2_client.list_consistency_groups(
|
||||
version='2.4')
|
||||
|
||||
# Verify keys
|
||||
[self.assertEqual(CG_SIMPLE_KEYS, set(cg.keys())) for cg in
|
||||
consistency_groups]
|
||||
|
||||
# Consistency group ids are in list exactly once
|
||||
for cg_id in (self.cg["id"], self.cg2["id"]):
|
||||
gen = [cgid["id"] for cgid in consistency_groups
|
||||
if cgid["id"] == cg_id]
|
||||
msg = ("Expected id %s exactly once in consistency group list" %
|
||||
cg_id)
|
||||
self.assertEqual(1, len(gen), msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_consistency_groups_with_detail_v2_4(self):
|
||||
|
||||
# List consistency groups
|
||||
consistency_groups = self.shares_v2_client.list_consistency_groups(
|
||||
detailed=True, version='2.4')
|
||||
|
||||
# Verify keys
|
||||
[self.assertTrue(CG_DETAIL_REQUIRED_KEYS.issubset(set(cg.keys())))
|
||||
for cg in consistency_groups]
|
||||
|
||||
# Consistency group ids are in list exactly once
|
||||
for cg_id in (self.cg["id"], self.cg2["id"]):
|
||||
gen = [cgid["id"] for cgid in consistency_groups
|
||||
if cgid["id"] == cg_id]
|
||||
msg = ("Expected id %s exactly once in consistency group list" %
|
||||
cg_id)
|
||||
self.assertEqual(1, len(gen), msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_filter_shares_by_consistency_group_id_v2_4(self):
|
||||
|
||||
shares = self.shares_v2_client.list_shares(
|
||||
detailed=True,
|
||||
params={'consistency_group_id': self.cg['id']},
|
||||
version='2.4'
|
||||
)
|
||||
|
||||
share_ids = [share['id'] for share in shares]
|
||||
|
||||
self.assertEqual(2, len(shares),
|
||||
'Incorrect number of shares returned. Expected 2, '
|
||||
'got %s' % len(shares))
|
||||
self.assertIn(self.shares[0]['id'], share_ids,
|
||||
'Share %s expected in returned list, but got %s'
|
||||
% (self.shares[0]['id'], share_ids))
|
||||
self.assertIn(self.shares[1]['id'], share_ids,
|
||||
'Share %s expected in returned list, but got %s'
|
||||
% (self.shares[0]['id'], share_ids))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_cgsnapshot_v2_4(self):
|
||||
|
||||
# Get consistency group
|
||||
consistency_group = self.shares_v2_client.get_consistency_group(
|
||||
self.cg['id'], version='2.4')
|
||||
|
||||
# Verify keys
|
||||
actual_keys = set(consistency_group.keys())
|
||||
self.assertTrue(CG_DETAIL_REQUIRED_KEYS.issubset(actual_keys),
|
||||
'Not all required keys returned for consistency '
|
||||
'group %s. Expected at least: %s, found %s' % (
|
||||
consistency_group['id'],
|
||||
CG_DETAIL_REQUIRED_KEYS,
|
||||
actual_keys))
|
||||
|
||||
# Verify values
|
||||
msg = "Expected name: '%s', actual name: '%s'" % (
|
||||
self.cg_name, consistency_group["name"])
|
||||
self.assertEqual(self.cg_name, str(consistency_group["name"]), msg)
|
||||
|
||||
msg = "Expected description: '%s', actual description: '%s'" % (
|
||||
self.cg_desc, consistency_group["description"])
|
||||
self.assertEqual(self.cg_desc, str(consistency_group["description"]),
|
||||
msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_cgsnapshot_members_v2_4(self):
|
||||
|
||||
cgsnapshot_members = self.shares_v2_client.list_cgsnapshot_members(
|
||||
self.cgsnapshot['id'], version='2.4')
|
||||
member_share_ids = [member['share_id'] for member in
|
||||
cgsnapshot_members]
|
||||
self.assertEqual(2, len(cgsnapshot_members),
|
||||
'Unexpected number of cgsnapshot members. Expected '
|
||||
'2, got %s.' % len(cgsnapshot_members))
|
||||
# Verify each share is represented in the cgsnapshot appropriately
|
||||
for share_id in (self.shares[0]['id'], self.shares[1]['id']):
|
||||
self.assertIn(share_id, member_share_ids,
|
||||
'Share missing %s missing from cgsnapshot. Found %s.'
|
||||
% (share_id, member_share_ids))
|
||||
for share in (self.shares[0], self.shares[1]):
|
||||
for member in cgsnapshot_members:
|
||||
if share['id'] == member['share_id']:
|
||||
self.assertEqual(share['size'], member['size'])
|
||||
self.assertEqual(share['share_proto'],
|
||||
member['share_protocol'])
|
||||
# TODO(akerr): Add back assert when bug 1483886 is fixed
|
||||
# self.assertEqual(share['share_type'],
|
||||
# member['share_type_id'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
def test_create_consistency_group_from_populated_cgsnapshot_v2_4(self):
|
||||
|
||||
cgsnapshot_members = self.shares_v2_client.list_cgsnapshot_members(
|
||||
self.cgsnapshot['id'], version='2.4')
|
||||
|
||||
new_consistency_group = self.create_consistency_group(
|
||||
cleanup_in_class=False,
|
||||
source_cgsnapshot_id=self.cgsnapshot['id'],
|
||||
version='2.4'
|
||||
)
|
||||
|
||||
new_consistency_group = self.shares_v2_client.get_consistency_group(
|
||||
new_consistency_group['id'], version='2.4')
|
||||
|
||||
# Verify that share_network information matches source CG
|
||||
self.assertEqual(self.cg['share_network_id'],
|
||||
new_consistency_group['share_network_id'])
|
||||
|
||||
new_shares = self.shares_v2_client.list_shares(
|
||||
params={'consistency_group_id': new_consistency_group['id']},
|
||||
detailed=True,
|
||||
version='2.4'
|
||||
)
|
||||
|
||||
# Verify each new share is available
|
||||
for share in new_shares:
|
||||
self.assertEqual('available', share['status'],
|
||||
'Share %s is not in available status.'
|
||||
% share['id'])
|
||||
|
||||
# Verify each cgsnapshot member is represented in the new cg
|
||||
# appropriately
|
||||
share_source_member_ids = [share['source_cgsnapshot_member_id'] for
|
||||
share in new_shares]
|
||||
for member in cgsnapshot_members:
|
||||
self.assertIn(member['id'], share_source_member_ids,
|
||||
'cgsnapshot member %s not represented by '
|
||||
'consistency group %s.' % (
|
||||
member['id'], new_consistency_group['id']))
|
||||
for share in new_shares:
|
||||
if share['source_cgsnapshot_member_id'] == member['id']:
|
||||
self.assertEqual(member['size'], share['size'])
|
||||
self.assertEqual(member['share_protocol'],
|
||||
share['share_proto'])
|
||||
# TODO(akerr): Add back assert when bug 1483886 is fixed
|
||||
# self.assertEqual(member['share_type_id'],
|
||||
# share['share_type'])
|
||||
self.assertEqual(self.cg['share_network_id'],
|
||||
share['share_network_id'])
|
||||
|
||||
|
||||
@testtools.skipUnless(CONF.share.run_consistency_group_tests,
|
||||
'Consistency Group tests disabled.')
|
||||
class ConsistencyGroupRenameTest(base.BaseSharesTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ConsistencyGroupRenameTest, cls).resource_setup()
|
||||
|
||||
# Create consistency group
|
||||
cls.cg_name = data_utils.rand_name("tempest-cg-name")
|
||||
cls.cg_desc = data_utils.rand_name("tempest-cg-description")
|
||||
cls.consistency_group = cls.create_consistency_group(
|
||||
name=cls.cg_name,
|
||||
description=cls.cg_desc,
|
||||
)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_update_consistency_group_v2_4(self):
|
||||
|
||||
# Get consistency_group
|
||||
consistency_group = self.shares_v2_client.get_consistency_group(
|
||||
self.consistency_group['id'], version='2.4')
|
||||
self.assertEqual(self.cg_name, consistency_group["name"])
|
||||
self.assertEqual(self.cg_desc, consistency_group["description"])
|
||||
|
||||
# Update consistency_group
|
||||
new_name = data_utils.rand_name("tempest-new-name")
|
||||
new_desc = data_utils.rand_name("tempest-new-description")
|
||||
updated = self.shares_v2_client.update_consistency_group(
|
||||
consistency_group["id"],
|
||||
name=new_name,
|
||||
description=new_desc,
|
||||
version='2.4'
|
||||
)
|
||||
self.assertEqual(new_name, updated["name"])
|
||||
self.assertEqual(new_desc, updated["description"])
|
||||
|
||||
# Get consistency_group
|
||||
consistency_group = self.shares_v2_client.get_consistency_group(
|
||||
self.consistency_group['id'], version='2.4')
|
||||
self.assertEqual(new_name, consistency_group["name"])
|
||||
self.assertEqual(new_desc, consistency_group["description"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_update_read_consistency_group_with_unicode_v2_4(self):
|
||||
value1 = u'ಠ_ಠ'
|
||||
value2 = u'ಠ_ರೃ'
|
||||
# Create consistency_group
|
||||
consistency_group = self.create_consistency_group(
|
||||
cleanup_in_class=False,
|
||||
name=value1,
|
||||
description=value1,
|
||||
version='2.4'
|
||||
)
|
||||
self.assertEqual(value1, consistency_group["name"])
|
||||
self.assertEqual(value1, consistency_group["description"])
|
||||
|
||||
# Update consistency_group
|
||||
updated = self.shares_v2_client.update_consistency_group(
|
||||
consistency_group["id"],
|
||||
name=value2,
|
||||
description=value2,
|
||||
version='2.4'
|
||||
)
|
||||
self.assertEqual(value2, updated["name"])
|
||||
self.assertEqual(value2, updated["description"])
|
||||
|
||||
# Get consistency_group
|
||||
consistency_group = self.shares_v2_client.get_consistency_group(
|
||||
consistency_group['id'], version='2.4')
|
||||
self.assertEqual(value2, consistency_group["name"])
|
||||
self.assertEqual(value2, consistency_group["description"])
|
@ -1,144 +0,0 @@
|
||||
# Copyright 2015 Andrew Kerr
|
||||
# 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 import config
|
||||
from tempest.lib import exceptions as lib_exc
|
||||
import testtools
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
CG_REQUIRED_ELEMENTS = {"id", "name", "description", "created_at", "status",
|
||||
"share_types", "project_id", "host", "links"}
|
||||
CGSNAPSHOT_REQUIRED_ELEMENTS = {"id", "name", "description", "created_at",
|
||||
"status", "project_id", "links"}
|
||||
|
||||
|
||||
@testtools.skipUnless(CONF.share.run_consistency_group_tests,
|
||||
'Consistency Group tests disabled.')
|
||||
class ConsistencyGroupsTest(base.BaseSharesTest):
|
||||
"""Covers consistency group functionality."""
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
|
||||
def test_create_populate_delete_consistency_group_v2_4(self):
|
||||
# Create a consistency group
|
||||
consistency_group = self.create_consistency_group(
|
||||
cleanup_in_class=False, version='2.4')
|
||||
self.assertTrue(CG_REQUIRED_ELEMENTS.issubset(
|
||||
consistency_group.keys()),
|
||||
'At least one expected element missing from consistency group '
|
||||
'response. Expected %(expected)s, got %(actual)s.' % {
|
||||
"expected": CG_REQUIRED_ELEMENTS,
|
||||
"actual": consistency_group.keys()})
|
||||
# Populate
|
||||
share = self.create_share(consistency_group_id=consistency_group['id'],
|
||||
cleanup_in_class=False,
|
||||
version='2.4')
|
||||
# Delete
|
||||
params = {"consistency_group_id": consistency_group['id']}
|
||||
self.shares_v2_client.delete_share(share['id'], params=params,
|
||||
version='2.4')
|
||||
self.shares_client.wait_for_resource_deletion(share_id=share['id'])
|
||||
self.shares_v2_client.delete_consistency_group(consistency_group['id'],
|
||||
version='2.4')
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
cg_id=consistency_group['id'])
|
||||
|
||||
# Verify
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_v2_client.get_consistency_group,
|
||||
consistency_group['id'])
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.get_share,
|
||||
share['id'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_delete_empty_cgsnapshot_v2_4(self):
|
||||
# Create base consistency group
|
||||
consistency_group = self.create_consistency_group(
|
||||
cleanup_in_class=False, version='2.4')
|
||||
# Create cgsnapshot
|
||||
cgsnapshot = self.create_cgsnapshot_wait_for_active(
|
||||
consistency_group["id"], cleanup_in_class=False, version='2.4')
|
||||
|
||||
self.assertTrue(CGSNAPSHOT_REQUIRED_ELEMENTS.issubset(
|
||||
cgsnapshot.keys()),
|
||||
'At least one expected element missing from cgsnapshot response. '
|
||||
'Expected %(expected)s, got %(actual)s.' % {
|
||||
"expected": CGSNAPSHOT_REQUIRED_ELEMENTS,
|
||||
"actual": cgsnapshot.keys()})
|
||||
|
||||
cgsnapshot_members = self.shares_v2_client.list_cgsnapshot_members(
|
||||
cgsnapshot['id'], version='2.4')
|
||||
|
||||
self.assertEmpty(cgsnapshot_members,
|
||||
'Expected 0 cgsnapshot members, got %s' % len(
|
||||
cgsnapshot_members))
|
||||
|
||||
# delete snapshot
|
||||
self.shares_v2_client.delete_cgsnapshot(cgsnapshot["id"],
|
||||
version='2.4')
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
cgsnapshot_id=cgsnapshot["id"])
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_v2_client.get_cgsnapshot,
|
||||
cgsnapshot['id'],
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_consistency_group_from_empty_cgsnapshot(self):
|
||||
# Create base consistency group
|
||||
consistency_group = self.create_consistency_group(
|
||||
cleanup_in_class=False)
|
||||
|
||||
# Create cgsnapshot
|
||||
cgsnapshot = self.create_cgsnapshot_wait_for_active(
|
||||
consistency_group["id"], cleanup_in_class=False)
|
||||
|
||||
cgsnapshot_members = self.shares_v2_client.list_cgsnapshot_members(
|
||||
cgsnapshot['id'])
|
||||
|
||||
self.assertEmpty(cgsnapshot_members,
|
||||
'Expected 0 cgsnapshot members, got %s' % len(
|
||||
cgsnapshot_members))
|
||||
|
||||
new_consistency_group = self.create_consistency_group(
|
||||
cleanup_in_class=False, source_cgsnapshot_id=cgsnapshot['id'])
|
||||
|
||||
new_shares = self.shares_client.list_shares(
|
||||
params={'consistency_group_id': new_consistency_group['id']})
|
||||
|
||||
self.assertEmpty(new_shares,
|
||||
'Expected 0 new shares, got %s' % len(new_shares))
|
||||
|
||||
msg = 'Expected cgsnapshot_id %s as source of consistency group %s' % (
|
||||
cgsnapshot['id'], new_consistency_group['source_cgsnapshot_id'])
|
||||
self.assertEqual(new_consistency_group['source_cgsnapshot_id'],
|
||||
cgsnapshot['id'], msg)
|
||||
|
||||
msg = ('Unexpected share_types on new consistency group. Expected '
|
||||
'%s, got %s.' % (consistency_group['share_types'],
|
||||
new_consistency_group['share_types']))
|
||||
self.assertEqual(sorted(consistency_group['share_types']),
|
||||
sorted(new_consistency_group['share_types']), msg)
|
||||
|
||||
# Assert the share_network information is the same
|
||||
msg = 'Expected share_network %s as share_network of cg %s' % (
|
||||
consistency_group['share_network_id'],
|
||||
new_consistency_group['share_network_id'])
|
||||
self.assertEqual(consistency_group['share_network_id'],
|
||||
new_consistency_group['share_network_id'],
|
||||
msg)
|
@ -1,226 +0,0 @@
|
||||
# Copyright 2015 Andrew Kerr
|
||||
# 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 import config
|
||||
from tempest.lib.common.utils import data_utils
|
||||
from tempest.lib import exceptions as lib_exc
|
||||
import testtools
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@testtools.skipUnless(CONF.share.run_consistency_group_tests,
|
||||
'Consistency Group tests disabled.')
|
||||
class ConsistencyGroupsAPIOnlyNegativeTest(base.BaseSharesTest):
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_delete_cg_without_passing_cg_id_v2_4(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_v2_client.delete_consistency_group,
|
||||
'',
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_delete_cg_with_wrong_id_v2_4(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_v2_client.delete_consistency_group,
|
||||
"wrong_consistency_group_id",
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_update_cg_with_wrong_id_v2_4(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_v2_client.update_consistency_group,
|
||||
'wrong_consistency_group_id',
|
||||
name='new_name',
|
||||
description='new_description',
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_get_cg_without_passing_cg_id_v2_4(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_v2_client.get_consistency_group,
|
||||
'',
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_filter_shares_on_invalid_cg_id_v2_4(self):
|
||||
shares = self.shares_v2_client.list_shares(
|
||||
detailed=True,
|
||||
params={'consistency_group_id': 'foobar'},
|
||||
version='2.4',
|
||||
)
|
||||
|
||||
self.assertEqual(0, len(shares),
|
||||
'Incorrect number of shares returned. Expected 0, '
|
||||
'got %s.' % len(shares))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_create_cgsnapshot_with_invalid_cg_id_value_v2_4(self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.create_cgsnapshot_wait_for_active,
|
||||
'foobar',
|
||||
cleanup_in_class=False,
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_create_cg_with_invalid_share_type_id_value_v2_4(self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.create_consistency_group,
|
||||
share_type_ids=['foobar'],
|
||||
cleanup_in_class=False,
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_create_cg_with_invalid_share_network_id_value_v2_4(self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.create_consistency_group,
|
||||
share_network_id='foobar',
|
||||
cleanup_in_class=False,
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_create_cg_with_invalid_source_cgsnapshot_id_value_v2_4(
|
||||
self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.create_consistency_group,
|
||||
source_cgsnapshot_id='foobar',
|
||||
cleanup_in_class=False,
|
||||
version='2.4')
|
||||
|
||||
|
||||
@testtools.skipUnless(CONF.share.run_consistency_group_tests,
|
||||
'Consistency Group tests disabled.')
|
||||
class ConsistencyGroupsNegativeTest(base.BaseSharesTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ConsistencyGroupsNegativeTest, cls).resource_setup()
|
||||
# Create a consistency group
|
||||
cls.cg_name = data_utils.rand_name("tempest-cg-name")
|
||||
cls.cg_desc = data_utils.rand_name("tempest-cg-description")
|
||||
cls.consistency_group = cls.create_consistency_group(
|
||||
name=cls.cg_name,
|
||||
description=cls.cg_desc
|
||||
)
|
||||
# Create a share in the consistency group
|
||||
cls.share_name = data_utils.rand_name("tempest-share-name")
|
||||
cls.share_desc = data_utils.rand_name("tempest-share-description")
|
||||
cls.share = cls.create_share(
|
||||
name=cls.share_name,
|
||||
description=cls.share_desc,
|
||||
consistency_group_id=cls.consistency_group['id'],
|
||||
)
|
||||
# Create a cgsnapshot of the consistency group
|
||||
cls.cgsnap_name = data_utils.rand_name("tempest-cgsnap-name")
|
||||
cls.cgsnap_desc = data_utils.rand_name("tempest-cgsnap-description")
|
||||
cls.cgsnapshot = cls.create_cgsnapshot_wait_for_active(
|
||||
cls.consistency_group["id"],
|
||||
name=cls.cgsnap_name,
|
||||
description=cls.cgsnap_desc)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_cg_with_nonexistent_source_cgsnapshot_id_value_v2_4(self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.create_consistency_group,
|
||||
source_cgsnapshot_id=self.share['id'],
|
||||
cleanup_in_class=False,
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_cg_with_nonexistent_share_network_id_value_v2_4(self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.create_consistency_group,
|
||||
share_network_id=self.share['id'],
|
||||
cleanup_in_class=False,
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_cg_with_nonexistent_share_type_id_value_v2_4(self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.create_consistency_group,
|
||||
share_type_ids=[self.share['id']],
|
||||
cleanup_in_class=False,
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_cgsnapshot_with_nonexistent_cg_id_value_v2_4(self):
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.create_cgsnapshot_wait_for_active,
|
||||
self.share['id'],
|
||||
cleanup_in_class=False,
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_delete_cg_in_use_by_cgsnapshot_v2_4(self):
|
||||
# Attempt delete of share type
|
||||
self.assertRaises(lib_exc.Conflict,
|
||||
self.shares_v2_client.delete_consistency_group,
|
||||
self.consistency_group['id'],
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_delete_share_in_use_by_cgsnapshot_v2_4(self):
|
||||
# Attempt delete of share type
|
||||
params = {'consistency_group_id': self.share['consistency_group_id']}
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.shares_v2_client.delete_share,
|
||||
self.share['id'],
|
||||
params=params,
|
||||
version='2.4')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_delete_cg_containing_a_share_v2_4(self):
|
||||
self.assertRaises(lib_exc.Conflict,
|
||||
self.shares_v2_client.delete_consistency_group,
|
||||
self.consistency_group['id'],
|
||||
version='2.4')
|
||||
# Verify consistency group is not put into error state from conflict
|
||||
cg = self.shares_v2_client.get_consistency_group(
|
||||
self.consistency_group['id'], version='2.4')
|
||||
self.assertEqual('available', cg['status'])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_filter_shares_on_nonexistent_cg_id_v2_4(self):
|
||||
shares = self.shares_v2_client.list_shares(
|
||||
detailed=True,
|
||||
params={'consistency_group_id': self.share['id']},
|
||||
version='2.4'
|
||||
)
|
||||
|
||||
self.assertEqual(0, len(shares),
|
||||
'Incorrect number of shares returned. Expected 0, '
|
||||
'got %s.' % len(shares))
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_filter_shares_on_empty_cg_id_v2_4(self):
|
||||
consistency_group = self.create_consistency_group(
|
||||
name='tempest_cg',
|
||||
description='tempest_cg_desc',
|
||||
cleanup_in_class=False,
|
||||
version='2.4',
|
||||
)
|
||||
shares = self.shares_v2_client.list_shares(
|
||||
detailed=True,
|
||||
params={'consistency_group_id': consistency_group['id']},
|
||||
version='2.4',
|
||||
)
|
||||
|
||||
self.assertEqual(0, len(shares),
|
||||
'Incorrect number of shares returned. Expected 0, '
|
||||
'got %s.' % len(shares))
|
395
manila_tempest_tests/tests/api/test_share_group_actions.py
Normal file
395
manila_tempest_tests/tests/api/test_share_group_actions.py
Normal file
@ -0,0 +1,395 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2016 Andrew Kerr
|
||||
# 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 import config
|
||||
from tempest.lib.common.utils import data_utils
|
||||
import testtools
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.common import constants
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
|
||||
@base.skip_if_microversion_lt(constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
class ShareGroupActionsTest(base.BaseSharesTest):
|
||||
"""Covers share group functionality."""
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareGroupActionsTest, cls).resource_setup()
|
||||
|
||||
# Create first share group
|
||||
cls.share_group_name = data_utils.rand_name("tempest-sg-name")
|
||||
cls.share_group_desc = data_utils.rand_name("tempest-sg-description")
|
||||
cls.share_group = cls.create_share_group(
|
||||
name=cls.share_group_name, description=cls.share_group_desc)
|
||||
|
||||
# Create second share group for purposes of sorting and snapshot
|
||||
# filtering
|
||||
cls.share_group2 = cls.create_share_group(
|
||||
name=cls.share_group_name, description=cls.share_group_desc)
|
||||
|
||||
# Create 2 shares - inside first and second share groups
|
||||
cls.share_name = data_utils.rand_name("tempest-share-name")
|
||||
cls.share_desc = data_utils.rand_name("tempest-share-description")
|
||||
cls.share_size = 1
|
||||
cls.share_size2 = 2
|
||||
cls.shares = cls.create_shares([
|
||||
{'kwargs': {
|
||||
'name': cls.share_name,
|
||||
'description': cls.share_desc,
|
||||
'size': size,
|
||||
'share_group_id': sg_id,
|
||||
'experimental': True,
|
||||
}} for size, sg_id in ((cls.share_size, cls.share_group['id']),
|
||||
(cls.share_size2, cls.share_group['id']),
|
||||
(cls.share_size, cls.share_group2['id']))
|
||||
])
|
||||
|
||||
# Create share group snapshots
|
||||
cls.sg_snap_name = data_utils.rand_name("tempest-sg-snap-name")
|
||||
cls.sg_snap_desc = data_utils.rand_name("tempest-sg-snap-desc")
|
||||
|
||||
cls.sg_snapshot = cls.create_share_group_snapshot_wait_for_active(
|
||||
cls.share_group["id"],
|
||||
name=cls.sg_snap_name,
|
||||
description=cls.sg_snap_desc,
|
||||
)
|
||||
|
||||
cls.sg_snapshot2 = cls.create_share_group_snapshot_wait_for_active(
|
||||
cls.share_group2['id'],
|
||||
name=cls.sg_snap_name,
|
||||
description=cls.sg_snap_desc,
|
||||
)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_share_group_min_supported_sg_microversion(self):
|
||||
|
||||
# Get share group
|
||||
share_group = self.shares_v2_client.get_share_group(
|
||||
self.share_group['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
|
||||
# Verify keys
|
||||
actual_keys = set(share_group.keys())
|
||||
self.assertTrue(
|
||||
constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS.issubset(actual_keys),
|
||||
'Not all required keys returned for share group %s. '
|
||||
'Expected at least: %s, found %s' % (
|
||||
share_group['id'],
|
||||
constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS,
|
||||
actual_keys))
|
||||
|
||||
# Verify values
|
||||
self.assertEqual(self.share_group_name, share_group["name"])
|
||||
self.assertEqual(self.share_group_desc, share_group["description"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_share_min_supported_sg_microversion(self):
|
||||
|
||||
# Get share
|
||||
share = self.shares_v2_client.get_share(
|
||||
self.shares[0]['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
experimental=True)
|
||||
|
||||
# Verify keys
|
||||
expected_keys = {
|
||||
"status", "description", "links", "availability_zone",
|
||||
"created_at", "share_proto", "name", "snapshot_id",
|
||||
"id", "size", "share_group_id",
|
||||
}
|
||||
actual_keys = set(share.keys())
|
||||
self.assertTrue(
|
||||
expected_keys.issubset(actual_keys),
|
||||
'Not all required keys returned for share %s. '
|
||||
'Expected at least: %s, found %s' % (
|
||||
share['id'], expected_keys, actual_keys))
|
||||
|
||||
# Verify values
|
||||
self.assertEqual(self.share_name, share["name"])
|
||||
self.assertEqual(self.share_desc, share["description"])
|
||||
self.assertEqual(self.share_size, int(share["size"]))
|
||||
self.assertEqual(self.share_group["id"], share["share_group_id"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_share_groups_min(self):
|
||||
|
||||
# List share groups
|
||||
share_groups = self.shares_v2_client.list_share_groups(
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
# Verify keys
|
||||
self.assertGreater(len(share_groups), 0)
|
||||
for sg in share_groups:
|
||||
keys = set(sg.keys())
|
||||
self.assertEqual(
|
||||
constants.SHARE_GROUP_SIMPLE_KEYS,
|
||||
keys,
|
||||
'Incorrect keys returned for share group %s. '
|
||||
'Expected: %s, found %s' % (
|
||||
sg['id'],
|
||||
constants.SHARE_GROUP_SIMPLE_KEYS,
|
||||
','.join(keys)))
|
||||
|
||||
# Share group ids are in list exactly once
|
||||
for sg_id in (self.share_group["id"], self.share_group2["id"]):
|
||||
gen = [sg["id"] for sg in share_groups if sg["id"] == sg_id]
|
||||
msg = ("Expected id %s exactly once in share group list" % sg_id)
|
||||
self.assertEqual(1, len(gen), msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_list_share_groups_with_detail_min(self):
|
||||
|
||||
# List share groups
|
||||
share_groups = self.shares_v2_client.list_share_groups(
|
||||
detailed=True, version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
# Verify keys
|
||||
for sg in share_groups:
|
||||
keys = set(sg.keys())
|
||||
self.assertTrue(
|
||||
constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS.issubset(
|
||||
keys),
|
||||
'Not all required keys returned for share group %s. '
|
||||
'Expected at least: %s, found %s' % (
|
||||
sg['id'],
|
||||
constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS,
|
||||
','.join(keys),
|
||||
)
|
||||
)
|
||||
|
||||
# Share group ids are in list exactly once
|
||||
for group_id in (self.share_group["id"], self.share_group2["id"]):
|
||||
gen = [share_group["id"] for share_group in share_groups
|
||||
if share_group["id"] == group_id]
|
||||
msg = ("Expected id %s exactly once in share group list" %
|
||||
group_id)
|
||||
self.assertEqual(1, len(gen), msg)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_filter_shares_by_share_group_id_min(self):
|
||||
shares = self.shares_v2_client.list_shares(
|
||||
detailed=True,
|
||||
params={'share_group_id': self.share_group['id']},
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
experimental=True,
|
||||
)
|
||||
|
||||
share_ids = [share['id'] for share in shares]
|
||||
|
||||
self.assertEqual(
|
||||
2, len(shares),
|
||||
'Incorrect number of shares returned. '
|
||||
'Expected 2, got %s' % len(shares))
|
||||
self.assertIn(
|
||||
self.shares[0]['id'], share_ids,
|
||||
'Share %s expected in returned list, but got %s' % (
|
||||
self.shares[0]['id'], share_ids))
|
||||
self.assertIn(
|
||||
self.shares[1]['id'], share_ids,
|
||||
'Share %s expected in returned list, but got %s' % (
|
||||
self.shares[0]['id'], share_ids))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_share_group_snapshot_min(self):
|
||||
# Get share group snapshot
|
||||
sg_snapshot = self.shares_v2_client.get_share_group_snapshot(
|
||||
self.sg_snapshot['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
|
||||
# Verify keys
|
||||
actual_keys = set(sg_snapshot.keys())
|
||||
self.assertTrue(
|
||||
constants.SHARE_GROUP_SNAPSHOT_DETAIL_REQUIRED_KEYS.issubset(
|
||||
actual_keys),
|
||||
'Not all required keys returned for share group %s. '
|
||||
'Expected at least: %s, found %s' % (
|
||||
sg_snapshot['id'],
|
||||
constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS,
|
||||
actual_keys,
|
||||
)
|
||||
)
|
||||
|
||||
# Verify values
|
||||
self.assertEqual(self.sg_snap_name, sg_snapshot["name"])
|
||||
self.assertEqual(self.sg_snap_desc, sg_snapshot["description"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_share_group_snapshot_members_min(self):
|
||||
sg_snapshot = self.shares_v2_client.get_share_group_snapshot(
|
||||
self.sg_snapshot['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
sg_snapshot_members = sg_snapshot['members']
|
||||
member_share_ids = [m['share_id'] for m in sg_snapshot_members]
|
||||
self.assertEqual(
|
||||
2, len(sg_snapshot_members),
|
||||
'Unexpected number of share group snapshot members. '
|
||||
'Expected 2, got %s.' % len(sg_snapshot_members))
|
||||
# Verify each share is represented in the share group snapshot
|
||||
# appropriately
|
||||
for share_id in (self.shares[0]['id'], self.shares[1]['id']):
|
||||
self.assertIn(
|
||||
share_id, member_share_ids,
|
||||
'Share missing %s missing from share group '
|
||||
'snapshot. Found %s.' % (share_id, member_share_ids))
|
||||
for share in (self.shares[0], self.shares[1]):
|
||||
for member in sg_snapshot_members:
|
||||
if share['id'] == member['share_id']:
|
||||
self.assertEqual(share['size'], member['size'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_share_group_from_populated_share_group_snapshot_min(self):
|
||||
|
||||
sg_snapshot = self.shares_v2_client.get_share_group_snapshot(
|
||||
self.sg_snapshot['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
snapshot_members = sg_snapshot['members']
|
||||
|
||||
new_share_group = self.create_share_group(
|
||||
cleanup_in_class=False,
|
||||
source_share_group_snapshot_id=self.sg_snapshot['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
|
||||
new_share_group = self.shares_v2_client.get_share_group(
|
||||
new_share_group['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
|
||||
# Verify that share_network information matches source share group
|
||||
self.assertEqual(
|
||||
self.share_group['share_network_id'],
|
||||
new_share_group['share_network_id'])
|
||||
|
||||
new_shares = self.shares_v2_client.list_shares(
|
||||
params={'share_group_id': new_share_group['id']},
|
||||
detailed=True,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
experimental=True,
|
||||
)
|
||||
|
||||
# Verify each new share is available
|
||||
for share in new_shares:
|
||||
self.assertEqual(
|
||||
'available', share['status'],
|
||||
'Share %s is not in available status.' % share['id'])
|
||||
|
||||
# Verify each sgsnapshot member is represented in the new sg
|
||||
# appropriately
|
||||
share_source_member_ids = [
|
||||
share['source_share_group_snapshot_member_id']
|
||||
for share in new_shares]
|
||||
for member in snapshot_members:
|
||||
self.assertIn(
|
||||
member['id'], share_source_member_ids,
|
||||
'Share group snapshot member %s not represented by '
|
||||
'share group %s.' % (member['id'], new_share_group['id']))
|
||||
for share in new_shares:
|
||||
if (share['source_share_group_snapshot_member_id'] == (
|
||||
member['id'])):
|
||||
self.assertEqual(member['size'], share['size'])
|
||||
self.assertEqual(
|
||||
self.share_group['share_network_id'],
|
||||
share['share_network_id'])
|
||||
|
||||
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
|
||||
@base.skip_if_microversion_lt(constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
class ShareGroupRenameTest(base.BaseSharesTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareGroupRenameTest, cls).resource_setup()
|
||||
|
||||
# Create share group
|
||||
cls.share_group_name = data_utils.rand_name("tempest-sg-name")
|
||||
cls.share_group_desc = data_utils.rand_name("tempest-sg-description")
|
||||
cls.share_group = cls.create_share_group(
|
||||
name=cls.share_group_name,
|
||||
description=cls.share_group_desc,
|
||||
)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_update_share_group_min(self):
|
||||
|
||||
# Get share_group
|
||||
share_group = self.shares_v2_client.get_share_group(
|
||||
self.share_group['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION
|
||||
)
|
||||
self.assertEqual(self.share_group_name, share_group["name"])
|
||||
self.assertEqual(self.share_group_desc, share_group["description"])
|
||||
|
||||
# Update share_group
|
||||
new_name = data_utils.rand_name("tempest-new-name")
|
||||
new_desc = data_utils.rand_name("tempest-new-description")
|
||||
updated = self.shares_v2_client.update_share_group(
|
||||
share_group["id"],
|
||||
name=new_name,
|
||||
description=new_desc,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
self.assertEqual(new_name, updated["name"])
|
||||
self.assertEqual(new_desc, updated["description"])
|
||||
|
||||
# Get share_group
|
||||
share_group = self.shares_v2_client.get_share_group(
|
||||
self.share_group['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
self.assertEqual(new_name, share_group["name"])
|
||||
self.assertEqual(new_desc, share_group["description"])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_update_read_share_group_with_unicode_min(self):
|
||||
value1 = u'ಠ_ಠ'
|
||||
value2 = u'ಠ_ರೃ'
|
||||
|
||||
# Create share_group
|
||||
share_group = self.create_share_group(
|
||||
cleanup_in_class=False,
|
||||
name=value1,
|
||||
description=value1,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
self.assertEqual(value1, share_group["name"])
|
||||
self.assertEqual(value1, share_group["description"])
|
||||
|
||||
# Update share group
|
||||
updated = self.shares_v2_client.update_share_group(
|
||||
share_group["id"],
|
||||
name=value2,
|
||||
description=value2,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
self.assertEqual(value2, updated["name"])
|
||||
self.assertEqual(value2, updated["description"])
|
||||
|
||||
# Get share group
|
||||
share_group = self.shares_v2_client.get_share_group(
|
||||
share_group['id'], version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
self.assertEqual(value2, share_group["name"])
|
||||
self.assertEqual(value2, share_group["description"])
|
165
manila_tempest_tests/tests/api/test_share_groups.py
Normal file
165
manila_tempest_tests/tests/api/test_share_groups.py
Normal file
@ -0,0 +1,165 @@
|
||||
# Copyright 2016 Andrew Kerr
|
||||
# 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 import config
|
||||
from tempest.lib import exceptions as lib_exc
|
||||
import testtools
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.common import constants
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
|
||||
@base.skip_if_microversion_lt(constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
class ShareGroupsTest(base.BaseSharesTest):
|
||||
"""Covers share group functionality."""
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_populate_delete_share_group_min(self):
|
||||
# Create a share group
|
||||
share_group = self.create_share_group(
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
keys = set(share_group.keys())
|
||||
self.assertTrue(
|
||||
constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS.issubset(keys),
|
||||
'At least one expected element missing from share group '
|
||||
'response. Expected %(expected)s, got %(actual)s.' % {
|
||||
"expected": constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS,
|
||||
"actual": keys}
|
||||
)
|
||||
# Populate
|
||||
share = self.create_share(
|
||||
share_group_id=share_group['id'],
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
experimental=True)
|
||||
|
||||
# Delete
|
||||
params = {"share_group_id": share_group['id']}
|
||||
self.shares_v2_client.delete_share(
|
||||
share['id'],
|
||||
params=params,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
self.shares_client.wait_for_resource_deletion(share_id=share['id'])
|
||||
self.shares_v2_client.delete_share_group(
|
||||
share_group['id'], version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
share_group_id=share_group['id'])
|
||||
|
||||
# Verify
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.get_share_group, share_group['id'])
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound, self.shares_client.get_share, share['id'])
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_delete_empty_share_group_snapshot_min(self):
|
||||
# Create base share group
|
||||
share_group = self.create_share_group(
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
# Create share group snapshot
|
||||
sg_snapshot = self.create_share_group_snapshot_wait_for_active(
|
||||
share_group["id"],
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
keys = set(sg_snapshot.keys())
|
||||
self.assertTrue(
|
||||
constants.SHARE_GROUP_SNAPSHOT_DETAIL_REQUIRED_KEYS.issubset(keys),
|
||||
'At least one expected element missing from share group snapshot '
|
||||
'response. Expected %(e)s, got %(a)s.' % {
|
||||
"e": constants.SHARE_GROUP_SNAPSHOT_DETAIL_REQUIRED_KEYS,
|
||||
"a": keys})
|
||||
|
||||
sg_snapshot_members = sg_snapshot['members']
|
||||
self.assertEmpty(
|
||||
sg_snapshot_members,
|
||||
'Expected 0 share_group_snapshot members, got %s' % len(
|
||||
sg_snapshot_members))
|
||||
|
||||
# Delete snapshot
|
||||
self.shares_v2_client.delete_share_group_snapshot(
|
||||
sg_snapshot["id"], version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
self.shares_v2_client.wait_for_resource_deletion(
|
||||
share_group_snapshot_id=sg_snapshot["id"])
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.get_share_group_snapshot,
|
||||
sg_snapshot['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_share_group_from_empty_share_group_snapshot_min(self):
|
||||
# Create base share group
|
||||
share_group = self.create_share_group(
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
# Create share group snapshot
|
||||
sg_snapshot = self.create_share_group_snapshot_wait_for_active(
|
||||
share_group["id"], cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
snapshot_members = sg_snapshot['members']
|
||||
|
||||
self.assertEmpty(
|
||||
snapshot_members,
|
||||
'Expected 0 share group snapshot members, got %s' %
|
||||
len(snapshot_members))
|
||||
|
||||
new_share_group = self.create_share_group(
|
||||
cleanup_in_class=False,
|
||||
source_share_group_snapshot_id=sg_snapshot['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
new_shares = self.shares_v2_client.list_shares(
|
||||
params={'share_group_id': new_share_group['id']},
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION, experimental=True)
|
||||
|
||||
self.assertEmpty(
|
||||
new_shares, 'Expected 0 new shares, got %s' % len(new_shares))
|
||||
|
||||
msg = ('Expected source_ishare_group_snapshot_id %s '
|
||||
'as source of share group %s' % (
|
||||
sg_snapshot['id'],
|
||||
new_share_group['source_share_group_snapshot_id']))
|
||||
self.assertEqual(
|
||||
new_share_group['source_share_group_snapshot_id'],
|
||||
sg_snapshot['id'],
|
||||
msg)
|
||||
|
||||
msg = ('Unexpected share_types on new share group. Expected '
|
||||
'%s, got %s.' % (share_group['share_types'],
|
||||
new_share_group['share_types']))
|
||||
self.assertEqual(
|
||||
sorted(share_group['share_types']),
|
||||
sorted(new_share_group['share_types']), msg)
|
||||
|
||||
# Assert the share_network information is the same
|
||||
msg = 'Expected share_network %s as share_network of cg %s' % (
|
||||
share_group['share_network_id'],
|
||||
new_share_group['share_network_id'])
|
||||
self.assertEqual(
|
||||
share_group['share_network_id'],
|
||||
new_share_group['share_network_id'],
|
||||
msg)
|
239
manila_tempest_tests/tests/api/test_share_groups_negative.py
Normal file
239
manila_tempest_tests/tests/api/test_share_groups_negative.py
Normal file
@ -0,0 +1,239 @@
|
||||
# Copyright 2016 Andrew Kerr
|
||||
# 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 import config
|
||||
from tempest.lib.common.utils import data_utils
|
||||
from tempest.lib import exceptions as lib_exc
|
||||
import testtools
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.common import constants
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
|
||||
@base.skip_if_microversion_lt(constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
class ShareGroupsNegativeTest(base.BaseSharesTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(ShareGroupsNegativeTest, cls).resource_setup()
|
||||
# Create a share group
|
||||
cls.share_group_name = data_utils.rand_name("tempest-sg-name")
|
||||
cls.share_group_desc = data_utils.rand_name("tempest-sg-description")
|
||||
cls.share_group = cls.create_share_group(
|
||||
name=cls.share_group_name,
|
||||
description=cls.share_group_desc
|
||||
)
|
||||
# Create a share in the share group
|
||||
cls.share_name = data_utils.rand_name("tempest-share-name")
|
||||
cls.share_desc = data_utils.rand_name("tempest-share-description")
|
||||
cls.share_size = 1
|
||||
cls.share = cls.create_share(
|
||||
name=cls.share_name,
|
||||
description=cls.share_desc,
|
||||
size=cls.share_size,
|
||||
share_group_id=cls.share_group['id'],
|
||||
experimental=True,
|
||||
)
|
||||
# Create a share group snapshot of the share group
|
||||
cls.sg_snap_name = data_utils.rand_name("tempest-sg-snap-name")
|
||||
cls.sg_snap_desc = data_utils.rand_name(
|
||||
"tempest-group-snap-description")
|
||||
cls.sg_snapshot = cls.create_share_group_snapshot_wait_for_active(
|
||||
cls.share_group["id"],
|
||||
name=cls.sg_snap_name,
|
||||
description=cls.sg_snap_desc
|
||||
)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_sg_with_invalid_source_sg_snapshot_id_value_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share_group,
|
||||
source_share_group_snapshot_id='foobar',
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_sg_with_nonexistent_source_sg_snapshot_id_value_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share_group,
|
||||
source_share_group_snapshot_id=self.share['id'],
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_sg_with_invalid_share_network_id_value_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share_group,
|
||||
share_network_id='foobar',
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_group_with_nonexistent_share_network_id_value_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share_group,
|
||||
share_network_id=self.share['id'],
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_sg_with_invalid_share_type_id_value_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share_group,
|
||||
share_type_ids=['foobar'],
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_sg_with_nonexistent_share_type_id_value_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share_group,
|
||||
share_type_ids=[self.share['id']],
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_sg_snapshot_with_invalid_sg_id_value_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share_group_snapshot_wait_for_active,
|
||||
'foobar',
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_create_sg_snapshot_with_nonexistent_sg_id_value_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
self.create_share_group_snapshot_wait_for_active,
|
||||
self.share['id'],
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_sg_with_invalid_id_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.get_share_group,
|
||||
"invalid_share_group_id",
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_get_sg_without_passing_group_id_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.get_share_group,
|
||||
'', version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_update_sg_with_invalid_id_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.update_share_group,
|
||||
'invalid_share_group_id',
|
||||
name='new_name',
|
||||
description='new_description',
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_delete_sg_with_invalid_id_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.delete_share_group,
|
||||
"invalid_share_group_id",
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_delete_sg_without_passing_sg_id_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.delete_share_group,
|
||||
'', version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_delete_sg_in_use_by_sg_snapshot_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.Conflict,
|
||||
self.shares_v2_client.delete_share_group,
|
||||
self.share_group['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_delete_share_in_use_by_sg_snapshot_min(self):
|
||||
params = {'share_group_id': self.share['share_group_id']}
|
||||
self.assertRaises(
|
||||
lib_exc.Forbidden,
|
||||
self.shares_v2_client.delete_share,
|
||||
self.share['id'],
|
||||
params=params,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_delete_sg_containing_a_share_min(self):
|
||||
self.assertRaises(
|
||||
lib_exc.Conflict,
|
||||
self.shares_v2_client.delete_share_group,
|
||||
self.share_group['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
|
||||
# Verify share group is not put into error state from conflict
|
||||
sg = self.shares_v2_client.get_share_group(
|
||||
self.share_group['id'],
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION)
|
||||
self.assertEqual('available', sg['status'])
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_filter_shares_on_invalid_group_id_min(self):
|
||||
shares = self.shares_v2_client.list_shares(
|
||||
detailed=True,
|
||||
params={'share_group_id': 'foobar'},
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
self.assertEqual(0, len(shares), 'Incorrect number of shares returned')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_filter_shares_on_nonexistent_group_id_min(self):
|
||||
shares = self.shares_v2_client.list_shares(
|
||||
detailed=True,
|
||||
params={'share_group_id': self.share['id']},
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
self.assertEqual(0, len(shares), 'Incorrect number of shares returned')
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
|
||||
def test_filter_shares_on_empty_share_group_id_min(self):
|
||||
share_group = self.create_share_group(
|
||||
name='tempest_sg',
|
||||
description='tempest_sg_desc',
|
||||
cleanup_in_class=False,
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
shares = self.shares_v2_client.list_shares(
|
||||
detailed=True,
|
||||
params={'share_group_id': share_group['id']},
|
||||
version=constants.MIN_SHARE_GROUP_MICROVERSION,
|
||||
)
|
||||
self.assertEqual(0, len(shares), 'Incorrect number of shares returned')
|
Loading…
Reference in New Issue
Block a user